ASSERTION FAILED: m_wrapper on webgl/max-active-contexts-webglcontextlost-prevent-default.html
https://bugs.webkit.org/show_bug.cgi?id=209863
<rdar://problem/61164936>
Reviewed by Darin Adler.
The HTMLCanvasElement JS wrapper needs to stay alive as long as JS events may need to be fired.
When the canvas has a WebGL context, the WebGL context may cause contextlost / contextrestored
/ contextchanged events at any point, unless the context is unrecoverably lost. To fix the
issue, we now override virtualHasPendingActivity() in HTMLCanvasElement and return true if
it has a WebGL context that is not unrecoverably lost and if relevant WebGL event listeners
are registed.
No new tests, covered by existing test.
* html/HTMLCanvasElement.cpp:
(WebCore::HTMLCanvasElement::~HTMLCanvasElement):
(WebCore::HTMLCanvasElement::virtualHasPendingActivity const):
(WebCore::HTMLCanvasElement::stop):
(WebCore::HTMLCanvasElement::eventListenersDidChange):
* html/HTMLCanvasElement.h:
* html/canvas/WebGLRenderingContextBase.cpp:
(WebCore::WebGLRenderingContextBase::isContextUnrecoverablyLost const):
* html/canvas/WebGLRenderingContextBase.h:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@259364 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 0c4d86c..ded931a 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,30 @@
+2020-04-01 Chris Dumez <cdumez@apple.com>
+
+ ASSERTION FAILED: m_wrapper on webgl/max-active-contexts-webglcontextlost-prevent-default.html
+ https://bugs.webkit.org/show_bug.cgi?id=209863
+ <rdar://problem/61164936>
+
+ Reviewed by Darin Adler.
+
+ The HTMLCanvasElement JS wrapper needs to stay alive as long as JS events may need to be fired.
+ When the canvas has a WebGL context, the WebGL context may cause contextlost / contextrestored
+ / contextchanged events at any point, unless the context is unrecoverably lost. To fix the
+ issue, we now override virtualHasPendingActivity() in HTMLCanvasElement and return true if
+ it has a WebGL context that is not unrecoverably lost and if relevant WebGL event listeners
+ are registed.
+
+ No new tests, covered by existing test.
+
+ * html/HTMLCanvasElement.cpp:
+ (WebCore::HTMLCanvasElement::~HTMLCanvasElement):
+ (WebCore::HTMLCanvasElement::virtualHasPendingActivity const):
+ (WebCore::HTMLCanvasElement::stop):
+ (WebCore::HTMLCanvasElement::eventListenersDidChange):
+ * html/HTMLCanvasElement.h:
+ * html/canvas/WebGLRenderingContextBase.cpp:
+ (WebCore::WebGLRenderingContextBase::isContextUnrecoverablyLost const):
+ * html/canvas/WebGLRenderingContextBase.h:
+
2020-04-01 Jer Noble <jer.noble@apple.com>
CRASH in MediaPlayerPrivateMediaSourceAVFObjC::addAudioRenderer(), uncaught ObjC exception
diff --git a/Source/WebCore/html/HTMLCanvasElement.cpp b/Source/WebCore/html/HTMLCanvasElement.cpp
index e6a2268..ef2b564 100644
--- a/Source/WebCore/html/HTMLCanvasElement.cpp
+++ b/Source/WebCore/html/HTMLCanvasElement.cpp
@@ -955,4 +955,28 @@
return "HTMLCanvasElement";
}
+bool HTMLCanvasElement::virtualHasPendingActivity() const
+{
+ if (isContextStopped())
+ return false;
+
+#if ENABLE(WEBGL)
+ if (is<WebGLRenderingContextBase>(m_context.get())) {
+ // WebGL rendering context may fire contextlost / contextchange / contextrestored events at any point.
+ return m_hasRelevantWebGLEventListener && !downcast<WebGLRenderingContextBase>(*m_context).isContextUnrecoverablyLost();
+ }
+#endif
+
+ return false;
+}
+
+void HTMLCanvasElement::eventListenersDidChange()
+{
+#if ENABLE(WEBGL)
+ m_hasRelevantWebGLEventListener = hasEventListeners(eventNames().webglcontextchangedEvent)
+ || hasEventListeners(eventNames().webglcontextlostEvent)
+ || hasEventListeners(eventNames().webglcontextrestoredEvent);
+#endif
+}
+
}
diff --git a/Source/WebCore/html/HTMLCanvasElement.h b/Source/WebCore/html/HTMLCanvasElement.h
index 2e62891..50e7c2c 100644
--- a/Source/WebCore/html/HTMLCanvasElement.h
+++ b/Source/WebCore/html/HTMLCanvasElement.h
@@ -133,7 +133,13 @@
HTMLCanvasElement(const QualifiedName&, Document&);
bool isHTMLCanvasElement() const final { return true; }
+
+ // ActiveDOMObject.
const char* activeDOMObjectName() const final;
+ bool virtualHasPendingActivity() const final;
+
+ // EventTarget.
+ void eventListenersDidChange() final;
void parseAttribute(const QualifiedName&, const AtomString&) final;
RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
@@ -171,6 +177,9 @@
// m_hasCreatedImageBuffer means we tried to malloc the buffer. We didn't necessarily get it.
mutable bool m_hasCreatedImageBuffer { false };
mutable bool m_didClearImageBuffer { false };
+#if ENABLE(WEBGL)
+ bool m_hasRelevantWebGLEventListener { false };
+#endif
mutable RefPtr<Image> m_presentedImage;
mutable RefPtr<Image> m_copiedImage; // FIXME: This is temporary for platforms that have to copy the image buffer to render (and for CSSCanvasValue).
diff --git a/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp b/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp
index 94292e3..4be9016 100644
--- a/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp
+++ b/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp
@@ -5502,6 +5502,11 @@
m_restoreTimer.startOneShot(0_s);
}
+bool WebGLRenderingContextBase::isContextUnrecoverablyLost() const
+{
+ return m_contextLost && !m_restoreAllowed;
+}
+
PlatformLayer* WebGLRenderingContextBase::platformLayer() const
{
return (!isContextLost() && !m_isPendingPolicyResolution) ? m_context->platformLayer() : 0;
diff --git a/Source/WebCore/html/canvas/WebGLRenderingContextBase.h b/Source/WebCore/html/canvas/WebGLRenderingContextBase.h
index d70cb25..77b2fd9 100644
--- a/Source/WebCore/html/canvas/WebGLRenderingContextBase.h
+++ b/Source/WebCore/html/canvas/WebGLRenderingContextBase.h
@@ -359,6 +359,8 @@
unsigned getMaxVertexAttribs() const { return m_maxVertexAttribs; }
+ bool isContextUnrecoverablyLost() const;
+
// Instanced Array helper functions.
void drawArraysInstanced(GCGLenum mode, GCGLint first, GCGLsizei count, GCGLsizei primcount);
void drawElementsInstanced(GCGLenum mode, GCGLsizei count, GCGLenum type, long long offset, GCGLsizei primcount);