static inline bool inheritColorFromParentStyleIfNeeded(RenderElement& object, bool applyToFill, Color& color) { if (color.isValid()) return true; if (!object.parent()) return false; const SVGRenderStyle& parentSVGStyle = object.parent()->style().svgStyle(); color = applyToFill ? parentSVGStyle.fillPaintColor() : parentSVGStyle.strokePaintColor(); return true; }
String RenderCounter::originalText() const { if (!m_counterNode) { RenderElement* beforeAfterContainer = parent(); while (true) { if (!beforeAfterContainer) return String(); if (!beforeAfterContainer->isAnonymous() && !beforeAfterContainer->isPseudoElement()) return String(); // RenderCounters are restricted to before and after pseudo elements PseudoId containerStyle = beforeAfterContainer->style()->styleType(); if ((containerStyle == BEFORE) || (containerStyle == AFTER)) break; beforeAfterContainer = beforeAfterContainer->parent(); } makeCounterNode(beforeAfterContainer, m_counter.identifier(), true)->addRenderer(const_cast<RenderCounter*>(this)); ASSERT(m_counterNode); } CounterNode* child = m_counterNode; int value = child->actsAsReset() ? child->value() : child->countInParent(); String text = listMarkerText(m_counter.listStyle(), value); if (!m_counter.separator().isNull()) { if (!child->actsAsReset()) child = child->parent(); while (CounterNode* parent = child->parent()) { text = listMarkerText(m_counter.listStyle(), child->countInParent()) + m_counter.separator() + text; child = parent; } } return text; }
void SVGRenderSupport::mapLocalToContainer(const RenderElement& renderer, const RenderLayerModelObject* repaintContainer, TransformState& transformState, bool* wasFixed) { transformState.applyTransform(renderer.localToParentTransform()); ASSERT(renderer.parent()); auto& parent = *renderer.parent(); // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform // to map an element from SVG viewport coordinates to CSS box coordinates. // RenderSVGRoot's mapLocalToContainer method expects CSS box coordinates. if (parent.isSVGRoot()) transformState.applyTransform(toRenderSVGRoot(parent).localToBorderBoxTransform()); MapCoordinatesFlags mode = UseTransforms; parent.mapLocalToContainer(repaintContainer, transformState, mode, wasFixed); }
bool AnimationController::updateAnimations(RenderElement& renderer, const RenderStyle& newStyle, std::unique_ptr<RenderStyle>& animatedStyle) { auto* oldStyle = renderer.hasInitializedStyle() ? &renderer.style() : nullptr; if ((!oldStyle || (!oldStyle->animations() && !oldStyle->transitions())) && (!newStyle.animations() && !newStyle.transitions())) return false; if (renderer.document().pageCacheState() != Document::NotInPageCache) return false; // Don't run transitions when printing. if (renderer.view().printing()) return false; // Fetch our current set of implicit animations from a hashtable. We then compare them // against the animations in the style and make sure we're in sync. If destination values // have changed, we reset the animation. We then do a blend to get new values and we return // a new style. // We don't support anonymous pseudo elements like :first-line or :first-letter. ASSERT(renderer.element()); CompositeAnimation& rendererAnimations = m_data->ensureCompositeAnimation(renderer); bool animationStateChanged = rendererAnimations.animate(renderer, oldStyle, newStyle, animatedStyle); if (renderer.parent() || newStyle.animations() || (oldStyle && oldStyle->animations())) { m_data->updateAnimationTimerForRenderer(renderer); #if ENABLE(REQUEST_ANIMATION_FRAME) renderer.view().frameView().scheduleAnimation(); #endif } return animationStateChanged; }
bool SVGRenderSupport::checkForSVGRepaintDuringLayout(const RenderElement& renderer) { if (!renderer.checkForRepaintDuringLayout()) return false; // When a parent container is transformed in SVG, all children will be painted automatically // so we are able to skip redundant repaint checks. auto parent = renderer.parent(); return !(parent && parent->isSVGContainer() && toRenderSVGContainer(parent)->didTransformToRootUpdate()); }
void RenderSVGRoot::addResourceForClientInvalidation(RenderSVGResourceContainer* resource) { RenderElement* svgRoot = resource->parent(); while (svgRoot && !is<RenderSVGRoot>(*svgRoot)) svgRoot = svgRoot->parent(); if (!svgRoot) return; downcast<RenderSVGRoot>(*svgRoot).m_resourcesNeedingToInvalidateClients.add(resource); }
void SVGRenderSupport::computeFloatRectForRepaint(const RenderElement& renderer, const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) { const SVGRenderStyle& svgStyle = renderer.style().svgStyle(); if (const ShadowData* shadow = svgStyle.shadow()) shadow->adjustRectForShadow(repaintRect); repaintRect.inflate(renderer.style().outlineWidth()); // Translate to coords in our parent renderer, and then call computeFloatRectForRepaint() on our parent. repaintRect = renderer.localToParentTransform().mapRect(repaintRect); renderer.parent()->computeFloatRectForRepaint(repaintContainer, repaintRect, fixed); }
void SVGRenderSupport::styleChanged(RenderElement& renderer, const RenderStyle* oldStyle) { auto parent = renderer.parent(); SVGRenderSupport::setRendererHasSVGShadow(renderer, (parent && SVGRenderSupport::rendererHasSVGShadow(*parent)) || renderer.style().svgStyle().shadow()); #if ENABLE(CSS_COMPOSITING) if (renderer.element() && renderer.element()->isSVGElement() && (!oldStyle || renderer.style().hasBlendMode() != oldStyle->hasBlendMode())) SVGRenderSupport::updateMaskedAncestorShouldIsolateBlending(renderer); #else UNUSED_PARAM(oldStyle); #endif }
PassRef<RenderStyle> AnimationController::updateAnimations(RenderElement& renderer, PassRef<RenderStyle> newStyle) { // Don't do anything if we're in the cache if (renderer.document().inPageCache()) return newStyle; RenderStyle* oldStyle = renderer.hasInitializedStyle() ? &renderer.style() : nullptr; if ((!oldStyle || (!oldStyle->animations() && !oldStyle->transitions())) && (!newStyle.get().animations() && !newStyle.get().transitions())) return newStyle; // Don't run transitions when printing. if (renderer.view().printing()) return newStyle; // Fetch our current set of implicit animations from a hashtable. We then compare them // against the animations in the style and make sure we're in sync. If destination values // have changed, we reset the animation. We then do a blend to get new values and we return // a new style. // We don't support anonymous pseudo elements like :first-line or :first-letter. ASSERT(renderer.element()); Ref<RenderStyle> newStyleBeforeAnimation(std::move(newStyle)); CompositeAnimation& rendererAnimations = m_data->ensureCompositeAnimation(&renderer); auto blendedStyle = rendererAnimations.animate(renderer, oldStyle, newStyleBeforeAnimation.get()); if (renderer.parent() || newStyleBeforeAnimation->animations() || (oldStyle && oldStyle->animations())) { m_data->updateAnimationTimerForRenderer(&renderer); #if ENABLE(REQUEST_ANIMATION_FRAME) renderer.view().frameView().scheduleAnimation(); #endif } if (&blendedStyle.get() != &newStyleBeforeAnimation.get()) { // If the animations/transitions change opacity or transform, we need to update // the style to impose the stacking rules. Note that this is also // done in StyleResolver::adjustRenderStyle(). if (blendedStyle.get().hasAutoZIndex() && (blendedStyle.get().opacity() < 1.0f || blendedStyle.get().hasTransform())) blendedStyle.get().setZIndex(0); } return blendedStyle; }
void SVGResourcesCache::clientStyleChanged(RenderElement& renderer, StyleDifference diff, const RenderStyle& newStyle) { if (diff == StyleDifferenceEqual || !renderer.parent()) return; // In this case the proper SVGFE*Element will decide whether the modified CSS properties require a relayout or repaint. if (renderer.isSVGResourceFilterPrimitive() && (diff == StyleDifferenceRepaint || diff == StyleDifferenceRepaintIfTextOrBorderOrOutline)) return; // Dynamic changes of CSS properties like 'clip-path' may require us to recompute the associated resources for a renderer. // FIXME: Avoid passing in a useless StyleDifference, but instead compare oldStyle/newStyle to see which resources changed // to be able to selectively rebuild individual resources, instead of all of them. if (rendererCanHaveResources(renderer)) { SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); cache->removeResourcesFromRenderer(renderer); cache->addResourcesFromRenderer(renderer, newStyle); } RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false); if (renderer.element() && !renderer.element()->isSVGElement()) renderer.element()->setNeedsStyleRecalc(SyntheticStyleChange); }
void TextAutoSizingValue::reset() { HashSet<RefPtr<Node> >::iterator end = m_autoSizedNodes.end(); for (HashSet<RefPtr<Node> >::iterator i = m_autoSizedNodes.begin(); i != end; ++i) { const RefPtr<Node>& autoSizingNode = *i; RenderText* text = static_cast<RenderText*>(autoSizingNode->renderer()); if (!text) continue; // Reset the font size back to the original specified size FontDescription fontDescription = text->style().fontDescription(); float originalSize = fontDescription.specifiedSize(); if (fontDescription.computedSize() != originalSize) { fontDescription.setComputedSize(originalSize); RefPtr<RenderStyle> style = cloneRenderStyleWithState(text->style()); style->setFontDescription(fontDescription); style->font().update(autoSizingNode->document().ensureStyleResolver().fontSelector()); text->parent()->setStyle(style.releaseNonNull()); } // Reset the line height of the parent. RenderElement* parentRenderer = text->parent(); if (!parentRenderer) continue; if (parentRenderer->isAnonymousBlock()) parentRenderer = parentRenderer->parent(); const RenderStyle& parentStyle = parentRenderer->style(); Length originalLineHeight = parentStyle.specifiedLineHeight(); if (originalLineHeight != parentStyle.lineHeight()) { RefPtr<RenderStyle> newParentStyle = cloneRenderStyleWithState(parentStyle); newParentStyle->setLineHeight(originalLineHeight); newParentStyle->setFontDescription(fontDescription); newParentStyle->font().update(autoSizingNode->document().ensureStyleResolver().fontSelector()); parentRenderer->setStyle(newParentStyle.releaseNonNull()); } } }
void SVGRenderSupport::styleChanged(RenderElement& renderer) { auto parent = renderer.parent(); SVGRenderSupport::setRendererHasSVGShadow(renderer, (parent && SVGRenderSupport::rendererHasSVGShadow(*parent)) || renderer.style().svgStyle().shadow()); }
void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild) { // Insert :before and :after content before/after the RenderRubyRun(s) if (child->isBeforeContent()) { if (child->isInline()) { // Add generated inline content normally RenderBlockFlow::addChild(child, firstChild()); } else { // Wrap non-inline content with an anonymous inline-block. RenderBlock* beforeBlock = rubyBeforeBlock(this); if (!beforeBlock) { beforeBlock = createAnonymousRubyInlineBlock(*this); RenderBlockFlow::addChild(beforeBlock, firstChild()); } beforeBlock->addChild(child); } return; } if (child->isAfterContent()) { if (child->isInline()) { // Add generated inline content normally RenderBlockFlow::addChild(child); } else { // Wrap non-inline content with an anonymous inline-block. RenderBlock* afterBlock = rubyAfterBlock(this); if (!afterBlock) { afterBlock = createAnonymousRubyInlineBlock(*this); RenderBlockFlow::addChild(afterBlock); } afterBlock->addChild(child); } return; } // If the child is a ruby run, just add it normally. if (child->isRubyRun()) { RenderBlockFlow::addChild(child, beforeChild); return; } if (beforeChild && !isAfterContent(beforeChild)) { // insert child into run ASSERT(!beforeChild->isRubyRun()); RenderElement* run = beforeChild->parent(); while (run && !run->isRubyRun()) run = run->parent(); if (run) { run->addChild(child, beforeChild); return; } ASSERT_NOT_REACHED(); // beforeChild should always have a run as parent! // Emergency fallback: fall through and just append. } // If the new child would be appended, try to add the child to the previous run // if possible, or create a new run otherwise. // (The RenderRubyRun object will handle the details) RenderRubyRun* lastRun = lastRubyRun(this); if (!lastRun || lastRun->hasRubyText()) { lastRun = RenderRubyRun::staticCreateRubyRun(this); RenderBlockFlow::addChild(lastRun, beforeChild); } lastRun->addChild(child); }
bool TextAutoSizingValue::adjustNodeSizes() { bool objectsRemoved = false; // Remove stale nodes. Nodes may have had their renderers detached. We'll // also need to remove the style from the documents m_textAutoSizedNodes // collection. Return true indicates we need to do that removal. Vector<RefPtr<Node> > nodesForRemoval; HashSet<RefPtr<Node> >::iterator end = m_autoSizedNodes.end(); for (HashSet<RefPtr<Node> >::iterator i = m_autoSizedNodes.begin(); i != end; ++i) { RefPtr<Node> autoSizingNode = *i; RenderText* text = static_cast<RenderText*>(autoSizingNode->renderer()); if (!text || !text->style().textSizeAdjust().isAuto() || !text->candidateComputedTextSize()) { // remove node. nodesForRemoval.append(autoSizingNode); objectsRemoved = true; } } unsigned count = nodesForRemoval.size(); for (unsigned i = 0; i < count; i++) m_autoSizedNodes.remove(nodesForRemoval[i]); // If we only have one piece of text with the style on the page don't // adjust it's size. if (m_autoSizedNodes.size() <= 1) return objectsRemoved; // Compute average size float cumulativeSize = 0; end = m_autoSizedNodes.end(); for (HashSet<RefPtr<Node> >::iterator i = m_autoSizedNodes.begin(); i != end; ++i) { RefPtr<Node> autoSizingNode = *i; RenderText* renderText = static_cast<RenderText*>(autoSizingNode->renderer()); cumulativeSize += renderText->candidateComputedTextSize(); } float averageSize = roundf(cumulativeSize / m_autoSizedNodes.size()); // Adjust sizes bool firstPass = true; end = m_autoSizedNodes.end(); for (HashSet<RefPtr<Node> >::iterator i = m_autoSizedNodes.begin(); i != end; ++i) { const RefPtr<Node>& autoSizingNode = *i; RenderText* text = static_cast<RenderText*>(autoSizingNode->renderer()); if (text && text->style().fontDescription().computedSize() != averageSize) { float specifiedSize = text->style().fontDescription().specifiedSize(); float scaleChange = averageSize / specifiedSize; if (scaleChange > MAX_SCALE_INCREASE && firstPass) { firstPass = false; averageSize = roundf(specifiedSize * MAX_SCALE_INCREASE); scaleChange = averageSize / specifiedSize; } RefPtr<RenderStyle> style = cloneRenderStyleWithState(text->style()); FontDescription fontDescription = style->fontDescription(); fontDescription.setComputedSize(averageSize); style->setFontDescription(fontDescription); style->font().update(autoSizingNode->document().ensureStyleResolver().fontSelector()); text->parent()->setStyle(style.releaseNonNull()); RenderElement* parentRenderer = text->parent(); if (parentRenderer->isAnonymousBlock()) parentRenderer = parentRenderer->parent(); // If we have a list we should resize ListMarkers separately. RenderObject* listMarkerRenderer = parentRenderer->firstChild(); if (listMarkerRenderer->isListMarker()) { RefPtr<RenderStyle> style = cloneRenderStyleWithState(listMarkerRenderer->style()); style->setFontDescription(fontDescription); style->font().update(autoSizingNode->document().ensureStyleResolver().fontSelector()); toRenderListMarker(*listMarkerRenderer).setStyle(style.releaseNonNull()); } // Resize the line height of the parent. const RenderStyle& parentStyle = parentRenderer->style(); Length lineHeightLength = parentStyle.specifiedLineHeight(); int specifiedLineHeight = 0; if (lineHeightLength.isPercent()) specifiedLineHeight = minimumValueForLength(lineHeightLength, fontDescription.specifiedSize()); else specifiedLineHeight = lineHeightLength.value(); int lineHeight = specifiedLineHeight * scaleChange; if (!lineHeightLength.isFixed() || lineHeightLength.value() != lineHeight) { RefPtr<RenderStyle> newParentStyle = cloneRenderStyleWithState(parentStyle); newParentStyle->setLineHeight(Length(lineHeight, Fixed)); newParentStyle->setSpecifiedLineHeight(lineHeightLength); newParentStyle->setFontDescription(fontDescription); newParentStyle->font().update(autoSizingNode->document().ensureStyleResolver().fontSelector()); parentRenderer->setStyle(newParentStyle.releaseNonNull()); } } } return objectsRemoved; }