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