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