1c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown/*
2c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
3c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
4c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
6c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
7c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
8c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * Copyright (C) 2012, 2013 Intel Corporation. All rights reserved.
9c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
10c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown *
11c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * Redistribution and use in source and binary forms, with or without
12c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * modification, are permitted provided that the following conditions
13c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * are met:
14c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * 1. Redistributions of source code must retain the above copyright
15c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown *    notice, this list of conditions and the following disclaimer.
16c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * 2. Redistributions in binary form must reproduce the above copyright
17c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown *    notice, this list of conditions and the following disclaimer in the
18c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown *    documentation and/or other materials provided with the distribution.
196ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown *
20c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
21c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
24c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
28692065128e66de77470de2c50ead2bef0452952aJeff Brown * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
296ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
306ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
316ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown */
3232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown
3332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include "config.h"
3432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include "core/html/canvas/CanvasRenderingContext2D.h"
3532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown
3632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include "bindings/core/v8/ExceptionMessages.h"
3732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include "bindings/core/v8/ExceptionState.h"
3832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include "bindings/core/v8/ExceptionStatePlaceholder.h"
3932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include "core/CSSPropertyNames.h"
4032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include "core/css/CSSFontSelector.h"
4132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include "core/css/StylePropertySet.h"
4232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include "core/css/parser/CSSParser.h"
4332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include "core/css/resolver/StyleResolver.h"
4432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include "core/dom/ExceptionCode.h"
45c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "core/dom/StyleEngine.h"
4632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include "core/events/Event.h"
47c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "core/fetch/ImageResource.h"
48c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "core/frame/ImageBitmap.h"
49c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "core/html/HTMLCanvasElement.h"
50c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "core/html/HTMLImageElement.h"
51c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "core/html/HTMLMediaElement.h"
52c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "core/html/HTMLVideoElement.h"
53c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "core/html/ImageData.h"
54c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "core/html/TextMetrics.h"
55c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "core/html/canvas/CanvasGradient.h"
56c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "core/html/canvas/CanvasPattern.h"
57c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "core/html/canvas/CanvasStyle.h"
5891c69ab01539f7ba28708f41ec1835cc2920d0a0Jeff Brown#include "core/html/canvas/HitRegionOptions.h"
5991c69ab01539f7ba28708f41ec1835cc2920d0a0Jeff Brown#include "core/html/canvas/Path2D.h"
60c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "core/rendering/RenderImage.h"
61e33348ba54cd68d6936cffd4507037c14d4b10c2Jeff Brown#include "core/rendering/RenderLayer.h"
62e33348ba54cd68d6936cffd4507037c14d4b10c2Jeff Brown#include "core/rendering/RenderTheme.h"
63e33348ba54cd68d6936cffd4507037c14d4b10c2Jeff Brown#include "platform/fonts/FontCache.h"
64e33348ba54cd68d6936cffd4507037c14d4b10c2Jeff Brown#include "platform/geometry/FloatQuad.h"
65e33348ba54cd68d6936cffd4507037c14d4b10c2Jeff Brown#include "platform/graphics/DrawLooperBuilder.h"
6691c69ab01539f7ba28708f41ec1835cc2920d0a0Jeff Brown#include "platform/graphics/GraphicsContextStateSaver.h"
67e33348ba54cd68d6936cffd4507037c14d4b10c2Jeff Brown#include "platform/text/TextRun.h"
6891c69ab01539f7ba28708f41ec1835cc2920d0a0Jeff Brown#include "wtf/CheckedArithmetic.h"
69e33348ba54cd68d6936cffd4507037c14d4b10c2Jeff Brown#include "wtf/MathExtras.h"
70c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "wtf/OwnPtr.h"
71c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown#include "wtf/Uint8ClampedArray.h"
72e33348ba54cd68d6936cffd4507037c14d4b10c2Jeff Brown#include "wtf/text/StringBuilder.h"
73600cba973fa6889728cd7ee9938ede12c80c005aJohn Spurlock
74c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brownnamespace blink {
7591c69ab01539f7ba28708f41ec1835cc2920d0a0Jeff Brown
7691c69ab01539f7ba28708f41ec1835cc2920d0a0Jeff Brownstatic const int defaultFontSize = 10;
77c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brownstatic const char defaultFontFamily[] = "sans-serif";
78c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brownstatic const char defaultFont[] = "10px sans-serif";
7991c69ab01539f7ba28708f41ec1835cc2920d0a0Jeff Brownstatic const char inherit[] = "inherit";
8091c69ab01539f7ba28708f41ec1835cc2920d0a0Jeff Brownstatic const char rtl[] = "rtl";
81c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brownstatic const char ltr[] = "ltr";
82c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brownstatic const double TryRestoreContextInterval = 0.5;
8391c69ab01539f7ba28708f41ec1835cc2920d0a0Jeff Brownstatic const unsigned MaxTryRestoreContextAttempts = 4;
8491c69ab01539f7ba28708f41ec1835cc2920d0a0Jeff Brown
850029c66203ab9ded4342976bf7a17bb63af8c44aJeff Brownstatic bool contextLostRestoredEventsEnabled()
8674e4156e5c62392c37f4a70358de30dcfff4956fMichael Wright{
8774e4156e5c62392c37f4a70358de30dcfff4956fMichael Wright    return RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled();
8874e4156e5c62392c37f4a70358de30dcfff4956fMichael Wright}
8974e4156e5c62392c37f4a70358de30dcfff4956fMichael Wright
9074e4156e5c62392c37f4a70358de30dcfff4956fMichael WrightCanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, const Canvas2DContextAttributes* attrs, bool usesCSSCompatibilityParseMode)
9174e4156e5c62392c37f4a70358de30dcfff4956fMichael Wright    : CanvasRenderingContext(canvas)
9274e4156e5c62392c37f4a70358de30dcfff4956fMichael Wright    , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode)
9374e4156e5c62392c37f4a70358de30dcfff4956fMichael Wright    , m_hasAlpha(!attrs || attrs->alpha())
9474e4156e5c62392c37f4a70358de30dcfff4956fMichael Wright    , m_isContextLost(false)
9574e4156e5c62392c37f4a70358de30dcfff4956fMichael Wright    , m_contextRestorable(true)
9674e4156e5c62392c37f4a70358de30dcfff4956fMichael Wright    , m_storageMode(!attrs ? PersistentStorage : attrs->parsedStorage())
9774e4156e5c62392c37f4a70358de30dcfff4956fMichael Wright    , m_tryRestoreContextAttemptCount(0)
9821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    , m_dispatchContextLostEventTimer(this, &CanvasRenderingContext2D::dispatchContextLostEvent)
9921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    , m_dispatchContextRestoredEventTimer(this, &CanvasRenderingContext2D::dispatchContextRestoredEvent)
10021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    , m_tryRestoreContextEventTimer(this, &CanvasRenderingContext2D::tryRestoreContextEvent)
10121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown{
10221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    m_stateStack.append(adoptPtrWillBeNoop(new State()));
10321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown}
10421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
10521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brownvoid CanvasRenderingContext2D::unwindStateStack()
1060029c66203ab9ded4342976bf7a17bb63af8c44aJeff Brown{
1070029c66203ab9ded4342976bf7a17bb63af8c44aJeff Brown    if (size_t stackSize = m_stateStack.size()) {
1080029c66203ab9ded4342976bf7a17bb63af8c44aJeff Brown        if (GraphicsContext* context = canvas()->existingDrawingContext()) {
1090029c66203ab9ded4342976bf7a17bb63af8c44aJeff Brown            while (--stackSize)
1100029c66203ab9ded4342976bf7a17bb63af8c44aJeff Brown                context->restore();
1110029c66203ab9ded4342976bf7a17bb63af8c44aJeff Brown        }
11232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown    }
11332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown}
11432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown
11532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff BrownCanvasRenderingContext2D::~CanvasRenderingContext2D()
11632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown{
11732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown}
11832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown
11932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brownvoid CanvasRenderingContext2D::validateStateStack()
12032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown{
12132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#if ENABLE(ASSERT)
12232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown    GraphicsContext* context = canvas()->existingDrawingContext();
12332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown    if (context && !context->contextDisabled())
12432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown        ASSERT(context->saveCount() == m_stateStack.size());
12532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#endif
12632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown}
12792cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brown
12892cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brownbool CanvasRenderingContext2D::isAccelerated() const
12992cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brown{
13092cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brown    if (!canvas()->hasImageBuffer())
13192cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brown        return false;
13292cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brown    GraphicsContext* context = drawingContext();
13392cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brown    return context && context->isAccelerated();
13492cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brown}
13592cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brown
13692cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brownbool CanvasRenderingContext2D::isContextLost() const
13792cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brown{
13892cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brown    return m_isContextLost;
13992cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brown}
14092cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brown
14192cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brownvoid CanvasRenderingContext2D::loseContext()
14232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown{
14332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown    if (m_isContextLost)
14432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown        return;
14532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown    m_isContextLost = true;
14632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown    m_dispatchContextLostEventTimer.startOneShot(0, FROM_HERE);
14732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown}
14832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown
14932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brownvoid CanvasRenderingContext2D::restoreContext()
1500029c66203ab9ded4342976bf7a17bb63af8c44aJeff Brown{
15121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    if (!m_contextRestorable)
15221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        return;
15321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // This code path is for restoring from an eviction
15421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Restoring from surface failure is handled internally
15521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    ASSERT(m_isContextLost && !canvas()->hasImageBuffer());
15621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
15721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    if (canvas()->buffer()) {
15821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (contextLostRestoredEventsEnabled()) {
15921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            m_dispatchContextRestoredEventTimer.startOneShot(0, FROM_HERE);
16021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } else {
16121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            // legacy synchronous context restoration.
16221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            reset();
16321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            m_isContextLost = false;
16421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
16521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
16621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown}
16721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
16821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brownvoid CanvasRenderingContext2D::trace(Visitor* visitor)
16921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown{
17021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown#if ENABLE(OILPAN)
17121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    visitor->trace(m_stateStack);
17221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    visitor->trace(m_fetchedFonts);
1734e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown    visitor->trace(m_hitRegionManager);
174b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown#endif
175b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown    CanvasRenderingContext::trace(visitor);
176b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown}
177b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown
178b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brownvoid CanvasRenderingContext2D::dispatchContextLostEvent(Timer<CanvasRenderingContext2D>*)
179b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown{
180b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown    if (contextLostRestoredEventsEnabled()) {
181b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown        RefPtrWillBeRawPtr<Event> event = Event::createCancelable(EventTypeNames::contextlost);
182b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown        canvas()->dispatchEvent(event);
183b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown        if (event->defaultPrevented()) {
184b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown            m_contextRestorable = false;
185b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown        }
186b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown    }
1874e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown
188b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown    // If an image buffer is present, it means the context was not lost due to
189b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown    // an eviction, but rather due to a surface failure (gpu context lost?)
190b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown    if (m_contextRestorable && canvas()->hasImageBuffer()) {
191b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown        m_tryRestoreContextAttemptCount = 0;
192b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown        m_tryRestoreContextEventTimer.startRepeating(TryRestoreContextInterval, FROM_HERE);
193b11499d2db0ba9782363ec6bf714b583e8585212Jeff Brown    }
1944e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown}
1954e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown
1964e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brownvoid CanvasRenderingContext2D::tryRestoreContextEvent(Timer<CanvasRenderingContext2D>* timer)
1974e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown{
19832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown    if (!m_isContextLost) {
199c3672cd3f7e2bd87d6de9dada499de82b62fae84Wale Ogunwale        // Canvas was already restored (possibly thanks to a resize), so stop trying.
200c3672cd3f7e2bd87d6de9dada499de82b62fae84Wale Ogunwale        m_tryRestoreContextEventTimer.stop();
201c3672cd3f7e2bd87d6de9dada499de82b62fae84Wale Ogunwale        return;
202c3672cd3f7e2bd87d6de9dada499de82b62fae84Wale Ogunwale    }
203c3672cd3f7e2bd87d6de9dada499de82b62fae84Wale Ogunwale    if (canvas()->hasImageBuffer() && canvas()->buffer()->restoreSurface()) {
204c3672cd3f7e2bd87d6de9dada499de82b62fae84Wale Ogunwale        m_tryRestoreContextEventTimer.stop();
205c3672cd3f7e2bd87d6de9dada499de82b62fae84Wale Ogunwale        dispatchContextRestoredEvent(0);
20632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown    }
20732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown
20832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown    if (++m_tryRestoreContextAttemptCount > MaxTryRestoreContextAttempts)
20932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown        canvas()->discardImageBuffer();
21032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown
21132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown    if (!canvas()->hasImageBuffer()) {
21232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown        // final attempt: allocate a brand new image buffer instead of restoring
21332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown        timer->stop();
21432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown        if (canvas()->buffer())
21532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown            dispatchContextRestoredEvent(0);
21632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown    }
21732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown}
21832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown
21932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brownvoid CanvasRenderingContext2D::dispatchContextRestoredEvent(Timer<CanvasRenderingContext2D>*)
22032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown{
221692065128e66de77470de2c50ead2bef0452952aJeff Brown    if (!m_isContextLost)
2226ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown        return;
2236ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown    reset();
22491c69ab01539f7ba28708f41ec1835cc2920d0a0Jeff Brown    m_isContextLost = false;
2256ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown    if (contextLostRestoredEventsEnabled()) {
2266ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown        RefPtrWillBeRawPtr<Event> event(Event::create(EventTypeNames::contextrestored));
2276ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown        canvas()->dispatchEvent(event);
2286ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown    }
2296ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown}
2306ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown
2316ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brownvoid CanvasRenderingContext2D::reset()
2326ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown{
2336ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown    validateStateStack();
2346ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown    unwindStateStack();
2356ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown    m_stateStack.resize(1);
2366ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown    m_stateStack.first() = adoptPtrWillBeNoop(new State());
2376ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown    m_path.clear();
2386ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown    validateStateStack();
2396ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown}
2406ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown
2416ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown// Important: Several of these properties are also stored in GraphicsContext's
242c5ed5910c9ef066cec6a13bbb404ec57b1e92637Jeff Brown// 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()!
245CanvasRenderingContext2D::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
270CanvasRenderingContext2D::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
303CanvasRenderingContext2D::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
345CanvasRenderingContext2D::State::~State()
346{
347#if !ENABLE(OILPAN)
348    if (m_realizedFont)
349        static_cast<CSSFontSelector*>(m_font.fontSelector())->unregisterForInvalidationCallbacks(this);
350#endif
351}
352
353void 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
361void CanvasRenderingContext2D::State::trace(Visitor* visitor)
362{
363    visitor->trace(m_strokeStyle);
364    visitor->trace(m_fillStyle);
365    CSSFontSelectorClient::trace(visitor);
366}
367
368void 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
390void 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
410CanvasStyle* CanvasRenderingContext2D::strokeStyle() const
411{
412    return state().m_strokeStyle.get();
413}
414
415void 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
443CanvasStyle* CanvasRenderingContext2D::fillStyle() const
444{
445    return state().m_fillStyle.get();
446}
447
448void 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
476float CanvasRenderingContext2D::lineWidth() const
477{
478    return state().m_lineWidth;
479}
480
481void 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
495String CanvasRenderingContext2D::lineCap() const
496{
497    return lineCapName(state().m_lineCap);
498}
499
500void 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
515String CanvasRenderingContext2D::lineJoin() const
516{
517    return lineJoinName(state().m_lineJoin);
518}
519
520void 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
535float CanvasRenderingContext2D::miterLimit() const
536{
537    return state().m_miterLimit;
538}
539
540void 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
554float CanvasRenderingContext2D::shadowOffsetX() const
555{
556    return state().m_shadowOffset.width();
557}
558
559void 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
570float CanvasRenderingContext2D::shadowOffsetY() const
571{
572    return state().m_shadowOffset.height();
573}
574
575void 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
586float CanvasRenderingContext2D::shadowBlur() const
587{
588    return state().m_shadowBlur;
589}
590
591void 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
602String CanvasRenderingContext2D::shadowColor() const
603{
604    return Color(state().m_shadowColor).serialized();
605}
606
607void 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
619const Vector<float>& CanvasRenderingContext2D::getLineDash() const
620{
621    return state().m_lineDash;
622}
623
624static 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
633void 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
648float CanvasRenderingContext2D::lineDashOffset() const
649{
650    return state().m_lineDashOffset;
651}
652
653void 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
663void 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
674float CanvasRenderingContext2D::globalAlpha() const
675{
676    return state().m_globalAlpha;
677}
678
679void 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
693String CanvasRenderingContext2D::globalCompositeOperation() const
694{
695    return compositeOperatorName(state().m_globalComposite, state().m_globalBlend);
696}
697
698void 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
715void 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
722void 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
750void 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
778void 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
806void 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
834void 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
859void 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
872void 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
881void 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
888void CanvasRenderingContext2D::setStrokeColor(const String& color, float alpha)
889{
890    setStrokeStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha));
891}
892
893void 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
900void 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
907void 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
914void 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
923void 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
930void CanvasRenderingContext2D::setFillColor(const String& color, float alpha)
931{
932    setFillStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha));
933}
934
935void 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
942void 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
949void 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
956void CanvasRenderingContext2D::beginPath()
957{
958    m_path.clear();
959}
960
961static 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
982static 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
990static 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
1001void 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
1045void CanvasRenderingContext2D::fill(const String& windingRuleString)
1046{
1047    fillInternal(m_path, windingRuleString);
1048}
1049
1050void CanvasRenderingContext2D::fill(Path2D* domPath, const String& windingRuleString)
1051{
1052    fillInternal(domPath->path(), windingRuleString);
1053}
1054
1055void 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
1095void CanvasRenderingContext2D::stroke()
1096{
1097    strokeInternal(m_path);
1098}
1099
1100void CanvasRenderingContext2D::stroke(Path2D* domPath)
1101{
1102    strokeInternal(domPath->path());
1103}
1104
1105void 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
1120void CanvasRenderingContext2D::clip(const String& windingRuleString)
1121{
1122    clipInternal(m_path, windingRuleString);
1123}
1124
1125void CanvasRenderingContext2D::clip(Path2D* domPath, const String& windingRuleString)
1126{
1127    clipInternal(domPath->path(), windingRuleString);
1128}
1129
1130bool CanvasRenderingContext2D::isPointInPath(const float x, const float y, const String& windingRuleString)
1131{
1132    return isPointInPathInternal(m_path, x, y, windingRuleString);
1133}
1134
1135bool CanvasRenderingContext2D::isPointInPath(Path2D* domPath, const float x, const float y, const String& windingRuleString)
1136{
1137    return isPointInPathInternal(domPath->path(), x, y, windingRuleString);
1138}
1139
1140bool 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
1157bool CanvasRenderingContext2D::isPointInStroke(const float x, const float y)
1158{
1159    return isPointInStrokeInternal(m_path, x, y);
1160}
1161
1162bool CanvasRenderingContext2D::isPointInStroke(Path2D* domPath, const float x, const float y)
1163{
1164    return isPointInStrokeInternal(domPath->path(), x, y);
1165}
1166
1167bool 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
1190void CanvasRenderingContext2D::scrollPathIntoView()
1191{
1192    scrollPathIntoViewInternal(m_path);
1193}
1194
1195void CanvasRenderingContext2D::scrollPathIntoView(Path2D* path2d)
1196{
1197    scrollPathIntoViewInternal(path2d->path());
1198}
1199
1200void 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
1226void 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
1271void 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
1312void 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
1354void CanvasRenderingContext2D::setShadow(float width, float height, float blur)
1355{
1356    setShadow(FloatSize(width, height), blur, Color::transparent);
1357}
1358
1359void 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
1367void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel)
1368{
1369    setShadow(FloatSize(width, height), blur, makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, 1));
1370}
1371
1372void 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
1380void 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
1385void 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
1390void 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
1395void CanvasRenderingContext2D::clearShadow()
1396{
1397    setShadow(FloatSize(), 0, Color::transparent);
1398}
1399
1400void 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
1414void 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
1428bool CanvasRenderingContext2D::shouldDrawShadows() const
1429{
1430    return alphaChannel(state().m_shadowColor) && (state().m_shadowBlur || !state().m_shadowOffset.isZero());
1431}
1432
1433static 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
1441static 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
1460void 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
1466void 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
1473void 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
1483void 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
1555void 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
1568void 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
1583void CanvasRenderingContext2D::setAlpha(float alpha)
1584{
1585    setGlobalAlpha(alpha);
1586}
1587
1588void CanvasRenderingContext2D::setCompositeOperation(const String& operation)
1589{
1590    setGlobalCompositeOperation(operation);
1591}
1592
1593void 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
1606bool 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
1613static void drawImageToContext(Image* image, GraphicsContext* context, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
1614{
1615    context->drawImage(image, dest, src, op);
1616}
1617
1618template<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
1628static void fillPrimitive(const FloatRect& rect, GraphicsContext* context)
1629{
1630    context->fillRect(rect);
1631}
1632
1633static void fillPrimitive(const Path& path, GraphicsContext* context)
1634{
1635    context->fillPath(path);
1636}
1637
1638template<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
1652static void strokePrimitive(const FloatRect& rect, GraphicsContext* context)
1653{
1654    context->strokeRect(rect);
1655}
1656
1657static void strokePrimitive(const Path& path, GraphicsContext* context)
1658{
1659    context->strokePath(path);
1660}
1661
1662template<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
1676PassRefPtrWillBeRawPtr<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
1682PassRefPtrWillBeRawPtr<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
1693PassRefPtrWillBeRawPtr<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
1729bool 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
1737bool 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
1758void CanvasRenderingContext2D::didDraw(const FloatRect& dirtyRect)
1759{
1760    if (dirtyRect.isEmpty())
1761        return;
1762
1763    canvas()->didDraw(dirtyRect);
1764}
1765
1766GraphicsContext* CanvasRenderingContext2D::drawingContext() const
1767{
1768    if (isContextLost())
1769        return 0;
1770    return canvas()->drawingContext();
1771}
1772
1773static 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
1783PassRefPtrWillBeRawPtr<ImageData> CanvasRenderingContext2D::createImageData(PassRefPtrWillBeRawPtr<ImageData> imageData) const
1784{
1785    return createEmptyImageData(imageData->size());
1786}
1787
1788PassRefPtrWillBeRawPtr<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
1808PassRefPtrWillBeRawPtr<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
1847void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy)
1848{
1849    putImageData(data, dx, dy, 0, 0, data->width(), data->height());
1850}
1851
1852void 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
1884String 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
1921void 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
1997String CanvasRenderingContext2D::textAlign() const
1998{
1999    return textAlignName(state().m_textAlign);
2000}
2001
2002void 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
2013String CanvasRenderingContext2D::textBaseline() const
2014{
2015    return textBaselineName(state().m_textBaseline);
2016}
2017
2018void 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
2029inline 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
2046String 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
2053void 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
2072void CanvasRenderingContext2D::fillText(const String& text, float x, float y)
2073{
2074    drawTextInternal(text, x, y, true);
2075}
2076
2077void CanvasRenderingContext2D::fillText(const String& text, float x, float y, float maxWidth)
2078{
2079    drawTextInternal(text, x, y, true, maxWidth, true);
2080}
2081
2082void CanvasRenderingContext2D::strokeText(const String& text, float x, float y)
2083{
2084    drawTextInternal(text, x, y, false);
2085}
2086
2087void CanvasRenderingContext2D::strokeText(const String& text, float x, float y, float maxWidth)
2088{
2089    drawTextInternal(text, x, y, false, maxWidth, true);
2090}
2091
2092PassRefPtrWillBeRawPtr<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
2133void 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
2245void 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
2260const 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
2269int 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
2291void CanvasRenderingContext2D::setIsHidden(bool hidden)
2292{
2293    ImageBuffer* buffer = canvas()->buffer();
2294    if (buffer)
2295        buffer->setIsHidden(hidden);
2296}
2297
2298blink::WebLayer* CanvasRenderingContext2D::platformLayer() const
2299{
2300    return canvas()->buffer() ? canvas()->buffer()->platformLayer() : 0;
2301}
2302
2303bool CanvasRenderingContext2D::imageSmoothingEnabled() const
2304{
2305    return state().m_imageSmoothingEnabled;
2306}
2307
2308void 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
2320PassRefPtrWillBeRawPtr<Canvas2DContextAttributes> CanvasRenderingContext2D::getContextAttributes() const
2321{
2322    RefPtrWillBeRawPtr<Canvas2DContextAttributes> attributes = Canvas2DContextAttributes::create();
2323    attributes->setAlpha(m_hasAlpha);
2324    return attributes.release();
2325}
2326
2327void CanvasRenderingContext2D::drawFocusIfNeeded(Element* element)
2328{
2329    drawFocusIfNeededInternal(m_path, element);
2330}
2331
2332void CanvasRenderingContext2D::drawFocusIfNeeded(Path2D* path2d, Element* element)
2333{
2334    drawFocusIfNeededInternal(path2d->path(), element);
2335}
2336
2337void 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
2349bool 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
2362void 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
2391void 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
2432void 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
2446void CanvasRenderingContext2D::removeHitRegion(const String& id)
2447{
2448    if (m_hitRegionManager)
2449        m_hitRegionManager->removeHitRegionById(id);
2450}
2451
2452void CanvasRenderingContext2D::clearHitRegions()
2453{
2454    if (m_hitRegionManager)
2455        m_hitRegionManager->removeAllHitRegions();
2456}
2457
2458HitRegion* CanvasRenderingContext2D::hitRegionAtPoint(const LayoutPoint& point)
2459{
2460    if (m_hitRegionManager)
2461        return m_hitRegionManager->getHitRegionAtPoint(point);
2462
2463    return 0;
2464}
2465
2466unsigned CanvasRenderingContext2D::hitRegionsCount() const
2467{
2468    if (m_hitRegionManager)
2469        return m_hitRegionManager->getHitRegionsCount();
2470
2471    return 0;
2472}
2473
2474} // namespace blink
2475