CSSStyleDeclaration should be annotated with CEReactions
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 31 Oct 2016 21:47:30 +0000 (21:47 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 31 Oct 2016 21:47:30 +0000 (21:47 +0000)
https://bugs.webkit.org/show_bug.cgi?id=163968

Reviewed by Antti Koivisto.

LayoutTests/imported/w3c:

Rebaselined the test now that all test cases pass.

* web-platform-tests/custom-elements/attribute-changed-callback-expected.txt:

Source/WebCore:

Added CEReactions to CSSStyleDeclaration.idl.

Test: fast/custom-elements/reactions/CSSStyleDeclaration.html

* bindings/js/JSCSSStyleDeclarationCustom.cpp:
(WebCore::JSCSSStyleDeclaration::putDelegate):
* css/CSSStyleDeclaration.idl:
* css/PropertySetCSSStyleDeclaration.cpp:
(WebCore::StyleAttributeMutationScope::StyleAttributeMutationScope): Remember the old value when this is
an inline style declaration for a custom element. Also store m_oldValue and m_customElement instead of
a mutation record so that we don't create a superfluous mutation record for custom elements.
(WebCore::StyleAttributeMutationScope::~StyleAttributeMutationScope): Enqueue attributeChangedCallback
when m_customElement is not null.
* dom/CustomElementReactionQueue.cpp:
(WebCore::CustomElementReactionQueue::observesStyleAttribute):
* dom/CustomElementReactionQueue.h:

LayoutTests:

Added a W3C style testharness.js test.

* fast/custom-elements/reactions/CSSStyleDeclaration-expected.txt: Added.
* fast/custom-elements/reactions/CSSStyleDeclaration.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208176 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/custom-elements/reactions/CSSStyleDeclaration-expected.txt [new file with mode: 0644]
LayoutTests/fast/custom-elements/reactions/CSSStyleDeclaration.html [new file with mode: 0644]
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/custom-elements/attribute-changed-callback-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp
Source/WebCore/css/CSSStyleDeclaration.idl
Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp
Source/WebCore/dom/CustomElementReactionQueue.cpp
Source/WebCore/dom/CustomElementReactionQueue.h

index eac46de..f0ce64c 100644 (file)
@@ -1,3 +1,15 @@
+2016-10-31  Ryosuke Niwa  <rniwa@webkit.org>
+
+        CSSStyleDeclaration should be annotated with CEReactions
+        https://bugs.webkit.org/show_bug.cgi?id=163968
+
+        Reviewed by Antti Koivisto.
+
+        Added a W3C style testharness.js test.
+
+        * fast/custom-elements/reactions/CSSStyleDeclaration-expected.txt: Added.
+        * fast/custom-elements/reactions/CSSStyleDeclaration.html: Added.
+
 2016-10-31  Zalan Bujtas  <zalan@apple.com>
 
         ASSERTION FAILED: !m_trailingWhitespaceWidth in WebCore::SimpleLineLayout::LineState::removeTrailingWhitespace
diff --git a/LayoutTests/fast/custom-elements/reactions/CSSStyleDeclaration-expected.txt b/LayoutTests/fast/custom-elements/reactions/CSSStyleDeclaration-expected.txt
new file mode 100644 (file)
index 0000000..d848009
--- /dev/null
@@ -0,0 +1,32 @@
+
+PASS cssText on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute 
+PASS cssText on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed 
+PASS cssText on CSSStyleDeclaration must enqueue an attributeChanged reaction when it mutates the observed style attribute 
+PASS cssText on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed 
+PASS setProperty on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute 
+PASS setProperty on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed 
+PASS setProperty on CSSStyleDeclaration must enqueue an attributeChanged reaction when it mutates the observed style attribute 
+PASS setProperty on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed 
+PASS setProperty on CSSStyleDeclaration must enqueue an attributeChanged reaction when it makes a property important and the style attribute is observed 
+PASS setProperty on CSSStyleDeclaration must enqueue an attributeChanged reaction when it makes a property important but the style attribute is not observed 
+PASS removeProperty on CSSStyleDeclaration must enqueue an attributeChanged reaction when it removes a property from the observed style attribute 
+PASS removeProperty on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it removes a property from the style attribute but the style attribute is not observed 
+PASS cssFloat on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute 
+PASS cssFloat on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed 
+PASS A camel case attribute (borderWidth) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute 
+PASS A camel case attribute (borderWidth) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed 
+PASS A camel case attribute (borderWidth) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it mutates the observed style attribute 
+PASS A camel case attribute (borderWidth) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed 
+PASS A dashed property (border-width) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute 
+PASS A dashed property (border-width) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed 
+PASS A dashed property (border-width) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it mutates the observed style attribute 
+PASS A dashed property (border-width) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed 
+PASS A webkit prefixed camel case attribute (webkitFilter) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute 
+PASS A webkit prefixed camel case attribute (webkitFilter) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed 
+PASS A webkit prefixed camel case attribute (webkitFilter) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it mutates the observed style attribute 
+PASS A webkit prefixed camel case attribute (webkitFilter) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed 
+PASS A webkit prefixed dashed property (-webkit-filter) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute 
+PASS A webkit prefixed dashed property (-webkit-filter) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed 
+PASS A webkit prefixed dashed property (-webkit-filter) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it mutates the observed style attribute 
+PASS A webkit prefixed dashed property (-webkit-filter) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed 
+
diff --git a/LayoutTests/fast/custom-elements/reactions/CSSStyleDeclaration.html b/LayoutTests/fast/custom-elements/reactions/CSSStyleDeclaration.html
new file mode 100644 (file)
index 0000000..057d111
--- /dev/null
@@ -0,0 +1,177 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Custom Elements: CEReactions on CSSStyleDeclaration interface</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="cssText, setProperty, setPropertyValue, setPropertyPriority, removeProperty, cssFloat, and all camel cased attributes of CSSStyleDeclaration interface must have CEReactions">
+<meta name="help" content="https://dom.spec.whatwg.org/#node">
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../imported/w3c/web-platform-tests/custom-elements/resources/custom-elements-helpers.js"></script>
+<script src="../../../imported/w3c/web-platform-tests/custom-elements/reactions/resources/reactions.js"></script>
+<script src="../resources/additional-helpers.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+function test_mutating_style_property_value(testFunction, name, options) {
+    const propertyName = (options || {}).propertyName || 'color';
+    const idlName = (options || {}).idlName || 'color';
+    const value1 = (options || {}).value1 || 'blue';
+    const rule1 = `${propertyName}: ${value1};`;
+    const value2 = (options || {}).value2 || 'red';
+    const rule2 = `${propertyName}: ${value2};`;
+
+    test(function () {
+        var element = define_new_custom_element(['style']);
+        var instance = document.createElement(element.name);
+        assert_array_equals(element.takeLog().types(), ['constructed']);
+        testFunction(instance, propertyName, idlName, value1);
+        assert_equals(instance.getAttribute('style'), rule1);
+        var logEntries = element.takeLog();
+        assert_array_equals(logEntries.types(), ['attributeChanged']);
+        assert_attribute_log_entry(logEntries.last(), {name: 'style', oldValue: null, newValue: rule1, namespace: null});
+    }, name + ' must enqueue an attributeChanged reaction when it adds the observed style attribute');
+
+    test(function () {
+        var element = define_new_custom_element(['title']);
+        var instance = document.createElement(element.name);
+        assert_array_equals(element.takeLog().types(), ['constructed']);
+        testFunction(instance, propertyName, idlName, value1);
+        assert_equals(instance.getAttribute('style'), rule1);
+        assert_array_equals(element.takeLog().types(), []);
+    }, name + ' must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed');
+
+    test(function () {
+        var element = define_new_custom_element(['style']);
+        var instance = document.createElement(element.name);
+        testFunction(instance, propertyName, idlName, value1);
+        assert_array_equals(element.takeLog().types(), ['constructed', 'attributeChanged']);
+        testFunction(instance, propertyName, idlName, value2);
+        assert_equals(instance.getAttribute('style'), rule2);
+        var logEntries = element.takeLog();
+        assert_array_equals(logEntries.types(), ['attributeChanged']);
+        assert_attribute_log_entry(logEntries.last(), {name: 'style', oldValue: rule1, newValue: rule2, namespace: null});
+    }, name + ' must enqueue an attributeChanged reaction when it mutates the observed style attribute');
+
+    test(function () {
+        var element = define_new_custom_element([]);
+        var instance = document.createElement(element.name);
+        testFunction(instance, propertyName, idlName, value1);
+        assert_array_equals(element.takeLog().types(), ['constructed']);
+        testFunction(instance, propertyName, idlName, value2);
+        assert_equals(instance.getAttribute('style'), rule2);
+        assert_array_equals(element.takeLog().types(), []);
+    }, name + ' must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed');
+}
+
+function test_removing_style_property_value(testFunction, name) {
+    test(function () {
+        var element = define_new_custom_element(['style']);
+        var instance = document.createElement(element.name);
+        instance.setAttribute('style', 'color: red; display: none;');
+        assert_array_equals(element.takeLog().types(), ['constructed', 'attributeChanged']);
+        testFunction(instance, 'color', 'color');
+        assert_equals(instance.getAttribute('style'), 'display: none;'); // Don't make this empty since browser behaviors are inconsistent now.
+        var logEntries = element.takeLog();
+        assert_array_equals(logEntries.types(), ['attributeChanged']);
+        assert_attribute_log_entry(logEntries.last(), {name: 'style', oldValue: 'color: red; display: none;', newValue: 'display: none;', namespace: null});
+    }, name + ' must enqueue an attributeChanged reaction when it removes a property from the observed style attribute');
+
+    test(function () {
+        var element = define_new_custom_element(['class']);
+        var instance = document.createElement(element.name);
+        instance.setAttribute('style', 'color: red; display: none;');
+        assert_array_equals(element.takeLog().types(), ['constructed']);
+        testFunction(instance, 'color', 'color');
+        assert_equals(instance.getAttribute('style'), 'display: none;'); // Don't make this empty since browser behaviors are inconsistent now.
+        assert_array_equals(element.takeLog().types(), []);
+    }, name + ' must not enqueue an attributeChanged reaction when it removes a property from the style attribute but the style attribute is not observed');
+}
+
+function test_mutating_style_property_priority(testFunction, name) {
+    test(function () {
+        var element = define_new_custom_element(['style']);
+        var instance = document.createElement(element.name);
+        instance.setAttribute('style', 'color: red');
+        assert_array_equals(element.takeLog().types(), ['constructed', 'attributeChanged']);
+        testFunction(instance, 'color', 'color', true);
+        assert_equals(instance.getAttribute('style'), 'color: red !important;');
+        var logEntries = element.takeLog();
+        assert_array_equals(logEntries.types(), ['attributeChanged']);
+        assert_attribute_log_entry(logEntries.last(), {name: 'style', oldValue: 'color: red', newValue: 'color: red !important;', namespace: null});
+    }, name + ' must enqueue an attributeChanged reaction when it makes a property important and the style attribute is observed');
+
+    test(function () {
+        var element = define_new_custom_element(['id']);
+        var instance = document.createElement(element.name);
+        instance.setAttribute('style', 'color: red');
+        assert_array_equals(element.takeLog().types(), ['constructed']);
+        testFunction(instance, 'color', 'color', true);
+        assert_equals(instance.getAttribute('style'), 'color: red !important;');
+        assert_array_equals(element.takeLog().types(), []);
+    }, name + ' must enqueue an attributeChanged reaction when it makes a property important but the style attribute is not observed');
+}
+
+test_mutating_style_property_value(function (instance, propertyName, idlName, value) {
+    instance.style.cssText = `${propertyName}: ${value}`;
+}, 'cssText on CSSStyleDeclaration');
+
+test_mutating_style_property_value(function (instance, propertyName, idlName, value) {
+    instance.style.setProperty(propertyName, value);
+}, 'setProperty on CSSStyleDeclaration');
+
+test_mutating_style_property_priority(function (instance, propertyName, idlName, isImportant) {
+    instance.style.setProperty(propertyName, instance.style[idlName], isImportant ? 'important': '');
+}, 'setProperty on CSSStyleDeclaration');
+
+test_removing_style_property_value(function (instance, propertyName, idlName) {
+    instance.style.removeProperty(propertyName);
+}, 'removeProperty on CSSStyleDeclaration');
+
+test(function () {
+    var element = define_new_custom_element(['style']);
+    var instance = document.createElement(element.name);
+    assert_array_equals(element.takeLog().types(), ['constructed']);
+    instance.style.cssFloat = 'left';
+    assert_equals(instance.getAttribute('style'), 'float: left;');
+    var logEntries = element.takeLog();
+    assert_array_equals(logEntries.types(), ['attributeChanged']);
+    assert_attribute_log_entry(logEntries.last(), {name: 'style', oldValue: null, newValue: 'float: left;', namespace: null});
+}, 'cssFloat on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute');
+
+test(function () {
+    var element = define_new_custom_element([]);
+    var instance = document.createElement(element.name);
+    assert_array_equals(element.takeLog().types(), ['constructed']);
+    instance.style.cssFloat = 'left';
+    assert_equals(instance.getAttribute('style'), 'float: left;');
+    assert_array_equals(element.takeLog().types(), []);
+}, 'cssFloat on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed');
+
+test_mutating_style_property_value(function (instance, propertyName, idlName, value) {
+    assert_equals(idlName, 'borderWidth');
+    instance.style.borderWidth = value;
+}, 'A camel case attribute (borderWidth) on CSSStyleDeclaration',
+    {propertyName: 'border-width', idlName: 'borderWidth', value1: '2px', value2: '4px'});
+
+test_mutating_style_property_value(function (instance, propertyName, idlName, value) {
+    assert_equals(propertyName, 'border-width');
+    instance.style['border-width'] = value;
+}, 'A dashed property (border-width) on CSSStyleDeclaration',
+    {propertyName: 'border-width', idlName: 'borderWidth', value1: '1px', value2: '5px'});
+
+test_mutating_style_property_value(function (instance, propertyName, idlName, value) {
+    instance.style.webkitFilter = value;
+}, 'A webkit prefixed camel case attribute (webkitFilter) on CSSStyleDeclaration',
+    {propertyName: 'filter', idlName: 'filter', value1: 'grayscale(20%)', value2: 'grayscale(30%)'});
+
+test_mutating_style_property_value(function (instance, propertyName, idlName, value) {
+    instance.style['-webkit-filter'] = value;
+}, 'A webkit prefixed dashed property (-webkit-filter) on CSSStyleDeclaration',
+    {propertyName: 'filter', idlName: 'filter', value1: 'grayscale(20%)', value2: 'grayscale(30%)'});
+
+</script>
+</body>
+</html>
index 2d7fbeb..2906dde 100644 (file)
@@ -1,3 +1,14 @@
+2016-10-31  Ryosuke Niwa  <rniwa@webkit.org>
+
+        CSSStyleDeclaration should be annotated with CEReactions
+        https://bugs.webkit.org/show_bug.cgi?id=163968
+
+        Reviewed by Antti Koivisto.
+
+        Rebaselined the test now that all test cases pass.
+
+        * web-platform-tests/custom-elements/attribute-changed-callback-expected.txt:
+
 2016-10-28  Darin Adler  <darin@apple.com>
 
         Move all classes in the HTML directory from ExceptionCode to Exception
index 96f5a01..39659ca 100644 (file)
@@ -7,6 +7,6 @@ PASS Mutating attributeChangedCallback after calling customElements.define must
 PASS attributedChangedCallback must not be invoked when the observed attributes does not contain the attribute 
 PASS Mutating observedAttributes after calling customElements.define must not affect the set of attributes for which attributedChangedCallback is invoked 
 PASS attributedChangedCallback must be enqueued for attributes specified in a non-Array iterable observedAttributes 
-FAIL attributedChangedCallback must be enqueued for style attribute change by mutating inline style declaration assert_equals: expected 1 but got 0
+PASS attributedChangedCallback must be enqueued for style attribute change by mutating inline style declaration 
 PASS attributedChangedCallback must not be enqueued when mutating inline style declaration if the style attribute is not observed 
 
index 5753a58..3e028a1 100644 (file)
@@ -1,3 +1,27 @@
+2016-10-31  Ryosuke Niwa  <rniwa@webkit.org>
+
+        CSSStyleDeclaration should be annotated with CEReactions
+        https://bugs.webkit.org/show_bug.cgi?id=163968
+
+        Reviewed by Antti Koivisto.
+
+        Added CEReactions to CSSStyleDeclaration.idl.
+
+        Test: fast/custom-elements/reactions/CSSStyleDeclaration.html
+
+        * bindings/js/JSCSSStyleDeclarationCustom.cpp:
+        (WebCore::JSCSSStyleDeclaration::putDelegate):
+        * css/CSSStyleDeclaration.idl:
+        * css/PropertySetCSSStyleDeclaration.cpp:
+        (WebCore::StyleAttributeMutationScope::StyleAttributeMutationScope): Remember the old value when this is
+        an inline style declaration for a custom element. Also store m_oldValue and m_customElement instead of
+        a mutation record so that we don't create a superfluous mutation record for custom elements.
+        (WebCore::StyleAttributeMutationScope::~StyleAttributeMutationScope): Enqueue attributeChangedCallback
+        when m_customElement is not null.
+        * dom/CustomElementReactionQueue.cpp:
+        (WebCore::CustomElementReactionQueue::observesStyleAttribute):
+        * dom/CustomElementReactionQueue.h:
+
 2016-10-31  Jer Noble  <jer.noble@apple.com>
 
         Unreviewed build fix for the build fix; AVStreamDataParser not defined on iOS.
index c14c197..1c491a6 100644 (file)
@@ -33,6 +33,7 @@
 #include "CSSStyleDeclaration.h"
 #include "CSSStyleSheet.h"
 #include "CSSValue.h"
+#include "CustomElementReactionQueue.h"
 #include "HashTools.h"
 #include "JSCSSStyleDeclaration.h"
 #include "JSCSSValue.h"
@@ -322,6 +323,9 @@ bool JSCSSStyleDeclaration::getOwnPropertySlotDelegate(ExecState* state, Propert
 
 bool JSCSSStyleDeclaration::putDelegate(ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot&, bool& putResult)
 {
+#if ENABLE(CUSTOM_ELEMENTS)
+    CustomElementReactionStack customElementReactionStack;
+#endif
     auto propertyInfo = parseJavaScriptCSSPropertyName(propertyName);
     if (!propertyInfo.propertyID)
         return false;
index 2c85a4c..4f733e5 100644 (file)
     JSCustomMarkFunction,
     SkipVTableValidation,
 ] interface CSSStyleDeclaration {
-    [SetterMayThrowException] attribute DOMString cssText;
+    [CEReactions, SetterMayThrowException] attribute DOMString cssText;
 
     DOMString getPropertyValue(DOMString propertyName);
     [Custom] CSSValue? getPropertyCSSValue(DOMString propertyName);
 
-    [MayThrowException] DOMString removeProperty(DOMString propertyName);
+    [CEReactions, MayThrowException] DOMString removeProperty(DOMString propertyName);
     DOMString? getPropertyPriority(DOMString propertyName);
 
-    [MayThrowException] void setProperty(DOMString propertyName, [TreatNullAs=EmptyString] DOMString value, [TreatNullAs=EmptyString] optional DOMString priority = "");
+    [CEReactions, MayThrowException] void setProperty(DOMString propertyName, [TreatNullAs=EmptyString] DOMString value, [TreatNullAs=EmptyString] optional DOMString priority = "");
 
     readonly attribute unsigned long length;
     getter DOMString item(unsigned long index);
index fd5e1b4..f553c82 100644 (file)
@@ -26,6 +26,7 @@
 #include "CSSParser.h"
 #include "CSSRule.h"
 #include "CSSStyleSheet.h"
+#include "CustomElementReactionQueue.h"
 #include "HTMLNames.h"
 #include "InspectorInstrumentation.h"
 #include "MutationObserverInterestGroup.h"
@@ -53,7 +54,8 @@ public:
         ASSERT(!s_currentDecl);
         s_currentDecl = decl;
 
-        if (!s_currentDecl->parentElement())
+        auto* element = s_currentDecl->parentElement();
+        if (!element)
             return;
 
         bool shouldReadOldValue = false;
@@ -62,14 +64,18 @@ public:
         if (m_mutationRecipients && m_mutationRecipients->isOldValueRequested())
             shouldReadOldValue = true;
 
-        AtomicString oldValue;
-        if (shouldReadOldValue)
-            oldValue = s_currentDecl->parentElement()->getAttribute(HTMLNames::styleAttr);
-
-        if (m_mutationRecipients) {
-            AtomicString requestedOldValue = m_mutationRecipients->isOldValueRequested() ? oldValue : nullAtom;
-            m_mutation = MutationRecord::createAttributes(*s_currentDecl->parentElement(), HTMLNames::styleAttr, requestedOldValue);
+#if ENABLE(CUSTOM_ELEMENTS)
+        if (UNLIKELY(element->isDefinedCustomElement())) {
+            auto* reactionQueue = element->reactionQueue();
+            if (reactionQueue && reactionQueue->observesStyleAttribute()) {
+                m_customElement = element;
+                shouldReadOldValue = true;
+            }
         }
+#endif
+
+        if (shouldReadOldValue)
+            m_oldValue = s_currentDecl->parentElement()->getAttribute(HTMLNames::styleAttr);
     }
 
     ~StyleAttributeMutationScope()
@@ -78,8 +84,16 @@ public:
         if (s_scopeCount)
             return;
 
-        if (m_mutation && s_shouldDeliver)
-            m_mutationRecipients->enqueueMutationRecord(m_mutation.releaseNonNull());
+        if (s_shouldDeliver) {
+            if (m_mutationRecipients) {
+                auto mutation = MutationRecord::createAttributes(*s_currentDecl->parentElement(), HTMLNames::styleAttr, m_oldValue);
+                m_mutationRecipients->enqueueMutationRecord(WTFMove(mutation));
+            }
+            if (m_customElement) {
+                AtomicString newValue = m_customElement->getAttribute(HTMLNames::styleAttr);
+                CustomElementReactionQueue::enqueueAttributeChangedCallbackIfNeeded(*m_customElement, HTMLNames::styleAttr, m_oldValue, newValue);
+            }
+        }
 
         s_shouldDeliver = false;
         if (!s_shouldNotifyInspector) {
@@ -111,7 +125,8 @@ private:
     static bool s_shouldDeliver;
 
     std::unique_ptr<MutationObserverInterestGroup> m_mutationRecipients;
-    RefPtr<MutationRecord> m_mutation;
+    AtomicString m_oldValue;
+    RefPtr<Element> m_customElement;
 };
 
 unsigned StyleAttributeMutationScope::s_scopeCount = 0;
index ae898ff..fb533e0 100644 (file)
@@ -32,6 +32,7 @@
 #include "DOMWindow.h"
 #include "Document.h"
 #include "Element.h"
+#include "HTMLNames.h"
 #include "JSCustomElementInterface.h"
 #include "JSDOMBinding.h"
 #include "Microtasks.h"
@@ -190,6 +191,11 @@ void CustomElementReactionQueue::enqueuePostUpgradeReactions(Element& element)
         queue->m_items.append({CustomElementReactionQueueItem::Type::Connected});
 }
 
+bool CustomElementReactionQueue::observesStyleAttribute() const
+{
+    return m_interface->observesAttribute(HTMLNames::styleAttr.localName());
+}
+
 void CustomElementReactionQueue::invokeAll(Element& element)
 {
     while (!m_items.isEmpty()) {
index 9c879d7..336ffc4 100644 (file)
@@ -53,6 +53,7 @@ public:
     static void enqueueAttributeChangedCallbackIfNeeded(Element&, const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue);
     static void enqueuePostUpgradeReactions(Element&);
 
+    bool observesStyleAttribute() const;
     void invokeAll(Element&);
     void clear();