ASSERTION FAILED: m_wrapper on webgl/max-active-contexts-webglcontextlost-prevent...
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 1 Apr 2020 21:51:18 +0000 (21:51 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 1 Apr 2020 21:51:18 +0000 (21:51 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@259364 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/html/HTMLCanvasElement.cpp
Source/WebCore/html/HTMLCanvasElement.h
Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp
Source/WebCore/html/canvas/WebGLRenderingContextBase.h

index 0c4d86c..ded931a 100644 (file)
@@ -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
index e6a2268..ef2b564 100644 (file)
@@ -955,4 +955,28 @@ const char* HTMLCanvasElement::activeDOMObjectName() const
     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
+}
+
 }
index 2e62891..50e7c2c 100644 (file)
@@ -133,7 +133,13 @@ private:
     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 @@ private:
     // 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).
index 94292e3..4be9016 100644 (file)
@@ -5502,6 +5502,11 @@ void WebGLRenderingContextBase::forceRestoreContext()
         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;
index d70cb25..77b2fd9 100644 (file)
@@ -359,6 +359,8 @@ public:
     
     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);