void RenderTreeUpdater::createRenderer(Element& element, RenderStyle&& style) { auto computeInsertionPosition = [this, &element, &style] () { #if ENABLE(CSS_REGIONS) if (element.shouldMoveToFlowThread(style)) return RenderTreePosition::insertionPositionForFlowThread(renderTreePosition().parent().element(), element, style); #endif renderTreePosition().computeNextSibling(element); return renderTreePosition(); }; if (!shouldCreateRenderer(element, renderTreePosition().parent())) return; #if ENABLE(CSS_REGIONS) // Even display: none elements need to be registered in FlowThreadController. registerElementForFlowThreadIfNeeded(element, style); #endif if (!element.rendererIsNeeded(style)) return; RenderTreePosition insertionPosition = computeInsertionPosition(); RenderElement* newRenderer = element.createElementRenderer(WTFMove(style), insertionPosition).leakPtr(); if (!newRenderer) return; if (!insertionPosition.canInsert(*newRenderer)) { newRenderer->destroy(); return; } // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail. newRenderer->setFlowThreadState(insertionPosition.parent().flowThreadState()); element.setRenderer(newRenderer); auto& initialStyle = newRenderer->style(); std::unique_ptr<RenderStyle> animatedStyle; newRenderer->animation().updateAnimations(*newRenderer, initialStyle, animatedStyle); if (animatedStyle) newRenderer->setStyleInternal(WTFMove(*animatedStyle)); newRenderer->initializeStyle(); #if ENABLE(FULLSCREEN_API) if (m_document.webkitIsFullScreen() && m_document.webkitCurrentFullScreenElement() == &element) { newRenderer = RenderFullScreen::wrapRenderer(newRenderer, &insertionPosition.parent(), m_document); if (!newRenderer) return; } #endif // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer. insertionPosition.insert(*newRenderer); if (AXObjectCache* cache = m_document.axObjectCache()) cache->updateCacheAfterNodeIsAttached(&element); }
void RenderTreeUpdater::updateTextRenderer(Text& text) { bool hasRenderer = text.renderer(); bool needsRenderer = textRendererIsNeeded(text, renderTreePosition()); if (hasRenderer) { if (needsRenderer) return; tearDownRenderer(text); invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text); return; } if (!needsRenderer) return; createTextRenderer(text, renderTreePosition()); invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text); }
void RenderTreeUpdater::updateRenderTree(ContainerNode& root) { ASSERT(root.renderer()); ASSERT(m_parentStack.isEmpty()); m_parentStack.append(Parent(root)); auto descendants = composedTreeDescendants(root); auto it = descendants.begin(); auto end = descendants.end(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=156172 it.dropAssertions(); while (it != end) { popParentsToDepth(it.depth()); auto& node = *it; if (auto* renderer = node.renderer()) renderTreePosition().invalidateNextSibling(*renderer); if (is<Text>(node)) { auto& text = downcast<Text>(node); if (parent().styleChange == Style::Detach || m_styleUpdate->textUpdate(text) || m_invalidatedWhitespaceOnlyTextSiblings.contains(&text)) updateTextRenderer(text); it.traverseNextSkippingChildren(); continue; } auto& element = downcast<Element>(node); auto* elementUpdate = m_styleUpdate->elementUpdate(element); if (!elementUpdate) { it.traverseNextSkippingChildren(); continue; } updateElementRenderer(element, *elementUpdate); bool mayHaveRenderedDescendants = element.renderer() || (element.hasDisplayContents() && shouldCreateRenderer(element, renderTreePosition().parent())); if (!mayHaveRenderedDescendants) { it.traverseNextSkippingChildren(); continue; } pushParent(element, elementUpdate ? elementUpdate->change : Style::NoChange); it.traverseNext(); } popParentsToDepth(0); m_invalidatedWhitespaceOnlyTextSiblings.clear(); }
void RenderTreeUpdater::updateBeforeOrAfterPseudoElement(Element& current, PseudoId pseudoId) { PseudoElement* pseudoElement = pseudoId == BEFORE ? current.beforePseudoElement() : current.afterPseudoElement(); if (auto* renderer = pseudoElement ? pseudoElement->renderer() : nullptr) renderTreePosition().invalidateNextSibling(*renderer); bool needsPseudoElement = WebCore::needsPseudoElement(current, pseudoId); if (!needsPseudoElement) { if (pseudoElement) { if (pseudoId == BEFORE) current.clearBeforePseudoElement(); else current.clearAfterPseudoElement(); } return; } RefPtr<PseudoElement> newPseudoElement; if (!pseudoElement) { newPseudoElement = PseudoElement::create(current, pseudoId); pseudoElement = newPseudoElement.get(); } auto newStyle = RenderStyle::clonePtr(*current.renderer()->getCachedPseudoStyle(pseudoId, ¤t.renderer()->style())); auto elementUpdate = Style::TreeResolver::createAnimatedElementUpdate(WTFMove(newStyle), *pseudoElement, Style::NoChange); if (elementUpdate.change == Style::NoChange) return; if (newPseudoElement) { InspectorInstrumentation::pseudoElementCreated(m_document.page(), *newPseudoElement); if (pseudoId == BEFORE) current.setBeforePseudoElement(newPseudoElement.releaseNonNull()); else current.setAfterPseudoElement(newPseudoElement.releaseNonNull()); } updateElementRenderer(*pseudoElement, elementUpdate); if (elementUpdate.change == Style::Detach) pseudoElement->didAttachRenderers(); else pseudoElement->didRecalcStyle(elementUpdate.change); }
void RenderTreeUpdater::updateElementRenderer(Element& element, const Style::ElementUpdate& update) { #if PLATFORM(IOS) CheckForVisibilityChange checkForVisibilityChange(element); #endif bool shouldTearDownRenderers = update.change == Style::Detach && (element.renderer() || element.isNamedFlowContentElement()); if (shouldTearDownRenderers) tearDownRenderers(element, TeardownType::KeepHoverAndActive); bool hasDisplayContents = update.style->display() == CONTENTS; if (hasDisplayContents != element.hasDisplayContents()) { element.setHasDisplayContents(hasDisplayContents); // Render tree position needs to be recomputed as rendering siblings may be found from the display:contents subtree. renderTreePosition().invalidateNextSibling(); } bool shouldCreateNewRenderer = !element.renderer() && !hasDisplayContents; if (shouldCreateNewRenderer) { if (element.hasCustomStyleResolveCallbacks()) element.willAttachRenderers(); createRenderer(element, RenderStyle::clone(*update.style)); invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(element); return; } if (!element.renderer()) return; auto& renderer = *element.renderer(); if (update.recompositeLayer) { renderer.setStyle(RenderStyle::clone(*update.style), StyleDifferenceRecompositeLayer); return; } if (update.change == Style::NoChange) { if (pseudoStyleCacheIsInvalid(&renderer, update.style.get())) { renderer.setStyle(RenderStyle::clone(*update.style), StyleDifferenceEqual); return; } return; } renderer.setStyle(RenderStyle::clone(*update.style), StyleDifferenceEqual); }
void RenderTreeUpdater::updateElementRenderer(Element& element, Style::ElementUpdate& update) { bool shouldTearDownRenderers = update.change == Style::Detach && (element.renderer() || element.isNamedFlowContentNode()); if (shouldTearDownRenderers) tearDownRenderers(element, TeardownType::KeepHoverAndActive); bool hasDisplayContest = update.style && update.style->display() == CONTENTS; if (hasDisplayContest != element.hasDisplayContents()) { element.setHasDisplayContents(hasDisplayContest); // Render tree position needs to be recomputed as rendering siblings may be found from the display:contents subtree. renderTreePosition().invalidateNextSibling(); } bool shouldCreateNewRenderer = !element.renderer() && update.style && !hasDisplayContest; if (shouldCreateNewRenderer) { if (element.hasCustomStyleResolveCallbacks()) element.willAttachRenderers(); createRenderer(element, WTFMove(*update.style)); invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(element); return; } if (!element.renderer()) return; auto& renderer = *element.renderer(); if (update.isSynthetic) { renderer.setStyle(WTFMove(*update.style), StyleDifferenceRecompositeLayer); return; } if (update.change == Style::NoChange) { if (pseudoStyleCacheIsInvalid(&renderer, update.style.get()) || (parent().styleChange == Style::Force && renderer.requiresForcedStyleRecalcPropagation())) { renderer.setStyle(WTFMove(*update.style), StyleDifferenceEqual); return; } return; } renderer.setStyle(WTFMove(*update.style), StyleDifferenceEqual); }