Title: [238686] trunk
Revision
238686
Author
justin_mich...@apple.com
Date
2018-11-29 13:01:15 -0800 (Thu, 29 Nov 2018)

Log Message

CSS Painting API should pass 'this' correctly to paint callback, and repaint when properties change.
https://bugs.webkit.org/show_bug.cgi?id=191443

Reviewed by Dean Jackson.

Source/_javascript_Core:

Export the simpler construct() method for use in WebCore.

* runtime/ConstructData.h:

Source/WebCore:

Instantiate a new instance of the paint class, and pass it as 'this' object when the paint callback is called.
Also, this patch makes sure that custom paint elements get repainted when properties that they care about get changed.
Finally, we fix two reference cycles that caused WorkletGlobalScope to never be destroyed.

Tests: fast/css-custom-paint/animate-repaint.html
       fast/css-custom-paint/animate.html

* bindings/js/JSDOMWrapper.cpp:
* bindings/js/JSPaintWorkletGlobalScopeCustom.cpp:
(WebCore::JSPaintWorkletGlobalScope::visitAdditionalChildren):
* bindings/js/JSWorkletGlobalScopeBase.cpp:
(WebCore::toJS):
* bindings/js/ScriptState.cpp:
(WebCore::execStateFromWorkletGlobalScope):
* css/CSSPaintCallback.h:
* css/CSSPaintCallback.idl:
* css/CSSPaintImageValue.h:
* css/StyleResolver.cpp:
(WebCore::StyleResolver::applyProperty):
* dom/Document.cpp:
(WebCore::Document::prepareForDestruction):
* dom/ScriptExecutionContext.cpp:
(WebCore::ScriptExecutionContext::vm):
* platform/graphics/CustomPaintImage.cpp:
(WebCore::CustomPaintImage::CustomPaintImage):
(WebCore::CustomPaintImage::doCustomPaint):
* platform/graphics/CustomPaintImage.h:
* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::addCustomPaintWatchProperty):
(WebCore::RenderStyle::changeRequiresRepaint const):
* rendering/style/RenderStyle.h:
* rendering/style/StyleRareNonInheritedData.cpp:
(WebCore::StyleRareNonInheritedData::StyleRareNonInheritedData):
(WebCore::StyleRareNonInheritedData::operator== const):
* rendering/style/StyleRareNonInheritedData.h:
* testing/Internals.cpp:
(WebCore::Internals::isAnyWorkletGlobalScopeAlive const):
* testing/Internals.h:
* testing/Internals.idl:
* worklets/PaintWorkletGlobalScope.cpp:
(WebCore::PaintWorkletGlobalScope::devicePixelRatio const):
(WebCore::PaintWorkletGlobalScope::PaintDefinition::PaintDefinition):
(WebCore::PaintWorkletGlobalScope::registerPaint):
* worklets/PaintWorkletGlobalScope.h:
(WebCore::PaintWorkletGlobalScope::~PaintWorkletGlobalScope):
* worklets/WorkletGlobalScope.cpp:
(WebCore::WorkletGlobalScope::WorkletGlobalScope):
(WebCore::WorkletGlobalScope::~WorkletGlobalScope):
(WebCore::WorkletGlobalScope::prepareForDestruction):
(WebCore::WorkletGlobalScope::allWorkletGlobalScopesSet):
(WebCore::WorkletGlobalScope::isJSExecutionForbidden const):
(WebCore::WorkletGlobalScope::logExceptionToConsole):
(WebCore::WorkletGlobalScope::addConsoleMessage):
(WebCore::WorkletGlobalScope::addMessage):
* worklets/WorkletGlobalScope.h:
(WebCore::WorkletGlobalScope::script):
(WebCore::WorkletGlobalScope::responsibleDocument):
(WebCore::WorkletGlobalScope::responsibleDocument const):
(WebCore::WorkletGlobalScope::identifier const): Deleted.
(WebCore::WorkletGlobalScope::responsableDocument): Deleted.
(WebCore::WorkletGlobalScope::responsableDocument const): Deleted.
* worklets/WorkletScriptController.cpp:
(WebCore::WorkletScriptController::~WorkletScriptController):
(WebCore::WorkletScriptController::disableEval):
(WebCore::WorkletScriptController::disableWebAssembly):
(WebCore::WorkletScriptController::initScript):

LayoutTests:

* fast/css-custom-paint/animate-expected.html: Added.
* fast/css-custom-paint/animate-repaint-expected.txt: Added.
* fast/css-custom-paint/animate-repaint.html: Added.
* fast/css-custom-paint/animate.html: Added.
* fast/css-custom-paint/constructor-expected.html: Added.
* fast/css-custom-paint/constructor.html: Added.
* fast/css-custom-paint/leaks-expected.txt: Added.
* fast/css-custom-paint/leaks.html: Added.
* fast/css-custom-paint/properties.html:
* fast/css-custom-paint/resources/leaks-frame.html: Added.
* platform/mac/fast/css-custom-paint/raf-leak-expected.txt: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (238685 => 238686)


--- trunk/LayoutTests/ChangeLog	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/LayoutTests/ChangeLog	2018-11-29 21:01:15 UTC (rev 238686)
@@ -1,3 +1,22 @@
+2018-11-29  Justin Michaud  <justin_mich...@apple.com>
+
+        CSS Painting API should pass 'this' correctly to paint callback, and repaint when properties change.
+        https://bugs.webkit.org/show_bug.cgi?id=191443
+
+        Reviewed by Dean Jackson.
+
+        * fast/css-custom-paint/animate-expected.html: Added.
+        * fast/css-custom-paint/animate-repaint-expected.txt: Added.
+        * fast/css-custom-paint/animate-repaint.html: Added.
+        * fast/css-custom-paint/animate.html: Added.
+        * fast/css-custom-paint/constructor-expected.html: Added.
+        * fast/css-custom-paint/constructor.html: Added.
+        * fast/css-custom-paint/leaks-expected.txt: Added.
+        * fast/css-custom-paint/leaks.html: Added.
+        * fast/css-custom-paint/properties.html:
+        * fast/css-custom-paint/resources/leaks-frame.html: Added.
+        * platform/mac/fast/css-custom-paint/raf-leak-expected.txt: Added.
+
 2018-11-29  Youenn Fablet  <you...@apple.com>
 
         A sender created through addTransceiver and populated using addTrack should have its source set

Added: trunk/LayoutTests/fast/css-custom-paint/animate-expected.html (0 => 238686)


--- trunk/LayoutTests/fast/css-custom-paint/animate-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/css-custom-paint/animate-expected.html	2018-11-29 21:01:15 UTC (rev 238686)
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<style>
+  #paint {
+    background: green;
+    width: 150px;
+    height: 150px;
+  }
+</style>
+
+<body>
+  <div id="paint"></div>
+</body>

Added: trunk/LayoutTests/fast/css-custom-paint/animate-repaint-expected.txt (0 => 238686)


--- trunk/LayoutTests/fast/css-custom-paint/animate-repaint-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/css-custom-paint/animate-repaint-expected.txt	2018-11-29 21:01:15 UTC (rev 238686)
@@ -0,0 +1,11 @@
+(repaint rects
+  (rect 0 0 800 600)
+  (rect 0 0 150 150)
+  (rect 8 8 784 150)
+  (rect 0 0 800 166)
+  (rect 0 0 800 600)
+  (rect 8 8 150 150)
+  (rect 8 8 150 150)
+  (rect 8 8 150 150)
+)
+

Added: trunk/LayoutTests/fast/css-custom-paint/animate-repaint.html (0 => 238686)


--- trunk/LayoutTests/fast/css-custom-paint/animate-repaint.html	                        (rev 0)
+++ trunk/LayoutTests/fast/css-custom-paint/animate-repaint.html	2018-11-29 21:01:15 UTC (rev 238686)
@@ -0,0 +1,66 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:CSSPaintingAPIEnabled=true ] -->
+<meta name="author" title="Justin Michaud" href=""
+<meta name="assert" content="Test that paint worklets repaint when properties change">
+<link rel="help" content="https://drafts.css-houdini.org/css-paint-api-1/">
+<script src=""
+
+<script id="code" type="text/worklet">
+  class MyPaint {
+    static get inputProperties() { return ['--my-prop']; }
+
+    paint(ctx, geom, properties) {
+      if (properties.get('--my-prop').toString() != "goodbye") {
+        ctx.fillStyle = "red";
+      } else {
+        ctx.fillStyle = "green";
+      }
+
+      ctx.fillRect(0, 0, geom.width, geom.height);
+    }
+  }
+  registerPaint('my-paint', MyPaint);
+</script>
+
+<script type="text/_javascript_">
+  if (window.testRunner && window.internals) {
+    window.testRunner.dumpAsText(false);
+    window.internals.startTrackingRepaints();
+  }
+  importWorklet(CSS.paintWorklet, document.getElementById('code').textContent);
+
+  // FIXME: Once importWorklet returns a promise, these setTimeouts should go away.
+  setTimeout(function() {
+    document.getElementById('paint').style.setProperty('--my-prop', 'goodbye');
+  }, 500);
+
+  setTimeout(function() {
+    var repaintRects = "No test runner";
+    if (window.testRunner && window.internals) {
+      window.internals.startTrackingRepaints();
+
+      // force a style recalc.
+      var dummy = document.body.offsetTop;
+
+      repaintRects = window.internals.repaintRectsAsText();
+
+      window.internals.stopTrackingRepaints();
+    }
+
+    var pre = document.createElement('pre');
+    document.body.appendChild(pre);
+    pre.innerHTML = repaintRects;
+  }, 1000);
+</script>
+
+<style>
+  #paint {
+    background-image: paint(my-paint);
+    --my-prop: hello;
+    width: 150px;
+    height: 150px;
+  }
+</style>
+
+<body>
+  <div id="paint"></div>
+</body>

Added: trunk/LayoutTests/fast/css-custom-paint/animate.html (0 => 238686)


--- trunk/LayoutTests/fast/css-custom-paint/animate.html	                        (rev 0)
+++ trunk/LayoutTests/fast/css-custom-paint/animate.html	2018-11-29 21:01:15 UTC (rev 238686)
@@ -0,0 +1,44 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:CSSPaintingAPIEnabled=true ] -->
+<meta name="author" title="Justin Michaud" href=""
+<meta name="assert" content="Test that paint worklets repaint when properties change">
+<link rel="help" content="https://drafts.css-houdini.org/css-paint-api-1/">
+<script src=""
+
+<script id="code" type="text/worklet">
+  class MyPaint {
+    static get inputProperties() { return ['--my-prop']; }
+
+    paint(ctx, geom, properties) {
+      if (properties.get('--my-prop').toString() != "goodbye") {
+        ctx.fillStyle = "red";
+      } else {
+        ctx.fillStyle = "green";
+      }
+
+      ctx.fillRect(0, 0, geom.width, geom.height);
+    }
+  }
+  registerPaint('my-paint', MyPaint);
+</script>
+
+<script type="text/_javascript_">
+  importWorklet(CSS.paintWorklet, document.getElementById('code').textContent);
+
+  // FIXME: Once importWorklet returns a promise, these setTimeouts should go away.
+  setTimeout(function() {
+    document.getElementById('paint').style.setProperty('--my-prop', 'goodbye');
+  }, 500);
+</script>
+
+<style>
+  #paint {
+    background-image: paint(my-paint);
+    --my-prop: hello;
+    width: 150px;
+    height: 150px;
+  }
+</style>
+
+<body>
+  <div id="paint"></div>
+</body>

Added: trunk/LayoutTests/fast/css-custom-paint/constructor-expected.html (0 => 238686)


--- trunk/LayoutTests/fast/css-custom-paint/constructor-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/css-custom-paint/constructor-expected.html	2018-11-29 21:01:15 UTC (rev 238686)
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<style>
+  .paint {
+    width: 150px;
+    height: 150px;
+  }
+</style>
+
+<body>
+  <div class="paint" style="background: white;"></div>
+  <div class="paint" style="background: green;"></div>
+  <div class="paint" style="background: green;"></div>
+</body>

Added: trunk/LayoutTests/fast/css-custom-paint/constructor.html (0 => 238686)


--- trunk/LayoutTests/fast/css-custom-paint/constructor.html	                        (rev 0)
+++ trunk/LayoutTests/fast/css-custom-paint/constructor.html	2018-11-29 21:01:15 UTC (rev 238686)
@@ -0,0 +1,52 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:CSSPaintingAPIEnabled=true ] -->
+<meta name="author" title="Justin Michaud" href=""
+<meta name="assert" content="Test that paint worklets do not crash if the constructor throws">
+<link rel="help" content="https://drafts.css-houdini.org/css-paint-api-1/">
+<script src=""
+
+<script id="code" type="text/worklet">
+  class MyPaint {
+    constructor() {
+      throw "Hello!";
+    }
+
+    paint(ctx, geom) {
+      ctx.fillStyle = "green";
+      ctx.fillRect(0, 0, geom.width, geom.height);
+    }
+  }
+
+  class MyPaint2 {
+    constructor() {
+    }
+
+    paint(ctx, geom) {
+      ctx.fillStyle = "green";
+      ctx.fillRect(0, 0, geom.width, geom.height);
+    }
+  }
+  registerPaint('my-paint', MyPaint);
+  registerPaint('my-paint2', MyPaint2);
+</script>
+
+<script type="text/_javascript_">
+  importWorklet(CSS.paintWorklet, document.getElementById('code').textContent);
+  setTimeout(function() {
+    if (window.internals && window.internals.isAnyWorkletGlobalScopeAlive()) {
+      document.getElementById('leaks').style.background = ""
+    }
+  }, 500);
+</script>
+
+<style>
+  .paint {
+    width: 150px;
+    height: 150px;
+  }
+</style>
+
+<body>
+  <div class="paint" style="background-image: paint(my-paint);"></div>
+  <div class="paint" style="background-image: paint(my-paint2);"></div>
+  <div id="leaks" style="background: red; width: 150px; height: 150px;"></div>
+</body>

Added: trunk/LayoutTests/fast/css-custom-paint/leaks-expected.txt (0 => 238686)


--- trunk/LayoutTests/fast/css-custom-paint/leaks-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/css-custom-paint/leaks-expected.txt	2018-11-29 21:01:15 UTC (rev 238686)
@@ -0,0 +1,10 @@
+Tests that using custom paint does not cause the paint worklet global scope to get leaked.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Worklet global scope did not leak
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/css-custom-paint/leaks.html (0 => 238686)


--- trunk/LayoutTests/fast/css-custom-paint/leaks.html	                        (rev 0)
+++ trunk/LayoutTests/fast/css-custom-paint/leaks.html	2018-11-29 21:01:15 UTC (rev 238686)
@@ -0,0 +1,37 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:CSSPaintingAPIEnabled=true ] -->
+<meta name="author" title="Justin Michaud" href=""
+<meta name="assert" content="Test that paint worklets don't leak">
+<link rel="help" content="https://drafts.css-houdini.org/css-paint-api-1/">
+<script src=""
+
+<iframe id="testFrame" src=""
+
+<script>
+description("Tests that using custom paint does not cause the paint worklet global scope to get leaked.");
+window.jsTestIsAsync = true;
+
+function paintShouldDie()
+{
+    return new Promise(function(resolve, reject) {
+        handle = setInterval(function() {
+            gc();
+            if (!internals.isAnyWorkletGlobalScopeAlive()) {
+                clearInterval(handle);
+                resolve();
+            }
+        }, 10);
+    });
+}
+
+var testFrame = document.getElementById("testFrame");
+testFrame._onload_ = function() {
+    setTimeout(function() {
+        testFrame.remove();
+        paintShouldDie().then(function() {
+            testPassed("Worklet global scope did not leak");
+            finishJSTest();
+        });
+    }, 10);
+}
+</script>
+<script src=""

Modified: trunk/LayoutTests/fast/css-custom-paint/properties.html (238685 => 238686)


--- trunk/LayoutTests/fast/css-custom-paint/properties.html	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/LayoutTests/fast/css-custom-paint/properties.html	2018-11-29 21:01:15 UTC (rev 238686)
@@ -21,6 +21,11 @@
 class MyPaint {
   static get inputProperties() { return ['height', '--my-prop', '--my-registered-prop', "--never-specified"]; }
   static get inputArguments() { return ['*', '*', '*']; }
+
+  constructor() { this.myAttribute = 42; }
+
+  testThis() { return this.myAttribute; }
+
   paint(ctx, geom, properties, args) {
     assert_equals(properties.get('height').toString(), args[0].toString());
     assert_equals(properties.get('height').value, 150);
@@ -30,6 +35,8 @@
     assert_equals(properties.get('width'), null);
     assert_equals(properties.get('--never-specified').toString(), '');
 
+    assert_equals(this.testThis(), 42);
+
     for (var i = 0; i < 6; i++){
       for (var j = 0; j < 6; j++){
         ctx.fillStyle = 'rgb(' + Math.floor(255 - 42.5 * i) + ',' +

Added: trunk/LayoutTests/fast/css-custom-paint/resources/leaks-frame.html (0 => 238686)


--- trunk/LayoutTests/fast/css-custom-paint/resources/leaks-frame.html	                        (rev 0)
+++ trunk/LayoutTests/fast/css-custom-paint/resources/leaks-frame.html	2018-11-29 21:01:15 UTC (rev 238686)
@@ -0,0 +1,31 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:CSSPaintingAPIEnabled=true ] -->
+<meta name="author" title="Justin Michaud" href=""
+<meta name="assert" content="Test that paint worklets don't leak">
+<link rel="help" content="https://drafts.css-houdini.org/css-paint-api-1/">
+
+<style>
+  .paint {
+    background-image: paint(my-paint);
+    width: 150px;
+    height: 150px;
+  }
+</style>
+
+<div class="paint"></div>
+
+<script id="code" type="text/worklet">
+const globalScope = this;
+class MyPaint {
+  paint(ctx, geom, properties, args) {
+    const dummy = globalScope; // Leak!
+    ctx.fillStyle = "green";
+    ctx.fillRect(0, 0, geom.width, geom.height);
+  }
+}
+MyPaint.createALeak = this;
+registerPaint('my-paint', MyPaint);
+</script>
+
+<script>
+CSS.paintWorklet.addModule(document.getElementById('code').textContent);
+</script>

Added: trunk/LayoutTests/platform/mac/fast/css-custom-paint/raf-leak-expected.txt (0 => 238686)


--- trunk/LayoutTests/platform/mac/fast/css-custom-paint/raf-leak-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/mac/fast/css-custom-paint/raf-leak-expected.txt	2018-11-29 21:01:15 UTC (rev 238686)
@@ -0,0 +1,5 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x8
+  RenderBlock {HTML} at (0,0) size 800x8
+    RenderBody {BODY} at (8,8) size 784x0

Modified: trunk/Source/_javascript_Core/ChangeLog (238685 => 238686)


--- trunk/Source/_javascript_Core/ChangeLog	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-11-29 21:01:15 UTC (rev 238686)
@@ -1,3 +1,14 @@
+2018-11-29  Justin Michaud  <justin_mich...@apple.com>
+
+        CSS Painting API should pass 'this' correctly to paint callback, and repaint when properties change.
+        https://bugs.webkit.org/show_bug.cgi?id=191443
+
+        Reviewed by Dean Jackson.
+
+        Export the simpler construct() method for use in WebCore.
+
+        * runtime/ConstructData.h:
+
 2018-11-28  Mark Lam  <mark....@apple.com>
 
         ENABLE_SEPARATED_WX_HEAP needs to be defined in Platform.h.

Modified: trunk/Source/_javascript_Core/runtime/ConstructData.h (238685 => 238686)


--- trunk/Source/_javascript_Core/runtime/ConstructData.h	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/_javascript_Core/runtime/ConstructData.h	2018-11-29 21:01:15 UTC (rev 238686)
@@ -59,7 +59,7 @@
 };
 
 // Convenience wrapper so you don't need to deal with CallData and CallType unless you are going to use them.
-JSObject* construct(ExecState*, JSValue functionObject, const ArgList&, const char* errorMessage);
+JS_EXPORT_PRIVATE JSObject* construct(ExecState*, JSValue functionObject, const ArgList&, const char* errorMessage);
 JS_EXPORT_PRIVATE JSObject* construct(ExecState*, JSValue constructor, ConstructType, const ConstructData&, const ArgList&, JSValue newTarget);
 
 ALWAYS_INLINE JSObject* construct(ExecState* exec, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args)

Modified: trunk/Source/WebCore/ChangeLog (238685 => 238686)


--- trunk/Source/WebCore/ChangeLog	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/ChangeLog	2018-11-29 21:01:15 UTC (rev 238686)
@@ -1,3 +1,77 @@
+2018-11-29  Justin Michaud  <justin_mich...@apple.com>
+
+        CSS Painting API should pass 'this' correctly to paint callback, and repaint when properties change.
+        https://bugs.webkit.org/show_bug.cgi?id=191443
+
+        Reviewed by Dean Jackson.
+
+        Instantiate a new instance of the paint class, and pass it as 'this' object when the paint callback is called. 
+        Also, this patch makes sure that custom paint elements get repainted when properties that they care about get changed.
+        Finally, we fix two reference cycles that caused WorkletGlobalScope to never be destroyed.
+
+        Tests: fast/css-custom-paint/animate-repaint.html
+               fast/css-custom-paint/animate.html
+
+        * bindings/js/JSDOMWrapper.cpp:
+        * bindings/js/JSPaintWorkletGlobalScopeCustom.cpp:
+        (WebCore::JSPaintWorkletGlobalScope::visitAdditionalChildren):
+        * bindings/js/JSWorkletGlobalScopeBase.cpp:
+        (WebCore::toJS):
+        * bindings/js/ScriptState.cpp:
+        (WebCore::execStateFromWorkletGlobalScope):
+        * css/CSSPaintCallback.h:
+        * css/CSSPaintCallback.idl:
+        * css/CSSPaintImageValue.h:
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::applyProperty):
+        * dom/Document.cpp:
+        (WebCore::Document::prepareForDestruction):
+        * dom/ScriptExecutionContext.cpp:
+        (WebCore::ScriptExecutionContext::vm):
+        * platform/graphics/CustomPaintImage.cpp:
+        (WebCore::CustomPaintImage::CustomPaintImage):
+        (WebCore::CustomPaintImage::doCustomPaint):
+        * platform/graphics/CustomPaintImage.h:
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::addCustomPaintWatchProperty):
+        (WebCore::RenderStyle::changeRequiresRepaint const):
+        * rendering/style/RenderStyle.h:
+        * rendering/style/StyleRareNonInheritedData.cpp:
+        (WebCore::StyleRareNonInheritedData::StyleRareNonInheritedData):
+        (WebCore::StyleRareNonInheritedData::operator== const):
+        * rendering/style/StyleRareNonInheritedData.h:
+        * testing/Internals.cpp:
+        (WebCore::Internals::isAnyWorkletGlobalScopeAlive const):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+        * worklets/PaintWorkletGlobalScope.cpp:
+        (WebCore::PaintWorkletGlobalScope::devicePixelRatio const):
+        (WebCore::PaintWorkletGlobalScope::PaintDefinition::PaintDefinition):
+        (WebCore::PaintWorkletGlobalScope::registerPaint):
+        * worklets/PaintWorkletGlobalScope.h:
+        (WebCore::PaintWorkletGlobalScope::~PaintWorkletGlobalScope):
+        * worklets/WorkletGlobalScope.cpp:
+        (WebCore::WorkletGlobalScope::WorkletGlobalScope):
+        (WebCore::WorkletGlobalScope::~WorkletGlobalScope):
+        (WebCore::WorkletGlobalScope::prepareForDestruction):
+        (WebCore::WorkletGlobalScope::allWorkletGlobalScopesSet):
+        (WebCore::WorkletGlobalScope::isJSExecutionForbidden const):
+        (WebCore::WorkletGlobalScope::logExceptionToConsole):
+        (WebCore::WorkletGlobalScope::addConsoleMessage):
+        (WebCore::WorkletGlobalScope::addMessage):
+        * worklets/WorkletGlobalScope.h:
+        (WebCore::WorkletGlobalScope::script):
+        (WebCore::WorkletGlobalScope::responsibleDocument):
+        (WebCore::WorkletGlobalScope::responsibleDocument const):
+        (WebCore::WorkletGlobalScope::identifier const): Deleted.
+        (WebCore::WorkletGlobalScope::responsableDocument): Deleted.
+        (WebCore::WorkletGlobalScope::responsableDocument const): Deleted.
+        * worklets/WorkletScriptController.cpp:
+        (WebCore::WorkletScriptController::~WorkletScriptController):
+        (WebCore::WorkletScriptController::disableEval):
+        (WebCore::WorkletScriptController::disableWebAssembly):
+        (WebCore::WorkletScriptController::initScript):
+
 2018-11-29  Alexey Proskuryakov  <a...@apple.com>
 
         Modernize the check for kCFURLRequestContentDecoderSkipURLCheck existence

Modified: trunk/Source/WebCore/bindings/js/JSDOMWrapper.cpp (238685 => 238686)


--- trunk/Source/WebCore/bindings/js/JSDOMWrapper.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/bindings/js/JSDOMWrapper.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -35,6 +35,7 @@
 #include <_javascript_Core/Error.h>
 
 namespace WebCore {
+using namespace JSC;
 
 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSDOMObject);
 

Modified: trunk/Source/WebCore/bindings/js/JSPaintWorkletGlobalScopeCustom.cpp (238685 => 238686)


--- trunk/Source/WebCore/bindings/js/JSPaintWorkletGlobalScopeCustom.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/bindings/js/JSPaintWorkletGlobalScopeCustom.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -34,8 +34,10 @@
 void JSPaintWorkletGlobalScope::visitAdditionalChildren(JSC::SlotVisitor& visitor)
 {
     auto locker = holdLock(wrapped().paintDefinitionLock());
-    for (auto& registered : wrapped().paintDefinitionMap().values())
+    for (auto& registered : wrapped().paintDefinitionMap().values()) {
         registered->paintCallback->visitJSFunction(visitor);
+        visitor.appendUnbarriered(registered->paintConstructor);
+    }
 }
 
 }

Modified: trunk/Source/WebCore/bindings/js/JSWorkletGlobalScopeBase.cpp (238685 => 238686)


--- trunk/Source/WebCore/bindings/js/JSWorkletGlobalScopeBase.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/bindings/js/JSWorkletGlobalScopeBase.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -128,7 +128,8 @@
 
 JSValue toJS(ExecState*, WorkletGlobalScope& workletGlobalScope)
 {
-    auto* contextWrapper = workletGlobalScope.script().workletGlobalScopeWrapper();
+    ASSERT(workletGlobalScope.script());
+    auto* contextWrapper = workletGlobalScope.script()->workletGlobalScopeWrapper();
     ASSERT(contextWrapper);
     return contextWrapper->proxy();
 }

Modified: trunk/Source/WebCore/bindings/js/ScriptState.cpp (238685 => 238686)


--- trunk/Source/WebCore/bindings/js/ScriptState.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/bindings/js/ScriptState.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -106,7 +106,9 @@
 #if ENABLE(CSS_PAINTING_API)
 JSC::ExecState* execStateFromWorkletGlobalScope(WorkletGlobalScope& workletGlobalScope)
 {
-    return workletGlobalScope.script().workletGlobalScopeWrapper()->globalExec();
+    if (!workletGlobalScope.script())
+        return nullptr;
+    return workletGlobalScope.script()->workletGlobalScopeWrapper()->globalExec();
 }
 #endif
 

Modified: trunk/Source/WebCore/css/CSSPaintCallback.h (238685 => 238686)


--- trunk/Source/WebCore/css/CSSPaintCallback.h	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/css/CSSPaintCallback.h	2018-11-29 21:01:15 UTC (rev 238686)
@@ -31,16 +31,18 @@
 #include "CSSPaintSize.h"
 #include "CallbackResult.h"
 #include "StylePropertyMapReadOnly.h"
+#include <_javascript_Core/JSCJSValue.h>
 #include <wtf/RefCounted.h>
+#include <wtf/WeakPtr.h>
 
 namespace WebCore {
 class PaintRenderingContext2D;
 
-class CSSPaintCallback : public RefCounted<CSSPaintCallback>, public ActiveDOMCallback {
+class CSSPaintCallback : public RefCounted<CSSPaintCallback>, public CanMakeWeakPtr<CSSPaintCallback>, public ActiveDOMCallback {
 public:
     using ActiveDOMCallback::ActiveDOMCallback;
 
-    virtual CallbackResult<void> handleEvent(PaintRenderingContext2D&, CSSPaintSize&, StylePropertyMapReadOnly&, const Vector<String>&) = 0;
+    virtual CallbackResult<void> handleEvent(JSC::JSValue, PaintRenderingContext2D&, CSSPaintSize&, StylePropertyMapReadOnly&, const Vector<String>&) = 0;
 
     virtual ~CSSPaintCallback()
     {

Modified: trunk/Source/WebCore/css/CSSPaintCallback.idl (238685 => 238686)


--- trunk/Source/WebCore/css/CSSPaintCallback.idl	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/css/CSSPaintCallback.idl	2018-11-29 21:01:15 UTC (rev 238686)
@@ -26,4 +26,5 @@
 [
     EnabledAtRuntime=CSSPaintingAPI,
     Conditional=CSS_PAINTING_API,
+    CallbackThisObject=any
 ] callback CSSPaintCallback = void (PaintRenderingContext2D context, CSSPaintSize size, StylePropertyMapReadOnly styleMap, sequence<USVString> arguments);

Modified: trunk/Source/WebCore/css/CSSPaintImageValue.h (238685 => 238686)


--- trunk/Source/WebCore/css/CSSPaintImageValue.h	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/css/CSSPaintImageValue.h	2018-11-29 21:01:15 UTC (rev 238686)
@@ -40,6 +40,8 @@
         return adoptRef(*new CSSPaintImageValue(name, WTFMove(arguments)));
     }
 
+    const String& name() const { return m_name; }
+
     RefPtr<Image> image(RenderElement&, const FloatSize&);
 
     bool equals(const CSSPaintImageValue& other) const { return m_name == other.m_name; }

Modified: trunk/Source/WebCore/css/StyleResolver.cpp (238685 => 238686)


--- trunk/Source/WebCore/css/StyleResolver.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/css/StyleResolver.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -42,6 +42,7 @@
 #include "CSSImageValue.h"
 #include "CSSKeyframeRule.h"
 #include "CSSKeyframesRule.h"
+#include "CSSPaintImageValue.h"
 #include "CSSParser.h"
 #include "CSSPrimitiveValueMappings.h"
 #include "CSSPropertyNames.h"
@@ -73,6 +74,7 @@
 #include "MediaQueryEvaluator.h"
 #include "NodeRenderStyle.h"
 #include "PageRuleCollector.h"
+#include "PaintWorkletGlobalScope.h"
 #include "Pair.h"
 #include "RenderScrollbar.h"
 #include "RenderStyleConstants.h"
@@ -1717,6 +1719,18 @@
     if (isInherit && !CSSProperty::isInheritedProperty(id))
         state.style()->setHasExplicitlyInheritedProperties();
 
+#if ENABLE(CSS_PAINTING_API)
+    if (is<CSSPaintImageValue>(*valueToApply) && document().paintWorkletGlobalScope()) {
+        // FIXME: This should use the "document paint registration map" from the spec, once it is implemented.
+        auto& paintWorklet = *document().paintWorkletGlobalScope();
+        auto locker = holdLock(paintWorklet.paintDefinitionLock());
+        if (auto* registration = paintWorklet.paintDefinitionMap().get(downcast<CSSPaintImageValue>(*valueToApply).name())) {
+            for (auto& property : registration->inputProperties)
+                state.style()->addCustomPaintWatchProperty(property);
+        }
+    }
+#endif
+
     // Use the generated StyleBuilder.
     StyleBuilder::applyProperty(id, *this, *valueToApply, isInitial, isInherit, customPropertyRegistered);
 }

Modified: trunk/Source/WebCore/dom/Document.cpp (238685 => 238686)


--- trunk/Source/WebCore/dom/Document.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/dom/Document.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -2531,6 +2531,13 @@
     }
 #endif
 
+#if ENABLE(CSS_PAINTING_API)
+    if (m_paintWorkletGlobalScope) {
+        m_paintWorkletGlobalScope->prepareForDestruction();
+        m_paintWorkletGlobalScope = nullptr;
+    }
+#endif
+
     m_hasPreparedForDestruction = true;
 
     // Note that m_pageCacheState can be Document::AboutToEnterPageCache if our frame

Modified: trunk/Source/WebCore/dom/ScriptExecutionContext.cpp (238685 => 238686)


--- trunk/Source/WebCore/dom/ScriptExecutionContext.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/dom/ScriptExecutionContext.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -482,7 +482,7 @@
         return downcast<WorkerGlobalScope>(*this).script()->vm();
 #if ENABLE(CSS_PAINTING_API)
     if (is<WorkletGlobalScope>(*this))
-        return downcast<WorkletGlobalScope>(*this).script().vm();
+        return downcast<WorkletGlobalScope>(*this).script()->vm();
 #endif
 
     RELEASE_ASSERT_NOT_REACHED();

Modified: trunk/Source/WebCore/platform/graphics/CustomPaintImage.cpp (238685 => 238686)


--- trunk/Source/WebCore/platform/graphics/CustomPaintImage.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/platform/graphics/CustomPaintImage.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -40,11 +40,12 @@
 #include "JSCSSPaintCallback.h"
 #include "PaintRenderingContext2D.h"
 #include "RenderElement.h"
+#include <_javascript_Core/ConstructData.h>
 
 namespace WebCore {
 
-CustomPaintImage::CustomPaintImage(const PaintWorkletGlobalScope::PaintDefinition& definition, const FloatSize& size, RenderElement& element, const Vector<String>& arguments)
-    : m_paintCallback(definition.paintCallback.get())
+CustomPaintImage::CustomPaintImage(PaintWorkletGlobalScope::PaintDefinition& definition, const FloatSize& size, RenderElement& element, const Vector<String>& arguments)
+    : m_paintDefinition(makeWeakPtr(definition))
     , m_inputProperties(definition.inputProperties)
     , m_element(makeWeakPtr(element))
     , m_arguments(arguments)
@@ -56,13 +57,20 @@
 
 ImageDrawResult CustomPaintImage::doCustomPaint(GraphicsContext& destContext, const FloatSize& destSize)
 {
-    if (!m_element || !m_element->element())
+    if (!m_element || !m_element->element() || !m_paintDefinition)
         return ImageDrawResult::DidNothing;
 
+    JSC::JSValue paintConstructor(m_paintDefinition->paintConstructor);
+
+    if (!paintConstructor)
+        return ImageDrawResult::DidNothing;
+
+    auto& paintCallback = m_paintDefinition->paintCallback.get();
+
     ASSERT(!m_element->needsLayout());
     ASSERT(!m_element->element()->document().needsStyleRecalc());
 
-    JSCSSPaintCallback& callback = static_cast<JSCSSPaintCallback&>(m_paintCallback.get());
+    JSCSSPaintCallback& callback = static_cast<JSCSSPaintCallback&>(paintCallback);
     auto* scriptExecutionContext = callback.scriptExecutionContext();
     if (!scriptExecutionContext)
         return ImageDrawResult::DidNothing;
@@ -103,7 +111,21 @@
     auto size = CSSPaintSize::create(destSize.width(), destSize.height());
     auto propertyMap = StylePropertyMapReadOnly::create(WTFMove(propertyValues));
 
-    auto result = m_paintCallback->handleEvent(*context, size, propertyMap, m_arguments);
+    auto& vm = *paintConstructor.getObject()->vm();
+    JSC::JSLockHolder lock(vm);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    auto& globalObject = *paintConstructor.getObject()->globalObject();
+
+    auto& state = *globalObject.globalExec();
+    JSC::ArgList noArgs;
+    JSC::JSValue thisObject = { JSC::construct(&state, WTFMove(paintConstructor), noArgs, "Failed to construct paint class") };
+
+    if (UNLIKELY(scope.exception())) {
+        reportException(&state, scope.exception());
+        return ImageDrawResult::DidNothing;
+    }
+
+    auto result = paintCallback.handleEvent(WTFMove(thisObject), *context, size, propertyMap, m_arguments);
     if (result.type() != CallbackResultType::Success)
         return ImageDrawResult::DidNothing;
 

Modified: trunk/Source/WebCore/platform/graphics/CustomPaintImage.h (238685 => 238686)


--- trunk/Source/WebCore/platform/graphics/CustomPaintImage.h	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/platform/graphics/CustomPaintImage.h	2018-11-29 21:01:15 UTC (rev 238686)
@@ -29,6 +29,8 @@
 
 #include "GeneratedImage.h"
 #include "PaintWorkletGlobalScope.h"
+#include <_javascript_Core/JSObject.h>
+#include <_javascript_Core/Weak.h>
 #include <wtf/WeakPtr.h>
 
 namespace WebCore {
@@ -38,7 +40,7 @@
 
 class CustomPaintImage final : public GeneratedImage {
 public:
-    static Ref<CustomPaintImage> create(const PaintWorkletGlobalScope::PaintDefinition& definition, const FloatSize& size, RenderElement& element, const Vector<String>& arguments)
+    static Ref<CustomPaintImage> create(PaintWorkletGlobalScope::PaintDefinition& definition, const FloatSize& size, RenderElement& element, const Vector<String>& arguments)
     {
         return adoptRef(*new CustomPaintImage(definition, size, element, arguments));
     }
@@ -47,7 +49,7 @@
     bool isCustomPaintImage() const override { return true; }
 
 private:
-    CustomPaintImage(const PaintWorkletGlobalScope::PaintDefinition&, const FloatSize&, RenderElement&, const Vector<String>& arguments);
+    CustomPaintImage(PaintWorkletGlobalScope::PaintDefinition&, const FloatSize&, RenderElement&, const Vector<String>& arguments);
 
     ImageDrawResult doCustomPaint(GraphicsContext&, const FloatSize&);
 
@@ -54,7 +56,7 @@
     ImageDrawResult draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, DecodingMode, ImageOrientationDescription) final;
     void drawPattern(GraphicsContext&, const FloatRect& destRect, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator, BlendMode) final;
 
-    Ref<CSSPaintCallback> m_paintCallback;
+    WeakPtr<PaintWorkletGlobalScope::PaintDefinition> m_paintDefinition;
     Vector<String> m_inputProperties;
     WeakPtr<RenderElement> m_element;
     Vector<String> m_arguments;

Modified: trunk/Source/WebCore/rendering/style/RenderStyle.cpp (238685 => 238686)


--- trunk/Source/WebCore/rendering/style/RenderStyle.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/rendering/style/RenderStyle.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -23,10 +23,12 @@
 #include "config.h"
 #include "RenderStyle.h"
 
-#include "ContentData.h"
+#include "CSSComputedStyleDeclaration.h"
 #include "CSSCustomPropertyValue.h"
 #include "CSSParser.h"
 #include "CSSPropertyNames.h"
+#include "CSSPropertyParser.h"
+#include "ContentData.h"
 #include "CursorList.h"
 #include "FloatRoundedRect.h"
 #include "FontCascade.h"
@@ -962,6 +964,16 @@
     ;
 }
 
+#if ENABLE(CSS_PAINTING_API)
+void RenderStyle::addCustomPaintWatchProperty(const String& name)
+{
+    auto& data = ""
+    if (!data.customPaintWatchedProperties)
+        data.customPaintWatchedProperties = std::make_unique<HashSet<String>>();
+    data.customPaintWatchedProperties->add(name);
+}
+#endif
+
 bool RenderStyle::changeRequiresRepaint(const RenderStyle& other, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties) const
 {
     if (!requiresPainting(*this) && !requiresPainting(other))
@@ -983,6 +995,45 @@
         && rareInheritedDataChangeRequiresRepaint(*m_rareInheritedData, *other.m_rareInheritedData))
         return true;
 
+#if ENABLE(CSS_PAINTING_API)
+    auto* propertiesA = m_rareNonInheritedData.ptr()->customPaintWatchedProperties.get();
+    auto* propertiesB = other.m_rareNonInheritedData.ptr()->customPaintWatchedProperties.get();
+
+    if (UNLIKELY(propertiesA || propertiesB)) {
+        // FIXME: We should not need to use ComputedStyleExtractor here.
+        ComputedStyleExtractor extractor((Element*) nullptr);
+
+        for (auto* watchPropertiesMap : { propertiesA, propertiesB }) {
+            if (!watchPropertiesMap)
+                continue;
+
+            for (auto& name : *watchPropertiesMap) {
+                RefPtr<CSSValue> valueA;
+                RefPtr<CSSValue> valueB;
+                if (isCustomPropertyName(name) && getCustomProperty(name) && other.getCustomProperty(name)) {
+                    valueA = CSSCustomPropertyValue::create(*getCustomProperty(name));
+                    valueB = CSSCustomPropertyValue::create(*other.getCustomProperty(name));
+                } else {
+                    CSSPropertyID propertyID = cssPropertyID(name);
+                    if (!propertyID)
+                        continue;
+                    valueA = extractor.valueForPropertyinStyle(*this, propertyID);
+                    valueB = extractor.valueForPropertyinStyle(other, propertyID);
+                }
+
+                if ((valueA && !valueB) || (!valueA && valueB))
+                    return true;
+
+                if (!valueA)
+                    continue;
+
+                if (!(*valueA == *valueB))
+                    return true;
+            }
+        }
+    }
+#endif
+
     return false;
 }
 

Modified: trunk/Source/WebCore/rendering/style/RenderStyle.h (238685 => 238686)


--- trunk/Source/WebCore/rendering/style/RenderStyle.h	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/rendering/style/RenderStyle.h	2018-11-29 21:01:15 UTC (rev 238686)
@@ -1267,6 +1267,10 @@
     void setApplePayButtonType(ApplePayButtonType type) { SET_VAR(m_rareNonInheritedData, applePayButtonType, static_cast<unsigned>(type)); }
 #endif
 
+#if ENABLE(CSS_PAINTING_API)
+    void addCustomPaintWatchProperty(const String& name);
+#endif
+
     // Support for paint-order, stroke-linecap, stroke-linejoin, and stroke-miterlimit from https://drafts.fxtf.org/paint/.
     void setPaintOrder(PaintOrder order) { SET_VAR(m_rareInheritedData, paintOrder, static_cast<unsigned>(order)); }
     PaintOrder paintOrder() const { return static_cast<PaintOrder>(m_rareInheritedData->paintOrder); }

Modified: trunk/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp (238685 => 238686)


--- trunk/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -169,6 +169,7 @@
     , justifyItems(o.justifyItems)
     , justifySelf(o.justifySelf)
     , customProperties(o.customProperties)
+    , customPaintWatchedProperties(o.customPaintWatchedProperties ? std::make_unique<HashSet<String>>(*o.customPaintWatchedProperties) : nullptr)
 #if ENABLE(TOUCH_EVENTS)
     , touchAction(o.touchAction)
 #endif
@@ -271,6 +272,8 @@
         && justifyItems == o.justifyItems
         && justifySelf == o.justifySelf
         && customProperties == o.customProperties
+        && ((customPaintWatchedProperties && o.customPaintWatchedProperties && *customPaintWatchedProperties == *o.customPaintWatchedProperties)
+            || (!customPaintWatchedProperties && !o.customPaintWatchedProperties))
         && pageSizeType == o.pageSizeType
         && transformStyle3D == o.transformStyle3D
         && backfaceVisibility == o.backfaceVisibility

Modified: trunk/Source/WebCore/rendering/style/StyleRareNonInheritedData.h (238685 => 238686)


--- trunk/Source/WebCore/rendering/style/StyleRareNonInheritedData.h	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/rendering/style/StyleRareNonInheritedData.h	2018-11-29 21:01:15 UTC (rev 238686)
@@ -172,6 +172,7 @@
     StyleSelfAlignmentData justifySelf;
 
     DataRef<StyleCustomPropertyData> customProperties;
+    std::unique_ptr<HashSet<String>> customPaintWatchedProperties;
 
 #if ENABLE(TOUCH_EVENTS)
     unsigned touchAction : 1; // TouchAction

Modified: trunk/Source/WebCore/testing/Internals.cpp (238685 => 238686)


--- trunk/Source/WebCore/testing/Internals.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/testing/Internals.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -173,6 +173,7 @@
 #include "WebCoreJSClientData.h"
 #include "WindowProxy.h"
 #include "WorkerThread.h"
+#include "WorkletGlobalScope.h"
 #include "WritingDirection.h"
 #include "XMLHttpRequest.h"
 #include <_javascript_Core/CodeBlock.h>
@@ -2387,6 +2388,15 @@
     return Document::allDocumentsMap().contains(makeObjectIdentifier<DocumentIdentifierType>(documentIdentifier));
 }
 
+bool Internals::isAnyWorkletGlobalScopeAlive() const
+{
+#if ENABLE(CSS_PAINTING_API)
+    return !WorkletGlobalScope::allWorkletGlobalScopesSet().isEmpty();
+#else
+    return false;
+#endif
+}
+
 String Internals::serviceWorkerClientIdentifier(const Document& document) const
 {
 #if ENABLE(SERVICE_WORKER)

Modified: trunk/Source/WebCore/testing/Internals.h (238685 => 238686)


--- trunk/Source/WebCore/testing/Internals.h	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/testing/Internals.h	2018-11-29 21:01:15 UTC (rev 238686)
@@ -388,6 +388,8 @@
     uint64_t documentIdentifier(const Document&) const;
     bool isDocumentAlive(uint64_t documentIdentifier) const;
 
+    bool isAnyWorkletGlobalScopeAlive() const;
+
     String serviceWorkerClientIdentifier(const Document&) const;
 
     RefPtr<WindowProxy> openDummyInspectorFrontend(const String& url);

Modified: trunk/Source/WebCore/testing/Internals.idl (238685 => 238686)


--- trunk/Source/WebCore/testing/Internals.idl	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/testing/Internals.idl	2018-11-29 21:01:15 UTC (rev 238686)
@@ -675,6 +675,8 @@
     unsigned long long documentIdentifier(Document document);
     boolean isDocumentAlive(unsigned long long documentIdentifier);
 
+    boolean isAnyWorkletGlobalScopeAlive();
+
     DOMString serviceWorkerClientIdentifier(Document document);
 
     Promise<void> clearCacheStorageMemoryRepresentation();

Modified: trunk/Source/WebCore/worklets/PaintWorkletGlobalScope.cpp (238685 => 238686)


--- trunk/Source/WebCore/worklets/PaintWorkletGlobalScope.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/worklets/PaintWorkletGlobalScope.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -33,6 +33,7 @@
 #include "JSCSSPaintCallback.h"
 #include "JSDOMConvertCallbacks.h"
 #include "JSDOMConvertSequences.h"
+#include "RenderView.h"
 #include <wtf/SetForScope.h>
 
 namespace WebCore {
@@ -50,15 +51,25 @@
 
 double PaintWorkletGlobalScope::devicePixelRatio() const
 {
-    if (!responsableDocument() || !responsableDocument()->domWindow())
+    if (!responsibleDocument() || !responsibleDocument()->domWindow())
         return 1.0;
-    return responsableDocument()->domWindow()->devicePixelRatio();
+    return responsibleDocument()->domWindow()->devicePixelRatio();
 }
 
+PaintWorkletGlobalScope::PaintDefinition::PaintDefinition(const AtomicString& name, JSC::JSObject* paintConstructor, Ref<CSSPaintCallback>&& paintCallback, Vector<String>&& inputProperties, Vector<String>&& inputArguments)
+    : name(name)
+    , paintConstructor(paintConstructor)
+    , paintCallback(WTFMove(paintCallback))
+    , inputProperties(WTFMove(inputProperties))
+    , inputArguments(WTFMove(inputArguments))
+{
+}
+
 // https://drafts.css-houdini.org/css-paint-api/#registering-custom-paint
 ExceptionOr<void> PaintWorkletGlobalScope::registerPaint(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const String& name, Strong<JSObject> paintConstructor)
 {
     auto& vm = *paintConstructor->vm();
+    JSC::JSLockHolder lock(vm);
     auto scope = DECLARE_THROW_SCOPE(vm);
 
     // Validate that paintConstructor is a VoidFunction
@@ -69,62 +80,70 @@
     if (name.isEmpty())
         return Exception { TypeError, "The first argument must not be the empty string" };
 
-    auto locker = holdLock(paintDefinitionLock());
+    {
+        auto locker = holdLock(paintDefinitionLock());
 
-    if (paintDefinitionMap().contains(name))
-        return Exception { InvalidModificationError, "This name has already been registered" };
+        if (paintDefinitionMap().contains(name))
+            return Exception { InvalidModificationError, "This name has already been registered" };
 
-    Vector<String> inputProperties;
+        Vector<String> inputProperties;
 
-    JSValue inputPropertiesIterableValue = paintConstructor->get(&state, Identifier::fromString(&vm, "inputProperties"));
-    RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
+        JSValue inputPropertiesIterableValue = paintConstructor->get(&state, Identifier::fromString(&vm, "inputProperties"));
+        RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
 
-    if (!inputPropertiesIterableValue.isUndefined())
-        inputProperties = convert<IDLSequence<IDLDOMString>>(state, inputPropertiesIterableValue);
-    RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
+        if (!inputPropertiesIterableValue.isUndefined())
+            inputProperties = convert<IDLSequence<IDLDOMString>>(state, inputPropertiesIterableValue);
+        RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
 
-    // FIXME: Validate input properties here (step 7).
+        // FIXME: Validate input properties here (step 7).
 
-    Vector<String> inputArguments;
+        Vector<String> inputArguments;
 
-    JSValue inputArgumentsIterableValue = paintConstructor->get(&state, Identifier::fromString(&vm, "inputArguments"));
-    RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
+        JSValue inputArgumentsIterableValue = paintConstructor->get(&state, Identifier::fromString(&vm, "inputArguments"));
+        RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
 
-    if (!inputArgumentsIterableValue.isUndefined())
-        inputArguments = convert<IDLSequence<IDLDOMString>>(state, inputArgumentsIterableValue);
-    RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
+        if (!inputArgumentsIterableValue.isUndefined())
+            inputArguments = convert<IDLSequence<IDLDOMString>>(state, inputArgumentsIterableValue);
+        RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
 
-    // FIXME: Parse syntax for inputArguments here (steps 11 and 12).
+        // FIXME: Parse syntax for inputArguments here (steps 11 and 12).
 
-    JSValue contextOptionsValue = paintConstructor->get(&state, Identifier::fromString(&vm, "contextOptions"));
-    RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
-    UNUSED_PARAM(contextOptionsValue);
+        JSValue contextOptionsValue = paintConstructor->get(&state, Identifier::fromString(&vm, "contextOptions"));
+        RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
+        UNUSED_PARAM(contextOptionsValue);
 
-    // FIXME: Convert to PaintRenderingContext2DSettings here (step 14).
+        // FIXME: Convert to PaintRenderingContext2DSettings here (step 14).
 
-    if (!paintConstructor->isConstructor(vm))
-        return Exception { TypeError, "The second argument must be a constructor" };
+        if (!paintConstructor->isConstructor(vm))
+            return Exception { TypeError, "The second argument must be a constructor" };
 
-    JSValue prototypeValue = paintConstructor->get(&state, vm.propertyNames->prototype);
-    RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
+        JSValue prototypeValue = paintConstructor->get(&state, vm.propertyNames->prototype);
+        RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
 
-    if (!prototypeValue.isObject())
-        return Exception { TypeError, "The second argument must have a prototype that is an object" };
+        if (!prototypeValue.isObject())
+            return Exception { TypeError, "The second argument must have a prototype that is an object" };
 
-    JSValue paintValue = prototypeValue.get(&state, Identifier::fromString(&vm, "paint"));
-    RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
+        JSValue paintValue = prototypeValue.get(&state, Identifier::fromString(&vm, "paint"));
+        RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
 
-    if (paintValue.isUndefined())
-        return Exception { TypeError, "The class must have a paint method" };
+        if (paintValue.isUndefined())
+            return Exception { TypeError, "The class must have a paint method" };
 
-    RefPtr<JSCSSPaintCallback> paint = convert<IDLCallbackFunction<JSCSSPaintCallback>>(state, paintValue, globalObject);
-    RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
+        RefPtr<JSCSSPaintCallback> paint = convert<IDLCallbackFunction<JSCSSPaintCallback>>(state, paintValue, globalObject);
+        RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
 
-    auto paintDefinition = std::unique_ptr<PaintDefinition>(new PaintDefinition { name, paint.releaseNonNull(), inputProperties, inputArguments });
-    paintDefinitionMap().add(name, WTFMove(paintDefinition));
+        auto paintDefinition = std::make_unique<PaintDefinition>(name, paintConstructor.get(), paint.releaseNonNull(), WTFMove(inputProperties), WTFMove(inputArguments));
+        paintDefinitionMap().add(name, WTFMove(paintDefinition));
+    }
 
+    // This is for the case when we have already visited the paint definition map, and the GC is currently running in the background.
+    vm.heap.writeBarrier(&globalObject);
+
     // FIXME: construct documentDefinition (step 22).
 
+    if (responsibleDocument() && responsibleDocument()->renderView())
+        responsibleDocument()->renderView()->repaintRootContents();
+
     return { };
 }
 

Modified: trunk/Source/WebCore/worklets/PaintWorkletGlobalScope.h (238685 => 238686)


--- trunk/Source/WebCore/worklets/PaintWorkletGlobalScope.h	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/worklets/PaintWorkletGlobalScope.h	2018-11-29 21:01:15 UTC (rev 238686)
@@ -29,6 +29,7 @@
 
 #include "CSSPaintCallback.h"
 #include "WorkletGlobalScope.h"
+#include <_javascript_Core/JSObject.h>
 #include <_javascript_Core/Strong.h>
 
 namespace JSC {
@@ -45,8 +46,12 @@
     ExceptionOr<void> registerPaint(JSC::ExecState&, JSDOMGlobalObject&, const String& name, JSC::Strong<JSC::JSObject> paintConstructor);
     double devicePixelRatio() const;
 
-    struct PaintDefinition {
+    struct PaintDefinition : public CanMakeWeakPtr<PaintDefinition> {
+        PaintDefinition(const AtomicString& name, JSC::JSObject* paintConstructor, Ref<CSSPaintCallback>&&, Vector<String>&& inputProperties, Vector<String>&& inputArguments);
+
         const AtomicString name;
+        // This map must be cleared before the vm is destroyed!
+        JSC::JSObject* paintConstructor { nullptr };
         const Ref<CSSPaintCallback> paintCallback;
         const Vector<String> inputProperties;
         const Vector<String> inputArguments;
@@ -55,9 +60,26 @@
     HashMap<String, std::unique_ptr<PaintDefinition>>& paintDefinitionMap() { ASSERT(m_paintDefinitionLock.isLocked()); return m_paintDefinitionMap; }
     Lock& paintDefinitionLock() { return m_paintDefinitionLock; }
 
+    void prepareForDestruction() final
+    {
+        {
+            auto locker = holdLock(paintDefinitionLock());
+            paintDefinitionMap().clear();
+        }
+        WorkletGlobalScope::prepareForDestruction();
+    }
+
 private:
     PaintWorkletGlobalScope(Document&, ScriptSourceCode&&);
 
+    ~PaintWorkletGlobalScope()
+    {
+#if !ASSERT_DISABLED
+        auto locker = holdLock(paintDefinitionLock());
+        ASSERT(paintDefinitionMap().isEmpty());
+#endif
+    }
+
     bool isPaintWorkletGlobalScope() const final { return true; }
 
     HashMap<String, std::unique_ptr<PaintDefinition>> m_paintDefinitionMap;

Modified: trunk/Source/WebCore/worklets/WorkletGlobalScope.cpp (238685 => 238686)


--- trunk/Source/WebCore/worklets/WorkletGlobalScope.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/worklets/WorkletGlobalScope.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -39,7 +39,6 @@
 #include "WorkletScriptController.h"
 
 #include <_javascript_Core/Exception.h>
-#include <_javascript_Core/IdentifiersFactory.h>
 #include <_javascript_Core/JSLock.h>
 #include <_javascript_Core/ScriptCallStack.h>
 
@@ -49,12 +48,14 @@
 WorkletGlobalScope::WorkletGlobalScope(Document& document, ScriptSourceCode&& code)
     : m_document(makeWeakPtr(document))
     , m_sessionID(m_document->sessionID())
-    , m_script(makeUniqueRef<WorkletScriptController>(this))
+    , m_script(std::make_unique<WorkletScriptController>(this))
     , m_topOrigin(SecurityOrigin::createUnique())
-    , m_identifier(makeString("WorkletGlobalScope:"_s, Inspector::IdentifiersFactory::createIdentifier()))
     , m_eventQueue(*this)
     , m_code(WTFMove(code))
 {
+    auto addResult = allWorkletGlobalScopesSet().add(this);
+    ASSERT_UNUSED(addResult, addResult);
+
     auto* frame = document.frame();
     m_jsRuntimeFlags = frame ? frame->settings()._javascript_RuntimeFlags() : JSC::RuntimeFlags();
     ASSERT(document.page());
@@ -65,10 +66,28 @@
 
 WorkletGlobalScope::~WorkletGlobalScope()
 {
+    ASSERT(!m_script);
     removeFromContextsMap();
-    m_script->workletGlobalScopeWrapper()->setConsoleClient(nullptr);
+    auto removeResult = allWorkletGlobalScopesSet().remove(this);
+    ASSERT_UNUSED(removeResult, removeResult);
 }
 
+void WorkletGlobalScope::prepareForDestruction()
+{
+    ASSERT(m_script);
+    stopActiveDOMObjects();
+    removeRejectedPromiseTracker();
+    removeAllEventListeners();
+    m_script->vm().notifyNeedTermination();
+    m_script = nullptr;
+}
+
+auto WorkletGlobalScope::allWorkletGlobalScopesSet() -> WorkletGlobalScopesSet&
+{
+    static NeverDestroyed<WorkletGlobalScopesSet> scopes;
+    return scopes;
+}
+
 String WorkletGlobalScope::origin() const
 {
     return m_topOrigin->toString();
@@ -88,7 +107,7 @@
 
 bool WorkletGlobalScope::isJSExecutionForbidden() const
 {
-    return m_script->isExecutionForbidden();
+    return !m_script || m_script->isExecutionForbidden();
 }
 
 void WorkletGlobalScope::disableEval(const String& errorMessage)
@@ -110,7 +129,7 @@
 
 void WorkletGlobalScope::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, RefPtr<ScriptCallStack>&& stack)
 {
-    if (!m_document)
+    if (!m_document || isJSExecutionForbidden())
         return;
     m_document->logExceptionToConsole(errorMessage, sourceURL, lineNumber, columnNumber, WTFMove(stack));
 }
@@ -117,23 +136,23 @@
 
 void WorkletGlobalScope::addConsoleMessage(std::unique_ptr<Inspector::ConsoleMessage>&& message)
 {
-    if (!m_document)
+    if (!m_document || isJSExecutionForbidden() || !message)
         return;
-    m_document->addConsoleMessage(WTFMove(message));
+    m_document->addConsoleMessage(std::make_unique<Inspector::ConsoleMessage>(message->source(), message->type(), message->level(), message->message(), 0));
 }
 
 void WorkletGlobalScope::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier)
 {
-    if (!m_document)
+    if (!m_document || isJSExecutionForbidden())
         return;
     m_document->addConsoleMessage(source, level, message, requestIdentifier);
 }
 
-void WorkletGlobalScope::addMessage(MessageSource source, MessageLevel level, const String& messageText, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, RefPtr<ScriptCallStack>&& callStack, JSC::ExecState* state, unsigned long requestIdentifier)
+void WorkletGlobalScope::addMessage(MessageSource source, MessageLevel level, const String& messageText, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, RefPtr<ScriptCallStack>&& callStack, JSC::ExecState*, unsigned long requestIdentifier)
 {
-    if (!m_document)
+    if (!m_document || isJSExecutionForbidden())
         return;
-    m_document->addMessage(source, level, messageText, sourceURL, lineNumber, columnNumber, WTFMove(callStack), state, requestIdentifier);
+    m_document->addMessage(source, level, messageText, sourceURL, lineNumber, columnNumber, WTFMove(callStack), nullptr, requestIdentifier);
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/worklets/WorkletGlobalScope.h (238685 => 238686)


--- trunk/Source/WebCore/worklets/WorkletGlobalScope.h	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/worklets/WorkletGlobalScope.h	2018-11-29 21:01:15 UTC (rev 238686)
@@ -38,7 +38,7 @@
 #include <_javascript_Core/ConsoleMessage.h>
 #include <_javascript_Core/RuntimeFlags.h>
 #include <pal/SessionID.h>
-#include <wtf/UniqueRef.h>
+#include <wtf/ObjectIdentifier.h>
 #include <wtf/WeakPtr.h>
 
 namespace WebCore {
@@ -45,15 +45,20 @@
 class WorkletScriptController;
 class ScriptSourceCode;
 
+enum WorkletGlobalScopeIdentifierType { };
+using WorkletGlobalScopeIdentifier = ObjectIdentifier<WorkletGlobalScopeIdentifierType>;
+
 class WorkletGlobalScope : public RefCounted<WorkletGlobalScope>, public ScriptExecutionContext, public EventTargetWithInlineData {
 public:
-    ~WorkletGlobalScope();
+    virtual ~WorkletGlobalScope();
 
+    using WorkletGlobalScopesSet = HashSet<const WorkletGlobalScope*>;
+    WEBCORE_EXPORT static WorkletGlobalScopesSet& allWorkletGlobalScopesSet();
+
     virtual bool isPaintWorkletGlobalScope() const { return false; }
 
     const URL& url() const final { return m_code.url(); }
     String origin() const final;
-    const String& identifier() const { return m_identifier; }
 
     void evaluate();
 
@@ -60,7 +65,7 @@
     using RefCounted::ref;
     using RefCounted::deref;
 
-    WorkletScriptController& script() { return m_script.get(); }
+    WorkletScriptController* script() { return m_script.get(); }
 
     void addConsoleMessage(std::unique_ptr<Inspector::ConsoleMessage>&&) final;
 
@@ -74,11 +79,15 @@
 
     JSC::RuntimeFlags jsRuntimeFlags() const { return m_jsRuntimeFlags; }
 
+    virtual void prepareForDestruction();
+
 protected:
     WorkletGlobalScope(Document&, ScriptSourceCode&&);
+    WorkletGlobalScope(const WorkletGlobalScope&) = delete;
+    WorkletGlobalScope(WorkletGlobalScope&&) = delete;
 
-    Document* responsableDocument() { return m_document.get(); }
-    const Document* responsableDocument() const { return m_document.get(); }
+    Document* responsibleDocument() { return m_document.get(); }
+    const Document* responsibleDocument() const { return m_document.get(); }
 
 private:
 #if ENABLE(INDEXED_DATABASE)
@@ -118,10 +127,9 @@
     WeakPtr<Document> m_document;
 
     PAL::SessionID m_sessionID;
-    UniqueRef<WorkletScriptController> m_script;
+    std::unique_ptr<WorkletScriptController> m_script;
 
     Ref<SecurityOrigin> m_topOrigin;
-    String m_identifier;
 
     // FIXME: This is not implemented properly, it just satisfies the compiler.
     // https://bugs.webkit.org/show_bug.cgi?id=191136

Modified: trunk/Source/WebCore/worklets/WorkletScriptController.cpp (238685 => 238686)


--- trunk/Source/WebCore/worklets/WorkletScriptController.cpp	2018-11-29 20:52:46 UTC (rev 238685)
+++ trunk/Source/WebCore/worklets/WorkletScriptController.cpp	2018-11-29 21:01:15 UTC (rev 238686)
@@ -59,13 +59,15 @@
 WorkletScriptController::~WorkletScriptController()
 {
     JSLockHolder lock(vm());
-    m_workletGlobalScopeWrapper.clear();
-    m_vm = nullptr;
+    forbidExecution();
+
     if (m_workletGlobalScopeWrapper) {
         m_workletGlobalScopeWrapper->clearDOMGuardedObjects();
         m_workletGlobalScopeWrapper->setConsoleClient(nullptr);
         m_consoleClient = nullptr;
     }
+    m_workletGlobalScopeWrapper.clear();
+    m_vm = nullptr;
 }
 
 void WorkletScriptController::forbidExecution()
@@ -82,6 +84,9 @@
 
 void WorkletScriptController::disableEval(const String& errorMessage)
 {
+    if (isExecutionForbidden())
+        return;
+
     initScriptIfNeeded();
     JSLockHolder lock { vm() };
 
@@ -90,6 +95,9 @@
 
 void WorkletScriptController::disableWebAssembly(const String& errorMessage)
 {
+    if (isExecutionForbidden())
+        return;
+
     initScriptIfNeeded();
     JSLockHolder lock { vm() };
 
@@ -132,6 +140,9 @@
 
 void WorkletScriptController::initScript()
 {
+    if (isExecutionForbidden())
+        return;
+
     if (is<PaintWorkletGlobalScope>(m_workletGlobalScope)) {
         initScriptWithSubclass<JSPaintWorkletGlobalScopePrototype, JSPaintWorkletGlobalScope, PaintWorkletGlobalScope>();
         return;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to