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