Changeset 223810 in webkit


Ignore:
Timestamp:
Oct 21, 2017 1:15:10 AM (7 years ago)
Author:
Antti Koivisto
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
Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r223809 r223810  
     12017-10-21  Antti Koivisto  <antti@apple.com>
     2
     3        Support ::before/::after pseudo elements with display:contents
     4        https://bugs.webkit.org/show_bug.cgi?id=178584
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        * TestExpectations: Enable imported/w3c/web-platform-tests/css/css-display-3/display-contents-before-after-002.html
     9
    1102017-10-20  Joseph Pecoraro  <pecoraro@apple.com>
    211
  • trunk/LayoutTests/TestExpectations

    r223748 r223810  
    12701270webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-dynamic-table-002-none.html [ ImageOnlyFailure ]
    12711271webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-flex-003.html [ ImageOnlyFailure ]
    1272 webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-before-after-002.html [ ImageOnlyFailure ]
    12731272webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-dynamic-table-001-inline.html [ ImageOnlyFailure ]
    12741273webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-dynamic-flex-002-none.html [ ImageOnlyFailure ]
  • trunk/Source/WebCore/ChangeLog

    r223805 r223810  
     12017-10-21  Antti Koivisto  <antti@apple.com>
     2
     3        Support ::before/::after pseudo elements with display:contents
     4        https://bugs.webkit.org/show_bug.cgi?id=178584
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        This is cases like
     9
     10        ::before { display:contents; content:'foo' }
     11
     12        * css/StyleResolver.cpp:
     13        (WebCore::StyleResolver::adjustDisplayContentsStyle): Added.
     14
     15            Allow display:contents on pseudo elements.
     16            Factor into function.
     17
     18        (WebCore::StyleResolver::adjustRenderStyle):
     19        * dom/PseudoElement.h:
     20
     21            Add a weak vector of content renderers.
     22
     23        * style/RenderTreePosition.h:
     24        (WebCore::RenderTreePosition::moveToLastChild):
     25
     26            Add a way to set a valid render tree position without a node.
     27
     28        * style/RenderTreeUpdaterGeneratedContent.cpp:
     29        (WebCore::createContentRenderers):
     30
     31            Take RenderTreePosition.
     32
     33        (WebCore::updateStyleForContentRenderers):
     34
     35            Update based on the content renderer vector instead of doing a tree walk.
     36
     37        (WebCore::removeAndDestroyContentRenderers):
     38
     39            Helper for destroying content renderers.
     40
     41        (WebCore::RenderTreeUpdater::GeneratedContent::updatePseudoElement):
     42
     43            In the normal case create a render tree position for the pseudo element renderer and
     44            use RenderTreePosition::moveToLastChild to make it a valid position. (The existing
     45            RenderTreePosition interface didn't have way to move to positions in anonymous boxes)
     46
     47            In the case of a non box generating display:contents pseudo element, use the current
     48            render tree position instead.
     49
     50            Ensure that pseudo element renderers are destroyed before creating the new ones since in
     51            display:contents case they are not descendants of the pseudo renderer and don't get cleared
     52            automatically.
     53
    1542017-10-20  Zalan Bujtas  <zalan@apple.com>
    255
  • trunk/Source/WebCore/css/StyleResolver.cpp

    r223728 r223810  
    790790}
    791791
     792static void adjustDisplayContentsStyle(RenderStyle& style, const Element* element)
     793{
     794    bool displayContentsEnabled = is<HTMLSlotElement>(element) || RuntimeEnabledFeatures::sharedFeatures().displayContentsEnabled();
     795    if (!displayContentsEnabled) {
     796        style.setDisplay(INLINE);
     797        return;
     798    }
     799    if (!element) {
     800        if (style.styleType() != BEFORE && style.styleType() != AFTER)
     801            style.setDisplay(NONE);
     802        return;
     803    }
     804    if (hasEffectiveDisplayNoneForDisplayContents(*element))
     805        style.setDisplay(NONE);
     806}
     807
    792808void StyleResolver::adjustRenderStyle(RenderStyle& style, const RenderStyle& parentStyle, const RenderStyle* parentBoxStyle, const Element* element)
    793809{
     
    800816    style.setOriginalDisplay(style.display());
    801817
    802     if (style.display() == CONTENTS) {
    803         bool elementSupportsDisplayContents = is<HTMLSlotElement>(element) || RuntimeEnabledFeatures::sharedFeatures().displayContentsEnabled();
    804         if (!elementSupportsDisplayContents)
    805             style.setDisplay(INLINE);
    806         else if (!element || hasEffectiveDisplayNoneForDisplayContents(*element))
    807             style.setDisplay(NONE);
    808     }
     818    if (style.display() == CONTENTS)
     819        adjustDisplayContentsStyle(style, element);
    809820
    810821    if (style.display() != NONE && style.display() != CONTENTS) {
  • trunk/Source/WebCore/dom/PseudoElement.h

    r223604 r223810  
    4545    bool canContainRangeEndPoint() const override { return false; }
    4646
     47    auto& contentRenderers() { return m_contentRenderers; }
     48
    4749    static String pseudoElementNameForEvents(PseudoId);
    4850
     
    5456    Element* m_hostElement;
    5557    PseudoId m_pseudoId;
     58    Vector<WeakPtr<RenderObject>> m_contentRenderers;
    5659};
    5760
  • trunk/Source/WebCore/style/RenderTreePosition.h

    r222679 r223810  
    3535class RenderTreePosition {
    3636public:
    37     explicit RenderTreePosition(RenderView& root)
    38         : m_parent(root)
    39         , m_hasValidNextSibling(true)
    40     {
    41     }
    42    
    4337    explicit RenderTreePosition(RenderElement& parent)
    4438        : m_parent(parent)
     
    5246
    5347    void computeNextSibling(const Node&);
     48    void moveToLastChild();
    5449    void invalidateNextSibling() { m_hasValidNextSibling = false; }
    5550    void invalidateNextSibling(const RenderObject&);
     
    6661#endif
    6762};
     63
     64inline void RenderTreePosition::moveToLastChild()
     65{
     66    m_nextSibling = nullptr;
     67    m_hasValidNextSibling = true;
     68}
    6869
    6970inline bool RenderTreePosition::canInsert(RenderElement& renderer) const
  • trunk/Source/WebCore/style/RenderTreeUpdaterGeneratedContent.cpp

    r223748 r223810  
    7070}
    7171
    72 static void createContentRenderers(RenderElement& renderer)
     72static void createContentRenderers(PseudoElement& pseudoElement, const RenderStyle& style, RenderTreePosition& renderTreePosition)
    7373{
    74     auto& style = renderer.style();
    7574    ASSERT(style.contentData());
    7675
    7776    for (const ContentData* content = style.contentData(); content; content = content->next()) {
    78         auto child = content->createContentRenderer(renderer.document(), style);
    79         if (renderer.isChildAllowed(*child, style))
    80             renderer.addChild(WTFMove(child));
     77        auto child = content->createContentRenderer(renderTreePosition.parent().document(), style);
     78        pseudoElement.contentRenderers().append(makeWeakPtr(*child));
     79        if (renderTreePosition.parent().isChildAllowed(*child, style))
     80            renderTreePosition.insert(WTFMove(child));
    8181    }
    8282}
    8383
    84 static void updateStyleForContentRenderers(RenderElement& renderer)
     84static void updateStyleForContentRenderers(PseudoElement& pseudoElement, const RenderStyle& style)
    8585{
    86     for (auto* child = renderer.nextInPreOrder(&renderer); child; child = child->nextInPreOrder(&renderer)) {
     86    for (auto& contentRenderer : pseudoElement.contentRenderers()) {
     87        if (!contentRenderer)
     88            continue;
    8789        // We only manage the style for the generated content which must be images or text.
    88         if (!is<RenderImage>(*child) && !is<RenderQuote>(*child))
     90        if (!is<RenderImage>(*contentRenderer) && !is<RenderQuote>(*contentRenderer))
    8991            continue;
    90         auto createdStyle = RenderStyle::createStyleInheritingFromPseudoStyle(renderer.style());
    91         downcast<RenderElement>(*child).setStyle(WTFMove(createdStyle));
     92        auto createdStyle = RenderStyle::createStyleInheritingFromPseudoStyle(style);
     93        downcast<RenderElement>(*contentRenderer).setStyle(WTFMove(createdStyle));
    9294    }
     95}
     96
     97static void removeAndDestroyContentRenderers(PseudoElement& pseudoElement)
     98{
     99    for (auto& contentRenderer : pseudoElement.contentRenderers()) {
     100        if (!contentRenderer)
     101            continue;
     102        contentRenderer->removeFromParentAndDestroy();
     103    }
     104    pseudoElement.contentRenderers().clear();
    93105}
    94106
     
    102114    if (!needsPseudoElement(update)) {
    103115        if (pseudoElement) {
     116            removeAndDestroyContentRenderers(*pseudoElement);
     117
    104118            if (pseudoId == BEFORE)
    105119                current.clearBeforePseudoElement();
     
    128142    m_updater.updateElementRenderer(*pseudoElement, *update);
    129143
    130     auto* pseudoRenderer = pseudoElement->renderer();
    131     if (!pseudoRenderer)
     144    auto* pseudoElementRenderer = pseudoElement->renderer();
     145    if (!pseudoElementRenderer && update->style->display() != CONTENTS)
    132146        return;
    133147
    134     if (update->change == Style::Detach)
    135         createContentRenderers(*pseudoRenderer);
    136     else
    137         updateStyleForContentRenderers(*pseudoRenderer);
     148    auto renderTreePosition = pseudoElementRenderer ? RenderTreePosition(*pseudoElementRenderer) : m_updater.renderTreePosition();
     149
     150    if (update->change == Style::Detach) {
     151        removeAndDestroyContentRenderers(*pseudoElement);
     152
     153        if (pseudoElementRenderer)
     154            renderTreePosition.moveToLastChild();
     155        else
     156            renderTreePosition.computeNextSibling(*pseudoElement);
     157
     158        createContentRenderers(*pseudoElement, *update->style, renderTreePosition);
     159    } else
     160        updateStyleForContentRenderers(*pseudoElement, *update->style);
    138161
    139162    if (m_updater.renderView().hasQuotesNeedingUpdate()) {
    140         for (auto& child : descendantsOfType<RenderQuote>(*pseudoRenderer))
     163        for (auto& child : descendantsOfType<RenderQuote>(renderTreePosition.parent()))
    141164            updateQuotesUpTo(&child);
    142165    }
    143     if (is<RenderListItem>(*pseudoRenderer))
    144         ListItem::updateMarker(downcast<RenderListItem>(*pseudoRenderer));
     166    if (is<RenderListItem>(renderTreePosition.parent()))
     167        ListItem::updateMarker(downcast<RenderListItem>(renderTreePosition.parent()));
    145168}
    146169
Note: See TracChangeset for help on using the changeset viewer.