Commit ea7d5af7 authored by ch.dumez@samsung.com's avatar ch.dumez@samsung.com

Partial revert of r174548: Make several functions in SVGRenderSupport templated for performance

Partial revert of r174548: Make several functions in SVGRenderSupport templated
for performance. This is an speculative attempt to fix a crash in
WebCore::SVGRenderSupport::computeContainerBoundingBoxes<WebCore::RenderSVGRoot>().

R=pdr@chromium.org
BUG=382428

Review URL: https://codereview.chromium.org/323043005

git-svn-id: svn://svn.chromium.org/blink/trunk@175955 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent b0a73998
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "core/rendering/svg/RenderSVGResourceMarker.h" #include "core/rendering/svg/RenderSVGResourceMarker.h"
#include "core/rendering/PaintInfo.h"
#include "core/rendering/svg/RenderSVGContainer.h" #include "core/rendering/svg/RenderSVGContainer.h"
#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGRenderSupport.h"
#include "platform/graphics/GraphicsContextStateSaver.h" #include "platform/graphics/GraphicsContextStateSaver.h"
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "core/rendering/HitTestRequest.h" #include "core/rendering/HitTestRequest.h"
#include "core/rendering/HitTestResult.h" #include "core/rendering/HitTestResult.h"
#include "core/rendering/LayoutRepainter.h" #include "core/rendering/LayoutRepainter.h"
#include "core/rendering/PaintInfo.h"
#include "core/rendering/PointerEventsHitRules.h" #include "core/rendering/PointerEventsHitRules.h"
#include "core/rendering/style/ShadowList.h" #include "core/rendering/style/ShadowList.h"
#include "core/rendering/svg/RenderSVGInline.h" #include "core/rendering/svg/RenderSVGInline.h"
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "core/rendering/svg/RenderSVGViewportContainer.h" #include "core/rendering/svg/RenderSVGViewportContainer.h"
#include "SVGNames.h" #include "SVGNames.h"
#include "core/rendering/PaintInfo.h"
#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGRenderSupport.h"
#include "core/svg/SVGSVGElement.h" #include "core/svg/SVGSVGElement.h"
#include "core/svg/SVGUseElement.h" #include "core/svg/SVGUseElement.h"
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "config.h" #include "config.h"
#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGRenderSupport.h"
#include "core/rendering/PaintInfo.h"
#include "core/rendering/RenderGeometryMap.h" #include "core/rendering/RenderGeometryMap.h"
#include "core/rendering/RenderLayer.h" #include "core/rendering/RenderLayer.h"
#include "core/rendering/SubtreeLayoutScope.h" #include "core/rendering/SubtreeLayoutScope.h"
...@@ -32,6 +33,11 @@ ...@@ -32,6 +33,11 @@
#include "core/rendering/svg/RenderSVGResourceClipper.h" #include "core/rendering/svg/RenderSVGResourceClipper.h"
#include "core/rendering/svg/RenderSVGResourceFilter.h" #include "core/rendering/svg/RenderSVGResourceFilter.h"
#include "core/rendering/svg/RenderSVGResourceMasker.h" #include "core/rendering/svg/RenderSVGResourceMasker.h"
#include "core/rendering/svg/RenderSVGRoot.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"
#include "core/svg/SVGElement.h" #include "core/svg/SVGElement.h"
#include "platform/geometry/TransformState.h" #include "platform/geometry/TransformState.h"
...@@ -104,6 +110,44 @@ bool SVGRenderSupport::checkForSVGRepaintDuringLayout(RenderObject* object) ...@@ -104,6 +110,44 @@ bool SVGRenderSupport::checkForSVGRepaintDuringLayout(RenderObject* object)
return !(parent && parent->isSVGContainer() && toRenderSVGContainer(parent)->didTransformToRootUpdate()); return !(parent && parent->isSVGContainer() && toRenderSVGContainer(parent)->didTransformToRootUpdate());
} }
// 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);
}
void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* 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->slowFirstChild(); 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;
}
bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo& paintInfo) bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo& paintInfo)
{ {
return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect); return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect);
...@@ -119,6 +163,29 @@ const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderObject* st ...@@ -119,6 +163,29 @@ const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderObject* st
return toRenderSVGRoot(start); return toRenderSVGRoot(start);
} }
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();
}
bool SVGRenderSupport::transformToRootChanged(RenderObject* ancestor) bool SVGRenderSupport::transformToRootChanged(RenderObject* ancestor)
{ {
while (ancestor && !ancestor->isSVGRoot()) { while (ancestor && !ancestor->isSVGRoot()) {
...@@ -132,6 +199,74 @@ bool SVGRenderSupport::transformToRootChanged(RenderObject* ancestor) ...@@ -132,6 +199,74 @@ bool SVGRenderSupport::transformToRootChanged(RenderObject* ancestor)
return false; return false;
} }
void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout)
{
bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start);
bool transformChanged = transformToRootChanged(start);
HashSet<RenderObject*> notlayoutedObjects;
for (RenderObject* child = start->slowFirstChild(); 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);
}
void SVGRenderSupport::layoutResourcesIfNeeded(const RenderObject* object) void SVGRenderSupport::layoutResourcesIfNeeded(const RenderObject* object)
{ {
ASSERT(object); ASSERT(object);
......
...@@ -24,33 +24,28 @@ ...@@ -24,33 +24,28 @@
#ifndef SVGRenderSupport_h #ifndef SVGRenderSupport_h
#define SVGRenderSupport_h #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 { namespace WebCore {
class AffineTransform;
class FloatPoint; class FloatPoint;
class FloatRect; class FloatRect;
class GraphicsContext;
class ImageBuffer; class ImageBuffer;
class LayoutRect; class LayoutRect;
struct PaintInfo;
class RenderBoxModelObject; class RenderBoxModelObject;
class RenderGeometryMap; class RenderGeometryMap;
class RenderLayerModelObject; class RenderLayerModelObject;
class RenderObject; class RenderObject;
class RenderStyle; class RenderStyle;
class RenderSVGRoot; class RenderSVGRoot;
class StrokeData;
class TransformState; class TransformState;
class SVGRenderSupport { class SVGRenderSupport {
public: public:
// Shares child layouting code between RenderSVGRoot/RenderSVG(Hidden)Container // Shares child layouting code between RenderSVGRoot/RenderSVG(Hidden)Container
template <typename RenderObjectType> static void layoutChildren(RenderObject*, bool selfNeedsLayout);
static void layoutChildren(RenderObjectType*, bool selfNeedsLayout);
// Layout resources used by this node. // Layout resources used by this node.
static void layoutResourcesIfNeeded(const RenderObject*); static void layoutResourcesIfNeeded(const RenderObject*);
...@@ -67,8 +62,7 @@ public: ...@@ -67,8 +62,7 @@ public:
// Determines whether the passed point lies in a clipping area // Determines whether the passed point lies in a clipping area
static bool pointInClippingArea(RenderObject*, const FloatPoint&); static bool pointInClippingArea(RenderObject*, const FloatPoint&);
template <typename RenderObjectType> static void computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox);
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&); static bool paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo&);
...@@ -99,137 +93,6 @@ private: ...@@ -99,137 +93,6 @@ private:
static bool layoutSizeOfNearestViewportChanged(const 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 } // namespace WebCore
#endif // SVGRenderSupport_h #endif // SVGRenderSupport_h
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
#include "core/svg/SVGRadialGradientElement.h" #include "core/svg/SVGRadialGradientElement.h"
#include "core/svg/SVGRectElement.h" #include "core/svg/SVGRectElement.h"
#include "core/svg/SVGStopElement.h" #include "core/svg/SVGStopElement.h"
#include "platform/graphics/DashArray.h"
#include "platform/graphics/GraphicsTypes.h" #include "platform/graphics/GraphicsTypes.h"
#include <math.h> #include <math.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment