eca54192b3827e9bcd99b69204a275a9691fc039
[WebKit-https.git] / Source / WebCore / html / canvas / CanvasRenderingContext2D.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
4  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5  * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
6  * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
7  * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "CanvasRenderingContext2D.h"
33
34 #include "AffineTransform.h"
35 #include "CSSFontSelector.h"
36 #include "CSSParser.h"
37 #include "CSSPropertyNames.h"
38 #include "CSSStyleSelector.h"
39 #include "CachedImage.h"
40 #include "CanvasGradient.h"
41 #include "CanvasPattern.h"
42 #include "CanvasStyle.h"
43 #include "Console.h"
44 #include "ExceptionCode.h"
45 #include "FloatConversion.h"
46 #include "FloatQuad.h"
47 #include "FontCache.h"
48 #include "GraphicsContext.h"
49 #include "HTMLCanvasElement.h"
50 #include "HTMLImageElement.h"
51 #include "HTMLMediaElement.h"
52 #include "HTMLNames.h"
53 #include "HTMLVideoElement.h"
54 #include "ImageBuffer.h"
55 #include "ImageData.h"
56 #include "KURL.h"
57 #include "Page.h"
58 #include "RenderHTMLCanvas.h"
59 #include "SecurityOrigin.h"
60 #include "Settings.h"
61 #include "StrokeStyleApplier.h"
62 #include "StylePropertySet.h"
63 #include "TextMetrics.h"
64 #include "TextRun.h"
65
66 #if USE(ACCELERATED_COMPOSITING)
67 #include "RenderLayer.h"
68 #endif
69
70 #include <wtf/ByteArray.h>
71 #include <wtf/CheckedArithmetic.h>
72 #include <wtf/MathExtras.h>
73 #include <wtf/OwnPtr.h>
74 #include <wtf/UnusedParam.h>
75
76 #if USE(CG)
77 #include <ApplicationServices/ApplicationServices.h>
78 #endif
79
80 using namespace std;
81
82 namespace WebCore {
83
84 using namespace HTMLNames;
85
86 static const char* const defaultFont = "10px sans-serif";
87
88 static bool isOriginClean(CachedImage* cachedImage, SecurityOrigin* securityOrigin)
89 {
90     if (!cachedImage->image()->hasSingleSecurityOrigin())
91         return false;
92     if (cachedImage->passesAccessControlCheck(securityOrigin))
93         return true;
94     return !securityOrigin->taintsCanvas(cachedImage->response().url());
95 }
96
97 class CanvasStrokeStyleApplier : public StrokeStyleApplier {
98 public:
99     CanvasStrokeStyleApplier(CanvasRenderingContext2D* canvasContext)
100         : m_canvasContext(canvasContext)
101     {
102     }
103
104     virtual void strokeStyle(GraphicsContext* c)
105     {
106         c->setStrokeThickness(m_canvasContext->lineWidth());
107         c->setLineCap(m_canvasContext->getLineCap());
108         c->setLineJoin(m_canvasContext->getLineJoin());
109         c->setMiterLimit(m_canvasContext->miterLimit());
110     }
111
112 private:
113     CanvasRenderingContext2D* m_canvasContext;
114 };
115
116 CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, bool usesCSSCompatibilityParseMode, bool usesDashboardCompatibilityMode)
117     : CanvasRenderingContext(canvas)
118     , m_stateStack(1)
119     , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode)
120 #if ENABLE(DASHBOARD_SUPPORT)
121     , m_usesDashboardCompatibilityMode(usesDashboardCompatibilityMode)
122 #endif
123 {
124 #if !ENABLE(DASHBOARD_SUPPORT)
125     ASSERT_UNUSED(usesDashboardCompatibilityMode, !usesDashboardCompatibilityMode);
126 #endif
127     if (GraphicsContext* context = canvas->drawingContext())
128         context->save();
129 }
130
131 void CanvasRenderingContext2D::unwindStateStack()
132 {
133     // Ensure that the state stack in the ImageBuffer's context
134     // is cleared before destruction, to avoid assertions in the
135     // GraphicsContext dtor.
136     if (size_t stackSize = m_stateStack.size()) {
137         if (GraphicsContext* context = canvas()->existingDrawingContext()) {
138             while (stackSize--)
139                 context->restore();
140         }
141     }
142 }
143
144 CanvasRenderingContext2D::~CanvasRenderingContext2D()
145 {
146 #if !ASSERT_DISABLED
147     unwindStateStack();
148 #endif
149 }
150
151 bool CanvasRenderingContext2D::isAccelerated() const
152 {
153 #if USE(IOSURFACE_CANVAS_BACKING_STORE) || ENABLE(ACCELERATED_2D_CANVAS)
154     return canvas()->hasCreatedImageBuffer() && drawingContext() && drawingContext()->isAcceleratedContext();
155 #else
156     return false;
157 #endif
158 }
159
160 void CanvasRenderingContext2D::reset()
161 {
162     unwindStateStack();
163     m_stateStack.resize(1);
164     m_stateStack.first() = State();
165     m_path.clear();
166     if (GraphicsContext* context = canvas()->drawingContext())
167         context->save();
168 }
169
170 CanvasRenderingContext2D::State::State()
171     : m_strokeStyle(CanvasStyle::createFromRGBA(Color::black))
172     , m_fillStyle(CanvasStyle::createFromRGBA(Color::black))
173     , m_lineWidth(1)
174     , m_lineCap(ButtCap)
175     , m_lineJoin(MiterJoin)
176     , m_miterLimit(10)
177     , m_shadowBlur(0)
178     , m_shadowColor(Color::transparent)
179     , m_globalAlpha(1)
180     , m_globalComposite(CompositeSourceOver)
181     , m_invertibleCTM(true)
182     , m_lineDashOffset(0)
183     , m_textAlign(StartTextAlign)
184     , m_textBaseline(AlphabeticTextBaseline)
185     , m_unparsedFont(defaultFont)
186     , m_realizedFont(false)
187 {
188 }
189
190 CanvasRenderingContext2D::State::State(const State& other)
191     : FontSelectorClient()
192     , m_unparsedStrokeColor(other.m_unparsedStrokeColor)
193     , m_unparsedFillColor(other.m_unparsedFillColor)
194     , m_strokeStyle(other.m_strokeStyle)
195     , m_fillStyle(other.m_fillStyle)
196     , m_lineWidth(other.m_lineWidth)
197     , m_lineCap(other.m_lineCap)
198     , m_lineJoin(other.m_lineJoin)
199     , m_miterLimit(other.m_miterLimit)
200     , m_shadowOffset(other.m_shadowOffset)
201     , m_shadowBlur(other.m_shadowBlur)
202     , m_shadowColor(other.m_shadowColor)
203     , m_globalAlpha(other.m_globalAlpha)
204     , m_globalComposite(other.m_globalComposite)
205     , m_transform(other.m_transform)
206     , m_invertibleCTM(other.m_invertibleCTM)
207     , m_lineDashOffset(other.m_lineDashOffset)
208     , m_textAlign(other.m_textAlign)
209     , m_textBaseline(other.m_textBaseline)
210     , m_unparsedFont(other.m_unparsedFont)
211     , m_font(other.m_font)
212     , m_realizedFont(other.m_realizedFont)
213 {
214     if (m_realizedFont)
215         m_font.fontSelector()->registerForInvalidationCallbacks(this);
216 }
217
218 CanvasRenderingContext2D::State& CanvasRenderingContext2D::State::operator=(const State& other)
219 {
220     if (this == &other)
221         return *this;
222
223     if (m_realizedFont)
224         m_font.fontSelector()->unregisterForInvalidationCallbacks(this);
225
226     m_unparsedStrokeColor = other.m_unparsedStrokeColor;
227     m_unparsedFillColor = other.m_unparsedFillColor;
228     m_strokeStyle = other.m_strokeStyle;
229     m_fillStyle = other.m_fillStyle;
230     m_lineWidth = other.m_lineWidth;
231     m_lineCap = other.m_lineCap;
232     m_lineJoin = other.m_lineJoin;
233     m_miterLimit = other.m_miterLimit;
234     m_shadowOffset = other.m_shadowOffset;
235     m_shadowBlur = other.m_shadowBlur;
236     m_shadowColor = other.m_shadowColor;
237     m_globalAlpha = other.m_globalAlpha;
238     m_globalComposite = other.m_globalComposite;
239     m_transform = other.m_transform;
240     m_invertibleCTM = other.m_invertibleCTM;
241     m_textAlign = other.m_textAlign;
242     m_textBaseline = other.m_textBaseline;
243     m_unparsedFont = other.m_unparsedFont;
244     m_font = other.m_font;
245     m_realizedFont = other.m_realizedFont;
246
247     if (m_realizedFont)
248         m_font.fontSelector()->registerForInvalidationCallbacks(this);
249
250     return *this;
251 }
252
253 CanvasRenderingContext2D::State::~State()
254 {
255     if (m_realizedFont)
256         m_font.fontSelector()->unregisterForInvalidationCallbacks(this);
257 }
258
259 void CanvasRenderingContext2D::State::fontsNeedUpdate(FontSelector* fontSelector)
260 {
261     ASSERT_ARG(fontSelector, fontSelector == m_font.fontSelector());
262     ASSERT(m_realizedFont);
263
264     m_font.update(fontSelector);
265 }
266
267 void CanvasRenderingContext2D::save()
268 {
269     ASSERT(m_stateStack.size() >= 1);
270     m_stateStack.append(state());
271     GraphicsContext* c = drawingContext();
272     if (!c)
273         return;
274     c->save();
275 }
276
277 void CanvasRenderingContext2D::restore()
278 {
279     ASSERT(m_stateStack.size() >= 1);
280     if (m_stateStack.size() <= 1)
281         return;
282     m_path.transform(state().m_transform);
283     m_stateStack.removeLast();
284     m_path.transform(state().m_transform.inverse());
285     GraphicsContext* c = drawingContext();
286     if (!c)
287         return;
288     c->restore();
289 }
290
291 void CanvasRenderingContext2D::setAllAttributesToDefault()
292 {
293     state().m_globalAlpha = 1;
294     state().m_shadowOffset = FloatSize();
295     state().m_shadowBlur = 0;
296     state().m_shadowColor = Color::transparent;
297     state().m_globalComposite = CompositeSourceOver;
298
299     GraphicsContext* context = drawingContext();
300     if (!context)
301         return;
302
303     applyShadow();
304     context->setAlpha(1);
305     context->setCompositeOperation(CompositeSourceOver);
306 }
307
308 CanvasStyle* CanvasRenderingContext2D::strokeStyle() const
309 {
310     return state().m_strokeStyle.get();
311 }
312
313 void CanvasRenderingContext2D::setStrokeStyle(PassRefPtr<CanvasStyle> prpStyle)
314 {
315     RefPtr<CanvasStyle> style = prpStyle;
316
317     if (!style)
318         return;
319
320     if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(*style))
321         return;
322
323     if (style->isCurrentColor()) {
324         if (style->hasOverrideAlpha())
325             style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentColor(canvas()), style->overrideAlpha()));
326         else
327             style = CanvasStyle::createFromRGBA(currentColor(canvas()));
328     } else
329         checkOrigin(style->canvasPattern());
330
331     state().m_strokeStyle = style.release();
332     GraphicsContext* c = drawingContext();
333     if (!c)
334         return;
335     state().m_strokeStyle->applyStrokeColor(c);
336     state().m_unparsedStrokeColor = String();
337 }
338
339 CanvasStyle* CanvasRenderingContext2D::fillStyle() const
340 {
341     return state().m_fillStyle.get();
342 }
343
344 void CanvasRenderingContext2D::setFillStyle(PassRefPtr<CanvasStyle> prpStyle)
345 {
346     RefPtr<CanvasStyle> style = prpStyle;
347
348     if (!style)
349         return;
350
351     if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(*style))
352         return;
353
354     if (style->isCurrentColor()) {
355         if (style->hasOverrideAlpha())
356             style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentColor(canvas()), style->overrideAlpha()));
357         else
358             style = CanvasStyle::createFromRGBA(currentColor(canvas()));
359     } else
360         checkOrigin(style->canvasPattern());
361
362     state().m_fillStyle = style.release();
363     GraphicsContext* c = drawingContext();
364     if (!c)
365         return;
366     state().m_fillStyle->applyFillColor(c);
367     state().m_unparsedFillColor = String();
368 }
369
370 float CanvasRenderingContext2D::lineWidth() const
371 {
372     return state().m_lineWidth;
373 }
374
375 void CanvasRenderingContext2D::setLineWidth(float width)
376 {
377     if (!(isfinite(width) && width > 0))
378         return;
379     state().m_lineWidth = width;
380     GraphicsContext* c = drawingContext();
381     if (!c)
382         return;
383     c->setStrokeThickness(width);
384 }
385
386 String CanvasRenderingContext2D::lineCap() const
387 {
388     return lineCapName(state().m_lineCap);
389 }
390
391 void CanvasRenderingContext2D::setLineCap(const String& s)
392 {
393     LineCap cap;
394     if (!parseLineCap(s, cap))
395         return;
396     state().m_lineCap = cap;
397     GraphicsContext* c = drawingContext();
398     if (!c)
399         return;
400     c->setLineCap(cap);
401 }
402
403 String CanvasRenderingContext2D::lineJoin() const
404 {
405     return lineJoinName(state().m_lineJoin);
406 }
407
408 void CanvasRenderingContext2D::setLineJoin(const String& s)
409 {
410     LineJoin join;
411     if (!parseLineJoin(s, join))
412         return;
413     state().m_lineJoin = join;
414     GraphicsContext* c = drawingContext();
415     if (!c)
416         return;
417     c->setLineJoin(join);
418 }
419
420 float CanvasRenderingContext2D::miterLimit() const
421 {
422     return state().m_miterLimit;
423 }
424
425 void CanvasRenderingContext2D::setMiterLimit(float limit)
426 {
427     if (!(isfinite(limit) && limit > 0))
428         return;
429     state().m_miterLimit = limit;
430     GraphicsContext* c = drawingContext();
431     if (!c)
432         return;
433     c->setMiterLimit(limit);
434 }
435
436 float CanvasRenderingContext2D::shadowOffsetX() const
437 {
438     return state().m_shadowOffset.width();
439 }
440
441 void CanvasRenderingContext2D::setShadowOffsetX(float x)
442 {
443     if (!isfinite(x))
444         return;
445     state().m_shadowOffset.setWidth(x);
446     applyShadow();
447 }
448
449 float CanvasRenderingContext2D::shadowOffsetY() const
450 {
451     return state().m_shadowOffset.height();
452 }
453
454 void CanvasRenderingContext2D::setShadowOffsetY(float y)
455 {
456     if (!isfinite(y))
457         return;
458     state().m_shadowOffset.setHeight(y);
459     applyShadow();
460 }
461
462 float CanvasRenderingContext2D::shadowBlur() const
463 {
464     return state().m_shadowBlur;
465 }
466
467 void CanvasRenderingContext2D::setShadowBlur(float blur)
468 {
469     if (!(isfinite(blur) && blur >= 0))
470         return;
471     state().m_shadowBlur = blur;
472     applyShadow();
473 }
474
475 String CanvasRenderingContext2D::shadowColor() const
476 {
477     return Color(state().m_shadowColor).serialized();
478 }
479
480 void CanvasRenderingContext2D::setShadowColor(const String& color)
481 {
482     if (!parseColorOrCurrentColor(state().m_shadowColor, color, canvas()))
483         return;
484     applyShadow();
485 }
486
487 const DashArray* CanvasRenderingContext2D::webkitLineDash() const
488 {
489     return &state().m_lineDash;
490 }
491
492 void CanvasRenderingContext2D::setWebkitLineDash(const DashArray& dash)
493 {
494     state().m_lineDash = dash;
495
496     GraphicsContext* c = drawingContext();
497     if (!c)
498         return;
499     c->setLineDash(state().m_lineDash, state().m_lineDashOffset);
500 }
501
502 float CanvasRenderingContext2D::webkitLineDashOffset() const
503 {
504     return state().m_lineDashOffset;
505 }
506
507 void CanvasRenderingContext2D::setWebkitLineDashOffset(float offset)
508 {
509     if (!isfinite(offset))
510         return;
511
512     state().m_lineDashOffset = offset;
513
514     GraphicsContext* c = drawingContext();
515     if (!c)
516         return;
517     c->setLineDash(state().m_lineDash, state().m_lineDashOffset);
518 }
519
520 float CanvasRenderingContext2D::globalAlpha() const
521 {
522     return state().m_globalAlpha;
523 }
524
525 void CanvasRenderingContext2D::setGlobalAlpha(float alpha)
526 {
527     if (!(alpha >= 0 && alpha <= 1))
528         return;
529     state().m_globalAlpha = alpha;
530     GraphicsContext* c = drawingContext();
531     if (!c)
532         return;
533     c->setAlpha(alpha);
534 }
535
536 String CanvasRenderingContext2D::globalCompositeOperation() const
537 {
538     return compositeOperatorName(state().m_globalComposite);
539 }
540
541 void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operation)
542 {
543     CompositeOperator op;
544     if (!parseCompositeOperator(operation, op))
545         return;
546     state().m_globalComposite = op;
547     GraphicsContext* c = drawingContext();
548     if (!c)
549         return;
550     c->setCompositeOperation(op);
551 }
552
553 void CanvasRenderingContext2D::scale(float sx, float sy)
554 {
555     GraphicsContext* c = drawingContext();
556     if (!c)
557         return;
558     if (!state().m_invertibleCTM)
559         return;
560
561     if (!isfinite(sx) | !isfinite(sy))
562         return;
563
564     AffineTransform newTransform = state().m_transform;
565     newTransform.scaleNonUniform(sx, sy);
566     if (!newTransform.isInvertible()) {
567         state().m_invertibleCTM = false;
568         return;
569     }
570
571     state().m_transform = newTransform;
572     c->scale(FloatSize(sx, sy));
573     m_path.transform(AffineTransform().scaleNonUniform(1.0 / sx, 1.0 / sy));
574 }
575
576 void CanvasRenderingContext2D::rotate(float angleInRadians)
577 {
578     GraphicsContext* c = drawingContext();
579     if (!c)
580         return;
581     if (!state().m_invertibleCTM)
582         return;
583
584     if (!isfinite(angleInRadians))
585         return;
586
587     AffineTransform newTransform = state().m_transform;
588     newTransform.rotate(angleInRadians / piDouble * 180.0);
589     if (!newTransform.isInvertible()) {
590         state().m_invertibleCTM = false;
591         return;
592     }
593
594     state().m_transform = newTransform;
595     c->rotate(angleInRadians);
596     m_path.transform(AffineTransform().rotate(-angleInRadians / piDouble * 180.0));
597 }
598
599 void CanvasRenderingContext2D::translate(float tx, float ty)
600 {
601     GraphicsContext* c = drawingContext();
602     if (!c)
603         return;
604     if (!state().m_invertibleCTM)
605         return;
606
607     if (!isfinite(tx) | !isfinite(ty))
608         return;
609
610     AffineTransform newTransform = state().m_transform;
611     newTransform.translate(tx, ty);
612     if (!newTransform.isInvertible()) {
613         state().m_invertibleCTM = false;
614         return;
615     }
616
617     state().m_transform = newTransform;
618     c->translate(tx, ty);
619     m_path.transform(AffineTransform().translate(-tx, -ty));
620 }
621
622 void CanvasRenderingContext2D::transform(float m11, float m12, float m21, float m22, float dx, float dy)
623 {
624     GraphicsContext* c = drawingContext();
625     if (!c)
626         return;
627     if (!state().m_invertibleCTM)
628         return;
629
630     if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) | !isfinite(m12) | !isfinite(m22) | !isfinite(dy))
631         return;
632
633     AffineTransform transform(m11, m12, m21, m22, dx, dy);
634     AffineTransform newTransform = state().m_transform * transform;
635     if (!newTransform.isInvertible()) {
636         state().m_invertibleCTM = false;
637         return;
638     }
639
640     state().m_transform = newTransform;
641     c->concatCTM(transform);
642     m_path.transform(transform.inverse());
643 }
644
645 void CanvasRenderingContext2D::setTransform(float m11, float m12, float m21, float m22, float dx, float dy)
646 {
647     GraphicsContext* c = drawingContext();
648     if (!c)
649         return;
650
651     if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) | !isfinite(m12) | !isfinite(m22) | !isfinite(dy))
652         return;
653
654     AffineTransform ctm = state().m_transform;
655     if (!ctm.isInvertible())
656         return;
657     c->setCTM(canvas()->baseTransform());
658     state().m_transform = AffineTransform();
659     m_path.transform(ctm);
660
661     state().m_invertibleCTM = true;
662     transform(m11, m12, m21, m22, dx, dy);
663 }
664
665 void CanvasRenderingContext2D::setStrokeColor(const String& color)
666 {
667     if (color == state().m_unparsedStrokeColor)
668         return;
669     setStrokeStyle(CanvasStyle::createFromString(color, canvas()->document()));
670     state().m_unparsedStrokeColor = color;
671 }
672
673 void CanvasRenderingContext2D::setStrokeColor(float grayLevel)
674 {
675     if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, 1.0f))
676         return;
677     setStrokeStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, 1.0f));
678 }
679
680 void CanvasRenderingContext2D::setStrokeColor(const String& color, float alpha)
681 {
682     setStrokeStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha));
683 }
684
685 void CanvasRenderingContext2D::setStrokeColor(float grayLevel, float alpha)
686 {
687     if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
688         return;
689     setStrokeStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, alpha));
690 }
691
692 void CanvasRenderingContext2D::setStrokeColor(float r, float g, float b, float a)
693 {
694     if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(r, g, b, a))
695         return;
696     setStrokeStyle(CanvasStyle::createFromRGBAChannels(r, g, b, a));
697 }
698
699 void CanvasRenderingContext2D::setStrokeColor(float c, float m, float y, float k, float a)
700 {
701     if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentCMYKA(c, m, y, k, a))
702         return;
703     setStrokeStyle(CanvasStyle::createFromCMYKAChannels(c, m, y, k, a));
704 }
705
706 void CanvasRenderingContext2D::setFillColor(const String& color)
707 {
708     if (color == state().m_unparsedFillColor)
709         return;
710     setFillStyle(CanvasStyle::createFromString(color, canvas()->document()));
711     state().m_unparsedFillColor = color;
712 }
713
714 void CanvasRenderingContext2D::setFillColor(float grayLevel)
715 {
716     if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, 1.0f))
717         return;
718     setFillStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, 1.0f));
719 }
720
721 void CanvasRenderingContext2D::setFillColor(const String& color, float alpha)
722 {
723     setFillStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha));
724 }
725
726 void CanvasRenderingContext2D::setFillColor(float grayLevel, float alpha)
727 {
728     if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
729         return;
730     setFillStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, alpha));
731 }
732
733 void CanvasRenderingContext2D::setFillColor(float r, float g, float b, float a)
734 {
735     if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(r, g, b, a))
736         return;
737     setFillStyle(CanvasStyle::createFromRGBAChannels(r, g, b, a));
738 }
739
740 void CanvasRenderingContext2D::setFillColor(float c, float m, float y, float k, float a)
741 {
742     if (state().m_fillStyle && state().m_fillStyle->isEquivalentCMYKA(c, m, y, k, a))
743         return;
744     setFillStyle(CanvasStyle::createFromCMYKAChannels(c, m, y, k, a));
745 }
746
747 void CanvasRenderingContext2D::beginPath()
748 {
749     m_path.clear();
750 }
751
752 void CanvasRenderingContext2D::closePath()
753 {
754     if (m_path.isEmpty())
755         return;
756
757     FloatRect boundRect = m_path.fastBoundingRect();
758     if (boundRect.width() || boundRect.height())
759         m_path.closeSubpath();
760 }
761
762 void CanvasRenderingContext2D::moveTo(float x, float y)
763 {
764     if (!isfinite(x) | !isfinite(y))
765         return;
766     if (!state().m_invertibleCTM)
767         return;
768     m_path.moveTo(FloatPoint(x, y));
769 }
770
771 void CanvasRenderingContext2D::lineTo(float x, float y)
772 {
773     if (!isfinite(x) | !isfinite(y))
774         return;
775     if (!state().m_invertibleCTM)
776         return;
777
778     FloatPoint p1 = FloatPoint(x, y);
779     if (!m_path.hasCurrentPoint())
780         m_path.moveTo(p1);
781     else if (p1 != m_path.currentPoint())
782         m_path.addLineTo(FloatPoint(x, y));
783 }
784
785 void CanvasRenderingContext2D::quadraticCurveTo(float cpx, float cpy, float x, float y)
786 {
787     if (!isfinite(cpx) | !isfinite(cpy) | !isfinite(x) | !isfinite(y))
788         return;
789     if (!state().m_invertibleCTM)
790         return;
791     if (!m_path.hasCurrentPoint())
792         m_path.moveTo(FloatPoint(cpx, cpy));
793
794     FloatPoint p1 = FloatPoint(x, y);
795     if (p1 != m_path.currentPoint())
796         m_path.addQuadCurveTo(FloatPoint(cpx, cpy), p1);
797 }
798
799 void CanvasRenderingContext2D::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y)
800 {
801     if (!isfinite(cp1x) | !isfinite(cp1y) | !isfinite(cp2x) | !isfinite(cp2y) | !isfinite(x) | !isfinite(y))
802         return;
803     if (!state().m_invertibleCTM)
804         return;
805     if (!m_path.hasCurrentPoint())
806         m_path.moveTo(FloatPoint(cp1x, cp1y));
807
808     FloatPoint p1 = FloatPoint(x, y);
809     if (p1 != m_path.currentPoint())
810         m_path.addBezierCurveTo(FloatPoint(cp1x, cp1y), FloatPoint(cp2x, cp2y), p1);
811 }
812
813 void CanvasRenderingContext2D::arcTo(float x1, float y1, float x2, float y2, float r, ExceptionCode& ec)
814 {
815     ec = 0;
816     if (!isfinite(x1) | !isfinite(y1) | !isfinite(x2) | !isfinite(y2) | !isfinite(r))
817         return;
818
819     if (r < 0) {
820         ec = INDEX_SIZE_ERR;
821         return;
822     }
823
824     if (!state().m_invertibleCTM)
825         return;
826
827     FloatPoint p1 = FloatPoint(x1, y1);
828     FloatPoint p2 = FloatPoint(x2, y2);
829
830     if (!m_path.hasCurrentPoint())
831         m_path.moveTo(p1);
832     else if (p1 == m_path.currentPoint() || p1 == p2 || !r)
833         lineTo(x1, y1);
834     else
835         m_path.addArcTo(p1, p2, r);
836 }
837
838 void CanvasRenderingContext2D::arc(float x, float y, float r, float sa, float ea, bool anticlockwise, ExceptionCode& ec)
839 {
840     ec = 0;
841     if (!isfinite(x) | !isfinite(y) | !isfinite(r) | !isfinite(sa) | !isfinite(ea))
842         return;
843
844     if (r < 0) {
845         ec = INDEX_SIZE_ERR;
846         return;
847     }
848
849     if (!r || sa == ea) {
850         // The arc is empty but we still need to draw the connecting line
851         lineTo(x + r * cosf(sa), y + r * sinf(sa));
852         return;
853     }
854
855     if (!state().m_invertibleCTM)
856         return;
857
858     // If 'sa' and 'ea' differ by more than 2Pi, just add a circle starting/ending at 'sa'
859     if (anticlockwise && sa - ea >= 2 * piFloat) {
860         m_path.addArc(FloatPoint(x, y), r, sa, sa - 2 * piFloat, anticlockwise);
861         return;
862     }
863     if (!anticlockwise && ea - sa >= 2 * piFloat) {
864         m_path.addArc(FloatPoint(x, y), r, sa, sa + 2 * piFloat, anticlockwise);
865         return;
866     }
867
868     m_path.addArc(FloatPoint(x, y), r, sa, ea, anticlockwise);
869 }
870
871 static bool validateRectForCanvas(float& x, float& y, float& width, float& height)
872 {
873     if (!isfinite(x) | !isfinite(y) | !isfinite(width) | !isfinite(height))
874         return false;
875
876     if (!width && !height)
877         return false;
878
879     if (width < 0) {
880         width = -width;
881         x -= width;
882     }
883
884     if (height < 0) {
885         height = -height;
886         y -= height;
887     }
888
889     return true;
890 }
891
892 void CanvasRenderingContext2D::rect(float x, float y, float width, float height)
893 {
894     if (!state().m_invertibleCTM)
895         return;
896
897     if (!isfinite(x) || !isfinite(y) || !isfinite(width) || !isfinite(height))
898         return;
899
900     if (!width && !height) {
901         m_path.moveTo(FloatPoint(x, y));
902         return;
903     }
904
905     m_path.addRect(FloatRect(x, y, width, height));
906 }
907
908 #if ENABLE(DASHBOARD_SUPPORT)
909 void CanvasRenderingContext2D::clearPathForDashboardBackwardCompatibilityMode()
910 {
911     if (m_usesDashboardCompatibilityMode)
912         m_path.clear();
913 }
914 #endif
915
916 static bool isFullCanvasCompositeMode(CompositeOperator op)
917 {
918     // See 4.8.11.1.3 Compositing
919     // CompositeSourceAtop and CompositeDestinationOut are not listed here as the platforms already
920     // implement the specification's behavior.
921     return op == CompositeSourceIn || op == CompositeSourceOut || op == CompositeDestinationIn || op == CompositeDestinationAtop;
922 }
923
924 void CanvasRenderingContext2D::fill()
925 {
926     GraphicsContext* c = drawingContext();
927     if (!c)
928         return;
929     if (!state().m_invertibleCTM)
930         return;
931
932     if (!m_path.isEmpty()) {
933         if (isFullCanvasCompositeMode(state().m_globalComposite)) {
934             fullCanvasCompositedFill(m_path);
935             didDrawEntireCanvas();
936         } else if (state().m_globalComposite == CompositeCopy) {
937             clearCanvas();
938             c->fillPath(m_path);
939             didDrawEntireCanvas();
940         } else {
941             c->fillPath(m_path);
942             didDraw(m_path.fastBoundingRect());
943         }
944     }
945
946 #if ENABLE(DASHBOARD_SUPPORT)
947     clearPathForDashboardBackwardCompatibilityMode();
948 #endif
949 }
950
951 void CanvasRenderingContext2D::stroke()
952 {
953     GraphicsContext* c = drawingContext();
954     if (!c)
955         return;
956     if (!state().m_invertibleCTM)
957         return;
958
959     if (!m_path.isEmpty()) {
960         FloatRect dirtyRect = m_path.fastBoundingRect();
961         // Fast approximation of the stroke's bounding rect.
962         // This yields a slightly oversized rect but is very fast
963         // compared to Path::strokeBoundingRect().
964         dirtyRect.inflate(state().m_miterLimit + state().m_lineWidth);
965
966         c->strokePath(m_path);
967         didDraw(dirtyRect);
968     }
969
970 #if ENABLE(DASHBOARD_SUPPORT)
971     clearPathForDashboardBackwardCompatibilityMode();
972 #endif
973 }
974
975 void CanvasRenderingContext2D::clip()
976 {
977     GraphicsContext* c = drawingContext();
978     if (!c)
979         return;
980     if (!state().m_invertibleCTM)
981         return;
982     c->canvasClip(m_path);
983 #if ENABLE(DASHBOARD_SUPPORT)
984     clearPathForDashboardBackwardCompatibilityMode();
985 #endif
986 }
987
988 bool CanvasRenderingContext2D::isPointInPath(const float x, const float y)
989 {
990     GraphicsContext* c = drawingContext();
991     if (!c)
992         return false;
993     if (!state().m_invertibleCTM)
994         return false;
995
996     FloatPoint point(x, y);
997     AffineTransform ctm = state().m_transform;
998     FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
999     if (!isfinite(transformedPoint.x()) || !isfinite(transformedPoint.y()))
1000         return false;
1001     return m_path.contains(transformedPoint);
1002 }
1003
1004 void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height)
1005 {
1006     if (!validateRectForCanvas(x, y, width, height))
1007         return;
1008     GraphicsContext* context = drawingContext();
1009     if (!context)
1010         return;
1011     if (!state().m_invertibleCTM)
1012         return;
1013     FloatRect rect(x, y, width, height);
1014
1015     save();
1016     setAllAttributesToDefault();
1017     context->clearRect(rect);
1018     didDraw(rect);
1019     restore();
1020 }
1021
1022 void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height)
1023 {
1024     if (!validateRectForCanvas(x, y, width, height))
1025         return;
1026
1027     GraphicsContext* c = drawingContext();
1028     if (!c)
1029         return;
1030     if (!state().m_invertibleCTM)
1031         return;
1032
1033     // from the HTML5 Canvas spec:
1034     // If x0 = x1 and y0 = y1, then the linear gradient must paint nothing
1035     // If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint nothing
1036     Gradient* gradient = c->fillGradient();
1037     if (gradient && gradient->isZeroSize())
1038         return;
1039
1040     FloatRect rect(x, y, width, height);
1041
1042     if (rectContainsCanvas(rect)) {
1043         c->fillRect(rect);
1044         didDrawEntireCanvas();
1045     } else if (isFullCanvasCompositeMode(state().m_globalComposite)) {
1046         fullCanvasCompositedFill(rect);
1047         didDrawEntireCanvas();
1048     } else if (state().m_globalComposite == CompositeCopy) {
1049         clearCanvas();
1050         c->fillRect(rect);
1051         didDrawEntireCanvas();
1052     } else {
1053         c->fillRect(rect);
1054         didDraw(rect);
1055     }
1056 }
1057
1058 void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height)
1059 {
1060     if (!validateRectForCanvas(x, y, width, height))
1061         return;
1062     strokeRect(x, y, width, height, state().m_lineWidth);
1063 }
1064
1065 void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height, float lineWidth)
1066 {
1067     if (!validateRectForCanvas(x, y, width, height))
1068         return;
1069
1070     if (!(lineWidth >= 0))
1071         return;
1072
1073     GraphicsContext* c = drawingContext();
1074     if (!c)
1075         return;
1076     if (!state().m_invertibleCTM)
1077         return;
1078
1079     FloatRect rect(x, y, width, height);
1080
1081     FloatRect boundingRect = rect;
1082     boundingRect.inflate(lineWidth / 2);
1083
1084     c->strokeRect(rect, lineWidth);
1085     didDraw(boundingRect);
1086 }
1087
1088 void CanvasRenderingContext2D::setShadow(float width, float height, float blur)
1089 {
1090     state().m_shadowOffset = FloatSize(width, height);
1091     state().m_shadowBlur = blur;
1092     state().m_shadowColor = Color::transparent;
1093     applyShadow();
1094 }
1095
1096 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color)
1097 {
1098     if (!parseColorOrCurrentColor(state().m_shadowColor, color, canvas()))
1099         return;
1100
1101     state().m_shadowOffset = FloatSize(width, height);
1102     state().m_shadowBlur = blur;
1103     applyShadow();
1104 }
1105
1106 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel)
1107 {
1108     state().m_shadowOffset = FloatSize(width, height);
1109     state().m_shadowBlur = blur;
1110     state().m_shadowColor = makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, 1.0f);
1111     applyShadow();
1112 }
1113
1114 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color, float alpha)
1115 {
1116     RGBA32 rgba;
1117
1118     if (!parseColorOrCurrentColor(rgba, color, canvas()))
1119         return;
1120
1121     state().m_shadowColor = colorWithOverrideAlpha(rgba, alpha);
1122     state().m_shadowOffset = FloatSize(width, height);
1123     state().m_shadowBlur = blur;
1124     applyShadow();
1125 }
1126
1127 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel, float alpha)
1128 {
1129     state().m_shadowOffset = FloatSize(width, height);
1130     state().m_shadowBlur = blur;
1131     state().m_shadowColor = makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, alpha);
1132     applyShadow();
1133 }
1134
1135 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float r, float g, float b, float a)
1136 {
1137     state().m_shadowOffset = FloatSize(width, height);
1138     state().m_shadowBlur = blur;
1139     state().m_shadowColor = makeRGBA32FromFloats(r, g, b, a);
1140     applyShadow();
1141 }
1142
1143 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a)
1144 {
1145     state().m_shadowOffset = FloatSize(width, height);
1146     state().m_shadowBlur = blur;
1147     state().m_shadowColor = makeRGBAFromCMYKA(c, m, y, k, a);
1148     applyShadow();
1149 }
1150
1151 void CanvasRenderingContext2D::clearShadow()
1152 {
1153     state().m_shadowOffset = FloatSize();
1154     state().m_shadowBlur = 0;
1155     state().m_shadowColor = Color::transparent;
1156     applyShadow();
1157 }
1158
1159 void CanvasRenderingContext2D::applyShadow()
1160 {
1161     GraphicsContext* c = drawingContext();
1162     if (!c)
1163         return;
1164
1165     if (shouldDrawShadows()) {
1166         float width = state().m_shadowOffset.width();
1167         float height = state().m_shadowOffset.height();
1168         c->setLegacyShadow(FloatSize(width, -height), state().m_shadowBlur, state().m_shadowColor, ColorSpaceDeviceRGB);
1169     } else
1170         c->setLegacyShadow(FloatSize(), 0, Color::transparent, ColorSpaceDeviceRGB);
1171 }
1172
1173 bool CanvasRenderingContext2D::shouldDrawShadows() const
1174 {
1175     return alphaChannel(state().m_shadowColor) && (state().m_shadowBlur || !state().m_shadowOffset.isZero());
1176 }
1177
1178 static LayoutSize size(HTMLImageElement* image)
1179 {
1180     if (CachedImage* cachedImage = image->cachedImage())
1181         return cachedImage->imageSizeForRenderer(image->renderer(), 1.0f); // FIXME: Not sure about this.
1182     return IntSize();
1183 }
1184
1185 #if ENABLE(VIDEO)
1186 static IntSize size(HTMLVideoElement* video)
1187 {
1188     if (MediaPlayer* player = video->player())
1189         return player->naturalSize();
1190     return IntSize();
1191 }
1192 #endif
1193
1194 static inline FloatRect normalizeRect(const FloatRect& rect)
1195 {
1196     return FloatRect(min(rect.x(), rect.maxX()),
1197         min(rect.y(), rect.maxY()),
1198         max(rect.width(), -rect.width()),
1199         max(rect.height(), -rect.height()));
1200 }
1201
1202 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float y, ExceptionCode& ec)
1203 {
1204     if (!image) {
1205         ec = TYPE_MISMATCH_ERR;
1206         return;
1207     }
1208     LayoutSize s = size(image);
1209     drawImage(image, x, y, s.width(), s.height(), ec);
1210 }
1211
1212 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
1213     float x, float y, float width, float height, ExceptionCode& ec)
1214 {
1215     if (!image) {
1216         ec = TYPE_MISMATCH_ERR;
1217         return;
1218     }
1219     LayoutSize s = size(image);
1220     drawImage(image, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec);
1221 }
1222
1223 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
1224     float sx, float sy, float sw, float sh,
1225     float dx, float dy, float dw, float dh, ExceptionCode& ec)
1226 {
1227     drawImage(image, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec);
1228 }
1229
1230 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode& ec)
1231 {
1232     drawImage(image, srcRect, dstRect, state().m_globalComposite, ec);
1233 }
1234
1235 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect, const CompositeOperator& op, ExceptionCode& ec)
1236 {
1237     if (!image) {
1238         ec = TYPE_MISMATCH_ERR;
1239         return;
1240     }
1241
1242     ec = 0;
1243
1244     if (!isfinite(dstRect.x()) || !isfinite(dstRect.y()) || !isfinite(dstRect.width()) || !isfinite(dstRect.height())
1245         || !isfinite(srcRect.x()) || !isfinite(srcRect.y()) || !isfinite(srcRect.width()) || !isfinite(srcRect.height()))
1246         return;
1247
1248     if (!dstRect.width() || !dstRect.height())
1249         return;
1250
1251     if (!image->complete())
1252         return;
1253
1254     FloatRect normalizedSrcRect = normalizeRect(srcRect);
1255     FloatRect normalizedDstRect = normalizeRect(dstRect);
1256
1257     FloatRect imageRect = FloatRect(FloatPoint(), size(image));
1258     if (!srcRect.width() || !srcRect.height()) {
1259         ec = INDEX_SIZE_ERR;
1260         return;
1261     }
1262     if (!imageRect.contains(normalizedSrcRect))
1263         return;
1264
1265     GraphicsContext* c = drawingContext();
1266     if (!c)
1267         return;
1268     if (!state().m_invertibleCTM)
1269         return;
1270
1271     CachedImage* cachedImage = image->cachedImage();
1272     if (!cachedImage)
1273         return;
1274
1275     checkOrigin(image);
1276
1277     if (rectContainsCanvas(normalizedDstRect)) {
1278         c->drawImage(cachedImage->imageForRenderer(image->renderer()), ColorSpaceDeviceRGB, normalizedDstRect, normalizedSrcRect, op);
1279         didDrawEntireCanvas();
1280     } else if (isFullCanvasCompositeMode(op)) {
1281         fullCanvasCompositedDrawImage(cachedImage->imageForRenderer(image->renderer()), ColorSpaceDeviceRGB, normalizedDstRect, normalizedSrcRect, op);
1282         didDrawEntireCanvas();
1283     } else if (op == CompositeCopy) {
1284         clearCanvas();
1285         c->drawImage(cachedImage->imageForRenderer(image->renderer()), ColorSpaceDeviceRGB, normalizedDstRect, normalizedSrcRect, op);
1286         didDrawEntireCanvas();
1287     } else {
1288         c->drawImage(cachedImage->imageForRenderer(image->renderer()), ColorSpaceDeviceRGB, normalizedDstRect, normalizedSrcRect, op);
1289         didDraw(normalizedDstRect);
1290     }
1291 }
1292
1293 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, float x, float y, ExceptionCode& ec)
1294 {
1295     drawImage(sourceCanvas, 0, 0, sourceCanvas->width(), sourceCanvas->height(), x, y, sourceCanvas->width(), sourceCanvas->height(), ec);
1296 }
1297
1298 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas,
1299     float x, float y, float width, float height, ExceptionCode& ec)
1300 {
1301     drawImage(sourceCanvas, FloatRect(0, 0, sourceCanvas->width(), sourceCanvas->height()), FloatRect(x, y, width, height), ec);
1302 }
1303
1304 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas,
1305     float sx, float sy, float sw, float sh,
1306     float dx, float dy, float dw, float dh, ExceptionCode& ec)
1307 {
1308     drawImage(sourceCanvas, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec);
1309 }
1310
1311 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, const FloatRect& srcRect,
1312     const FloatRect& dstRect, ExceptionCode& ec)
1313 {
1314     if (!sourceCanvas) {
1315         ec = TYPE_MISMATCH_ERR;
1316         return;
1317     }
1318
1319     FloatRect srcCanvasRect = FloatRect(FloatPoint(), sourceCanvas->size());
1320
1321     if (!srcCanvasRect.width() || !srcCanvasRect.height()) {
1322         ec = INVALID_STATE_ERR;
1323         return;
1324     }
1325
1326     if (!srcRect.width() || !srcRect.height()) {
1327         ec = INDEX_SIZE_ERR;
1328         return;
1329     }
1330
1331     ec = 0;
1332
1333     if (!srcCanvasRect.contains(normalizeRect(srcRect)) || !dstRect.width() || !dstRect.height())
1334         return;
1335
1336     GraphicsContext* c = drawingContext();
1337     if (!c)
1338         return;
1339     if (!state().m_invertibleCTM)
1340         return;
1341
1342     // FIXME: Do this through platform-independent GraphicsContext API.
1343     ImageBuffer* buffer = sourceCanvas->buffer();
1344     if (!buffer)
1345         return;
1346
1347     checkOrigin(sourceCanvas);
1348
1349 #if ENABLE(ACCELERATED_2D_CANVAS)
1350     // If we're drawing from one accelerated canvas 2d to another, avoid calling sourceCanvas->makeRenderingResultsAvailable()
1351     // as that will do a readback to software.
1352     CanvasRenderingContext* sourceContext = sourceCanvas->renderingContext();
1353     // FIXME: Implement an accelerated path for drawing from a WebGL canvas to a 2d canvas when possible.
1354     if (!isAccelerated() || !sourceContext || !sourceContext->isAccelerated() || !sourceContext->is2d())
1355         sourceCanvas->makeRenderingResultsAvailable();
1356 #else
1357     sourceCanvas->makeRenderingResultsAvailable();
1358 #endif
1359
1360     // drawImageBuffer's srcRect is in buffer pixels (backing store pixels, in our case), dstRect is in canvas pixels.
1361     FloatRect bufferSrcRect(sourceCanvas->convertLogicalToDevice(srcRect));
1362
1363     if (rectContainsCanvas(dstRect)) {
1364         c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, dstRect, bufferSrcRect, state().m_globalComposite);
1365         didDrawEntireCanvas();
1366     } else if (isFullCanvasCompositeMode(state().m_globalComposite)) {
1367         fullCanvasCompositedDrawImage(buffer, ColorSpaceDeviceRGB, dstRect, bufferSrcRect, state().m_globalComposite);
1368         didDrawEntireCanvas();
1369     } else if (state().m_globalComposite == CompositeCopy) {
1370         clearCanvas();
1371         c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, dstRect, bufferSrcRect, state().m_globalComposite);
1372         didDrawEntireCanvas();
1373     } else {
1374         c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, dstRect, bufferSrcRect, state().m_globalComposite);
1375         didDraw(dstRect);
1376     }
1377 }
1378
1379 #if ENABLE(VIDEO)
1380 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, float x, float y, ExceptionCode& ec)
1381 {
1382     if (!video) {
1383         ec = TYPE_MISMATCH_ERR;
1384         return;
1385     }
1386     IntSize s = size(video);
1387     drawImage(video, x, y, s.width(), s.height(), ec);
1388 }
1389
1390 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video,
1391                                          float x, float y, float width, float height, ExceptionCode& ec)
1392 {
1393     if (!video) {
1394         ec = TYPE_MISMATCH_ERR;
1395         return;
1396     }
1397     IntSize s = size(video);
1398     drawImage(video, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec);
1399 }
1400
1401 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video,
1402     float sx, float sy, float sw, float sh,
1403     float dx, float dy, float dw, float dh, ExceptionCode& ec)
1404 {
1405     drawImage(video, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec);
1406 }
1407
1408 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, const FloatRect& srcRect, const FloatRect& dstRect,
1409                                          ExceptionCode& ec)
1410 {
1411     if (!video) {
1412         ec = TYPE_MISMATCH_ERR;
1413         return;
1414     }
1415
1416     ec = 0;
1417
1418     if (video->readyState() == HTMLMediaElement::HAVE_NOTHING || video->readyState() == HTMLMediaElement::HAVE_METADATA)
1419         return;
1420
1421     FloatRect videoRect = FloatRect(FloatPoint(), size(video));
1422     if (!srcRect.width() || !srcRect.height()) {
1423         ec = INDEX_SIZE_ERR;
1424         return;
1425     }
1426
1427     if (!videoRect.contains(normalizeRect(srcRect)) || !dstRect.width() || !dstRect.height())
1428         return;
1429
1430     GraphicsContext* c = drawingContext();
1431     if (!c)
1432         return;
1433     if (!state().m_invertibleCTM)
1434         return;
1435
1436     checkOrigin(video);
1437
1438     GraphicsContextStateSaver stateSaver(*c);
1439     c->clip(dstRect);
1440     c->translate(dstRect.x(), dstRect.y());
1441     c->scale(FloatSize(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height()));
1442     c->translate(-srcRect.x(), -srcRect.y());
1443     video->paintCurrentFrameInContext(c, IntRect(IntPoint(), size(video)));
1444     stateSaver.restore();
1445     didDraw(dstRect);
1446 }
1447 #endif
1448
1449 void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image,
1450     float sx, float sy, float sw, float sh,
1451     float dx, float dy, float dw, float dh,
1452     const String& compositeOperation)
1453 {
1454     CompositeOperator op;
1455     if (!parseCompositeOperator(compositeOperation, op))
1456         op = CompositeSourceOver;
1457
1458     ExceptionCode ec;
1459     drawImage(image, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), op, ec);
1460 }
1461
1462 void CanvasRenderingContext2D::setAlpha(float alpha)
1463 {
1464     setGlobalAlpha(alpha);
1465 }
1466
1467 void CanvasRenderingContext2D::setCompositeOperation(const String& operation)
1468 {
1469     setGlobalCompositeOperation(operation);
1470 }
1471
1472 void CanvasRenderingContext2D::clearCanvas()
1473 {
1474     FloatRect canvasRect(0, 0, canvas()->width(), canvas()->height());
1475     GraphicsContext* c = drawingContext();
1476     if (!c)
1477         return;
1478
1479     c->save();
1480     c->setCTM(canvas()->baseTransform());
1481     c->clearRect(canvasRect);
1482     c->restore();
1483 }
1484
1485 Path CanvasRenderingContext2D::transformAreaToDevice(const Path& path) const
1486 {
1487     Path transformed(path);
1488     transformed.transform(state().m_transform);
1489     transformed.transform(canvas()->baseTransform());
1490     return transformed;
1491 }
1492
1493 Path CanvasRenderingContext2D::transformAreaToDevice(const FloatRect& rect) const
1494 {
1495     Path path;
1496     path.addRect(rect);
1497     return transformAreaToDevice(path);
1498 }
1499
1500 bool CanvasRenderingContext2D::rectContainsCanvas(const FloatRect& rect) const
1501 {
1502     FloatQuad quad(rect);
1503     FloatQuad canvasQuad(FloatRect(0, 0, canvas()->width(), canvas()->height()));
1504     return state().m_transform.mapQuad(quad).containsQuad(canvasQuad);
1505 }
1506
1507 template<class T> IntRect CanvasRenderingContext2D::calculateCompositingBufferRect(const T& area, IntSize* croppedOffset)
1508 {
1509     IntRect canvasRect(0, 0, canvas()->width(), canvas()->height());
1510     canvasRect = canvas()->baseTransform().mapRect(canvasRect);
1511     Path path = transformAreaToDevice(area);
1512     IntRect bufferRect = enclosingIntRect(path.fastBoundingRect());
1513     IntPoint originalLocation = bufferRect.location();
1514     bufferRect.intersect(canvasRect);
1515     if (croppedOffset)
1516         *croppedOffset = originalLocation - bufferRect.location();
1517     return bufferRect;
1518 }
1519
1520 PassOwnPtr<ImageBuffer> CanvasRenderingContext2D::createCompositingBuffer(const IntRect& bufferRect)
1521 {
1522     RenderingMode renderMode = isAccelerated() ? Accelerated : Unaccelerated;
1523     return ImageBuffer::create(bufferRect.size(), 1, ColorSpaceDeviceRGB, renderMode);
1524 }
1525
1526 void CanvasRenderingContext2D::compositeBuffer(ImageBuffer* buffer, const IntRect& bufferRect, CompositeOperator op)
1527 {
1528     IntRect canvasRect(0, 0, canvas()->width(), canvas()->height());
1529     canvasRect = canvas()->baseTransform().mapRect(canvasRect);
1530
1531     GraphicsContext* c = drawingContext();
1532     if (!c)
1533         return;
1534
1535     c->save();
1536     c->setCTM(AffineTransform());
1537     c->setCompositeOperation(op);
1538
1539     c->save();
1540     c->clipOut(bufferRect);
1541     c->clearRect(canvasRect);
1542     c->restore();
1543
1544     c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, bufferRect.location(), state().m_globalComposite);
1545     c->restore();
1546 }
1547
1548 static void drawImageToContext(Image* image, GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
1549 {
1550     context->drawImage(image, styleColorSpace, dest, src, op);
1551 }
1552
1553 static void drawImageToContext(ImageBuffer* imageBuffer, GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
1554 {
1555     context->drawImageBuffer(imageBuffer, styleColorSpace, dest, src, op);
1556 }
1557
1558 template<class T> void  CanvasRenderingContext2D::fullCanvasCompositedDrawImage(T* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
1559 {
1560     ASSERT(isFullCanvasCompositeMode(op));
1561
1562     IntSize croppedOffset;
1563     IntRect bufferRect = calculateCompositingBufferRect(dest, &croppedOffset);
1564     if (bufferRect.isEmpty()) {
1565         clearCanvas();
1566         return;
1567     }
1568
1569     OwnPtr<ImageBuffer> buffer = createCompositingBuffer(bufferRect);
1570     if (!buffer)
1571         return;
1572
1573     GraphicsContext* c = drawingContext();
1574     if (!c)
1575         return;
1576
1577     FloatRect adjustedDest = dest;
1578     adjustedDest.setLocation(FloatPoint(0, 0));
1579     AffineTransform effectiveTransform = c->getCTM();
1580     IntRect transformedAdjustedRect = enclosingIntRect(effectiveTransform.mapRect(adjustedDest));
1581     buffer->context()->translate(-transformedAdjustedRect.location().x(), -transformedAdjustedRect.location().y());
1582     buffer->context()->translate(croppedOffset.width(), croppedOffset.height());
1583     buffer->context()->concatCTM(effectiveTransform);
1584     drawImageToContext(image, buffer->context(), styleColorSpace, adjustedDest, src, CompositeSourceOver);
1585
1586     compositeBuffer(buffer.get(), bufferRect, op);
1587 }
1588
1589 template<class T> void CanvasRenderingContext2D::fullCanvasCompositedFill(const T& area)
1590 {
1591     ASSERT(isFullCanvasCompositeMode(state().m_globalComposite));
1592
1593     IntRect bufferRect = calculateCompositingBufferRect(area, 0);
1594     if (bufferRect.isEmpty()) {
1595         clearCanvas();
1596         return;
1597     }
1598
1599     OwnPtr<ImageBuffer> buffer = createCompositingBuffer(bufferRect);
1600     if (!buffer)
1601         return;
1602
1603     Path path = transformAreaToDevice(area);
1604     path.translate(FloatSize(-bufferRect.x(), -bufferRect.y()));
1605
1606     buffer->context()->setCompositeOperation(CompositeSourceOver);
1607     state().m_fillStyle->applyFillColor(buffer->context());
1608     buffer->context()->fillPath(path);
1609
1610     compositeBuffer(buffer.get(), bufferRect, state().m_globalComposite);
1611 }
1612
1613 void CanvasRenderingContext2D::prepareGradientForDashboard(CanvasGradient* gradient) const
1614 {
1615 #if ENABLE(DASHBOARD_SUPPORT)
1616     if (m_usesDashboardCompatibilityMode)
1617         gradient->setDashboardCompatibilityMode();
1618 #else
1619     UNUSED_PARAM(gradient);
1620 #endif
1621 }
1622
1623 PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1, ExceptionCode& ec)
1624 {
1625     if (!isfinite(x0) || !isfinite(y0) || !isfinite(x1) || !isfinite(y1)) {
1626         ec = NOT_SUPPORTED_ERR;
1627         return 0;
1628     }
1629
1630     RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1));
1631     prepareGradientForDashboard(gradient.get());
1632     return gradient.release();
1633 }
1634
1635 PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1, ExceptionCode& ec)
1636 {
1637     if (!isfinite(x0) || !isfinite(y0) || !isfinite(r0) || !isfinite(x1) || !isfinite(y1) || !isfinite(r1)) {
1638         ec = NOT_SUPPORTED_ERR;
1639         return 0;
1640     }
1641
1642     if (r0 < 0 || r1 < 0) {
1643         ec = INDEX_SIZE_ERR;
1644         return 0;
1645     }
1646
1647     RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1);
1648     prepareGradientForDashboard(gradient.get());
1649     return gradient.release();
1650 }
1651
1652 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageElement* image,
1653     const String& repetitionType, ExceptionCode& ec)
1654 {
1655     if (!image) {
1656         ec = TYPE_MISMATCH_ERR;
1657         return 0;
1658     }
1659     bool repeatX, repeatY;
1660     ec = 0;
1661     CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
1662     if (ec)
1663         return 0;
1664
1665     if (!image->complete())
1666         return 0;
1667
1668     CachedImage* cachedImage = image->cachedImage();
1669     if (!cachedImage || !image->cachedImage()->imageForRenderer(image->renderer()))
1670         return CanvasPattern::create(Image::nullImage(), repeatX, repeatY, true);
1671
1672     bool originClean = isOriginClean(cachedImage, canvas()->securityOrigin());
1673     return CanvasPattern::create(cachedImage->imageForRenderer(image->renderer()), repeatX, repeatY, originClean);
1674 }
1675
1676 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElement* canvas,
1677     const String& repetitionType, ExceptionCode& ec)
1678 {
1679     if (!canvas) {
1680         ec = TYPE_MISMATCH_ERR;
1681         return 0;
1682     }
1683     if (!canvas->width() || !canvas->height()) {
1684         ec = INVALID_STATE_ERR;
1685         return 0;
1686     }
1687
1688     bool repeatX, repeatY;
1689     ec = 0;
1690     CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
1691     if (ec)
1692         return 0;
1693     return CanvasPattern::create(canvas->copiedImage(), repeatX, repeatY, canvas->originClean());
1694 }
1695
1696 void CanvasRenderingContext2D::didDrawEntireCanvas()
1697 {
1698     didDraw(FloatRect(FloatPoint::zero(), canvas()->size()), CanvasDidDrawApplyClip);
1699 }
1700
1701 void CanvasRenderingContext2D::didDraw(const FloatRect& r, unsigned options)
1702 {
1703     GraphicsContext* c = drawingContext();
1704     if (!c)
1705         return;
1706     if (!state().m_invertibleCTM)
1707         return;
1708
1709 #if ENABLE(ACCELERATED_2D_CANVAS) && USE(ACCELERATED_COMPOSITING)
1710     // If we are drawing to hardware and we have a composited layer, just call contentChanged().
1711     if (isAccelerated()) {
1712         RenderBox* renderBox = canvas()->renderBox();
1713         if (renderBox && renderBox->hasLayer() && renderBox->layer()->hasAcceleratedCompositing()) {
1714             renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
1715             canvas()->clearCopiedImage();
1716             return;
1717         }
1718     }
1719 #endif
1720
1721     FloatRect dirtyRect = r;
1722     if (options & CanvasDidDrawApplyTransform) {
1723         AffineTransform ctm = state().m_transform;
1724         dirtyRect = ctm.mapRect(r);
1725     }
1726
1727     if (options & CanvasDidDrawApplyShadow && alphaChannel(state().m_shadowColor)) {
1728         // The shadow gets applied after transformation
1729         FloatRect shadowRect(dirtyRect);
1730         shadowRect.move(state().m_shadowOffset);
1731         shadowRect.inflate(state().m_shadowBlur);
1732         dirtyRect.unite(shadowRect);
1733     }
1734
1735     if (options & CanvasDidDrawApplyClip) {
1736         // FIXME: apply the current clip to the rectangle. Unfortunately we can't get the clip
1737         // back out of the GraphicsContext, so to take clip into account for incremental painting,
1738         // we'd have to keep the clip path around.
1739     }
1740
1741     canvas()->didDraw(dirtyRect);
1742 }
1743
1744 GraphicsContext* CanvasRenderingContext2D::drawingContext() const
1745 {
1746     return canvas()->drawingContext();
1747 }
1748
1749 static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size)
1750 {
1751     Checked<int, RecordOverflow> dataSize = 4;
1752     dataSize *= size.width();
1753     dataSize *= size.height();
1754     if (dataSize.hasOverflowed())
1755         return 0;
1756
1757     RefPtr<ImageData> data = ImageData::create(size);
1758     memset(data->data()->data()->data(), 0, data->data()->data()->length());
1759     return data.release();
1760 }
1761
1762 PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(PassRefPtr<ImageData> imageData, ExceptionCode& ec) const
1763 {
1764     if (!imageData) {
1765         ec = NOT_SUPPORTED_ERR;
1766         return 0;
1767     }
1768
1769     return createEmptyImageData(imageData->size());
1770 }
1771
1772 PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(float sw, float sh, ExceptionCode& ec) const
1773 {
1774     ec = 0;
1775     if (!sw || !sh) {
1776         ec = INDEX_SIZE_ERR;
1777         return 0;
1778     }
1779     if (!isfinite(sw) || !isfinite(sh)) {
1780         ec = NOT_SUPPORTED_ERR;
1781         return 0;
1782     }
1783
1784     FloatSize logicalSize(fabs(sw), fabs(sh));
1785     FloatSize deviceSize = canvas()->convertLogicalToDevice(logicalSize);
1786     if (!deviceSize.isExpressibleAsIntSize())
1787         return 0;
1788
1789     IntSize size(deviceSize.width(), deviceSize.height());
1790     if (size.width() < 1)
1791         size.setWidth(1);
1792     if (size.height() < 1)
1793         size.setHeight(1);
1794
1795     return createEmptyImageData(size);
1796 }
1797
1798 PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy, float sw, float sh, ExceptionCode& ec) const
1799 {
1800     if (!canvas()->originClean()) {
1801         DEFINE_STATIC_LOCAL(String, consoleMessage, ("Unable to get image data from canvas because the canvas has been tainted by cross-origin data."));
1802         canvas()->document()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage);
1803         ec = SECURITY_ERR;
1804         return 0;
1805     }
1806     if (!sw || !sh) {
1807         ec = INDEX_SIZE_ERR;
1808         return 0;
1809     }
1810     if (!isfinite(sx) || !isfinite(sy) || !isfinite(sw) || !isfinite(sh)) {
1811         ec = NOT_SUPPORTED_ERR;
1812         return 0;
1813     }
1814
1815     if (sw < 0) {
1816         sx += sw;
1817         sw = -sw;
1818     }    
1819     if (sh < 0) {
1820         sy += sh;
1821         sh = -sh;
1822     }
1823     
1824     FloatRect logicalRect(sx, sy, sw, sh);
1825     FloatRect deviceRect = canvas()->convertLogicalToDevice(logicalRect);
1826     if (deviceRect.width() < 1)
1827         deviceRect.setWidth(1);
1828     if (deviceRect.height() < 1)
1829         deviceRect.setHeight(1);
1830     if (!deviceRect.isExpressibleAsIntRect())
1831         return 0;
1832
1833     IntRect imageDataRect(deviceRect);
1834     ImageBuffer* buffer = canvas()->buffer();
1835     if (!buffer)
1836         return createEmptyImageData(imageDataRect.size());
1837
1838     RefPtr<ByteArray> byteArray = buffer->getUnmultipliedImageData(imageDataRect);
1839     if (!byteArray)
1840         return 0;
1841
1842     return ImageData::create(imageDataRect.size(), byteArray.release());
1843 }
1844
1845 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, ExceptionCode& ec)
1846 {
1847     if (!data) {
1848         ec = TYPE_MISMATCH_ERR;
1849         return;
1850     }
1851     putImageData(data, dx, dy, 0, 0, data->width(), data->height(), ec);
1852 }
1853
1854 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, float dirtyX, float dirtyY,
1855                                             float dirtyWidth, float dirtyHeight, ExceptionCode& ec)
1856 {
1857     if (!data) {
1858         ec = TYPE_MISMATCH_ERR;
1859         return;
1860     }
1861     if (!isfinite(dx) || !isfinite(dy) || !isfinite(dirtyX) || !isfinite(dirtyY) || !isfinite(dirtyWidth) || !isfinite(dirtyHeight)) {
1862         ec = NOT_SUPPORTED_ERR;
1863         return;
1864     }
1865
1866     ImageBuffer* buffer = canvas()->buffer();
1867     if (!buffer)
1868         return;
1869
1870     if (dirtyWidth < 0) {
1871         dirtyX += dirtyWidth;
1872         dirtyWidth = -dirtyWidth;
1873     }
1874
1875     if (dirtyHeight < 0) {
1876         dirtyY += dirtyHeight;
1877         dirtyHeight = -dirtyHeight;
1878     }
1879
1880     FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
1881     clipRect.intersect(IntRect(0, 0, data->width(), data->height()));
1882     IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
1883     IntRect destRect = enclosingIntRect(clipRect);
1884     destRect.move(destOffset);
1885     destRect.intersect(IntRect(IntPoint(), buffer->internalSize()));
1886     if (destRect.isEmpty())
1887         return;
1888     IntRect sourceRect(destRect);
1889     sourceRect.move(-destOffset);
1890
1891     buffer->putByteArray(Unmultiplied, data->data()->data(), IntSize(data->width(), data->height()), sourceRect, IntPoint(destOffset));
1892     didDraw(destRect, CanvasDidDrawApplyNone); // ignore transform, shadow and clip
1893 }
1894
1895 String CanvasRenderingContext2D::font() const
1896 {
1897     return state().m_unparsedFont;
1898 }
1899
1900 void CanvasRenderingContext2D::setFont(const String& newFont)
1901 {
1902     RefPtr<StylePropertySet> tempDecl = StylePropertySet::create();
1903     CSSParser parser(!m_usesCSSCompatibilityParseMode);
1904
1905     String declarationText("font: ");
1906     declarationText += newFont;
1907     parser.parseDeclaration(tempDecl.get(), declarationText, 0, 0);
1908     if (tempDecl->isEmpty())
1909         return;
1910
1911     // The parse succeeded.
1912     state().m_unparsedFont = newFont;
1913
1914     // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
1915     // relative to the canvas.
1916     RefPtr<RenderStyle> newStyle = RenderStyle::create();
1917     if (RenderStyle* computedStyle = canvas()->computedStyle())
1918         newStyle->setFontDescription(computedStyle->fontDescription());
1919     newStyle->font().update(newStyle->font().fontSelector());
1920
1921     // Now map the font property longhands into the style.
1922     CSSStyleSelector* styleSelector = canvas()->styleSelector();
1923     styleSelector->applyPropertyToStyle(CSSPropertyFontFamily, tempDecl->getPropertyCSSValue(CSSPropertyFontFamily).get(), newStyle.get());
1924     styleSelector->applyPropertyToCurrentStyle(CSSPropertyFontStyle, tempDecl->getPropertyCSSValue(CSSPropertyFontStyle).get());
1925     styleSelector->applyPropertyToCurrentStyle(CSSPropertyFontVariant, tempDecl->getPropertyCSSValue(CSSPropertyFontVariant).get());
1926     styleSelector->applyPropertyToCurrentStyle(CSSPropertyFontWeight, tempDecl->getPropertyCSSValue(CSSPropertyFontWeight).get());
1927
1928     // As described in BUG66291, setting font-size on a font may entail a CSSPrimitiveValue::computeLengthDouble call,
1929     // which assumes the fontMetrics are available for the affected font, otherwise a crash occurs (see http://trac.webkit.org/changeset/96122).
1930     // The updateFont() call below updates the fontMetrics and ensures the proper setting of font-size.
1931     styleSelector->updateFont();
1932     styleSelector->applyPropertyToCurrentStyle(CSSPropertyFontSize, tempDecl->getPropertyCSSValue(CSSPropertyFontSize).get());
1933     styleSelector->applyPropertyToCurrentStyle(CSSPropertyLineHeight, tempDecl->getPropertyCSSValue(CSSPropertyLineHeight).get());
1934
1935     state().m_font = newStyle->font();
1936     state().m_font.update(styleSelector->fontSelector());
1937     state().m_realizedFont = true;
1938     styleSelector->fontSelector()->registerForInvalidationCallbacks(&state());
1939 }
1940
1941 String CanvasRenderingContext2D::textAlign() const
1942 {
1943     return textAlignName(state().m_textAlign);
1944 }
1945
1946 void CanvasRenderingContext2D::setTextAlign(const String& s)
1947 {
1948     TextAlign align;
1949     if (!parseTextAlign(s, align))
1950         return;
1951     state().m_textAlign = align;
1952 }
1953
1954 String CanvasRenderingContext2D::textBaseline() const
1955 {
1956     return textBaselineName(state().m_textBaseline);
1957 }
1958
1959 void CanvasRenderingContext2D::setTextBaseline(const String& s)
1960 {
1961     TextBaseline baseline;
1962     if (!parseTextBaseline(s, baseline))
1963         return;
1964     state().m_textBaseline = baseline;
1965 }
1966
1967 void CanvasRenderingContext2D::fillText(const String& text, float x, float y)
1968 {
1969     drawTextInternal(text, x, y, true);
1970 }
1971
1972 void CanvasRenderingContext2D::fillText(const String& text, float x, float y, float maxWidth)
1973 {
1974     drawTextInternal(text, x, y, true, maxWidth, true);
1975 }
1976
1977 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y)
1978 {
1979     drawTextInternal(text, x, y, false);
1980 }
1981
1982 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y, float maxWidth)
1983 {
1984     drawTextInternal(text, x, y, false, maxWidth, true);
1985 }
1986
1987 PassRefPtr<TextMetrics> CanvasRenderingContext2D::measureText(const String& text)
1988 {
1989     FontCachePurgePreventer fontCachePurgePreventer;
1990
1991     RefPtr<TextMetrics> metrics = TextMetrics::create();
1992
1993 #if PLATFORM(QT)
1994     // We always use complex text shaping since it can't be turned off for QPainterPath::addText().
1995     Font::CodePath oldCodePath = Font::codePath();
1996     Font::setCodePath(Font::Complex);
1997 #endif
1998
1999     metrics->setWidth(accessFont().width(TextRun(text.characters(), text.length())));
2000
2001 #if PLATFORM(QT)
2002     Font::setCodePath(oldCodePath);
2003 #endif
2004
2005     return metrics.release();
2006 }
2007
2008 void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, float maxWidth, bool useMaxWidth)
2009 {
2010     GraphicsContext* c = drawingContext();
2011     if (!c)
2012         return;
2013     if (!state().m_invertibleCTM)
2014         return;
2015     if (!isfinite(x) | !isfinite(y))
2016         return;
2017     if (useMaxWidth && !isfinite(maxWidth))
2018         return;
2019
2020     FontCachePurgePreventer fontCachePurgePreventer;
2021
2022     const Font& font = accessFont();
2023     const FontMetrics& fontMetrics = font.fontMetrics();
2024
2025     // FIXME: Need to turn off font smoothing.
2026
2027     RenderStyle* computedStyle = canvas()->computedStyle();
2028     TextDirection direction = computedStyle ? computedStyle->direction() : LTR;
2029     bool isRTL = direction == RTL;
2030     bool override = computedStyle ? isOverride(computedStyle->unicodeBidi()) : false;
2031
2032     unsigned length = text.length();
2033     const UChar* string = text.characters();
2034     TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, direction, override, TextRun::NoRounding);
2035
2036     // Draw the item text at the correct point.
2037     FloatPoint location(x, y);
2038     switch (state().m_textBaseline) {
2039     case TopTextBaseline:
2040     case HangingTextBaseline:
2041         location.setY(y + fontMetrics.ascent());
2042         break;
2043     case BottomTextBaseline:
2044     case IdeographicTextBaseline:
2045         location.setY(y - fontMetrics.descent());
2046         break;
2047     case MiddleTextBaseline:
2048         location.setY(y - fontMetrics.descent() + fontMetrics.height() / 2);
2049         break;
2050     case AlphabeticTextBaseline:
2051     default:
2052          // Do nothing.
2053         break;
2054     }
2055
2056     float fontWidth = font.width(TextRun(text, false, 0, 0, TextRun::AllowTrailingExpansion, direction, override));
2057
2058     useMaxWidth = (useMaxWidth && maxWidth < fontWidth);
2059     float width = useMaxWidth ? maxWidth : fontWidth;
2060
2061     TextAlign align = state().m_textAlign;
2062     if (align == StartTextAlign)
2063         align = isRTL ? RightTextAlign : LeftTextAlign;
2064     else if (align == EndTextAlign)
2065         align = isRTL ? LeftTextAlign : RightTextAlign;
2066
2067     switch (align) {
2068     case CenterTextAlign:
2069         location.setX(location.x() - width / 2);
2070         break;
2071     case RightTextAlign:
2072         location.setX(location.x() - width);
2073         break;
2074     default:
2075         break;
2076     }
2077
2078     // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text.
2079     FloatRect textRect = FloatRect(location.x() - fontMetrics.height() / 2, location.y() - fontMetrics.ascent() - fontMetrics.lineGap(),
2080                                    width + fontMetrics.height(), fontMetrics.lineSpacing());
2081     if (!fill)
2082         textRect.inflate(c->strokeThickness() / 2);
2083
2084 #if USE(CG)
2085     CanvasStyle* drawStyle = fill ? state().m_fillStyle.get() : state().m_strokeStyle.get();
2086     if (drawStyle->canvasGradient() || drawStyle->canvasPattern()) {
2087         // FIXME: The rect is not big enough for miters on stroked text.
2088         IntRect maskRect = enclosingIntRect(textRect);
2089
2090 #if USE(IOSURFACE_CANVAS_BACKING_STORE)
2091         OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), 1, ColorSpaceDeviceRGB, Accelerated);
2092 #else
2093         OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), 1);
2094 #endif
2095
2096         GraphicsContext* maskImageContext = maskImage->context();
2097
2098         if (fill)
2099             maskImageContext->setFillColor(Color::black, ColorSpaceDeviceRGB);
2100         else {
2101             maskImageContext->setStrokeColor(Color::black, ColorSpaceDeviceRGB);
2102             maskImageContext->setStrokeThickness(c->strokeThickness());
2103         }
2104
2105         maskImageContext->setTextDrawingMode(fill ? TextModeFill : TextModeStroke);
2106
2107         if (useMaxWidth) {
2108             maskImageContext->translate(location.x() - maskRect.x(), location.y() - maskRect.y());
2109             // We draw when fontWidth is 0 so compositing operations (eg, a "copy" op) still work.
2110             maskImageContext->scale(FloatSize((fontWidth > 0 ? (width / fontWidth) : 0), 1));
2111             maskImageContext->drawBidiText(font, textRun, FloatPoint(0, 0));
2112         } else {
2113             maskImageContext->translate(-maskRect.x(), -maskRect.y());
2114             maskImageContext->drawBidiText(font, textRun, location);
2115         }
2116
2117         GraphicsContextStateSaver stateSaver(*c);
2118         c->clipToImageBuffer(maskImage.get(), maskRect);
2119         drawStyle->applyFillColor(c);
2120         c->fillRect(maskRect);
2121         return;
2122     }
2123 #endif
2124
2125     c->setTextDrawingMode(fill ? TextModeFill : TextModeStroke);
2126
2127 #if PLATFORM(QT)
2128     // We always use complex text shaping since it can't be turned off for QPainterPath::addText().
2129     Font::CodePath oldCodePath = Font::codePath();
2130     Font::setCodePath(Font::Complex);
2131 #endif
2132
2133     if (useMaxWidth) {
2134         GraphicsContextStateSaver stateSaver(*c);
2135         c->translate(location.x(), location.y());
2136         // We draw when fontWidth is 0 so compositing operations (eg, a "copy" op) still work.
2137         c->scale(FloatSize((fontWidth > 0 ? (width / fontWidth) : 0), 1));
2138         c->drawBidiText(font, textRun, FloatPoint(0, 0));
2139     } else
2140         c->drawBidiText(font, textRun, location);
2141
2142     if (fill)
2143         didDraw(textRect);
2144     else {
2145         // When stroking text, pointy miters can extend outside of textRect, so we
2146         // punt and dirty the whole canvas.
2147         didDraw(FloatRect(0, 0, canvas()->width(), canvas()->height()));
2148     }
2149
2150 #if PLATFORM(QT)
2151     Font::setCodePath(oldCodePath);
2152 #endif
2153 }
2154
2155 const Font& CanvasRenderingContext2D::accessFont()
2156 {
2157     canvas()->document()->updateStyleIfNeeded();
2158
2159     if (!state().m_realizedFont)
2160         setFont(state().m_unparsedFont);
2161     return state().m_font;
2162 }
2163
2164 #if ENABLE(ACCELERATED_2D_CANVAS) && USE(ACCELERATED_COMPOSITING)
2165 PlatformLayer* CanvasRenderingContext2D::platformLayer() const
2166 {
2167     return canvas()->buffer() ? canvas()->buffer()->platformLayer() : 0;
2168 }
2169 #endif
2170
2171 } // namespace WebCore