- Revision
- 223810
- Author
- [email protected]
- Date
- 2017-10-21 01:15:10 -0700 (Sat, 21 Oct 2017)
Log Message
Support ::before/::after pseudo elements with display:contents
https://bugs.webkit.org/show_bug.cgi?id=178584
Reviewed by Ryosuke Niwa.
Source/WebCore:
This is cases like
::before { display:contents; content:'foo' }
* css/StyleResolver.cpp:
(WebCore::StyleResolver::adjustDisplayContentsStyle): Added.
Allow display:contents on pseudo elements.
Factor into function.
(WebCore::StyleResolver::adjustRenderStyle):
* dom/PseudoElement.h:
Add a weak vector of content renderers.
* style/RenderTreePosition.h:
(WebCore::RenderTreePosition::moveToLastChild):
Add a way to set a valid render tree position without a node.
* style/RenderTreeUpdaterGeneratedContent.cpp:
(WebCore::createContentRenderers):
Take RenderTreePosition.
(WebCore::updateStyleForContentRenderers):
Update based on the content renderer vector instead of doing a tree walk.
(WebCore::removeAndDestroyContentRenderers):
Helper for destroying content renderers.
(WebCore::RenderTreeUpdater::GeneratedContent::updatePseudoElement):
In the normal case create a render tree position for the pseudo element renderer and
use RenderTreePosition::moveToLastChild to make it a valid position. (The existing
RenderTreePosition interface didn't have way to move to positions in anonymous boxes)
In the case of a non box generating display:contents pseudo element, use the current
render tree position instead.
Ensure that pseudo element renderers are destroyed before creating the new ones since in
display:contents case they are not descendants of the pseudo renderer and don't get cleared
automatically.
LayoutTests:
* TestExpectations: Enable imported/w3c/web-platform-tests/css/css-display-3/display-contents-before-after-002.html
Modified Paths
Diff
Modified: trunk/LayoutTests/ChangeLog (223809 => 223810)
--- trunk/LayoutTests/ChangeLog 2017-10-21 06:52:47 UTC (rev 223809)
+++ trunk/LayoutTests/ChangeLog 2017-10-21 08:15:10 UTC (rev 223810)
@@ -1,3 +1,12 @@
+2017-10-21 Antti Koivisto <[email protected]>
+
+ Support ::before/::after pseudo elements with display:contents
+ https://bugs.webkit.org/show_bug.cgi?id=178584
+
+ Reviewed by Ryosuke Niwa.
+
+ * TestExpectations: Enable imported/w3c/web-platform-tests/css/css-display-3/display-contents-before-after-002.html
+
2017-10-20 Joseph Pecoraro <[email protected]>
Web Inspector: Support `async test() { ... }` in Inspector Test Suites
Modified: trunk/LayoutTests/TestExpectations (223809 => 223810)
--- trunk/LayoutTests/TestExpectations 2017-10-21 06:52:47 UTC (rev 223809)
+++ trunk/LayoutTests/TestExpectations 2017-10-21 08:15:10 UTC (rev 223810)
@@ -1269,7 +1269,6 @@
webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-dynamic-before-after-001.html [ ImageOnlyFailure ]
webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-dynamic-table-002-none.html [ ImageOnlyFailure ]
webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-flex-003.html [ ImageOnlyFailure ]
-webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-before-after-002.html [ ImageOnlyFailure ]
webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-dynamic-table-001-inline.html [ ImageOnlyFailure ]
webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-dynamic-flex-002-none.html [ ImageOnlyFailure ]
webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-flex-002.html [ ImageOnlyFailure ]
Modified: trunk/Source/WebCore/ChangeLog (223809 => 223810)
--- trunk/Source/WebCore/ChangeLog 2017-10-21 06:52:47 UTC (rev 223809)
+++ trunk/Source/WebCore/ChangeLog 2017-10-21 08:15:10 UTC (rev 223810)
@@ -1,3 +1,56 @@
+2017-10-21 Antti Koivisto <[email protected]>
+
+ Support ::before/::after pseudo elements with display:contents
+ https://bugs.webkit.org/show_bug.cgi?id=178584
+
+ Reviewed by Ryosuke Niwa.
+
+ This is cases like
+
+ ::before { display:contents; content:'foo' }
+
+ * css/StyleResolver.cpp:
+ (WebCore::StyleResolver::adjustDisplayContentsStyle): Added.
+
+ Allow display:contents on pseudo elements.
+ Factor into function.
+
+ (WebCore::StyleResolver::adjustRenderStyle):
+ * dom/PseudoElement.h:
+
+ Add a weak vector of content renderers.
+
+ * style/RenderTreePosition.h:
+ (WebCore::RenderTreePosition::moveToLastChild):
+
+ Add a way to set a valid render tree position without a node.
+
+ * style/RenderTreeUpdaterGeneratedContent.cpp:
+ (WebCore::createContentRenderers):
+
+ Take RenderTreePosition.
+
+ (WebCore::updateStyleForContentRenderers):
+
+ Update based on the content renderer vector instead of doing a tree walk.
+
+ (WebCore::removeAndDestroyContentRenderers):
+
+ Helper for destroying content renderers.
+
+ (WebCore::RenderTreeUpdater::GeneratedContent::updatePseudoElement):
+
+ In the normal case create a render tree position for the pseudo element renderer and
+ use RenderTreePosition::moveToLastChild to make it a valid position. (The existing
+ RenderTreePosition interface didn't have way to move to positions in anonymous boxes)
+
+ In the case of a non box generating display:contents pseudo element, use the current
+ render tree position instead.
+
+ Ensure that pseudo element renderers are destroyed before creating the new ones since in
+ display:contents case they are not descendants of the pseudo renderer and don't get cleared
+ automatically.
+
2017-10-20 Zalan Bujtas <[email protected]>
[FrameView::layout cleanup] Use SetForScope to ensure layout state correctness
Modified: trunk/Source/WebCore/css/StyleResolver.cpp (223809 => 223810)
--- trunk/Source/WebCore/css/StyleResolver.cpp 2017-10-21 06:52:47 UTC (rev 223809)
+++ trunk/Source/WebCore/css/StyleResolver.cpp 2017-10-21 08:15:10 UTC (rev 223810)
@@ -789,6 +789,22 @@
return tagNames.get().contains(element.localName());
}
+static void adjustDisplayContentsStyle(RenderStyle& style, const Element* element)
+{
+ bool displayContentsEnabled = is<HTMLSlotElement>(element) || RuntimeEnabledFeatures::sharedFeatures().displayContentsEnabled();
+ if (!displayContentsEnabled) {
+ style.setDisplay(INLINE);
+ return;
+ }
+ if (!element) {
+ if (style.styleType() != BEFORE && style.styleType() != AFTER)
+ style.setDisplay(NONE);
+ return;
+ }
+ if (hasEffectiveDisplayNoneForDisplayContents(*element))
+ style.setDisplay(NONE);
+}
+
void StyleResolver::adjustRenderStyle(RenderStyle& style, const RenderStyle& parentStyle, const RenderStyle* parentBoxStyle, const Element* element)
{
// If the composed tree parent has display:contents, the parent box style will be different from the parent style.
@@ -799,13 +815,8 @@
// Cache our original display.
style.setOriginalDisplay(style.display());
- if (style.display() == CONTENTS) {
- bool elementSupportsDisplayContents = is<HTMLSlotElement>(element) || RuntimeEnabledFeatures::sharedFeatures().displayContentsEnabled();
- if (!elementSupportsDisplayContents)
- style.setDisplay(INLINE);
- else if (!element || hasEffectiveDisplayNoneForDisplayContents(*element))
- style.setDisplay(NONE);
- }
+ if (style.display() == CONTENTS)
+ adjustDisplayContentsStyle(style, element);
if (style.display() != NONE && style.display() != CONTENTS) {
if (element) {
Modified: trunk/Source/WebCore/dom/PseudoElement.h (223809 => 223810)
--- trunk/Source/WebCore/dom/PseudoElement.h 2017-10-21 06:52:47 UTC (rev 223809)
+++ trunk/Source/WebCore/dom/PseudoElement.h 2017-10-21 08:15:10 UTC (rev 223810)
@@ -44,6 +44,8 @@
bool canStartSelection() const override { return false; }
bool canContainRangeEndPoint() const override { return false; }
+ auto& contentRenderers() { return m_contentRenderers; }
+
static String pseudoElementNameForEvents(PseudoId);
private:
@@ -53,6 +55,7 @@
Element* m_hostElement;
PseudoId m_pseudoId;
+ Vector<WeakPtr<RenderObject>> m_contentRenderers;
};
const QualifiedName& pseudoElementTagName();
Modified: trunk/Source/WebCore/style/RenderTreePosition.h (223809 => 223810)
--- trunk/Source/WebCore/style/RenderTreePosition.h 2017-10-21 06:52:47 UTC (rev 223809)
+++ trunk/Source/WebCore/style/RenderTreePosition.h 2017-10-21 08:15:10 UTC (rev 223810)
@@ -34,12 +34,6 @@
class RenderTreePosition {
public:
- explicit RenderTreePosition(RenderView& root)
- : m_parent(root)
- , m_hasValidNextSibling(true)
- {
- }
-
explicit RenderTreePosition(RenderElement& parent)
: m_parent(parent)
{
@@ -51,6 +45,7 @@
bool canInsert(RenderText&) const;
void computeNextSibling(const Node&);
+ void moveToLastChild();
void invalidateNextSibling() { m_hasValidNextSibling = false; }
void invalidateNextSibling(const RenderObject&);
@@ -66,6 +61,12 @@
#endif
};
+inline void RenderTreePosition::moveToLastChild()
+{
+ m_nextSibling = nullptr;
+ m_hasValidNextSibling = true;
+}
+
inline bool RenderTreePosition::canInsert(RenderElement& renderer) const
{
ASSERT(!renderer.parent());
Modified: trunk/Source/WebCore/style/RenderTreeUpdaterGeneratedContent.cpp (223809 => 223810)
--- trunk/Source/WebCore/style/RenderTreeUpdaterGeneratedContent.cpp 2017-10-21 06:52:47 UTC (rev 223809)
+++ trunk/Source/WebCore/style/RenderTreeUpdaterGeneratedContent.cpp 2017-10-21 08:15:10 UTC (rev 223810)
@@ -69,29 +69,41 @@
ASSERT(!lastQuote);
}
-static void createContentRenderers(RenderElement& renderer)
+static void createContentRenderers(PseudoElement& pseudoElement, const RenderStyle& style, RenderTreePosition& renderTreePosition)
{
- auto& style = renderer.style();
ASSERT(style.contentData());
for (const ContentData* content = style.contentData(); content; content = content->next()) {
- auto child = content->createContentRenderer(renderer.document(), style);
- if (renderer.isChildAllowed(*child, style))
- renderer.addChild(WTFMove(child));
+ auto child = content->createContentRenderer(renderTreePosition.parent().document(), style);
+ pseudoElement.contentRenderers().append(makeWeakPtr(*child));
+ if (renderTreePosition.parent().isChildAllowed(*child, style))
+ renderTreePosition.insert(WTFMove(child));
}
}
-static void updateStyleForContentRenderers(RenderElement& renderer)
+static void updateStyleForContentRenderers(PseudoElement& pseudoElement, const RenderStyle& style)
{
- for (auto* child = renderer.nextInPreOrder(&renderer); child; child = child->nextInPreOrder(&renderer)) {
+ for (auto& contentRenderer : pseudoElement.contentRenderers()) {
+ if (!contentRenderer)
+ continue;
// We only manage the style for the generated content which must be images or text.
- if (!is<RenderImage>(*child) && !is<RenderQuote>(*child))
+ if (!is<RenderImage>(*contentRenderer) && !is<RenderQuote>(*contentRenderer))
continue;
- auto createdStyle = RenderStyle::createStyleInheritingFromPseudoStyle(renderer.style());
- downcast<RenderElement>(*child).setStyle(WTFMove(createdStyle));
+ auto createdStyle = RenderStyle::createStyleInheritingFromPseudoStyle(style);
+ downcast<RenderElement>(*contentRenderer).setStyle(WTFMove(createdStyle));
}
}
+static void removeAndDestroyContentRenderers(PseudoElement& pseudoElement)
+{
+ for (auto& contentRenderer : pseudoElement.contentRenderers()) {
+ if (!contentRenderer)
+ continue;
+ contentRenderer->removeFromParentAndDestroy();
+ }
+ pseudoElement.contentRenderers().clear();
+}
+
void RenderTreeUpdater::GeneratedContent::updatePseudoElement(Element& current, const std::optional<Style::ElementUpdate>& update, PseudoId pseudoId)
{
PseudoElement* pseudoElement = pseudoId == BEFORE ? current.beforePseudoElement() : current.afterPseudoElement();
@@ -101,6 +113,8 @@
if (!needsPseudoElement(update)) {
if (pseudoElement) {
+ removeAndDestroyContentRenderers(*pseudoElement);
+
if (pseudoId == BEFORE)
current.clearBeforePseudoElement();
else
@@ -127,21 +141,30 @@
m_updater.updateElementRenderer(*pseudoElement, *update);
- auto* pseudoRenderer = pseudoElement->renderer();
- if (!pseudoRenderer)
+ auto* pseudoElementRenderer = pseudoElement->renderer();
+ if (!pseudoElementRenderer && update->style->display() != CONTENTS)
return;
- if (update->change == Style::Detach)
- createContentRenderers(*pseudoRenderer);
- else
- updateStyleForContentRenderers(*pseudoRenderer);
+ auto renderTreePosition = pseudoElementRenderer ? RenderTreePosition(*pseudoElementRenderer) : m_updater.renderTreePosition();
+ if (update->change == Style::Detach) {
+ removeAndDestroyContentRenderers(*pseudoElement);
+
+ if (pseudoElementRenderer)
+ renderTreePosition.moveToLastChild();
+ else
+ renderTreePosition.computeNextSibling(*pseudoElement);
+
+ createContentRenderers(*pseudoElement, *update->style, renderTreePosition);
+ } else
+ updateStyleForContentRenderers(*pseudoElement, *update->style);
+
if (m_updater.renderView().hasQuotesNeedingUpdate()) {
- for (auto& child : descendantsOfType<RenderQuote>(*pseudoRenderer))
+ for (auto& child : descendantsOfType<RenderQuote>(renderTreePosition.parent()))
updateQuotesUpTo(&child);
}
- if (is<RenderListItem>(*pseudoRenderer))
- ListItem::updateMarker(downcast<RenderListItem>(*pseudoRenderer));
+ if (is<RenderListItem>(renderTreePosition.parent()))
+ ListItem::updateMarker(downcast<RenderListItem>(renderTreePosition.parent()));
}
bool RenderTreeUpdater::GeneratedContent::needsPseudoElement(const std::optional<Style::ElementUpdate>& update)