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 TryRestoreSurfaceInterval = 0.5; |
| 80 static const unsigned MaxTryRestoreSurfaceAttemps = 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_stateStack(1) | 89 , m_stateStack(1) |
83 , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode) | 90 , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode) |
84 , m_hasAlpha(!attrs || attrs->alpha()) | 91 , m_hasAlpha(!attrs || attrs->alpha()) |
| 92 , m_isContextLost(false) |
| 93 , m_contextRestorable(true) |
| 94 , m_storageMode(!attrs ? PersistentStorage : attrs->parsedStorage()) |
| 95 , m_tryRestoreSurfaceAttemptCount(0) |
| 96 , m_dispatchContextLostEventTimer(this, &CanvasRenderingContext2D::dispatchC
ontextLostEvent) |
| 97 , m_dispatchContextRestoredEventTimer(this, &CanvasRenderingContext2D::dispa
tchContextRestoredEvent) |
| 98 , m_tryRestoreSurfaceEventTimer(this, &CanvasRenderingContext2D::tryRestoreS
urfaceEvent) |
85 { | 99 { |
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. |
94 if (size_t stackSize = m_stateStack.size()) { | 108 if (size_t stackSize = m_stateStack.size()) { |
(...skipping 12 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_tryRestoreSurfaceAttemptCount = 0; |
| 177 m_tryRestoreSurfaceEventTimer.startRepeating(TryRestoreSurfaceInterval,
FROM_HERE); |
| 178 } |
| 179 } |
| 180 |
| 181 void CanvasRenderingContext2D::tryRestoreSurfaceEvent(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_tryRestoreSurfaceEventTimer.stop(); |
| 186 return; |
| 187 } |
| 188 if (canvas()->hasImageBuffer() && canvas()->buffer()->restoreSurface()) { |
| 189 m_tryRestoreSurfaceEventTimer.stop(); |
| 190 dispatchContextRestoredEvent(0); |
| 191 } |
| 192 |
| 193 if (++m_tryRestoreSurfaceAttemptCount > MaxTryRestoreSurfaceAttemps) |
| 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() = State(); | 220 m_stateStack.first() = 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 1531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1658 canvas()->notifyObserversCanvasChanged(dirtyRect); | 1757 canvas()->notifyObserversCanvasChanged(dirtyRect); |
1659 return; | 1758 return; |
1660 } | 1759 } |
1661 } | 1760 } |
1662 | 1761 |
1663 canvas()->didDraw(dirtyRect); | 1762 canvas()->didDraw(dirtyRect); |
1664 } | 1763 } |
1665 | 1764 |
1666 GraphicsContext* CanvasRenderingContext2D::drawingContext() const | 1765 GraphicsContext* CanvasRenderingContext2D::drawingContext() const |
1667 { | 1766 { |
| 1767 if (isContextLost()) |
| 1768 return 0; |
1668 return canvas()->drawingContext(); | 1769 return canvas()->drawingContext(); |
1669 } | 1770 } |
1670 | 1771 |
1671 static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size) | 1772 static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size) |
1672 { | 1773 { |
1673 if (RefPtr<ImageData> data = ImageData::create(size)) { | 1774 if (RefPtr<ImageData> data = ImageData::create(size)) { |
1674 data->data()->zeroFill(); | 1775 data->data()->zeroFill(); |
1675 return data.release(); | 1776 return data.release(); |
1676 } | 1777 } |
1677 | 1778 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1748 FloatRect logicalRect(sx, sy, sw, sh); | 1849 FloatRect logicalRect(sx, sy, sw, sh); |
1749 if (logicalRect.width() < 1) | 1850 if (logicalRect.width() < 1) |
1750 logicalRect.setWidth(1); | 1851 logicalRect.setWidth(1); |
1751 if (logicalRect.height() < 1) | 1852 if (logicalRect.height() < 1) |
1752 logicalRect.setHeight(1); | 1853 logicalRect.setHeight(1); |
1753 if (!logicalRect.isExpressibleAsIntRect()) | 1854 if (!logicalRect.isExpressibleAsIntRect()) |
1754 return nullptr; | 1855 return nullptr; |
1755 | 1856 |
1756 IntRect imageDataRect = enclosingIntRect(logicalRect); | 1857 IntRect imageDataRect = enclosingIntRect(logicalRect); |
1757 ImageBuffer* buffer = canvas()->buffer(); | 1858 ImageBuffer* buffer = canvas()->buffer(); |
1758 if (!buffer) | 1859 if (!buffer || isContextLost()) |
1759 return createEmptyImageData(imageDataRect.size()); | 1860 return createEmptyImageData(imageDataRect.size()); |
1760 | 1861 |
1761 RefPtr<Uint8ClampedArray> byteArray = buffer->getUnmultipliedImageData(image
DataRect); | 1862 RefPtr<Uint8ClampedArray> byteArray = buffer->getUnmultipliedImageData(image
DataRect); |
1762 if (!byteArray) | 1863 if (!byteArray) |
1763 return nullptr; | 1864 return nullptr; |
1764 | 1865 |
1765 return ImageData::create(imageDataRect.size(), byteArray.release()); | 1866 return ImageData::create(imageDataRect.size(), byteArray.release()); |
1766 } | 1867 } |
1767 | 1868 |
1768 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy,
ExceptionState& exceptionState) | 1869 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy,
ExceptionState& exceptionState) |
(...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2300 c->setAlphaAsFloat(1.0); | 2401 c->setAlphaAsFloat(1.0); |
2301 c->clearShadow(); | 2402 c->clearShadow(); |
2302 c->setCompositeOperation(CompositeSourceOver, blink::WebBlendModeNormal); | 2403 c->setCompositeOperation(CompositeSourceOver, blink::WebBlendModeNormal); |
2303 c->drawFocusRing(path, focusRingWidth, focusRingOutline, focusRingColor); | 2404 c->drawFocusRing(path, focusRingWidth, focusRingOutline, focusRingColor); |
2304 c->restore(); | 2405 c->restore(); |
2305 | 2406 |
2306 didDraw(dirtyRect); | 2407 didDraw(dirtyRect); |
2307 } | 2408 } |
2308 | 2409 |
2309 } // namespace WebCore | 2410 } // namespace WebCore |
OLD | NEW |