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