- Revision
- 281793
- Author
- [email protected]
- Date
- 2021-08-31 00:40:52 -0700 (Tue, 31 Aug 2021)
Log Message
Re-generalize top layer element concept
https://bugs.webkit.org/show_bug.cgi?id=229488
Reviewed by Antti Koivisto.
r281548 made the concept of top layer is confined to dialog element to eliminate the runtime cost
of making 5+ function calls and looking up the list hash set per removal of every element.
This patch re-generalize this concept for all elements by introducing a new node flag to avoid
the runtime cost so that we may use it in the future for the full screen element.
No new tests since there should be no observable behavior changes.
This patch also inverts the relationship between member functions in Element and Document
to reduce the number of function calls involved by 1.
* dom/Document.cpp:
(Document::removedLastRef): Make sure the list of top layer elements is empty.
(WebCore::Document::addTopLayerElement): Renamed from addToTopLayer. The code to update the layer
has been moved to Element::addToTopLayer. Also release-time assert that the element is connected
to this document.
(WebCore::Document::removeTopLayerElement): Ditto.
* dom/Document.h:
* dom/Element.cpp:
(WebCore::Element::removedFromAncestor): Call removeTopLayerElement if this element had a top layer.
(WebCore::renderLayerForElement): Added.
(WebCore::Element::addToTopLayer): Moved from Document. Set the node flag: IsInTopLayer.
(WebCore::Element::removeFromTopLayer): Ditto, clear the node flag.
(WebCore::Element::isInTopLayerWillChange): Deleted.
(WebCore::Element::isInTopLayerDidChange): Deleted.
* dom/Element.h:
(WebCore::Element::isInTopLayer const): Rewritten to make use of new node flag.
* dom/Node.h:
(WebCore::NodeFlag): Added a new node flag: IsInTopLayer.
* html/HTMLDialogElement.cpp:
(WebCore::HTMLDialogElement::showModal):
(WebCore::HTMLDialogElement::close):
(WebCore::HTMLDialogElement::removedFromAncestor): Deleted.
* html/HTMLDialogElement.h:
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (281792 => 281793)
--- trunk/Source/WebCore/ChangeLog 2021-08-31 07:18:14 UTC (rev 281792)
+++ trunk/Source/WebCore/ChangeLog 2021-08-31 07:40:52 UTC (rev 281793)
@@ -1,3 +1,45 @@
+2021-08-31 Ryosuke Niwa <[email protected]>
+
+ Re-generalize top layer element concept
+ https://bugs.webkit.org/show_bug.cgi?id=229488
+
+ Reviewed by Antti Koivisto.
+
+ r281548 made the concept of top layer is confined to dialog element to eliminate the runtime cost
+ of making 5+ function calls and looking up the list hash set per removal of every element.
+
+ This patch re-generalize this concept for all elements by introducing a new node flag to avoid
+ the runtime cost so that we may use it in the future for the full screen element.
+
+ No new tests since there should be no observable behavior changes.
+
+ This patch also inverts the relationship between member functions in Element and Document
+ to reduce the number of function calls involved by 1.
+
+ * dom/Document.cpp:
+ (Document::removedLastRef): Make sure the list of top layer elements is empty.
+ (WebCore::Document::addTopLayerElement): Renamed from addToTopLayer. The code to update the layer
+ has been moved to Element::addToTopLayer. Also release-time assert that the element is connected
+ to this document.
+ (WebCore::Document::removeTopLayerElement): Ditto.
+ * dom/Document.h:
+ * dom/Element.cpp:
+ (WebCore::Element::removedFromAncestor): Call removeTopLayerElement if this element had a top layer.
+ (WebCore::renderLayerForElement): Added.
+ (WebCore::Element::addToTopLayer): Moved from Document. Set the node flag: IsInTopLayer.
+ (WebCore::Element::removeFromTopLayer): Ditto, clear the node flag.
+ (WebCore::Element::isInTopLayerWillChange): Deleted.
+ (WebCore::Element::isInTopLayerDidChange): Deleted.
+ * dom/Element.h:
+ (WebCore::Element::isInTopLayer const): Rewritten to make use of new node flag.
+ * dom/Node.h:
+ (WebCore::NodeFlag): Added a new node flag: IsInTopLayer.
+ * html/HTMLDialogElement.cpp:
+ (WebCore::HTMLDialogElement::showModal):
+ (WebCore::HTMLDialogElement::close):
+ (WebCore::HTMLDialogElement::removedFromAncestor): Deleted.
+ * html/HTMLDialogElement.h:
+
2021-08-26 Darin Adler <[email protected]>
Cut down on use of CFGetTypeID, using dynamic_cf_cast instead; related streamlining
Modified: trunk/Source/WebCore/dom/Document.cpp (281792 => 281793)
--- trunk/Source/WebCore/dom/Document.cpp 2021-08-31 07:18:14 UTC (rev 281792)
+++ trunk/Source/WebCore/dom/Document.cpp 2021-08-31 07:40:52 UTC (rev 281793)
@@ -825,6 +825,7 @@
destroyTreeScopeData();
removeDetachedChildren();
+ RELEASE_ASSERT(m_topLayerElements.isEmpty());
m_formController = nullptr;
m_markers->detach();
@@ -8474,24 +8475,19 @@
return animations;
}
-void Document::addToTopLayer(Element& element)
+void Document::addTopLayerElement(Element& element)
{
- element.isInTopLayerWillChange();
-
+ RELEASE_ASSERT(&element.document() == this && element.isConnected() && !element.isInTopLayer());
// To add an element to a top layer, remove it from top layer and then append it to top layer.
- m_topLayerElements.appendOrMoveToLast(element);
-
- element.isInTopLayerDidChange();
+ auto result = m_topLayerElements.add(element);
+ RELEASE_ASSERT(result.isNewEntry);
}
-void Document::removeFromTopLayer(Element& element)
+void Document::removeTopLayerElement(Element& element)
{
- element.isInTopLayerWillChange();
-
- if (!m_topLayerElements.remove(element))
- return;
-
- element.isInTopLayerDidChange();
+ RELEASE_ASSERT(&element.document() == this && element.isInTopLayer());
+ auto didRemove = m_topLayerElements.remove(element);
+ RELEASE_ASSERT(didRemove);
}
HTMLDialogElement* Document::activeModalDialog() const
Modified: trunk/Source/WebCore/dom/Document.h (281792 => 281793)
--- trunk/Source/WebCore/dom/Document.h 2021-08-31 07:18:14 UTC (rev 281792)
+++ trunk/Source/WebCore/dom/Document.h 2021-08-31 07:40:52 UTC (rev 281793)
@@ -1517,8 +1517,8 @@
DocumentTimelinesController* timelinesController() const { return m_timelinesController.get(); }
WEBCORE_EXPORT DocumentTimelinesController& ensureTimelinesController();
- void addToTopLayer(Element&);
- void removeFromTopLayer(Element&);
+ void addTopLayerElement(Element&);
+ void removeTopLayerElement(Element&);
const ListHashSet<Ref<Element>>& topLayerElements() const { return m_topLayerElements; }
HTMLDialogElement* activeModalDialog() const;
Modified: trunk/Source/WebCore/dom/Element.cpp (281792 => 281793)
--- trunk/Source/WebCore/dom/Element.cpp 2021-08-31 07:18:14 UTC (rev 281792)
+++ trunk/Source/WebCore/dom/Element.cpp 2021-08-31 07:40:52 UTC (rev 281793)
@@ -2254,7 +2254,7 @@
if (containsFullScreenElement())
setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
#endif
-
+
if (auto* page = document().page()) {
#if ENABLE(POINTER_LOCK)
page->pointerLockController().elementWasRemoved(*this);
@@ -2326,6 +2326,9 @@
}
#endif
+ if (UNLIKELY(isInTopLayer()))
+ removeFromTopLayer();
+
if (hasNodeFlag(NodeFlag::HasElementIdentifier)) {
document().identifiedElementWasRemovedFromDocument(*this);
clearNodeFlag(NodeFlag::HasElementIdentifier);
@@ -3356,24 +3359,48 @@
child.ancestorWillEnterFullscreen();
}
-void Element::isInTopLayerWillChange()
+static inline RenderLayer* renderLayerForElement(Element& element)
{
- if (renderer()) {
- if (renderer()->hasLayer())
- downcast<RenderLayerModelObject>(*renderer()).layer()->establishesTopLayerWillChange();
- }
+ auto* renderer = element.renderer();
+ if (!renderer || !renderer->hasLayer() || !is<RenderLayerModelObject>(renderer))
+ return nullptr;
+ return downcast<RenderLayerModelObject>(*renderer).layer();
}
-void Element::isInTopLayerDidChange()
+void Element::addToTopLayer()
{
- invalidateStyle();
+ RELEASE_ASSERT(!isInTopLayer());
+ ScriptDisallowedScope scriptDisallowedScope;
- if (renderer()) {
- if (renderer()->hasLayer())
- downcast<RenderLayerModelObject>(*renderer()).layer()->establishesTopLayerDidChange();
- }
+ if (auto* layer = renderLayerForElement(*this))
+ layer->establishesTopLayerWillChange();
+
+ document().addTopLayerElement(*this);
+ setNodeFlag(NodeFlag::IsInTopLayer);
+
+ invalidateStyleInternal();
+
+ if (auto* layer = renderLayerForElement(*this))
+ layer->establishesTopLayerDidChange();
}
+void Element::removeFromTopLayer()
+{
+ RELEASE_ASSERT(isInTopLayer());
+ ScriptDisallowedScope scriptDisallowedScope;
+
+ if (auto* layer = renderLayerForElement(*this))
+ layer->establishesTopLayerWillChange();
+
+ document().removeTopLayerElement(*this);
+ clearNodeFlag(NodeFlag::IsInTopLayer);
+
+ invalidateStyleInternal();
+
+ if (auto* layer = renderLayerForElement(*this))
+ layer->establishesTopLayerDidChange();
+}
+
static PseudoElement* beforeOrAfterPseudoElement(const Element& host, PseudoId pseudoElementSpecifier)
{
switch (pseudoElementSpecifier) {
Modified: trunk/Source/WebCore/dom/Element.h (281792 => 281793)
--- trunk/Source/WebCore/dom/Element.h 2021-08-31 07:18:14 UTC (rev 281792)
+++ trunk/Source/WebCore/dom/Element.h 2021-08-31 07:40:52 UTC (rev 281793)
@@ -511,9 +511,9 @@
const RenderStyle* lastStyleChangeEventStyle(PseudoId) const;
void setLastStyleChangeEventStyle(PseudoId, std::unique_ptr<const RenderStyle>&&);
- bool isInTopLayer() const { return document().topLayerElements().contains(makeRef(*const_cast<Element*>(this))); }
- void isInTopLayerWillChange();
- void isInTopLayerDidChange();
+ bool isInTopLayer() const { return hasNodeFlag(NodeFlag::IsInTopLayer); }
+ void addToTopLayer();
+ void removeFromTopLayer();
#if ENABLE(FULLSCREEN_API)
bool containsFullScreenElement() const { return hasNodeFlag(NodeFlag::ContainsFullScreenElement); }
Modified: trunk/Source/WebCore/dom/Node.h (281792 => 281793)
--- trunk/Source/WebCore/dom/Node.h 2021-08-31 07:18:14 UTC (rev 281792)
+++ trunk/Source/WebCore/dom/Node.h 2021-08-31 07:40:52 UTC (rev 281793)
@@ -566,10 +566,10 @@
ContainsFullScreenElement = 1 << 24,
#endif
IsComputedStyleInvalidFlag = 1 << 25,
-
HasShadowRootContainingSlots = 1 << 26,
+ IsInTopLayer = 1 << 27,
- // Bits 27-31 are free.
+ // Bits 28-31 are free.
};
enum class TabIndexState : uint8_t {
Modified: trunk/Source/WebCore/html/HTMLDialogElement.cpp (281792 => 281793)
--- trunk/Source/WebCore/html/HTMLDialogElement.cpp 2021-08-31 07:18:14 UTC (rev 281792)
+++ trunk/Source/WebCore/html/HTMLDialogElement.cpp 2021-08-31 07:40:52 UTC (rev 281793)
@@ -66,7 +66,7 @@
m_isModal = true;
if (!isInTopLayer())
- document().addToTopLayer(*this);
+ addToTopLayer();
// FIXME: Add steps 8 & 9 from spec. (webkit.org/b/227537)
@@ -86,7 +86,7 @@
m_returnValue = result;
if (isInTopLayer())
- document().removeFromTopLayer(*this);
+ removeFromTopLayer();
// FIXME: Add step 6 from spec. (webkit.org/b/227537)
@@ -95,13 +95,6 @@
});
}
-void HTMLDialogElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
-{
- HTMLElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
- if (isInTopLayer())
- document().removeFromTopLayer(*this);
-}
-
void HTMLDialogElement::queueCancelTask()
{
document().eventLoop().queueTask(TaskSource::UserInteraction, [protectedThis = GCReachableRef { *this }] {
Modified: trunk/Source/WebCore/html/HTMLDialogElement.h (281792 => 281793)
--- trunk/Source/WebCore/html/HTMLDialogElement.h 2021-08-31 07:18:14 UTC (rev 281792)
+++ trunk/Source/WebCore/html/HTMLDialogElement.h 2021-08-31 07:40:52 UTC (rev 281793)
@@ -50,8 +50,6 @@
private:
HTMLDialogElement(const QualifiedName&, Document&);
- void removedFromAncestor(RemovalType, ContainerNode& oldParentOfRemovedTree) final;
-
String m_returnValue;
bool m_isModal { false };
};