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