Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(994)

Unified Diff: Source/core/rendering/svg/SVGRenderSupport.h

Issue 291243007: Make several functions in SVGRenderSupport templated for performance (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/rendering/svg/SVGInlineTextBox.cpp ('k') | Source/core/rendering/svg/SVGRenderSupport.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/rendering/svg/SVGRenderSupport.h
diff --git a/Source/core/rendering/svg/SVGRenderSupport.h b/Source/core/rendering/svg/SVGRenderSupport.h
index fc80a7ca6813593ecf026f337d92796aee22b424..641e08cb675fe573c9207ce9cc48c824a2f54c4b 100644
--- a/Source/core/rendering/svg/SVGRenderSupport.h
+++ b/Source/core/rendering/svg/SVGRenderSupport.h
@@ -25,6 +25,12 @@
#define SVGRenderSupport_h
#include "core/rendering/PaintInfo.h"
+#include "core/rendering/svg/RenderSVGRoot.h"
+#include "core/rendering/svg/RenderSVGShape.h"
+#include "core/rendering/svg/RenderSVGText.h"
+#include "core/rendering/svg/RenderSVGViewportContainer.h"
+#include "core/rendering/svg/SVGResources.h"
+#include "core/rendering/svg/SVGResourcesCache.h"
namespace WebCore {
@@ -40,50 +46,189 @@ class RenderStyle;
class RenderSVGRoot;
class TransformState;
-namespace SVGRenderSupport {
-// Shares child layouting code between RenderSVGRoot/RenderSVG(Hidden)Container
-void layoutChildren(RenderObject*, bool selfNeedsLayout);
-
-// Layout resources used by this node.
-void layoutResourcesIfNeeded(const RenderObject*);
-
-// Helper function determining wheter overflow is hidden
-bool isOverflowHidden(const RenderObject*);
-
-// Calculates the repaintRect in combination with filter, clipper and masker in local coordinates.
-void intersectRepaintRectWithResources(const RenderObject*, FloatRect&);
-
-// Determines whether a container needs to be laid out because it's filtered and a child is being laid out.
-bool filtersForceContainerLayout(RenderObject*);
-
-// Determines whether the passed point lies in a clipping area
-bool pointInClippingArea(RenderObject*, const FloatPoint&);
-
-void computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox);
-bool paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo&);
-
-// Important functions used by nearly all SVG renderers centralizing coordinate transformations / repaint rect calculations
-LayoutRect clippedOverflowRectForRepaint(const RenderObject*, const RenderLayerModelObject* repaintContainer);
-void computeFloatRectForRepaint(const RenderObject*, const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed);
-void mapLocalToContainer(const RenderObject*, const RenderLayerModelObject* repaintContainer, TransformState&, bool* wasFixed = 0);
-const RenderObject* pushMappingToContainer(const RenderObject*, const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&);
-bool checkForSVGRepaintDuringLayout(RenderObject*);
-
-// Shared between SVG renderers and resources.
-void applyStrokeStyleToContext(GraphicsContext*, const RenderStyle*, const RenderObject*);
-void applyStrokeStyleToStrokeData(StrokeData*, const RenderStyle*, const RenderObject*);
-
-// Determines if any ancestor's transform has changed.
-bool transformToRootChanged(RenderObject*);
-
-// FIXME: These methods do not belong here.
-const RenderSVGRoot* findTreeRootObject(const RenderObject*);
-
-// Helper method for determining if a RenderObject marked as text (isText()== true)
-// can/will be rendered as part of a <text>.
-bool isRenderableTextNode(const RenderObject*);
-
-} // namespace SVGRenderSupport
+class SVGRenderSupport {
+public:
+ // Shares child layouting code between RenderSVGRoot/RenderSVG(Hidden)Container
+ template <typename RenderObjectType>
+ static void layoutChildren(RenderObjectType*, bool selfNeedsLayout);
+
+ // Layout resources used by this node.
+ static void layoutResourcesIfNeeded(const RenderObject*);
+
+ // Helper function determining wheter overflow is hidden
+ static bool isOverflowHidden(const RenderObject*);
+
+ // Calculates the repaintRect in combination with filter, clipper and masker in local coordinates.
+ static void intersectRepaintRectWithResources(const RenderObject*, FloatRect&);
+
+ // Determines whether a container needs to be laid out because it's filtered and a child is being laid out.
+ static bool filtersForceContainerLayout(RenderObject*);
+
+ // Determines whether the passed point lies in a clipping area
+ static bool pointInClippingArea(RenderObject*, const FloatPoint&);
+
+ template <typename RenderObjectType>
+ static void computeContainerBoundingBoxes(const RenderObjectType* container, FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox);
+
+ static bool paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo&);
+
+ // Important functions used by nearly all SVG renderers centralizing coordinate transformations / repaint rect calculations
+ static LayoutRect clippedOverflowRectForRepaint(const RenderObject*, const RenderLayerModelObject* repaintContainer);
+ static void computeFloatRectForRepaint(const RenderObject*, const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed);
+ static void mapLocalToContainer(const RenderObject*, const RenderLayerModelObject* repaintContainer, TransformState&, bool* wasFixed = 0);
+ static const RenderObject* pushMappingToContainer(const RenderObject*, const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&);
+ static bool checkForSVGRepaintDuringLayout(RenderObject*);
+
+ // Shared between SVG renderers and resources.
+ static void applyStrokeStyleToContext(GraphicsContext*, const RenderStyle*, const RenderObject*);
+ static void applyStrokeStyleToStrokeData(StrokeData*, const RenderStyle*, const RenderObject*);
+
+ // Determines if any ancestor's transform has changed.
+ static bool transformToRootChanged(RenderObject*);
+
+ // FIXME: These methods do not belong here.
+ static const RenderSVGRoot* findTreeRootObject(const RenderObject*);
+
+ // Helper method for determining if a RenderObject marked as text (isText()== true)
+ // can/will be rendered as part of a <text>.
+ static bool isRenderableTextNode(const RenderObject*);
+
+private:
+ static void updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox);
+ static void invalidateResourcesOfChildren(RenderObject* start);
+ static bool layoutSizeOfNearestViewportChanged(const RenderObject* start);
+};
+
+template <typename RenderObjectType>
+void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObjectType* container, FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox)
+{
+ objectBoundingBox = FloatRect();
+ objectBoundingBoxValid = false;
+ strokeBoundingBox = FloatRect();
+
+ // When computing the strokeBoundingBox, we use the repaintRects of the container's children so that the container's stroke includes
+ // the resources applied to the children (such as clips and filters). This allows filters applied to containers to correctly bound
+ // the children, and also improves inlining of SVG content, as the stroke bound is used in that situation also.
+ for (RenderObject* current = container->firstChild(); current; current = current->nextSibling()) {
+ if (current->isSVGHiddenContainer())
+ continue;
+
+ const AffineTransform& transform = current->localToParentTransform();
+ updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current,
+ transform.mapRect(current->objectBoundingBox()));
+ strokeBoundingBox.unite(transform.mapRect(current->repaintRectInLocalCoordinates()));
+ }
+
+ repaintBoundingBox = strokeBoundingBox;
+}
+
+template <typename RenderObjectType>
+void SVGRenderSupport::layoutChildren(RenderObjectType* start, bool selfNeedsLayout)
+{
+ bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start);
+ bool transformChanged = transformToRootChanged(start);
+ HashSet<RenderObject*> notlayoutedObjects;
+
+ for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
+ bool needsLayout = selfNeedsLayout;
+ bool childEverHadLayout = child->everHadLayout();
+
+ 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;
+ }
+ }
+ }
+
+ SubtreeLayoutScope layoutScope(*child);
+ // Resource containers are nasty: they can invalidate clients outside the current SubtreeLayoutScope.
+ // Since they only care about viewport size changes (to resolve their relative lengths), we trigger
+ // their invalidation directly from SVGSVGElement::svgAttributeChange() or at a higher
+ // SubtreeLayoutScope (in RenderView::layout()).
+ if (needsLayout && !child->isSVGResourceContainer())
+ layoutScope.setNeedsLayout(child);
+
+ layoutResourcesIfNeeded(child);
+
+ if (child->needsLayout()) {
+ 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 && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled())
+ child->repaint();
+ } else if (layoutSizeChanged) {
+ notlayoutedObjects.add(child);
+ }
+ }
+
+ 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);
+}
+
+// Update a bounding box taking into account the validity of the other bounding box.
+inline void SVGRenderSupport::updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox)
+{
+ bool otherValid = other->isSVGContainer() ? toRenderSVGContainer(other)->isObjectBoundingBoxValid() : true;
+ if (!otherValid)
+ return;
+
+ if (!objectBoundingBoxValid) {
+ objectBoundingBox = otherBoundingBox;
+ objectBoundingBoxValid = true;
+ return;
+ }
+
+ objectBoundingBox.uniteEvenIfEmpty(otherBoundingBox);
+}
+
+inline void SVGRenderSupport::invalidateResourcesOfChildren(RenderObject* start)
+{
+ ASSERT(!start->needsLayout());
+ if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(start))
+ resources->removeClientFromCache(start, false);
+
+ for (RenderObject* child = start->slowFirstChild(); child; child = child->nextSibling())
+ invalidateResourcesOfChildren(child);
+}
+
+inline bool SVGRenderSupport::layoutSizeOfNearestViewportChanged(const RenderObject* start)
+{
+ while (start && !start->isSVGRoot() && !start->isSVGViewportContainer())
+ start = start->parent();
+
+ ASSERT(start);
+ ASSERT(start->isSVGRoot() || start->isSVGViewportContainer());
+ if (start->isSVGViewportContainer())
+ return toRenderSVGViewportContainer(start)->isLayoutSizeChanged();
+
+ return toRenderSVGRoot(start)->isLayoutSizeChanged();
+}
} // namespace WebCore
« no previous file with comments | « Source/core/rendering/svg/SVGInlineTextBox.cpp ('k') | Source/core/rendering/svg/SVGRenderSupport.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698