Skip to content
Permalink
Browse files
Resolve ::before and ::after pseudo elements during style resolution
https://bugs.webkit.org/show_bug.cgi?id=178339

Reviewed by Ryosuke Niwa.

They are currently resolved during render tree building which creates problems with display:contents and animations.

* dom/PseudoElement.cpp:
(WebCore::PseudoElement::PseudoElement):

    Call InspectorInstrumentation from constructor.

* style/RenderTreeUpdater.cpp:
(WebCore::RenderTreeUpdater::Parent::Parent):
(WebCore::RenderTreeUpdater::updateRenderTree):
(WebCore::RenderTreeUpdater::pushParent):

    Push the full update to the parent stack.

(WebCore::RenderTreeUpdater::popParent):
(WebCore::RenderTreeUpdater::updateBeforeDescendants):
(WebCore::RenderTreeUpdater::updateAfterDescendants):
(WebCore::RenderTreeUpdater::invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded):
* style/RenderTreeUpdater.h:
* style/RenderTreeUpdaterGeneratedContent.cpp:
(WebCore::RenderTreeUpdater::GeneratedContent::updatePseudoElement):

    No need to resolve pseudo style, we have it already.

(WebCore::RenderTreeUpdater::GeneratedContent::needsPseudoElement):
(WebCore::RenderTreeUpdater::GeneratedContent::updateBeforePseudoElement): Deleted.
(WebCore::RenderTreeUpdater::GeneratedContent::updateAfterPseudoElement): Deleted.
* style/RenderTreeUpdaterGeneratedContent.h:
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::resolveElement):
(WebCore::Style::TreeResolver::resolvePseudoStyle):

    Resolve pseudos.

(WebCore::Style::TreeResolver::createAnimatedElementUpdate):

    Make a private member function.

(WebCore::Style::TreeResolver::resolveComposedTree):
* style/StyleTreeResolver.h:
* style/StyleUpdate.cpp:
(WebCore::Style::Update::elementUpdates const):
(WebCore::Style::Update::elementUpdates):

    Bundle the style update for an element and the associated before/after pseudos.

(WebCore::Style::Update::elementStyle const):
(WebCore::Style::Update::elementStyle):
(WebCore::Style::Update::addElement):
(WebCore::Style::Update::elementUpdate const): Deleted.
(WebCore::Style::Update::elementUpdate): Deleted.
* style/StyleUpdate.h:


Canonical link: https://commits.webkit.org/194604@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@223500 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
anttijk committed Oct 17, 2017
1 parent f28337f commit d92038ac04e6bbd955ee03804a8597a0a5c4227f
@@ -1,3 +1,63 @@
2017-10-17 Antti Koivisto <antti@apple.com>

Resolve ::before and ::after pseudo elements during style resolution
https://bugs.webkit.org/show_bug.cgi?id=178339

Reviewed by Ryosuke Niwa.

They are currently resolved during render tree building which creates problems with display:contents and animations.

* dom/PseudoElement.cpp:
(WebCore::PseudoElement::PseudoElement):

Call InspectorInstrumentation from constructor.

* style/RenderTreeUpdater.cpp:
(WebCore::RenderTreeUpdater::Parent::Parent):
(WebCore::RenderTreeUpdater::updateRenderTree):
(WebCore::RenderTreeUpdater::pushParent):

Push the full update to the parent stack.

(WebCore::RenderTreeUpdater::popParent):
(WebCore::RenderTreeUpdater::updateBeforeDescendants):
(WebCore::RenderTreeUpdater::updateAfterDescendants):
(WebCore::RenderTreeUpdater::invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded):
* style/RenderTreeUpdater.h:
* style/RenderTreeUpdaterGeneratedContent.cpp:
(WebCore::RenderTreeUpdater::GeneratedContent::updatePseudoElement):

No need to resolve pseudo style, we have it already.

(WebCore::RenderTreeUpdater::GeneratedContent::needsPseudoElement):
(WebCore::RenderTreeUpdater::GeneratedContent::updateBeforePseudoElement): Deleted.
(WebCore::RenderTreeUpdater::GeneratedContent::updateAfterPseudoElement): Deleted.
* style/RenderTreeUpdaterGeneratedContent.h:
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::resolveElement):
(WebCore::Style::TreeResolver::resolvePseudoStyle):

Resolve pseudos.

(WebCore::Style::TreeResolver::createAnimatedElementUpdate):

Make a private member function.

(WebCore::Style::TreeResolver::resolveComposedTree):
* style/StyleTreeResolver.h:
* style/StyleUpdate.cpp:
(WebCore::Style::Update::elementUpdates const):
(WebCore::Style::Update::elementUpdates):

Bundle the style update for an element and the associated before/after pseudos.

(WebCore::Style::Update::elementStyle const):
(WebCore::Style::Update::elementStyle):
(WebCore::Style::Update::addElement):
(WebCore::Style::Update::elementUpdate const): Deleted.
(WebCore::Style::Update::elementUpdate): Deleted.
* style/StyleUpdate.h:

2017-10-17 Keith Miller <keith_miller@apple.com>

Change WebCore sources to work with unified source builds
@@ -28,6 +28,7 @@
#include "config.h"
#include "PseudoElement.h"

#include "CSSAnimationController.h"
#include "ContentData.h"
#include "InspectorInstrumentation.h"
#include "RenderElement.h"
@@ -71,10 +72,22 @@ PseudoElement::~PseudoElement()
ASSERT(!m_hostElement);
}

Ref<PseudoElement> PseudoElement::create(Element& host, PseudoId pseudoId)
{
auto pseudoElement = adoptRef(*new PseudoElement(host, pseudoId));

InspectorInstrumentation::pseudoElementCreated(host.document().page(), pseudoElement.get());

return pseudoElement;
}

void PseudoElement::clearHostElement()
{
InspectorInstrumentation::pseudoElementDestroyed(document().page(), *this);

if (auto* frame = document().frame())
frame->animation().cancelAnimations(*this);

m_hostElement = nullptr;
}

@@ -33,10 +33,7 @@ namespace WebCore {

class PseudoElement final : public Element {
public:
static Ref<PseudoElement> create(Element& host, PseudoId pseudoId)
{
return adoptRef(*new PseudoElement(host, pseudoId));
}
static Ref<PseudoElement> create(Element& host, PseudoId);
virtual ~PseudoElement();

Element* hostElement() const { return m_hostElement; }
@@ -74,9 +74,9 @@ RenderTreeUpdater::Parent::Parent(ContainerNode& root)
{
}

RenderTreeUpdater::Parent::Parent(Element& element, Style::Change styleChange)
RenderTreeUpdater::Parent::Parent(Element& element, const Style::ElementUpdates* updates)
: element(&element)
, styleChange(styleChange)
, updates(updates)
, renderTreePosition(element.renderer() ? std::make_optional(RenderTreePosition(*element.renderer())) : std::nullopt)
{
}
@@ -175,7 +175,7 @@ void RenderTreeUpdater::updateRenderTree(ContainerNode& root)
if (is<Text>(node)) {
auto& text = downcast<Text>(node);
auto* textUpdate = m_styleUpdate->textUpdate(text);
if (parent().styleChange == Style::Detach || textUpdate || m_invalidatedWhitespaceOnlyTextSiblings.contains(&text))
if ((parent().updates && parent().updates->update.change == Style::Detach) || textUpdate || m_invalidatedWhitespaceOnlyTextSiblings.contains(&text))
updateTextRenderer(text, textUpdate);

it.traverseNextSkippingChildren();
@@ -184,25 +184,25 @@ void RenderTreeUpdater::updateRenderTree(ContainerNode& root)

auto& element = downcast<Element>(node);

auto* elementUpdate = m_styleUpdate->elementUpdate(element);
auto* elementUpdates = m_styleUpdate->elementUpdates(element);

// We hop through display: contents elements in findRenderingRoot, so
// there may be other updates down the tree.
if (!elementUpdate && !element.hasDisplayContents()) {
if (!elementUpdates && !element.hasDisplayContents()) {
it.traverseNextSkippingChildren();
continue;
}

if (elementUpdate)
updateElementRenderer(element, *elementUpdate);
if (elementUpdates)
updateElementRenderer(element, elementUpdates->update);

bool mayHaveRenderedDescendants = element.renderer() || (element.hasDisplayContents() && shouldCreateRenderer(element, renderTreePosition().parent()));
if (!mayHaveRenderedDescendants) {
it.traverseNextSkippingChildren();
continue;
}

pushParent(element, elementUpdate ? elementUpdate->change : Style::NoChange);
pushParent(element, elementUpdates);

it.traverseNext();
}
@@ -222,18 +222,18 @@ RenderTreePosition& RenderTreeUpdater::renderTreePosition()
return *m_parentStack.last().renderTreePosition;
}

void RenderTreeUpdater::pushParent(Element& element, Style::Change changeType)
void RenderTreeUpdater::pushParent(Element& element, const Style::ElementUpdates* updates)
{
m_parentStack.append(Parent(element, changeType));
m_parentStack.append(Parent(element, updates));

updateBeforeDescendants(element);
updateBeforeDescendants(element, updates);
}

void RenderTreeUpdater::popParent()
{
auto& parent = m_parentStack.last();
if (parent.element)
updateAfterDescendants(*parent.element, parent.styleChange);
updateAfterDescendants(*parent.element, parent.updates);

m_parentStack.removeLast();
}
@@ -246,14 +246,16 @@ void RenderTreeUpdater::popParentsToDepth(unsigned depth)
popParent();
}

void RenderTreeUpdater::updateBeforeDescendants(Element& element)
void RenderTreeUpdater::updateBeforeDescendants(Element& element, const Style::ElementUpdates* updates)
{
generatedContent().updateBeforePseudoElement(element);
if (updates)
generatedContent().updatePseudoElement(element, updates->beforePseudoElementUpdate, BEFORE);
}

void RenderTreeUpdater::updateAfterDescendants(Element& element, Style::Change styleChange)
void RenderTreeUpdater::updateAfterDescendants(Element& element, const Style::ElementUpdates* updates)
{
generatedContent().updateAfterPseudoElement(element);
if (updates)
generatedContent().updatePseudoElement(element, updates->afterPseudoElementUpdate, AFTER);

auto* renderer = element.renderer();
if (!renderer)
@@ -267,7 +269,7 @@ void RenderTreeUpdater::updateAfterDescendants(Element& element, Style::Change s
if (is<RenderBlockFlow>(*renderer))
MultiColumn::update(downcast<RenderBlockFlow>(*renderer));

if (element.hasCustomStyleResolveCallbacks() && styleChange == Style::Detach)
if (element.hasCustomStyleResolveCallbacks() && updates && updates->update.change == Style::Detach)
element.didAttachRenderers();
}

@@ -470,7 +472,7 @@ void RenderTreeUpdater::invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(
// the current node gaining or losing the renderer. This can only affect white space text nodes.
for (Node* sibling = current.nextSibling(); sibling; sibling = sibling->nextSibling()) {
if (is<Element>(*sibling)) {
if (m_styleUpdate->elementUpdate(downcast<Element>(*sibling)))
if (m_styleUpdate->elementUpdates(downcast<Element>(*sibling)))
return;
// Text renderers beyond rendered elements can't be affected.
if (sibling->renderer())
@@ -62,23 +62,23 @@ class RenderTreeUpdater {
void updateElementRenderer(Element&, const Style::ElementUpdate&);
void createRenderer(Element&, RenderStyle&&);
void invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(Node&);
void updateBeforeDescendants(Element&);
void updateAfterDescendants(Element&, Style::Change);
void updateBeforeDescendants(Element&, const Style::ElementUpdates*);
void updateAfterDescendants(Element&, const Style::ElementUpdates*);

struct Parent {
Element* element { nullptr };
Style::Change styleChange { Style::NoChange };
const Style::ElementUpdates* updates { nullptr };
std::optional<RenderTreePosition> renderTreePosition;

Parent(ContainerNode& root);
Parent(Element&, Style::Change);
Parent(Element&, const Style::ElementUpdates*);
};
Parent& parent() { return m_parentStack.last(); }
RenderTreePosition& renderTreePosition();

GeneratedContent& generatedContent() { return *m_generatedContent; }

void pushParent(Element&, Style::Change);
void pushParent(Element&, const Style::ElementUpdates*);
void popParent();
void popParentsToDepth(unsigned depth);

@@ -44,16 +44,6 @@ RenderTreeUpdater::GeneratedContent::GeneratedContent(RenderTreeUpdater& updater
{
}

void RenderTreeUpdater::GeneratedContent::updateBeforePseudoElement(Element& element)
{
updatePseudoElement(element, BEFORE);
}

void RenderTreeUpdater::GeneratedContent::updateAfterPseudoElement(Element& element)
{
updatePseudoElement(element, AFTER);
}

void RenderTreeUpdater::GeneratedContent::updateRemainingQuotes()
{
if (!m_updater.renderView().hasQuotesNeedingUpdate())
@@ -102,14 +92,14 @@ static void updateStyleForContentRenderers(RenderElement& renderer)
}
}

void RenderTreeUpdater::GeneratedContent::updatePseudoElement(Element& current, PseudoId pseudoId)
void RenderTreeUpdater::GeneratedContent::updatePseudoElement(Element& current, const std::optional<Style::ElementUpdate>& update, PseudoId pseudoId)
{
PseudoElement* pseudoElement = pseudoId == BEFORE ? current.beforePseudoElement() : current.afterPseudoElement();

if (auto* renderer = pseudoElement ? pseudoElement->renderer() : nullptr)
m_updater.renderTreePosition().invalidateNextSibling(*renderer);

if (!needsPseudoElement(current, pseudoId)) {
if (!needsPseudoElement(current, update)) {
if (pseudoElement) {
if (pseudoId == BEFORE)
current.clearBeforePseudoElement();
@@ -125,28 +115,23 @@ void RenderTreeUpdater::GeneratedContent::updatePseudoElement(Element& current,
pseudoElement = newPseudoElement.get();
}

auto newStyle = RenderStyle::clonePtr(*current.renderer()->getCachedPseudoStyle(pseudoId, &current.renderer()->style()));

auto elementUpdate = Style::TreeResolver::createAnimatedElementUpdate(WTFMove(newStyle), *pseudoElement, Style::NoChange);

if (elementUpdate.change == Style::NoChange)
if (update->change == Style::NoChange)
return;

if (newPseudoElement) {
InspectorInstrumentation::pseudoElementCreated(m_updater.m_document.page(), *newPseudoElement);
if (pseudoId == BEFORE)
current.setBeforePseudoElement(newPseudoElement.releaseNonNull());
else
current.setAfterPseudoElement(newPseudoElement.releaseNonNull());
}

m_updater.updateElementRenderer(*pseudoElement, elementUpdate);
m_updater.updateElementRenderer(*pseudoElement, *update);

auto* pseudoRenderer = pseudoElement->renderer();
if (!pseudoRenderer)
return;

if (elementUpdate.change == Style::Detach)
if (update->change == Style::Detach)
createContentRenderers(*pseudoRenderer);
else
updateStyleForContentRenderers(*pseudoRenderer);
@@ -159,13 +144,14 @@ void RenderTreeUpdater::GeneratedContent::updatePseudoElement(Element& current,
ListItem::updateMarker(downcast<RenderListItem>(*pseudoRenderer));
}

bool RenderTreeUpdater::GeneratedContent::needsPseudoElement(Element& current, PseudoId pseudoId)
bool RenderTreeUpdater::GeneratedContent::needsPseudoElement(Element& current, const std::optional<Style::ElementUpdate>& update)
{
if (!current.renderer() || !current.renderer()->canHaveGeneratedChildren())
ASSERT(!current.isPseudoElement());
if (!update)
return false;
if (current.isPseudoElement())
if (!current.renderer() || !current.renderer()->canHaveGeneratedChildren())
return false;
if (!pseudoElementRendererIsNeeded(current.renderer()->getCachedPseudoStyle(pseudoId)))
if (!pseudoElementRendererIsNeeded(update->style.get()))
return false;
return true;
}
@@ -37,15 +37,13 @@ class RenderTreeUpdater::GeneratedContent {
public:
GeneratedContent(RenderTreeUpdater&);

void updateBeforePseudoElement(Element&);
void updateAfterPseudoElement(Element&);
void updatePseudoElement(Element&, const std::optional<Style::ElementUpdate>&, PseudoId);
void updateRemainingQuotes();

private:
void updatePseudoElement(Element&, PseudoId);
void updateQuotesUpTo(RenderQuote*);

static bool needsPseudoElement(Element&, PseudoId);
static bool needsPseudoElement(Element&, const std::optional<Style::ElementUpdate>&);

RenderTreeUpdater& m_updater;
RenderQuote* m_previousUpdatedQuote { nullptr };

0 comments on commit d92038a

Please sign in to comment.