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