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