| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc.
All rights reserved. | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc.
All rights reserved. |
| 3 * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies) | 3 * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies) |
| 4 * Copyright (C) 2007 Alp Toker <alp@atoker.com> | 4 * Copyright (C) 2007 Alp Toker <alp@atoker.com> |
| 5 * Copyright (C) 2008 Eric Seidel <eric@webkit.org> | 5 * Copyright (C) 2008 Eric Seidel <eric@webkit.org> |
| 6 * Copyright (C) 2008 Dirk Schulze <krit@webkit.org> | 6 * Copyright (C) 2008 Dirk Schulze <krit@webkit.org> |
| 7 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. | 7 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. |
| 8 * Copyright (C) 2012, 2013 Intel Corporation. All rights reserved. | 8 * Copyright (C) 2012, 2013 Intel Corporation. All rights reserved. |
| 9 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. | 9 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. |
| 10 * | 10 * |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 #include "wtf/Uint8ClampedArray.h" | 69 #include "wtf/Uint8ClampedArray.h" |
| 70 #include "wtf/text/StringBuilder.h" | 70 #include "wtf/text/StringBuilder.h" |
| 71 | 71 |
| 72 using namespace std; | 72 using namespace std; |
| 73 | 73 |
| 74 namespace WebCore { | 74 namespace WebCore { |
| 75 | 75 |
| 76 static const int defaultFontSize = 10; | 76 static const int defaultFontSize = 10; |
| 77 static const char defaultFontFamily[] = "sans-serif"; | 77 static const char defaultFontFamily[] = "sans-serif"; |
| 78 static const char defaultFont[] = "10px sans-serif"; | 78 static const char defaultFont[] = "10px sans-serif"; |
| 79 static const double TryRestoreContextInterval = 0.5; |
| 80 static const unsigned MaxTryRestoreContextAttempts = 4; |
| 81 |
| 82 static bool contextLostRestoredEventsEnabled() |
| 83 { |
| 84 return RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled(); |
| 85 } |
| 79 | 86 |
| 80 CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, co
nst Canvas2DContextAttributes* attrs, bool usesCSSCompatibilityParseMode) | 87 CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, co
nst Canvas2DContextAttributes* attrs, bool usesCSSCompatibilityParseMode) |
| 81 : CanvasRenderingContext(canvas) | 88 : CanvasRenderingContext(canvas) |
| 82 , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode) | 89 , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode) |
| 83 , m_hasAlpha(!attrs || attrs->alpha()) | 90 , m_hasAlpha(!attrs || attrs->alpha()) |
| 91 , m_isContextLost(false) |
| 92 , m_contextRestorable(true) |
| 93 , m_storageMode(!attrs ? PersistentStorage : attrs->parsedStorage()) |
| 94 , m_tryRestoreContextAttemptCount(0) |
| 95 , m_dispatchContextLostEventTimer(this, &CanvasRenderingContext2D::dispatchC
ontextLostEvent) |
| 96 , m_dispatchContextRestoredEventTimer(this, &CanvasRenderingContext2D::dispa
tchContextRestoredEvent) |
| 97 , m_tryRestoreContextEventTimer(this, &CanvasRenderingContext2D::tryRestoreC
ontextEvent) |
| 84 { | 98 { |
| 85 m_stateStack.append(adoptPtrWillBeNoop(new State())); | 99 m_stateStack.append(adoptPtrWillBeNoop(new State())); |
| 86 ScriptWrappable::init(this); | 100 ScriptWrappable::init(this); |
| 87 } | 101 } |
| 88 | 102 |
| 89 void CanvasRenderingContext2D::unwindStateStack() | 103 void CanvasRenderingContext2D::unwindStateStack() |
| 90 { | 104 { |
| 91 // Ensure that the state stack in the ImageBuffer's context | 105 // Ensure that the state stack in the ImageBuffer's context |
| 92 // is cleared before destruction, to avoid assertions in the | 106 // is cleared before destruction, to avoid assertions in the |
| 93 // GraphicsContext dtor. | 107 // GraphicsContext dtor. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 107 } | 121 } |
| 108 | 122 |
| 109 bool CanvasRenderingContext2D::isAccelerated() const | 123 bool CanvasRenderingContext2D::isAccelerated() const |
| 110 { | 124 { |
| 111 if (!canvas()->hasImageBuffer()) | 125 if (!canvas()->hasImageBuffer()) |
| 112 return false; | 126 return false; |
| 113 GraphicsContext* context = drawingContext(); | 127 GraphicsContext* context = drawingContext(); |
| 114 return context && context->isAccelerated(); | 128 return context && context->isAccelerated(); |
| 115 } | 129 } |
| 116 | 130 |
| 131 bool CanvasRenderingContext2D::isContextLost() const |
| 132 { |
| 133 return m_isContextLost; |
| 134 } |
| 135 |
| 136 void CanvasRenderingContext2D::loseContext() |
| 137 { |
| 138 if (m_isContextLost) |
| 139 return; |
| 140 m_isContextLost = true; |
| 141 m_dispatchContextLostEventTimer.startOneShot(0, FROM_HERE); |
| 142 } |
| 143 |
| 144 void CanvasRenderingContext2D::restoreContext() |
| 145 { |
| 146 if (!m_contextRestorable) |
| 147 return; |
| 148 // This code path is for restoring from an eviction |
| 149 // Restoring from surface failure is handled internally |
| 150 ASSERT(m_isContextLost && !canvas()->hasImageBuffer()); |
| 151 |
| 152 if (canvas()->buffer()) { |
| 153 if (contextLostRestoredEventsEnabled()) { |
| 154 m_dispatchContextRestoredEventTimer.startOneShot(0, FROM_HERE); |
| 155 } else { |
| 156 // legacy synchronous context restoration. |
| 157 reset(); |
| 158 m_isContextLost = false; |
| 159 } |
| 160 } |
| 161 } |
| 162 |
| 163 void CanvasRenderingContext2D::dispatchContextLostEvent(Timer<CanvasRenderingCon
text2D>*) |
| 164 { |
| 165 if (contextLostRestoredEventsEnabled()) { |
| 166 RefPtr<Event> event(Event::createCancelable(EventTypeNames::contextlost)
); |
| 167 canvas()->dispatchEvent(event); |
| 168 if (event->defaultPrevented()) { |
| 169 m_contextRestorable = false; |
| 170 } |
| 171 } |
| 172 |
| 173 // If an image buffer is present, it means the context was not lost due to |
| 174 // an eviction, but rather due to a surface failure (gpu context lost?) |
| 175 if (m_contextRestorable && canvas()->hasImageBuffer()) { |
| 176 m_tryRestoreContextAttemptCount = 0; |
| 177 m_tryRestoreContextEventTimer.startRepeating(TryRestoreContextInterval,
FROM_HERE); |
| 178 } |
| 179 } |
| 180 |
| 181 void CanvasRenderingContext2D::tryRestoreContextEvent(Timer<CanvasRenderingConte
xt2D>* timer) |
| 182 { |
| 183 if (!m_isContextLost) { |
| 184 // Canvas was already restored (possibly thanks to a resize), so stop tr
ying. |
| 185 m_tryRestoreContextEventTimer.stop(); |
| 186 return; |
| 187 } |
| 188 if (canvas()->hasImageBuffer() && canvas()->buffer()->restoreSurface()) { |
| 189 m_tryRestoreContextEventTimer.stop(); |
| 190 dispatchContextRestoredEvent(0); |
| 191 } |
| 192 |
| 193 if (++m_tryRestoreContextAttemptCount > MaxTryRestoreContextAttempts) |
| 194 canvas()->discardImageBuffer(); |
| 195 |
| 196 if (!canvas()->hasImageBuffer()) { |
| 197 // final attempt: allocate a brand new image buffer instead of restoring |
| 198 timer->stop(); |
| 199 if (canvas()->buffer()) |
| 200 dispatchContextRestoredEvent(0); |
| 201 } |
| 202 } |
| 203 |
| 204 void CanvasRenderingContext2D::dispatchContextRestoredEvent(Timer<CanvasRenderin
gContext2D>*) |
| 205 { |
| 206 if (!m_isContextLost) |
| 207 return; |
| 208 reset(); |
| 209 m_isContextLost = false; |
| 210 if (contextLostRestoredEventsEnabled()) { |
| 211 RefPtr<Event> event(Event::create(EventTypeNames::contextrestored)); |
| 212 canvas()->dispatchEvent(event); |
| 213 } |
| 214 } |
| 215 |
| 117 void CanvasRenderingContext2D::reset() | 216 void CanvasRenderingContext2D::reset() |
| 118 { | 217 { |
| 119 unwindStateStack(); | 218 unwindStateStack(); |
| 120 m_stateStack.resize(1); | 219 m_stateStack.resize(1); |
| 121 m_stateStack.first() = adoptPtrWillBeNoop(new State()); | 220 m_stateStack.first() = adoptPtrWillBeNoop(new State()); |
| 122 m_path.clear(); | 221 m_path.clear(); |
| 123 } | 222 } |
| 124 | 223 |
| 125 // Important: Several of these properties are also stored in GraphicsContext's | 224 // Important: Several of these properties are also stored in GraphicsContext's |
| 126 // StrokeData. The default values that StrokeData uses may not the same values | 225 // StrokeData. The default values that StrokeData uses may not the same values |
| (...skipping 1530 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1657 canvas()->notifyObserversCanvasChanged(dirtyRect); | 1756 canvas()->notifyObserversCanvasChanged(dirtyRect); |
| 1658 return; | 1757 return; |
| 1659 } | 1758 } |
| 1660 } | 1759 } |
| 1661 | 1760 |
| 1662 canvas()->didDraw(dirtyRect); | 1761 canvas()->didDraw(dirtyRect); |
| 1663 } | 1762 } |
| 1664 | 1763 |
| 1665 GraphicsContext* CanvasRenderingContext2D::drawingContext() const | 1764 GraphicsContext* CanvasRenderingContext2D::drawingContext() const |
| 1666 { | 1765 { |
| 1766 if (isContextLost()) |
| 1767 return 0; |
| 1667 return canvas()->drawingContext(); | 1768 return canvas()->drawingContext(); |
| 1668 } | 1769 } |
| 1669 | 1770 |
| 1670 static PassRefPtrWillBeRawPtr<ImageData> createEmptyImageData(const IntSize& siz
e) | 1771 static PassRefPtrWillBeRawPtr<ImageData> createEmptyImageData(const IntSize& siz
e) |
| 1671 { | 1772 { |
| 1672 if (RefPtrWillBeRawPtr<ImageData> data = ImageData::create(size)) { | 1773 if (RefPtrWillBeRawPtr<ImageData> data = ImageData::create(size)) { |
| 1673 data->data()->zeroFill(); | 1774 data->data()->zeroFill(); |
| 1674 return data.release(); | 1775 return data.release(); |
| 1675 } | 1776 } |
| 1676 | 1777 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1742 FloatRect logicalRect(sx, sy, sw, sh); | 1843 FloatRect logicalRect(sx, sy, sw, sh); |
| 1743 if (logicalRect.width() < 1) | 1844 if (logicalRect.width() < 1) |
| 1744 logicalRect.setWidth(1); | 1845 logicalRect.setWidth(1); |
| 1745 if (logicalRect.height() < 1) | 1846 if (logicalRect.height() < 1) |
| 1746 logicalRect.setHeight(1); | 1847 logicalRect.setHeight(1); |
| 1747 if (!logicalRect.isExpressibleAsIntRect()) | 1848 if (!logicalRect.isExpressibleAsIntRect()) |
| 1748 return nullptr; | 1849 return nullptr; |
| 1749 | 1850 |
| 1750 IntRect imageDataRect = enclosingIntRect(logicalRect); | 1851 IntRect imageDataRect = enclosingIntRect(logicalRect); |
| 1751 ImageBuffer* buffer = canvas()->buffer(); | 1852 ImageBuffer* buffer = canvas()->buffer(); |
| 1752 if (!buffer) | 1853 if (!buffer || isContextLost()) |
| 1753 return createEmptyImageData(imageDataRect.size()); | 1854 return createEmptyImageData(imageDataRect.size()); |
| 1754 | 1855 |
| 1755 RefPtr<Uint8ClampedArray> byteArray = buffer->getUnmultipliedImageData(image
DataRect); | 1856 RefPtr<Uint8ClampedArray> byteArray = buffer->getUnmultipliedImageData(image
DataRect); |
| 1756 if (!byteArray) | 1857 if (!byteArray) |
| 1757 return nullptr; | 1858 return nullptr; |
| 1758 | 1859 |
| 1759 return ImageData::create(imageDataRect.size(), byteArray.release()); | 1860 return ImageData::create(imageDataRect.size(), byteArray.release()); |
| 1760 } | 1861 } |
| 1761 | 1862 |
| 1762 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy,
ExceptionState& exceptionState) | 1863 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy,
ExceptionState& exceptionState) |
| (...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2296 c->setAlphaAsFloat(1.0); | 2397 c->setAlphaAsFloat(1.0); |
| 2297 c->clearShadow(); | 2398 c->clearShadow(); |
| 2298 c->setCompositeOperation(CompositeSourceOver, blink::WebBlendModeNormal); | 2399 c->setCompositeOperation(CompositeSourceOver, blink::WebBlendModeNormal); |
| 2299 c->drawFocusRing(path, focusRingWidth, focusRingOutline, focusRingColor); | 2400 c->drawFocusRing(path, focusRingWidth, focusRingOutline, focusRingColor); |
| 2300 c->restore(); | 2401 c->restore(); |
| 2301 | 2402 |
| 2302 didDraw(dirtyRect); | 2403 didDraw(dirtyRect); |
| 2303 } | 2404 } |
| 2304 | 2405 |
| 2305 } // namespace WebCore | 2406 } // namespace WebCore |
| OLD | NEW |