Title: [286058] trunk/Source/WebCore
Revision
286058
Author
an...@apple.com
Date
2021-11-19 06:48:24 -0800 (Fri, 19 Nov 2021)

Log Message

Factor child change invalidation into class
https://bugs.webkit.org/show_bug.cgi?id=233311

Reviewed by Alan Bujtas.

Use similar pattern as ClassChangeInvalidation and others where we create a stack object scoped
over a DOM mutation. This will allow more sophisticated ruleset based invalidation in
future.

This patch moves the invalidation code from childrenChanged() to the new ChildChangeInvalidation class.
ChildChangeInvalidation is instantiated in ContainerNode and CharacterData mutation functions
that call childrenChanged(). It uses the same ChildChange argument type as childrenChanged().

There are no changes to invalidation functionality in this patch.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* dom/CharacterData.cpp:
(WebCore::makeChildChange):
(WebCore::CharacterData::parserAppendData):
(WebCore::CharacterData::setDataAndUpdate):
(WebCore::CharacterData::notifyParentAfterChange):
* dom/CharacterData.h:
* dom/ContainerNode.cpp:
(WebCore::ContainerNode::removeAllChildrenWithScriptAssertion):
(WebCore::makeChildChangeForRemoval):
(WebCore::ContainerNode::removeNodeWithScriptAssertion):
(WebCore::makeChildChangeForInsertion):
(WebCore::executeNodeInsertionWithScriptAssertion):
(WebCore::ContainerNode::insertBefore):
(WebCore::ContainerNode::parserInsertBefore):
(WebCore::ContainerNode::replaceChild):
(WebCore::ContainerNode::replaceAll):
(WebCore::ContainerNode::appendChildWithoutPreInsertionValidityCheck):
(WebCore::ContainerNode::parserAppendChild):
(WebCore::affectsElements):
* dom/ContainerNode.h:
(WebCore::ContainerNode::ChildChange::isInsertion const):

Add a new FinishedParsingChildren change type, only used when invalidating from Element::finishParsingChildren.

* dom/Element.cpp:
(WebCore::invalidateForSiblingCombinators):
(WebCore::Element::childTypeAllowed const):
(WebCore::Element::childrenChanged):
(WebCore::Element::finishParsingChildren):
(WebCore::checkForEmptyStyleChange): Deleted.
(WebCore::invalidateForForwardPositionalRules): Deleted.
(WebCore::invalidateForBackwardPositionalRules): Deleted.
(WebCore::checkForSiblingStyleChanges): Deleted.
* dom/Element.h:
* dom/ShadowRoot.cpp:
(WebCore::ShadowRoot::childrenChanged):
* style/ChildChangeInvalidation.cpp: Added.
(WebCore::Style::ChildChangeInvalidation::ChildChangeInvalidation):
(WebCore::Style::ChildChangeInvalidation::~ChildChangeInvalidation):
(WebCore::Style::ChildChangeInvalidation::invalidateAfterChange):
(WebCore::Style::ChildChangeInvalidation::checkForEmptyStyleChange):
(WebCore::Style::invalidateForForwardPositionalRules):
(WebCore::Style::invalidateForBackwardPositionalRules):
(WebCore::Style::ChildChangeInvalidation::checkForSiblingStyleChanges):
* style/ChildChangeInvalidation.h: Added.
(WebCore::Style::ChildChangeInvalidation::parentElement):
* style/StyleAdjuster.h:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (286057 => 286058)


--- trunk/Source/WebCore/ChangeLog	2021-11-19 14:39:07 UTC (rev 286057)
+++ trunk/Source/WebCore/ChangeLog	2021-11-19 14:48:24 UTC (rev 286058)
@@ -1,3 +1,70 @@
+2021-11-19  Antti Koivisto  <an...@apple.com>
+
+        Factor child change invalidation into class
+        https://bugs.webkit.org/show_bug.cgi?id=233311
+
+        Reviewed by Alan Bujtas.
+
+        Use similar pattern as ClassChangeInvalidation and others where we create a stack object scoped
+        over a DOM mutation. This will allow more sophisticated ruleset based invalidation in
+        future.
+
+        This patch moves the invalidation code from childrenChanged() to the new ChildChangeInvalidation class.
+        ChildChangeInvalidation is instantiated in ContainerNode and CharacterData mutation functions
+        that call childrenChanged(). It uses the same ChildChange argument type as childrenChanged().
+
+        There are no changes to invalidation functionality in this patch.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/CharacterData.cpp:
+        (WebCore::makeChildChange):
+        (WebCore::CharacterData::parserAppendData):
+        (WebCore::CharacterData::setDataAndUpdate):
+        (WebCore::CharacterData::notifyParentAfterChange):
+        * dom/CharacterData.h:
+        * dom/ContainerNode.cpp:
+        (WebCore::ContainerNode::removeAllChildrenWithScriptAssertion):
+        (WebCore::makeChildChangeForRemoval):
+        (WebCore::ContainerNode::removeNodeWithScriptAssertion):
+        (WebCore::makeChildChangeForInsertion):
+        (WebCore::executeNodeInsertionWithScriptAssertion):
+        (WebCore::ContainerNode::insertBefore):
+        (WebCore::ContainerNode::parserInsertBefore):
+        (WebCore::ContainerNode::replaceChild):
+        (WebCore::ContainerNode::replaceAll):
+        (WebCore::ContainerNode::appendChildWithoutPreInsertionValidityCheck):
+        (WebCore::ContainerNode::parserAppendChild):
+        (WebCore::affectsElements):
+        * dom/ContainerNode.h:
+        (WebCore::ContainerNode::ChildChange::isInsertion const):
+
+        Add a new FinishedParsingChildren change type, only used when invalidating from Element::finishParsingChildren.
+
+        * dom/Element.cpp:
+        (WebCore::invalidateForSiblingCombinators):
+        (WebCore::Element::childTypeAllowed const):
+        (WebCore::Element::childrenChanged):
+        (WebCore::Element::finishParsingChildren):
+        (WebCore::checkForEmptyStyleChange): Deleted.
+        (WebCore::invalidateForForwardPositionalRules): Deleted.
+        (WebCore::invalidateForBackwardPositionalRules): Deleted.
+        (WebCore::checkForSiblingStyleChanges): Deleted.
+        * dom/Element.h:
+        * dom/ShadowRoot.cpp:
+        (WebCore::ShadowRoot::childrenChanged):
+        * style/ChildChangeInvalidation.cpp: Added.
+        (WebCore::Style::ChildChangeInvalidation::ChildChangeInvalidation):
+        (WebCore::Style::ChildChangeInvalidation::~ChildChangeInvalidation):
+        (WebCore::Style::ChildChangeInvalidation::invalidateAfterChange):
+        (WebCore::Style::ChildChangeInvalidation::checkForEmptyStyleChange):
+        (WebCore::Style::invalidateForForwardPositionalRules):
+        (WebCore::Style::invalidateForBackwardPositionalRules):
+        (WebCore::Style::ChildChangeInvalidation::checkForSiblingStyleChanges):
+        * style/ChildChangeInvalidation.h: Added.
+        (WebCore::Style::ChildChangeInvalidation::parentElement):
+        * style/StyleAdjuster.h:
+
 2021-11-19  Carlos Garcia Campos  <cgar...@igalia.com>
 
         [GTK][a11y] Add implementation of action interface when building with ATSPI

Modified: trunk/Source/WebCore/Sources.txt (286057 => 286058)


--- trunk/Source/WebCore/Sources.txt	2021-11-19 14:39:07 UTC (rev 286057)
+++ trunk/Source/WebCore/Sources.txt	2021-11-19 14:48:24 UTC (rev 286058)
@@ -2523,6 +2523,7 @@
 storage/StorageNamespaceProvider.cpp
 storage/StorageQuotaManager.cpp
 style/AttributeChangeInvalidation.cpp
+style/ChildChangeInvalidation.cpp
 style/ClassChangeInvalidation.cpp
 style/ElementRuleCollector.cpp
 style/IdChangeInvalidation.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (286057 => 286058)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-11-19 14:39:07 UTC (rev 286057)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-11-19 14:48:24 UTC (rev 286058)
@@ -5342,6 +5342,7 @@
 		E4C1789B0EE6903800824D69 /* CSSSelectorList.h in Headers */ = {isa = PBXBuildFile; fileRef = E4C178960EE6903800824D69 /* CSSSelectorList.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E4C279590CF9741900E97B98 /* RenderMedia.h in Headers */ = {isa = PBXBuildFile; fileRef = E4C279570CF9741900E97B98 /* RenderMedia.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E4C3B1FA0F0E4161009693F6 /* LegacyTileCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E4C3B1F90F0E4161009693F6 /* LegacyTileCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		E4C4C61A27452A7900A040E7 /* ChildChangeInvalidation.h in Headers */ = {isa = PBXBuildFile; fileRef = E4C4C61827452A7900A040E7 /* ChildChangeInvalidation.h */; };
 		E4C91A0E1802343100A17F6D /* TextPaintStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = E4C91A0D1802343100A17F6D /* TextPaintStyle.h */; };
 		E4C91A16180999F100A17F6D /* RenderTextLineBoxes.h in Headers */ = {isa = PBXBuildFile; fileRef = E4C91A15180999F100A17F6D /* RenderTextLineBoxes.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E4D33F3B252AEECD00837D05 /* InlineRunAndOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = E4D33F39252AEECC00837D05 /* InlineRunAndOffset.h */; };
@@ -17044,6 +17045,8 @@
 		E4C279570CF9741900E97B98 /* RenderMedia.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderMedia.h; sourceTree = "<group>"; };
 		E4C3B1F90F0E4161009693F6 /* LegacyTileCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LegacyTileCache.h; sourceTree = "<group>"; };
 		E4C3B1FB0F0E4170009693F6 /* LegacyTileCache.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LegacyTileCache.mm; sourceTree = "<group>"; };
+		E4C4C61827452A7900A040E7 /* ChildChangeInvalidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChildChangeInvalidation.h; sourceTree = "<group>"; };
+		E4C4C61B27452A8A00A040E7 /* ChildChangeInvalidation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ChildChangeInvalidation.cpp; sourceTree = "<group>"; };
 		E4C91A0D1802343100A17F6D /* TextPaintStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextPaintStyle.h; sourceTree = "<group>"; };
 		E4C91A0F1802343900A17F6D /* TextPaintStyle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextPaintStyle.cpp; sourceTree = "<group>"; };
 		E4C91A15180999F100A17F6D /* RenderTextLineBoxes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderTextLineBoxes.h; sourceTree = "<group>"; };
@@ -30280,6 +30283,8 @@
 				E4A814D71C70E10500BF85AC /* AttributeChangeInvalidation.cpp */,
 				E4A814D91C70E10D00BF85AC /* AttributeChangeInvalidation.h */,
 				E4ABABF42368C6EF00FA4345 /* CascadeLevel.h */,
+				E4C4C61B27452A8A00A040E7 /* ChildChangeInvalidation.cpp */,
+				E4C4C61827452A7900A040E7 /* ChildChangeInvalidation.h */,
 				E4A814D51C6DEE8D00BF85AC /* ClassChangeInvalidation.cpp */,
 				E4A814D31C6DEC4000BF85AC /* ClassChangeInvalidation.h */,
 				FBDB619A16D6032A00BB3394 /* ElementRuleCollector.cpp */,
@@ -32733,6 +32738,7 @@
 				93F2CC932427FB9C005851D8 /* CharacterRange.h in Headers */,
 				97B8FFD116AE7F960038388D /* CharacterReferenceParserInlines.h in Headers */,
 				F55B3DB21251F12D003EF269 /* CheckboxInputType.h in Headers */,
+				E4C4C61A27452A7900A040E7 /* ChildChangeInvalidation.h in Headers */,
 				D619A308144E00BE004BC302 /* ChildListMutationScope.h in Headers */,
 				A81872200977D3C0005826D9 /* ChildNodeList.h in Headers */,
 				14D823520AF92A790004F057 /* Chrome.h in Headers */,

Modified: trunk/Source/WebCore/dom/CharacterData.cpp (286057 => 286058)


--- trunk/Source/WebCore/dom/CharacterData.cpp	2021-11-19 14:39:07 UTC (rev 286057)
+++ trunk/Source/WebCore/dom/CharacterData.cpp	2021-11-19 14:48:24 UTC (rev 286058)
@@ -23,6 +23,7 @@
 #include "CharacterData.h"
 
 #include "Attr.h"
+#include "ChildChangeInvalidation.h"
 #include "ElementTraversal.h"
 #include "EventNames.h"
 #include "FrameSelection.h"
@@ -73,6 +74,16 @@
     return m_data.substring(offset, count);
 }
 
+static ContainerNode::ChildChange makeChildChange(CharacterData& characterData, ContainerNode::ChildChange::Source source)
+{
+    return {
+        ContainerNode::ChildChange::Type::TextChanged,
+        ElementTraversal::previousSibling(characterData),
+        ElementTraversal::nextSibling(characterData),
+        source
+    };
+}
+
 unsigned CharacterData::parserAppendData(const String& string, unsigned offset, unsigned lengthLimit)
 {
     unsigned oldLength = m_data.length();
@@ -95,6 +106,11 @@
     if (!characterLengthLimit)
         return 0;
 
+    auto childChange = makeChildChange(*this, ContainerNode::ChildChange::Source::Parser);
+    std::optional<Style::ChildChangeInvalidation> styleInvalidation;
+    if (auto* parent = parentNode())
+        styleInvalidation.emplace(*parent, childChange);
+
     String oldData = m_data;
     if (string.is8Bit())
         m_data.append(string.characters8() + offset, characterLengthLimit);
@@ -105,7 +121,7 @@
     if (is<Text>(*this))
         downcast<Text>(*this).updateRendererAfterContentChange(oldLength, 0);
 
-    notifyParentAfterChange(ContainerNode::ChildChange::Source::Parser);
+    notifyParentAfterChange(childChange);
 
     auto mutationRecipients = MutationObserverInterestGroup::createForCharacterDataMutation(*this);
     if (UNLIKELY(mutationRecipients))
@@ -173,6 +189,12 @@
 
 void CharacterData::setDataAndUpdate(const String& newData, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength, UpdateLiveRanges shouldUpdateLiveRanges)
 {
+    auto childChange = makeChildChange(*this, ContainerNode::ChildChange::Source::API);
+
+    std::optional<Style::ChildChangeInvalidation> styleInvalidation;
+    if (auto* parent = parentNode())
+        styleInvalidation.emplace(*parent, childChange);
+
     String oldData = m_data;
     m_data = newData;
 
@@ -191,12 +213,12 @@
     if (document().frame())
         document().frame()->selection().textWasReplaced(this, offsetOfReplacedData, oldLength, newLength);
 
-    notifyParentAfterChange(ContainerNode::ChildChange::Source::API);
+    notifyParentAfterChange(childChange);
 
     dispatchModifiedEvent(oldData);
 }
 
-void CharacterData::notifyParentAfterChange(ContainerNode::ChildChange::Source source)
+void CharacterData::notifyParentAfterChange(const ContainerNode::ChildChange& childChange)
 {
     document().incDOMTreeVersion();
 
@@ -203,14 +225,7 @@
     if (!parentNode())
         return;
 
-    ContainerNode::ChildChange change = {
-        ContainerNode::ChildChange::Type::TextChanged,
-        ElementTraversal::previousSibling(*this),
-        ElementTraversal::nextSibling(*this),
-        source
-    };
-
-    parentNode()->childrenChanged(change);
+    parentNode()->childrenChanged(childChange);
 }
 
 void CharacterData::dispatchModifiedEvent(const String& oldData)

Modified: trunk/Source/WebCore/dom/CharacterData.h (286057 => 286058)


--- trunk/Source/WebCore/dom/CharacterData.h	2021-11-19 14:39:07 UTC (rev 286057)
+++ trunk/Source/WebCore/dom/CharacterData.h	2021-11-19 14:48:24 UTC (rev 286058)
@@ -65,7 +65,7 @@
 private:
     String nodeValue() const final;
     ExceptionOr<void> setNodeValue(const String&) final;
-    void notifyParentAfterChange(ContainerNode::ChildChange::Source);
+    void notifyParentAfterChange(const ContainerNode::ChildChange&);
 
     String m_data;
 };

Modified: trunk/Source/WebCore/dom/ContainerNode.cpp (286057 => 286058)


--- trunk/Source/WebCore/dom/ContainerNode.cpp	2021-11-19 14:39:07 UTC (rev 286057)
+++ trunk/Source/WebCore/dom/ContainerNode.cpp	2021-11-19 14:48:24 UTC (rev 286058)
@@ -25,6 +25,7 @@
 
 #include "AXObjectCache.h"
 #include "AllDescendantsCollection.h"
+#include "ChildChangeInvalidation.h"
 #include "ChildListMutationScope.h"
 #include "ClassCollection.h"
 #include "CommonVM.h"
@@ -111,29 +112,52 @@
 
     disconnectSubframesIfNeeded(*this, DescendantsOnly);
 
+    ContainerNode::ChildChange childChange { ChildChange::Type::AllChildrenRemoved, nullptr, nullptr, source };
+
     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
     ScriptDisallowedScope::InMainThread scriptDisallowedScope;
+    {
+        Style::ChildChangeInvalidation styleInvalidation(*this, childChange);
 
-    if (UNLIKELY(isShadowRoot() || isInShadowTree()))
-        containingShadowRoot()->willRemoveAllChildren(*this);
+        if (UNLIKELY(isShadowRoot() || isInShadowTree()))
+            containingShadowRoot()->willRemoveAllChildren(*this);
 
-    document().nodeChildrenWillBeRemoved(*this);
+        document().nodeChildrenWillBeRemoved(*this);
 
-    while (RefPtr<Node> child = m_firstChild) {
-        removeBetween(nullptr, child->nextSibling(), *child);
-        auto subtreeObservability = notifyChildNodeRemoved(*this, *child);
-        if (source == ChildChange::Source::API && subtreeObservability == RemovedSubtreeObservability::MaybeObservableByRefPtr)
-            willCreatePossiblyOrphanedTreeByRemoval(child.get());
+        while (RefPtr<Node> child = m_firstChild) {
+            removeBetween(nullptr, child->nextSibling(), *child);
+            auto subtreeObservability = notifyChildNodeRemoved(*this, *child);
+            if (source == ChildChange::Source::API && subtreeObservability == RemovedSubtreeObservability::MaybeObservableByRefPtr)
+                willCreatePossiblyOrphanedTreeByRemoval(child.get());
+        }
     }
 
     ASSERT_WITH_SECURITY_IMPLICATION(!document().selection().selection().isOrphan());
 
     if (deferChildrenChanged == DeferChildrenChanged::No)
-        childrenChanged(ContainerNode::ChildChange { ChildChange::Type::AllChildrenRemoved, nullptr, nullptr, source });
+        childrenChanged(childChange);
 
     return children;
 }
 
+static ContainerNode::ChildChange makeChildChangeForRemoval(Node& childToRemove, ContainerNode::ChildChange::Source source)
+{
+    auto changeType = [&] {
+        if (is<Element>(childToRemove))
+            return ContainerNode::ChildChange::Type::ElementRemoved;
+        if (is<Text>(childToRemove))
+            return ContainerNode::ChildChange::Type::TextRemoved;
+        return ContainerNode::ChildChange::Type::NonContentsChildRemoved;
+    }();
+
+    return {
+        changeType,
+        ElementTraversal::previousSibling(childToRemove),
+        ElementTraversal::nextSibling(childToRemove),
+        source
+    };
+}
+
 ALWAYS_INLINE bool ContainerNode::removeNodeWithScriptAssertion(Node& childToRemove, ChildChange::Source source)
 {
     Ref<Node> protectedChildToRemove(childToRemove);
@@ -162,11 +186,13 @@
     if (childToRemove.parentNode() != this)
         return false;
 
-    ChildChange change;
+    auto childChange = makeChildChangeForRemoval(childToRemove, source);
+
     RemovedSubtreeObservability subtreeObservability;
     {
         WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
         ScriptDisallowedScope::InMainThread scriptDisallowedScope;
+        Style::ChildChangeInvalidation styleInvalidation(*this, childChange);
 
         if (UNLIKELY(isShadowRoot() || isInShadowTree()))
             containingShadowRoot()->resolveSlotsBeforeNodeInsertionOrRemoval();
@@ -178,17 +204,9 @@
 
         RefPtr<Node> previousSibling = childToRemove.previousSibling();
         RefPtr<Node> nextSibling = childToRemove.nextSibling();
+
         removeBetween(previousSibling.get(), nextSibling.get(), childToRemove);
         subtreeObservability = notifyChildNodeRemoved(*this, childToRemove);
-
-        change.type = is<Element>(childToRemove) ?
-            ChildChange::Type::ElementRemoved :
-            (is<Text>(childToRemove) ?
-                ChildChange::Type::TextRemoved :
-                ChildChange::Type::NonContentsChildRemoved);
-        change.previousSiblingElement = (!previousSibling || is<Element>(*previousSibling)) ? downcast<Element>(previousSibling.get()) : ElementTraversal::previousSibling(*previousSibling);
-        change.nextSiblingElement = (!nextSibling || is<Element>(*nextSibling)) ? downcast<Element>(nextSibling.get()) : ElementTraversal::nextSibling(*nextSibling);
-        change.source = source;
     }
 
     if (source == ChildChange::Source::API && subtreeObservability == RemovedSubtreeObservability::MaybeObservableByRefPtr)
@@ -197,7 +215,7 @@
     ASSERT_WITH_SECURITY_IMPLICATION(!document().selection().selection().isOrphan());
 
     // FIXME: Move childrenChanged into ScriptDisallowedScope block.
-    childrenChanged(change);
+    childrenChanged(childChange);
 
     return true;
 }
@@ -204,14 +222,38 @@
 
 enum class ReplacedAllChildren { No, Yes };
 
+static ContainerNode::ChildChange makeChildChangeForInsertion(ContainerNode& containerNode, Node& child, Node* beforeChild, ContainerNode::ChildChange::Source source, ReplacedAllChildren replacedAllChildren)
+{
+    if (replacedAllChildren == ReplacedAllChildren::Yes)
+        return { ContainerNode::ChildChange::Type::AllChildrenReplaced, nullptr, nullptr, source };
+
+    auto changeType = [&] {
+        if (is<Element>(child))
+            return ContainerNode::ChildChange::Type::ElementInserted;
+        if (is<Text>(child))
+            return ContainerNode::ChildChange::Type::TextInserted;
+        return ContainerNode::ChildChange::Type::NonContentsChildInserted;
+    }();
+
+    return {
+        changeType,
+        beforeChild ? ElementTraversal::previousSibling(*beforeChild) : ElementTraversal::lastChild(containerNode),
+        !beforeChild || is<Element>(*beforeChild) ? downcast<Element>(beforeChild) : ElementTraversal::nextSibling(*beforeChild),
+        source
+    };
+}
+
 template<typename DOMInsertionWork>
-static ALWAYS_INLINE void executeNodeInsertionWithScriptAssertion(ContainerNode& containerNode, Node& child,
+static ALWAYS_INLINE void executeNodeInsertionWithScriptAssertion(ContainerNode& containerNode, Node& child, Node* beforeChild,
     ContainerNode::ChildChange::Source source, ReplacedAllChildren replacedAllChildren, DOMInsertionWork doNodeInsertion)
 {
+    auto childChange = makeChildChangeForInsertion(containerNode, child, beforeChild, source, replacedAllChildren);
+
     NodeVector postInsertionNotificationTargets;
     {
         WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
         ScriptDisallowedScope::InMainThread scriptDisallowedScope;
+        Style::ChildChangeInvalidation styleInvalidation(containerNode, childChange);
 
         if (UNLIKELY(containerNode.isShadowRoot() || containerNode.isInShadowTree()))
             containerNode.containingShadowRoot()->resolveSlotsBeforeNodeInsertionOrRemoval();
@@ -222,20 +264,7 @@
     }
 
     // FIXME: Move childrenChanged into ScriptDisallowedScope block.
-    if (replacedAllChildren == ReplacedAllChildren::Yes)
-        containerNode.childrenChanged(ContainerNode::ChildChange { ContainerNode::ChildChange::Type::AllChildrenReplaced, nullptr, nullptr, source });
-    else {
-        containerNode.childrenChanged(ContainerNode::ChildChange {
-            child.isElementNode() ?
-                ContainerNode::ChildChange::Type::ElementInserted :
-                (child.isTextNode() ?
-                    ContainerNode::ChildChange::Type::TextInserted :
-                    ContainerNode::ChildChange::Type::NonContentsChildInserted),
-            ElementTraversal::previousSibling(child),
-            ElementTraversal::nextSibling(child),
-            source
-        });
-    }
+    containerNode.childrenChanged(childChange);
 
     ASSERT(ScriptDisallowedScope::InMainThread::isEventDispatchAllowedInSubtree(child));
     for (auto& target : postInsertionNotificationTargets)
@@ -448,7 +477,7 @@
         if (child->parentNode())
             break;
 
-        executeNodeInsertionWithScriptAssertion(*this, child.get(), ChildChange::Source::API, ReplacedAllChildren::No, [&] {
+        executeNodeInsertionWithScriptAssertion(*this, child.get(), next.ptr(), ChildChange::Source::API, ReplacedAllChildren::No, [&] {
             child->setTreeScopeRecursively(treeScope());
             insertBeforeCommon(next, child);
         });
@@ -507,7 +536,7 @@
     if (nextChild.previousSibling() == &newChild || &nextChild == &newChild) // nothing to do
         return;
 
-    executeNodeInsertionWithScriptAssertion(*this, newChild, ChildChange::Source::Parser, ReplacedAllChildren::No, [&] {
+    executeNodeInsertionWithScriptAssertion(*this, newChild, &nextChild, ChildChange::Source::Parser, ReplacedAllChildren::No, [&] {
         if (&document() != &newChild.document())
             document().adoptNode(newChild);
 
@@ -581,7 +610,7 @@
         if (child->parentNode())
             break;
 
-        executeNodeInsertionWithScriptAssertion(*this, child.get(), ChildChange::Source::API, ReplacedAllChildren::No, [&] {
+        executeNodeInsertionWithScriptAssertion(*this, child.get(), refChild.get(), ChildChange::Source::API, ReplacedAllChildren::No, [&] {
             child->setTreeScopeRecursively(treeScope());
             if (refChild)
                 insertBeforeCommon(*refChild, child.get());
@@ -682,7 +711,7 @@
     ChildListMutationScope mutation(*this);
     removeAllChildrenWithScriptAssertion(ChildChange::Source::API, DeferChildrenChanged::Yes);
 
-    executeNodeInsertionWithScriptAssertion(*this, *node, ChildChange::Source::API, ReplacedAllChildren::Yes, [&] {
+    executeNodeInsertionWithScriptAssertion(*this, *node, nullptr, ChildChange::Source::API, ReplacedAllChildren::Yes, [&] {
         InspectorInstrumentation::willInsertDOMNode(document(), *this);
         node->setTreeScopeRecursively(treeScope());
         appendChildCommon(*node);
@@ -763,7 +792,7 @@
             break;
 
         // Append child to the end of the list
-        executeNodeInsertionWithScriptAssertion(*this, child.get(), ChildChange::Source::API, ReplacedAllChildren::No, [&] {
+        executeNodeInsertionWithScriptAssertion(*this, child.get(), nullptr, ChildChange::Source::API, ReplacedAllChildren::No, [&] {
             child->setTreeScopeRecursively(treeScope());
             appendChildCommon(child);
         });
@@ -779,7 +808,7 @@
     ASSERT(!newChild.isDocumentFragment());
     ASSERT(!hasTagName(HTMLNames::templateTag));
 
-    executeNodeInsertionWithScriptAssertion(*this, newChild, ChildChange::Source::Parser, ReplacedAllChildren::No, [&] {
+    executeNodeInsertionWithScriptAssertion(*this, newChild, nullptr, ChildChange::Source::Parser, ReplacedAllChildren::No, [&] {
         if (&document() != &newChild.document())
             document().adoptNode(newChild);
 
@@ -812,6 +841,8 @@
     case ContainerNode::ChildChange::Type::NonContentsChildInserted:
     case ContainerNode::ChildChange::Type::NonContentsChildRemoved:
         return false;
+    case ContainerNode::ChildChange::Type::FinishedParsingChildren:
+        break;
     }
     ASSERT_NOT_REACHED();
     return false;

Modified: trunk/Source/WebCore/dom/ContainerNode.h (286057 => 286058)


--- trunk/Source/WebCore/dom/ContainerNode.h	2021-11-19 14:39:07 UTC (rev 286057)
+++ trunk/Source/WebCore/dom/ContainerNode.h	2021-11-19 14:48:24 UTC (rev 286058)
@@ -74,7 +74,7 @@
     void cloneChildNodes(ContainerNode& clone);
 
     struct ChildChange {
-        enum class Type : uint8_t { ElementInserted, ElementRemoved, TextInserted, TextRemoved, TextChanged, AllChildrenRemoved, NonContentsChildRemoved, NonContentsChildInserted, AllChildrenReplaced };
+        enum class Type : uint8_t { ElementInserted, ElementRemoved, TextInserted, TextRemoved, TextChanged, AllChildrenRemoved, NonContentsChildRemoved, NonContentsChildInserted, AllChildrenReplaced, FinishedParsingChildren };
         enum class Source : bool { Parser, API };
 
         ChildChange::Type type;
@@ -96,6 +96,8 @@
             case ChildChange::Type::AllChildrenRemoved:
             case ChildChange::Type::NonContentsChildRemoved:
                 return false;
+            case ChildChange::Type::FinishedParsingChildren:
+                break;
             }
             ASSERT_NOT_REACHED();
             return false;

Modified: trunk/Source/WebCore/dom/Element.cpp (286057 => 286058)


--- trunk/Source/WebCore/dom/Element.cpp	2021-11-19 14:39:07 UTC (rev 286057)
+++ trunk/Source/WebCore/dom/Element.cpp	2021-11-19 14:48:24 UTC (rev 286058)
@@ -30,6 +30,7 @@
 #include "Attr.h"
 #include "AttributeChangeInvalidation.h"
 #include "CSSParser.h"
+#include "ChildChangeInvalidation.h"
 #include "Chrome.h"
 #include "ChromeClient.h"
 #include "ClassChangeInvalidation.h"
@@ -2038,7 +2039,7 @@
     return styleResolver().styleForElement(*this, resolutionContext);
 }
 
-static void invalidateForSiblingCombinators(Element* sibling)
+void invalidateForSiblingCombinators(Element* sibling)
 {
     for (; sibling; sibling = sibling->nextElementSibling()) {
         if (sibling->styleIsAffectedByPreviousSibling())
@@ -2642,124 +2643,11 @@
     }
     return false;
 }
-
-static void checkForEmptyStyleChange(Element& element)
-{
-    if (element.styleAffectedByEmpty()) {
-        auto* style = element.renderStyle();
-        if (!style || (!style->emptyState() || element.hasChildNodes()))
-            element.invalidateStyleForSubtree();
-    }
-}
-
-
-static void invalidateForForwardPositionalRules(Element& parent, Element* elementAfterChange)
-{
-    bool childrenAffected = parent.childrenAffectedByForwardPositionalRules();
-    bool descendantsAffected = parent.descendantsAffectedByForwardPositionalRules();
-
-    if (!childrenAffected && !descendantsAffected)
-        return;
-
-    for (auto* sibling = elementAfterChange; sibling; sibling = sibling->nextElementSibling()) {
-        if (childrenAffected)
-            sibling->invalidateStyleInternal();
-        if (descendantsAffected) {
-            for (auto* siblingChild = sibling->firstElementChild(); siblingChild; siblingChild = siblingChild->nextElementSibling())
-                siblingChild->invalidateStyleForSubtreeInternal();
-        }
-    }
-}
-
-static void invalidateForBackwardPositionalRules(Element& parent, Element* elementBeforeChange)
-{
-    bool childrenAffected = parent.childrenAffectedByBackwardPositionalRules();
-    bool descendantsAffected = parent.descendantsAffectedByBackwardPositionalRules();
-
-    if (!childrenAffected && !descendantsAffected)
-        return;
-
-    for (auto* sibling = elementBeforeChange; sibling; sibling = sibling->previousElementSibling()) {
-        if (childrenAffected)
-            sibling->invalidateStyleInternal();
-        if (descendantsAffected) {
-            for (auto* siblingChild = sibling->firstElementChild(); siblingChild; siblingChild = siblingChild->nextElementSibling())
-                siblingChild->invalidateStyleForSubtreeInternal();
-        }
-    }
-}
-
-enum SiblingCheckType { FinishedParsingChildren, SiblingElementRemoved, Other };
-
-static void checkForSiblingStyleChanges(Element& parent, SiblingCheckType checkType, Element* elementBeforeChange, Element* elementAfterChange)
-{
-    // :empty selector.
-    checkForEmptyStyleChange(parent);
-
-    if (parent.styleValidity() >= Style::Validity::SubtreeInvalid)
-        return;
-
-    // :first-child.  In the parser callback case, we don't have to check anything, since we were right the first time.
-    // In the DOM case, we only need to do something if |afterChange| is not 0.
-    // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
-    if (parent.childrenAffectedByFirstChildRules() && elementAfterChange) {
-        // Find our new first child.
-        RefPtr<Element> newFirstElement = ElementTraversal::firstChild(parent);
-        // Find the first element node following |afterChange|
-
-        // This is the insert/append case.
-        if (newFirstElement != elementAfterChange) {
-            auto* style = elementAfterChange->renderStyle();
-            if (!style || style->firstChildState())
-                elementAfterChange->invalidateStyleForSubtreeInternal();
-        }
-
-        // We also have to handle node removal.
-        if (checkType == SiblingElementRemoved && newFirstElement == elementAfterChange && newFirstElement) {
-            auto* style = newFirstElement->renderStyle();
-            if (!style || !style->firstChildState())
-                newFirstElement->invalidateStyleForSubtreeInternal();
-        }
-    }
-
-    // :last-child.  In the parser callback case, we don't have to check anything, since we were right the first time.
-    // In the DOM case, we only need to do something if |afterChange| is not 0.
-    if (parent.childrenAffectedByLastChildRules() && elementBeforeChange) {
-        // Find our new last child.
-        RefPtr<Element> newLastElement = ElementTraversal::lastChild(parent);
-
-        if (newLastElement != elementBeforeChange) {
-            auto* style = elementBeforeChange->renderStyle();
-            if (!style || style->lastChildState())
-                elementBeforeChange->invalidateStyleForSubtreeInternal();
-        }
-
-        // We also have to handle node removal.  The parser callback case is similar to node removal as well in that we need to change the last child
-        // to match now.
-        if ((checkType == SiblingElementRemoved || checkType == FinishedParsingChildren) && newLastElement == elementBeforeChange && newLastElement) {
-            auto* style = newLastElement->renderStyle();
-            if (!style || !style->lastChildState())
-                newLastElement->invalidateStyleForSubtreeInternal();
-        }
-    }
-
-    invalidateForSiblingCombinators(elementAfterChange);
-
-    invalidateForForwardPositionalRules(parent, elementAfterChange);
-    invalidateForBackwardPositionalRules(parent, elementBeforeChange);
-}
-
 void Element::childrenChanged(const ChildChange& change)
 {
     ContainerNode::childrenChanged(change);
-    if (change.source == ChildChange::Source::Parser)
-        checkForEmptyStyleChange(*this);
-    else {
-        auto checkType = change.type == ChildChange::Type::ElementRemoved ? SiblingElementRemoved : Other;
-        checkForSiblingStyleChanges(*this, checkType, change.previousSiblingElement, change.nextSiblingElement);
-    }
 
-    if (ShadowRoot* shadowRoot = this->shadowRoot()) {
+    if (auto* shadowRoot = this->shadowRoot()) {
         switch (change.type) {
         case ChildChange::Type::ElementInserted:
         case ChildChange::Type::ElementRemoved:
@@ -2776,6 +2664,7 @@
             break;
         case ChildChange::Type::NonContentsChildInserted:
         case ChildChange::Type::NonContentsChildRemoved:
+        case ChildChange::Type::FinishedParsingChildren:
             break;
         }
     }
@@ -2802,7 +2691,13 @@
 {
     ContainerNode::finishParsingChildren();
     setIsParsingChildrenFinished();
-    checkForSiblingStyleChanges(*this, FinishedParsingChildren, ElementTraversal::lastChild(*this), nullptr);
+
+    Style::ChildChangeInvalidation styleInvalidation(*this, {
+        ChildChange::Type::FinishedParsingChildren,
+        ElementTraversal::lastChild(*this),
+        nullptr,
+        ChildChange::Source::Parser
+    });
 }
 
 static void appendAttributes(StringBuilder& builder, const Element& element)

Modified: trunk/Source/WebCore/dom/Element.h (286057 => 286058)


--- trunk/Source/WebCore/dom/Element.h	2021-11-19 14:39:07 UTC (rev 286057)
+++ trunk/Source/WebCore/dom/Element.h	2021-11-19 14:48:24 UTC (rev 286058)
@@ -763,6 +763,8 @@
     RefPtr<ElementData> m_elementData;
 };
 
+void invalidateForSiblingCombinators(Element* sibling);
+
 } // namespace WebCore
 
 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::Element)

Modified: trunk/Source/WebCore/dom/ShadowRoot.cpp (286057 => 286058)


--- trunk/Source/WebCore/dom/ShadowRoot.cpp	2021-11-19 14:39:07 UTC (rev 286057)
+++ trunk/Source/WebCore/dom/ShadowRoot.cpp	2021-11-19 14:48:24 UTC (rev 286058)
@@ -144,6 +144,9 @@
     case ChildChange::Type::NonContentsChildInserted:
     case ChildChange::Type::AllChildrenReplaced:
         break;
+    case ChildChange::Type::FinishedParsingChildren:
+        ASSERT_NOT_REACHED();
+        break;
     }
 }
 

Added: trunk/Source/WebCore/style/ChildChangeInvalidation.cpp (0 => 286058)


--- trunk/Source/WebCore/style/ChildChangeInvalidation.cpp	                        (rev 0)
+++ trunk/Source/WebCore/style/ChildChangeInvalidation.cpp	2021-11-19 14:48:24 UTC (rev 286058)
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ChildChangeInvalidation.h"
+
+#include "NodeRenderStyle.h"
+#include "ShadowRoot.h"
+#include "SlotAssignment.h"
+
+namespace WebCore::Style {
+
+ChildChangeInvalidation::ChildChangeInvalidation(ContainerNode& container, const ContainerNode::ChildChange& childChange)
+    : m_parentElement(is<Element>(container) ? downcast<Element>(&container) : nullptr)
+    , m_isEnabled(m_parentElement ? m_parentElement->needsStyleInvalidation() : false)
+    , m_childChange(childChange)
+{
+    // FIXME: Do smarter invalidation similat to ClassChangeInvalidation.
+}
+
+ChildChangeInvalidation::~ChildChangeInvalidation()
+{
+    if (!m_isEnabled)
+        return;
+
+    invalidateAfterChange();
+}
+
+void ChildChangeInvalidation::invalidateAfterChange()
+{
+    checkForEmptyStyleChange();
+
+    if (m_childChange.type == ContainerNode::ChildChange::Type::FinishedParsingChildren) {
+        checkForSiblingStyleChanges();
+        return;
+    }
+
+    if (m_childChange.source == ContainerNode::ChildChange::Source::Parser)
+        return;
+
+    checkForSiblingStyleChanges();
+}
+
+void ChildChangeInvalidation::checkForEmptyStyleChange()
+{
+    auto& element = parentElement();
+    if (!element.styleAffectedByEmpty())
+        return;
+
+    auto* style = element.renderStyle();
+    if (!style || (!style->emptyState() || element.hasChildNodes()))
+        element.invalidateStyleForSubtree();
+}
+
+static void invalidateForForwardPositionalRules(Element& parent, Element* elementAfterChange)
+{
+    bool childrenAffected = parent.childrenAffectedByForwardPositionalRules();
+    bool descendantsAffected = parent.descendantsAffectedByForwardPositionalRules();
+
+    if (!childrenAffected && !descendantsAffected)
+        return;
+
+    for (auto* sibling = elementAfterChange; sibling; sibling = sibling->nextElementSibling()) {
+        if (childrenAffected)
+            sibling->invalidateStyleInternal();
+        if (descendantsAffected) {
+            for (auto* siblingChild = sibling->firstElementChild(); siblingChild; siblingChild = siblingChild->nextElementSibling())
+                siblingChild->invalidateStyleForSubtreeInternal();
+        }
+    }
+}
+
+static void invalidateForBackwardPositionalRules(Element& parent, Element* elementBeforeChange)
+{
+    bool childrenAffected = parent.childrenAffectedByBackwardPositionalRules();
+    bool descendantsAffected = parent.descendantsAffectedByBackwardPositionalRules();
+
+    if (!childrenAffected && !descendantsAffected)
+        return;
+
+    for (auto* sibling = elementBeforeChange; sibling; sibling = sibling->previousElementSibling()) {
+        if (childrenAffected)
+            sibling->invalidateStyleInternal();
+        if (descendantsAffected) {
+            for (auto* siblingChild = sibling->firstElementChild(); siblingChild; siblingChild = siblingChild->nextElementSibling())
+                siblingChild->invalidateStyleForSubtreeInternal();
+        }
+    }
+}
+
+void ChildChangeInvalidation::checkForSiblingStyleChanges()
+{
+    auto& parent = parentElement();
+    auto* elementBeforeChange = m_childChange.previousSiblingElement;
+    auto* elementAfterChange = m_childChange.nextSiblingElement;
+
+    // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
+    // In the DOM case, we only need to do something if |afterChange| is not 0.
+    // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
+    if (parent.childrenAffectedByFirstChildRules() && elementAfterChange) {
+        // Find our new first child.
+        RefPtr<Element> newFirstElement = ElementTraversal::firstChild(parent);
+        // Find the first element node following |afterChange|
+
+        // This is the insert/append case.
+        if (newFirstElement != elementAfterChange) {
+            auto* style = elementAfterChange->renderStyle();
+            if (!style || style->firstChildState())
+                elementAfterChange->invalidateStyleForSubtreeInternal();
+        }
+
+        // We also have to handle node removal.
+        if (m_childChange.type == ContainerNode::ChildChange::Type::ElementRemoved && newFirstElement == elementAfterChange && newFirstElement) {
+            auto* style = newFirstElement->renderStyle();
+            if (!style || !style->firstChildState())
+                newFirstElement->invalidateStyleForSubtreeInternal();
+        }
+    }
+
+    // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
+    // In the DOM case, we only need to do something if |afterChange| is not 0.
+    if (parent.childrenAffectedByLastChildRules() && elementBeforeChange) {
+        // Find our new last child.
+        RefPtr<Element> newLastElement = ElementTraversal::lastChild(parent);
+
+        if (newLastElement != elementBeforeChange) {
+            auto* style = elementBeforeChange->renderStyle();
+            if (!style || style->lastChildState())
+                elementBeforeChange->invalidateStyleForSubtreeInternal();
+        }
+
+        // We also have to handle node removal. The parser callback case is similar to node removal as well in that we need to change the last child
+        // to match now.
+        bool removedOrFinished = m_childChange.type == ContainerNode::ChildChange::Type::ElementRemoved || m_childChange.type == ContainerNode::ChildChange::Type::FinishedParsingChildren;
+        if (removedOrFinished && newLastElement == elementBeforeChange && newLastElement) {
+            auto* style = newLastElement->renderStyle();
+            if (!style || !style->lastChildState())
+                newLastElement->invalidateStyleForSubtreeInternal();
+        }
+    }
+
+    invalidateForSiblingCombinators(elementAfterChange);
+
+    invalidateForForwardPositionalRules(parent, elementAfterChange);
+    invalidateForBackwardPositionalRules(parent, elementBeforeChange);
+}
+
+}

Added: trunk/Source/WebCore/style/ChildChangeInvalidation.h (0 => 286058)


--- trunk/Source/WebCore/style/ChildChangeInvalidation.h	                        (rev 0)
+++ trunk/Source/WebCore/style/ChildChangeInvalidation.h	2021-11-19 14:48:24 UTC (rev 286058)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "Element.h"
+
+namespace WebCore {
+namespace Style {
+
+class ChildChangeInvalidation {
+public:
+    ChildChangeInvalidation(ContainerNode&, const ContainerNode::ChildChange&);
+    ~ChildChangeInvalidation();
+
+private:
+    void invalidateAfterChange();
+    void checkForEmptyStyleChange();
+    void checkForSiblingStyleChanges();
+
+    Element& parentElement() { return *m_parentElement; }
+
+    Element* m_parentElement { nullptr };
+    const bool m_isEnabled;
+
+    const ContainerNode::ChildChange& m_childChange;
+};
+
+}
+}

Modified: trunk/Source/WebCore/style/StyleAdjuster.h (286057 => 286058)


--- trunk/Source/WebCore/style/StyleAdjuster.h	2021-11-19 14:39:07 UTC (rev 286057)
+++ trunk/Source/WebCore/style/StyleAdjuster.h	2021-11-19 14:48:24 UTC (rev 286058)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "RenderStyleConstants.h"
+#include "TextSizeAdjustment.h"
 #include <wtf/OptionSet.h>
 
 namespace WebCore {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to