void Text::reattachIfNeeded(const AttachContext& context) { bool layoutObjectIsNeeded = false; ContainerNode* layoutParent = LayoutTreeBuilderTraversal::parent(*this); if (layoutParent) { if (LayoutObject* parentLayoutObject = layoutParent->layoutObject()) { if (textLayoutObjectIsNeeded(*parentLayoutObject->style(), *parentLayoutObject)) layoutObjectIsNeeded = true; } } if (layoutObjectIsNeeded == !!layoutObject()) return; // The following is almost the same as Node::reattach() except that we create a layoutObject only if needed. // Not calling reattach() to avoid repeated calls to Text::textLayoutObjectIsNeeded(). AttachContext reattachContext(context); reattachContext.performingReattach = true; if (styleChangeType() < NeedsReattachStyleChange) detach(reattachContext); if (layoutObjectIsNeeded) LayoutTreeBuilderForText(*this, layoutParent->layoutObject()).createLayoutObject(); CharacterData::attach(reattachContext); }
void Text::reattachIfNeeded(const AttachContext& context) { bool rendererIsNeeded = false; ContainerNode* renderingParent = NodeRenderingTraversal::parent(*this); if (renderingParent) { if (RenderObject* parentRenderer = renderingParent->renderer()) { if (textRendererIsNeeded(*parentRenderer->style(), *parentRenderer)) rendererIsNeeded = true; } } if (rendererIsNeeded == !!renderer()) return; // The following is almost the same as Node::reattach() except that we create renderer only if needed. // Not calling reattach() to avoid repeated calls to Text::textRendererIsNeeded(). AttachContext reattachContext(context); reattachContext.performingReattach = true; if (styleChangeType() < NeedsReattachStyleChange) detach(reattachContext); if (rendererIsNeeded) RenderTreeBuilderForText(*this, renderingParent->renderer()).createRenderer(); CharacterData::attach(reattachContext); }
StyleRecalcChange Element::recalcOwnStyle(StyleRecalcChange change) { ASSERT(document().inStyleRecalc()); ASSERT(!parentNode()->needsStyleRecalc()); ASSERT(change >= Inherit || needsStyleRecalc()); ASSERT(parentRenderStyle()); RefPtr<RenderStyle> oldStyle = renderStyle(); RefPtr<RenderStyle> newStyle = styleForRenderer(); StyleRecalcChange localChange = RenderStyle::stylePropagationDiff(oldStyle.get(), newStyle.get()); ASSERT(newStyle); if (localChange == Reattach) { AttachContext reattachContext; reattachContext.resolvedStyle = newStyle.get(); reattach(reattachContext); return Reattach; } ASSERT(oldStyle); if (RenderObject* renderer = this->renderer()) { if (localChange != NoChange) renderer->setStyle(newStyle.get()); } if (styleChangeType() >= SubtreeStyleChange) return Force; if (change > Inherit || localChange > Inherit) return max(localChange, change); return localChange; }
void ShadowRoot::recalcStyle(StyleRecalcChange change) { // ShadowRoot doesn't support custom callbacks. ASSERT(!hasCustomStyleCallbacks()); StyleResolverParentScope parentScope(*this); if (styleChangeType() >= SubtreeStyleChange) change = Force; if (change < Force && hasRareData() && childNeedsStyleRecalc()) checkForChildrenAdjacentRuleChanges(); // There's no style to update so just calling recalcStyle means we're updated. clearNeedsStyleRecalc(); // FIXME: This doesn't handle :hover + div properly like Element::recalcStyle does. Text* lastTextNode = 0; for (Node* child = lastChild(); child; child = child->previousSibling()) { if (child->isTextNode()) { toText(child)->recalcTextStyle(change, lastTextNode); lastTextNode = toText(child); } else if (child->isElementNode()) { if (child->shouldCallRecalcStyle(change)) toElement(child)->recalcStyle(change, lastTextNode); if (child->renderer()) lastTextNode = 0; } } clearChildNeedsStyleRecalc(); }
void SVGElement::willRecalcStyle(StyleChange change) { if (!hasSVGRareData() || styleChangeType() == SyntheticStyleChange) return; // If the style changes because of a regular property change (not induced by SMIL animations themselves) // reset the "computed style without SMIL style properties", so the base value change gets reflected. if (change > NoChange || needsStyleRecalc()) svgRareData()->setNeedsOverrideComputedStyleUpdate(); }
void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue) { if (name == HTMLNames::idAttr) updateId(oldValue, newValue); if (inActiveDocument() && styleChangeType() < SubtreeStyleChange && affectedByAttributeSelector(name.localName())) setNeedsStyleRecalc(LocalStyleChange); if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(*this, name)) recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue)); }
void Element::classAttributeChanged(const AtomicString& newClassString) { bool testShouldInvalidateStyle = inActiveDocument() && styleChangeType() < SubtreeStyleChange; ASSERT(elementData()); const SpaceSplitString oldClasses = elementData()->classNames(); elementData()->setClass(newClassString, false); const SpaceSplitString& newClasses = elementData()->classNames(); if (testShouldInvalidateStyle && classChangeNeedsStyleRecalc(oldClasses, newClasses)) setNeedsStyleRecalc(LocalStyleChange); if (!newClasses.size()) elementData()->clearClass(); }
void Element::attach(const AttachContext& context) { ASSERT(document().inStyleRecalc()); // We've already been through detach when doing an attach, but we might // need to clear any state that's been added since then. if (hasRareData() && styleChangeType() == NeedsReattachStyleChange) { ElementRareData* data = elementRareData(); data->clearComputedStyle(); } RenderTreeBuilder(this, context.resolvedStyle).createRendererForElementIfNeeded(); ContainerNode::attach(context); }
void ShadowRoot::recalcStyle(StyleRecalcChange change) { // ShadowRoot doesn't support custom callbacks. ASSERT(!hasCustomStyleCallbacks()); StyleResolverParentScope parentScope(*this); if (styleChangeType() >= SubtreeStyleChange) change = Force; // There's no style to update so just calling recalcStyle means we're updated. clearNeedsStyleRecalc(); recalcChildStyle(change); clearChildNeedsStyleRecalc(); }
void ShadowRoot::recalcStyle(StyleRecalcChange change) { if (styleChangeType() >= SubtreeStyleChange) change = Force; // There's no style to update so just calling recalcStyle means we're updated. clearNeedsStyleRecalc(); for (Node* child = lastChild(); child; child = child->previousSibling()) { if (child->isTextNode()) { toText(child)->recalcTextStyle(change); } else if (child->isElementNode()) { if (child->shouldCallRecalcStyle(change)) toElement(child)->recalcStyle(change); } } clearChildNeedsStyleRecalc(); }
void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason) { bool testShouldInvalidateStyle = inActiveDocument() && styleChangeType() < SubtreeStyleChange; if (isStyledElement() && name == HTMLNames::styleAttr) { styleAttributeChanged(newValue); } if (name == HTMLNames::idAttr) { AtomicString oldId = elementData()->idForStyleResolution(); AtomicString newId = newValue; if (newId != oldId) { elementData()->setIdForStyleResolution(newId); if (testShouldInvalidateStyle && (affectedByIdSelector(oldId) || affectedByIdSelector(newId))) setNeedsStyleRecalc(LocalStyleChange); } } else if (name == HTMLNames::classAttr) { classAttributeChanged(newValue); } }
void Element::recalcStyle(StyleChange change) { RenderStyle* currentStyle = renderStyle(); bool hasParentStyle = parentNode() ? parentNode()->renderStyle() : false; bool hasPositionalRules = changed() && currentStyle && currentStyle->childrenAffectedByPositionalRules(); bool hasDirectAdjacentRules = currentStyle && currentStyle->childrenAffectedByDirectAdjacentRules(); #if ENABLE(SVG) if (!hasParentStyle && isShadowNode() && isSVGElement()) hasParentStyle = true; #endif if ((change > NoChange || changed())) { if (hasRareData()) rareData()->resetComputedStyle(); } if (hasParentStyle && (change >= Inherit || changed())) { RefPtr<RenderStyle> newStyle = document()->styleSelector()->styleForElement(this); StyleChange ch = diff(currentStyle, newStyle.get()); if (ch == Detach || !currentStyle) { if (attached()) detach(); attach(); // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along. // attach recalulates the style for all children. No need to do it twice. setChanged(NoStyleChange); setHasChangedChild(false); return; } if (currentStyle) { // Preserve "affected by" bits that were propagated to us from descendants in the case where we didn't do a full // style change (e.g., only inline style changed). if (currentStyle->affectedByHoverRules()) newStyle->setAffectedByHoverRules(true); if (currentStyle->affectedByActiveRules()) newStyle->setAffectedByActiveRules(true); if (currentStyle->affectedByDragRules()) newStyle->setAffectedByDragRules(true); if (currentStyle->childrenAffectedByForwardPositionalRules()) newStyle->setChildrenAffectedByForwardPositionalRules(); if (currentStyle->childrenAffectedByBackwardPositionalRules()) newStyle->setChildrenAffectedByBackwardPositionalRules(); if (currentStyle->childrenAffectedByFirstChildRules()) newStyle->setChildrenAffectedByFirstChildRules(); if (currentStyle->childrenAffectedByLastChildRules()) newStyle->setChildrenAffectedByLastChildRules(); if (currentStyle->childrenAffectedByDirectAdjacentRules()) newStyle->setChildrenAffectedByDirectAdjacentRules(); } if (ch != NoChange) { setRenderStyle(newStyle); } else if (changed() && (styleChangeType() != AnimationStyleChange) && (document()->usesSiblingRules() || document()->usesDescendantRules())) { // Although no change occurred, we use the new style so that the cousin style sharing code won't get // fooled into believing this style is the same. This is only necessary if the document actually uses // sibling/descendant rules, since otherwise it isn't possible for ancestor styles to affect sharing of // descendants. if (renderer()) renderer()->setStyleInternal(newStyle.get()); else setRenderStyle(newStyle); } else if (styleChangeType() == AnimationStyleChange) setRenderStyle(newStyle); if (change != Force) { if ((document()->usesDescendantRules() || hasPositionalRules) && styleChangeType() >= FullStyleChange) change = Force; else change = ch; } } // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar. // For now we will just worry about the common case, since it's a lot trickier to get the second case right // without doing way too much re-resolution. bool forceCheckOfNextElementSibling = false; for (Node *n = firstChild(); n; n = n->nextSibling()) { bool childRulesChanged = n->changed() && n->styleChangeType() == FullStyleChange; if (forceCheckOfNextElementSibling && n->isElementNode()) n->setChanged(); if (change >= Inherit || n->isTextNode() || n->hasChangedChild() || n->changed()) n->recalcStyle(change); if (n->isElementNode()) forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules; } setChanged(NoStyleChange); setHasChangedChild(false); }