Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1039)

Unified Diff: Source/core/html/canvas/CanvasRenderingContext2D.cpp

Issue 211503006: Implementation of 2D canvas context lost/restored events (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: adding missing file Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/core/html/canvas/CanvasRenderingContext2D.cpp
diff --git a/Source/core/html/canvas/CanvasRenderingContext2D.cpp b/Source/core/html/canvas/CanvasRenderingContext2D.cpp
index 677c2e496b2033ab0ea155587467767f78c6d02c..7f47bcf0dc9ec0a193bbc5b0573285d7a283dd8e 100644
--- a/Source/core/html/canvas/CanvasRenderingContext2D.cpp
+++ b/Source/core/html/canvas/CanvasRenderingContext2D.cpp
@@ -76,12 +76,26 @@ namespace WebCore {
static const int defaultFontSize = 10;
static const char defaultFontFamily[] = "sans-serif";
static const char defaultFont[] = "10px sans-serif";
+static const double TryRestoreSurfaceInterval = 0.5;
+static const unsigned MaxTryRestoreSurfaceAttemps = 4;
+
+static bool contextLostRestoredEventsEnabled()
+{
+ return RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled();
+}
CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, const Canvas2DContextAttributes* attrs, bool usesCSSCompatibilityParseMode)
: CanvasRenderingContext(canvas)
, m_stateStack(1)
, m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode)
, m_hasAlpha(!attrs || attrs->alpha())
+ , m_isContextLost(false)
+ , m_contextRestorable(true)
+ , m_storageMode(!attrs ? PersistentStorage : attrs->parsedStorage())
+ , m_tryRestoreSurfaceAttemptCount(0)
+ , m_dispatchContextLostEventTimer(this, &CanvasRenderingContext2D::dispatchContextLostEvent)
+ , m_dispatchContextRestoredEventTimer(this, &CanvasRenderingContext2D::dispatchContextRestoredEvent)
+ , m_tryRestoreSurfaceEventTimer(this, &CanvasRenderingContext2D::tryRestoreSurfaceEvent)
{
ScriptWrappable::init(this);
}
@@ -114,6 +128,91 @@ bool CanvasRenderingContext2D::isAccelerated() const
return context && context->isAccelerated();
}
+bool CanvasRenderingContext2D::isContextLost() const
+{
+ return m_isContextLost;
+}
+
+void CanvasRenderingContext2D::loseContext()
+{
+ if (m_isContextLost)
+ return;
+ m_isContextLost = true;
+ m_dispatchContextLostEventTimer.startOneShot(0, FROM_HERE);
+}
+
+void CanvasRenderingContext2D::restoreContext()
+{
+ if (!m_contextRestorable)
+ return;
+ // This code path is for restoring from an eviction
+ // Restoring from surface failure is handled internally
+ ASSERT(m_isContextLost && !canvas()->hasImageBuffer());
+
+ if (canvas()->buffer()) {
+ if (contextLostRestoredEventsEnabled()) {
+ m_dispatchContextRestoredEventTimer.startOneShot(0, FROM_HERE);
+ } else {
+ // legacy synchronous context restoration.
+ reset();
+ m_isContextLost = false;
+ }
+ }
+}
+
+void CanvasRenderingContext2D::dispatchContextLostEvent(Timer<CanvasRenderingContext2D>*)
+{
+ if (contextLostRestoredEventsEnabled()) {
+ RefPtr<Event> event(Event::createCancelable(EventTypeNames::contextlost));
+ canvas()->dispatchEvent(event);
+ if (event->defaultPrevented()) {
+ m_contextRestorable = false;
+ }
+ }
+
+ // If an image buffer is present, it means the context was not lost due to
+ // an eviction, but rather due to a surface failure (gpu context lost?)
+ if (m_contextRestorable && canvas()->hasImageBuffer()) {
+ m_tryRestoreSurfaceAttemptCount = 0;
+ m_tryRestoreSurfaceEventTimer.startRepeating(TryRestoreSurfaceInterval, FROM_HERE);
+ }
+}
+
+void CanvasRenderingContext2D::tryRestoreSurfaceEvent(Timer<CanvasRenderingContext2D>* timer)
+{
+ if (!m_isContextLost) {
+ // Canvas was already restored (possibly thanks to a resize), so stop trying.
+ m_tryRestoreSurfaceEventTimer.stop();
+ return;
+ }
+ if (canvas()->hasImageBuffer() && canvas()->buffer()->restoreSurface()) {
+ m_tryRestoreSurfaceEventTimer.stop();
+ dispatchContextRestoredEvent(0);
+ }
+
+ if (++m_tryRestoreSurfaceAttemptCount > MaxTryRestoreSurfaceAttemps)
+ canvas()->discardImageBuffer();
+
+ if (!canvas()->hasImageBuffer()) {
+ // final attempt: allocate a brand new image buffer instead of restoring
+ timer->stop();
+ if (canvas()->buffer())
+ dispatchContextRestoredEvent(0);
+ }
+}
+
+void CanvasRenderingContext2D::dispatchContextRestoredEvent(Timer<CanvasRenderingContext2D>*)
+{
+ if (!m_isContextLost)
+ return;
+ reset();
+ m_isContextLost = false;
+ if (contextLostRestoredEventsEnabled()) {
+ RefPtr<Event> event(Event::create(EventTypeNames::contextrestored));
+ canvas()->dispatchEvent(event);
+ }
+}
+
void CanvasRenderingContext2D::reset()
{
unwindStateStack();
@@ -1665,6 +1764,8 @@ void CanvasRenderingContext2D::didDraw(const FloatRect& dirtyRect)
GraphicsContext* CanvasRenderingContext2D::drawingContext() const
{
+ if (isContextLost())
+ return 0;
return canvas()->drawingContext();
}
@@ -1755,7 +1856,7 @@ PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy,
IntRect imageDataRect = enclosingIntRect(logicalRect);
ImageBuffer* buffer = canvas()->buffer();
- if (!buffer)
+ if (!buffer || isContextLost())
return createEmptyImageData(imageDataRect.size());
RefPtr<Uint8ClampedArray> byteArray = buffer->getUnmultipliedImageData(imageDataRect);

Powered by Google App Engine
This is Rietveld 408576698