void SVGRenderSupport::intersectRepaintRectWithShadows(const RenderObject* object, FloatRect& repaintRect) { // Since -webkit-svg-shadow enables shadow drawing for its children, but its children // don't inherit the shadow in their SVGRenderStyle, we need to search our parents for // shadows in order to correctly compute our repaint rect. ASSERT(object); const RenderObject* currentObject = object; AffineTransform localToRootTransform; while (currentObject && rendererHasSVGShadow(currentObject)) { RenderStyle* style = currentObject->style(); if (style) { const SVGRenderStyle* svgStyle = style->svgStyle(); if (svgStyle) { if (const ShadowData* shadow = svgStyle->shadow()) shadow->adjustRectForShadow(repaintRect); } } repaintRect = currentObject->localToParentTransform().mapRect(repaintRect); localToRootTransform *= currentObject->localToParentTransform(); currentObject = currentObject->parent(); }; if (localToRootTransform.isIdentity()) return; AffineTransform rootToLocalTransform = localToRootTransform.inverse(); repaintRect = rootToLocalTransform.mapRect(repaintRect); }
void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) { bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start); bool transformChanged = transformToRootChanged(start); bool hasSVGShadow = rendererHasSVGShadow(start); bool needsBoundariesUpdate = start->needsBoundariesUpdate(); HashSet<RenderObject*> notlayoutedObjects; for (RenderObject* child = start->firstChildSlow(); child; child = child->nextSibling()) { bool needsLayout = selfNeedsLayout; bool childEverHadLayout = child->everHadLayout(); if (needsBoundariesUpdate && hasSVGShadow) { // If we have a shadow, our shadow is baked into our children's cached boundaries, // so they need to update. child->setNeedsBoundariesUpdate(); needsLayout = true; } if (transformChanged) { // If the transform changed we need to update the text metrics (note: this also happens for layoutSizeChanged=true). if (child->isSVGText()) toRenderSVGText(child)->setNeedsTextMetricsUpdate(); needsLayout = true; } if (layoutSizeChanged) { // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths if (SVGElement* element = child->node()->isSVGElement() ? toSVGElement(child->node()) : 0) { if (element->hasRelativeLengths()) { // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object if (child->isSVGShape()) toRenderSVGShape(child)->setNeedsShapeUpdate(); else if (child->isSVGText()) { toRenderSVGText(child)->setNeedsTextMetricsUpdate(); toRenderSVGText(child)->setNeedsPositioningValuesUpdate(); } needsLayout = true; } } } if (needsLayout) child->setNeedsLayout(MarkOnlyThis); if (child->needsLayout()) { toRenderElement(child)->layout(); // Renderers are responsible for repainting themselves when changing, except // for the initial paint to avoid potential double-painting caused by non-sensical "old" bounds. // We could handle this in the individual objects, but for now it's easier to have // parent containers call repaint(). (RenderBlock::layout* has similar logic.) if (!childEverHadLayout) child->repaint(); } else if (layoutSizeChanged) notlayoutedObjects.add(child); ASSERT(!child->needsLayout()); } if (!layoutSizeChanged) { ASSERT(notlayoutedObjects.isEmpty()); return; } // If the layout size changed, invalidate all resources of all children that didn't go through the layout() code path. HashSet<RenderObject*>::iterator end = notlayoutedObjects.end(); for (HashSet<RenderObject*>::iterator it = notlayoutedObjects.begin(); it != end; ++it) invalidateResourcesOfChildren(*it); }
void SVGRenderSupport::layoutChildren(RenderElement& start, bool selfNeedsLayout) { bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start); bool transformChanged = transformToRootChanged(&start); bool hasSVGShadow = rendererHasSVGShadow(start); bool needsBoundariesUpdate = start.needsBoundariesUpdate(); HashSet<RenderElement*> elementsThatDidNotReceiveLayout; for (RenderObject* child = start.firstChild(); child; child = child->nextSibling()) { bool needsLayout = selfNeedsLayout; bool childEverHadLayout = child->everHadLayout(); if (needsBoundariesUpdate && hasSVGShadow) { // If we have a shadow, our shadow is baked into our children's cached boundaries, // so they need to update. child->setNeedsBoundariesUpdate(); needsLayout = true; } if (transformChanged) { // If the transform changed we need to update the text metrics (note: this also happens for layoutSizeChanged=true). if (is<RenderSVGText>(*child)) downcast<RenderSVGText>(*child).setNeedsTextMetricsUpdate(); needsLayout = true; } if (layoutSizeChanged) { // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths if (SVGElement* element = is<SVGElement>(*child->node()) ? downcast<SVGElement>(child->node()) : nullptr) { if (element->hasRelativeLengths()) { // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object if (is<RenderSVGShape>(*child)) downcast<RenderSVGShape>(*child).setNeedsShapeUpdate(); else if (is<RenderSVGText>(*child)) { RenderSVGText& svgText = downcast<RenderSVGText>(*child); svgText.setNeedsTextMetricsUpdate(); svgText.setNeedsPositioningValuesUpdate(); } needsLayout = true; } } } if (needsLayout) child->setNeedsLayout(MarkOnlyThis); if (child->needsLayout()) { downcast<RenderElement>(*child).layout(); // Renderers are responsible for repainting themselves when changing, except // for the initial paint to avoid potential double-painting caused by non-sensical "old" bounds. // We could handle this in the individual objects, but for now it's easier to have // parent containers call repaint(). (RenderBlock::layout* has similar logic.) if (!childEverHadLayout) child->repaint(); } else if (layoutSizeChanged && is<RenderElement>(*child)) elementsThatDidNotReceiveLayout.add(downcast<RenderElement>(child)); ASSERT(!child->needsLayout()); } if (!layoutSizeChanged) { ASSERT(elementsThatDidNotReceiveLayout.isEmpty()); return; } // If the layout size changed, invalidate all resources of all children that didn't go through the layout() code path. for (auto* element : elementsThatDidNotReceiveLayout) invalidateResourcesOfChildren(*element); }