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 |