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