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