Changeset 223748 in webkit


Ignore:
Timestamp:
Oct 20, 2017 1:29:03 AM (7 years ago)
Author:
Antti Koivisto
Message:

Support ::before/::after pseudo elements on elements with display:contents
https://bugs.webkit.org/show_bug.cgi?id=178513

Reviewed by Ryosuke Niwa.

LayoutTests/imported/w3c:

  • web-platform-tests/cssom/getComputedStyle-pseudo-expected.txt:

Source/WebCore:

Add support for

div { display:contents }
div::after { content:'foo' }

That is support non-box generating elements with generated content.

  • style/RenderTreePosition.cpp:

(WebCore::RenderTreePosition::nextSiblingRenderer const):

Implement full pseudo-inclusive traversal starting from any element (including pseudo)
to locate the next rendering sibling. In case of display:content this may need to look
into descendants.

  • style/RenderTreeUpdater.cpp:

(WebCore::textRendererIsNeeded):

RenderTreePosition::nextSiblingRenderer can no longer be called with a node that already has a renderer.
Maintain the existing behavior.

  • style/RenderTreeUpdaterGeneratedContent.cpp:

(WebCore::RenderTreeUpdater::GeneratedContent::updatePseudoElement):
(WebCore::RenderTreeUpdater::GeneratedContent::needsPseudoElement):

Don't require for host to have a renderer.

  • style/RenderTreeUpdaterGeneratedContent.h:
  • style/StyleTreeResolver.cpp:

(WebCore::Style::TreeResolver::resolvePseudoStyle):

LayoutTests:

  • TestExpectations: Enable imported/w3c/web-platform-tests/css/css-display-3/display-contents-before-after-001.html
Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r223744 r223748  
     12017-10-19  Antti Koivisto  <antti@apple.com>
     2
     3        Support ::before/::after pseudo elements on elements with display:contents
     4        https://bugs.webkit.org/show_bug.cgi?id=178513
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        * TestExpectations: Enable imported/w3c/web-platform-tests/css/css-display-3/display-contents-before-after-001.html
     9
    1102017-10-20  Yusuke Suzuki  <utatane.tea@gmail.com>
    211
  • trunk/LayoutTests/TestExpectations

    r223678 r223748  
    12741274webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-dynamic-flex-002-none.html [ ImageOnlyFailure ]
    12751275webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-flex-002.html [ ImageOnlyFailure ]
    1276 webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-before-after-001.html [ ImageOnlyFailure ]
    12771276webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-flow-root-001.html [ ImageOnlyFailure ]
    12781277webkit.org/b/157477 imported/w3c/web-platform-tests/css/css-display-3/display-contents-dynamic-flex-003-none.html [ ImageOnlyFailure ]
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r223701 r223748  
     12017-10-19  Antti Koivisto  <antti@apple.com>
     2
     3        Support ::before/::after pseudo elements on elements with display:contents
     4        https://bugs.webkit.org/show_bug.cgi?id=178513
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        * web-platform-tests/cssom/getComputedStyle-pseudo-expected.txt:
     9
    1102017-10-19  Andy Estes  <aestes@apple.com>
    211
  • trunk/LayoutTests/imported/w3c/web-platform-tests/cssom/getComputedStyle-pseudo-expected.txt

    r223327 r223748  
    11
    22PASS Resolution of width is correct for ::before and ::after pseudo-elements
    3 FAIL Resolution of width is correct for ::before and ::after pseudo-elements of display: contents elements assert_equals: expected "50px" but got "50%"
     3PASS Resolution of width is correct for ::before and ::after pseudo-elements of display: contents elements
    44PASS Resolution of nonexistent pseudo-element styles
    55FAIL Resolution of pseudo-element styles in display: none elements assert_equals: Pseudo-styles of display: none elements should be correct expected "\"Foo\"" but got "Foo"
  • trunk/Source/WebCore/ChangeLog

    r223747 r223748  
     12017-10-19  Antti Koivisto  <antti@apple.com>
     2
     3        Support ::before/::after pseudo elements on elements with display:contents
     4        https://bugs.webkit.org/show_bug.cgi?id=178513
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        Add support for
     9
     10            div { display:contents }
     11            div::after { content:'foo' }
     12
     13        That is support non-box generating elements with generated content.
     14
     15        * style/RenderTreePosition.cpp:
     16        (WebCore::RenderTreePosition::nextSiblingRenderer const):
     17
     18            Implement full pseudo-inclusive traversal starting from any element (including pseudo)
     19            to locate the next rendering sibling. In case of display:content this may need to look
     20            into descendants.
     21
     22        * style/RenderTreeUpdater.cpp:
     23        (WebCore::textRendererIsNeeded):
     24
     25            RenderTreePosition::nextSiblingRenderer can no longer be called with a node that already has a renderer.
     26            Maintain the existing behavior.
     27
     28        * style/RenderTreeUpdaterGeneratedContent.cpp:
     29        (WebCore::RenderTreeUpdater::GeneratedContent::updatePseudoElement):
     30        (WebCore::RenderTreeUpdater::GeneratedContent::needsPseudoElement):
     31
     32            Don't require for host to have a renderer.
     33
     34        * style/RenderTreeUpdaterGeneratedContent.h:
     35        * style/StyleTreeResolver.cpp:
     36        (WebCore::Style::TreeResolver::resolvePseudoStyle):
     37
    1382017-10-20  Keith Miller  <keith_miller@apple.com>
    239
  • trunk/Source/WebCore/style/RenderTreePosition.cpp

    r222259 r223748  
    7676RenderObject* RenderTreePosition::nextSiblingRenderer(const Node& node) const
    7777{
     78    ASSERT(!node.renderer());
     79
    7880    auto* parentElement = m_parent.element();
    7981    if (!parentElement)
    8082        return nullptr;
    81     if (node.isAfterPseudoElement())
     83    // FIXME: PlugingReplacement shadow trees are very wrong.
     84    if (parentElement == &node)
    8285        return nullptr;
    8386
     87    Vector<Element*, 30> elementStack;
     88
     89    // In the common case ancestor == parentElement immediately and this just pushes parentElement into stack.
     90    auto* ancestor = is<PseudoElement>(node) ? downcast<PseudoElement>(node).hostElement() : node.parentElementInComposedTree();
     91    while (true) {
     92        elementStack.append(ancestor);
     93        if (ancestor == parentElement)
     94            break;
     95        ancestor = ancestor->parentElementInComposedTree();
     96        ASSERT(ancestor);
     97    }
     98    elementStack.reverse();
     99
    84100    auto composedDescendants = composedTreeDescendants(*parentElement);
    85     auto it = node.isBeforePseudoElement() ? composedDescendants.begin() : composedDescendants.at(node);
     101
     102    auto initializeIteratorConsideringPseudoElements = [&] {
     103        if (is<PseudoElement>(node)) {
     104            auto* host = downcast<PseudoElement>(node).hostElement();
     105            if (node.isBeforePseudoElement()) {
     106                if (host != parentElement)
     107                    return composedDescendants.at(*host).traverseNext();
     108                return composedDescendants.begin();
     109            }
     110            ASSERT(node.isAfterPseudoElement());
     111            elementStack.removeLast();
     112            if (host != parentElement)
     113                return composedDescendants.at(*host).traverseNextSkippingChildren();
     114            return composedDescendants.end();
     115        }
     116        return composedDescendants.at(node).traverseNextSkippingChildren();
     117    };
     118
     119    auto pushCheckingForAfterPseudoElementRenderer = [&] (Element& element) -> RenderElement* {
     120        ASSERT(!element.isPseudoElement());
     121        if (auto* before = element.beforePseudoElement()) {
     122            if (auto* renderer = before->renderer())
     123                return renderer;
     124        }
     125        elementStack.append(&element);
     126        return nullptr;
     127    };
     128
     129    auto popCheckingForAfterPseudoElementRenderers = [&] (unsigned iteratorDepthToMatch) -> RenderElement* {
     130        while (elementStack.size() > iteratorDepthToMatch) {
     131            auto& element = *elementStack.takeLast();
     132            if (auto* after = element.afterPseudoElement()) {
     133                if (auto* renderer = after->renderer())
     134                    return renderer;
     135            }
     136        }
     137        return nullptr;
     138    };
     139
     140    auto it = initializeIteratorConsideringPseudoElements();
    86141    auto end = composedDescendants.end();
    87142
    88143    while (it != end) {
    89         auto& node = *it;
    90         bool hasDisplayContents = is<Element>(node) && downcast<Element>(node).hasDisplayContents();
    91         if (hasDisplayContents) {
    92             it.traverseNext();
    93             continue;
    94         }
     144        if (auto* renderer = popCheckingForAfterPseudoElementRenderers(it.depth()))
     145            return renderer;
     146
    95147        if (auto* renderer = it->renderer())
    96148            return renderer;
    97        
     149
     150        if (is<Element>(*it)) {
     151            auto& element = downcast<Element>(*it);
     152            if (element.hasDisplayContents()) {
     153                if (auto* renderer = pushCheckingForAfterPseudoElementRenderer(element))
     154                    return renderer;
     155                it.traverseNext();
     156                continue;
     157            }
     158        }
     159
    98160        it.traverseNextSkippingChildren();
    99161    }
    100     if (PseudoElement* after = parentElement->afterPseudoElement())
    101         return after->renderer();
    102     return nullptr;
     162
     163    return popCheckingForAfterPseudoElementRenderers(0);
    103164}
    104165
  • trunk/Source/WebCore/style/RenderTreeUpdater.cpp

    r223728 r223748  
    419419        while (first && first->isFloatingOrOutOfFlowPositioned())
    420420            first = first->nextSibling();
    421         RenderObject* nextRenderer = renderTreePosition.nextSiblingRenderer(textNode);
     421        RenderObject* nextRenderer = textNode.renderer() ? textNode.renderer() : renderTreePosition.nextSiblingRenderer(textNode);
    422422        if (!first || nextRenderer == first) {
    423423            // Whitespace at the start of a block just goes away. Don't even make a render object for this text.
  • trunk/Source/WebCore/style/RenderTreeUpdaterGeneratedContent.cpp

    r223604 r223748  
    100100        m_updater.renderTreePosition().invalidateNextSibling(*renderer);
    101101
    102     if (!needsPseudoElement(current, update)) {
     102    if (!needsPseudoElement(update)) {
    103103        if (pseudoElement) {
    104104            if (pseudoId == BEFORE)
     
    145145}
    146146
    147 bool RenderTreeUpdater::GeneratedContent::needsPseudoElement(Element& current, const std::optional<Style::ElementUpdate>& update)
     147bool RenderTreeUpdater::GeneratedContent::needsPseudoElement(const std::optional<Style::ElementUpdate>& update)
    148148{
    149     ASSERT(!current.isPseudoElement());
    150149    if (!update)
    151150        return false;
    152     if (!current.renderer() || !current.renderer()->canHaveGeneratedChildren())
     151    if (!m_updater.renderTreePosition().parent().canHaveGeneratedChildren())
    153152        return false;
    154153    if (!pseudoElementRendererIsNeeded(update->style.get()))
  • trunk/Source/WebCore/style/RenderTreeUpdaterGeneratedContent.h

    r223604 r223748  
    4444    void updateQuotesUpTo(RenderQuote*);
    4545   
    46     static bool needsPseudoElement(Element&, const std::optional<Style::ElementUpdate>&);
     46    bool needsPseudoElement(const std::optional<Style::ElementUpdate>&);
    4747
    4848    RenderTreeUpdater& m_updater;
  • trunk/Source/WebCore/style/StyleTreeResolver.cpp

    r223728 r223748  
    228228ElementUpdate TreeResolver::resolvePseudoStyle(Element& element, const ElementUpdate& elementUpdate, PseudoId pseudoId)
    229229{
     230    if (elementUpdate.style->display() == NONE)
     231        return { };
    230232    if (!elementUpdate.style->hasPseudoStyle(pseudoId))
    231233        return { };
Note: See TracChangeset for help on using the changeset viewer.