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