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 {