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