Commit 0f594757 authored by zimmermann@webkit.org's avatar zimmermann@webkit.org
Browse files

2010-04-30 Nikolas Zimmermann <nzimmermann@rim.com>

        Reviewed by Dirk Schulze.

        REGRESSION: RenderPath does not handle repaints correctly anymore if bounds changed
        https://bugs.webkit.org/show_bug.cgi?id=38385

        The last SVG performance patch broke repainting if bounds of a RenderPath get smaller.
        It would only repaint the smaller part, not the original larger bounds.

        Remove all lazy calculation of the repaint rects, instead calculate object/strokeBoundingBox and repaintRectInLocalCoordinates
        once in layout - after LayoutRepainter grabbed the initial bounds, before calling repaintAfterLayout(). We can now inline
        all these functions, and save a lot of m_path.isEmpty() checks, which are expensive. No need to store a seperated markerBoundingBox(),
        combine with strokeBoundingBox() -> save one FloatRect per RenderPath. Move strokeBoundingBox() from SVGRenderBase to RenderObject,
        right next to objectBoundingBox() - to save unnecessary toSVGRenderBase() calls. Completly remove this method.

        Overall this is a regression fix, a performance improvement and saves memory. Something for everyone.

        Tests: svg/custom/repaint-stroke-width-changes.svg

        * rendering/RenderObject.cpp: Added strokeBoundingBox() here, to avoid the toSVGRenderBase() dance.
        (WebCore::RenderObject::strokeBoundingBox):
        * rendering/RenderObject.h: Ditto.
        * rendering/RenderPath.cpp:
        (WebCore::RenderPath::RenderPath):
        (WebCore::RenderPath::layout): Fix regression, do repainting correctly, by recalculating the boundaries, if needed, instead of nulling them.
        (WebCore::RenderPath::paint): Cache SVGRenderStyle in local variable, remove no longer valid FIXME.
        (WebCore::RenderPath::calculateMarkerBoundsIfNeeded): Return a FloatRect, to avoid having to store the marker bounding box seperated.
        (WebCore::RenderPath::styleWillChange): Mark boundaries as dirty.
        (WebCore::RenderPath::updateCachedBoundaries): New function to (re-)calculate all cached boundaries, only called from layout().
        * rendering/RenderPath.h: Rename cached rect variables to have more sensible names.
        (WebCore::RenderPath::objectBoundingBox): Inlined, just returns the cached value - no more lazy creation. Huge speedup as this is hot code.
        (WebCore::RenderPath::strokeBoundingBox): Ditto.
        (WebCore::RenderPath::repaintRectInLocalCoordinates): Ditto.
        * rendering/RenderSVGBlock.h: Remove toSVGRenderBase() method.
        * rendering/RenderSVGImage.h: Ditto.
        * rendering/RenderSVGInline.cpp: No need to call toSVGRenderBase() just to get the strokeBoundingBox(). Unifies code to retrieve bounding boxes.
        (WebCore::RenderSVGInline::strokeBoundingBox):
        * rendering/RenderSVGInline.h: Remove toSVGRenderBase() method.
        * rendering/RenderSVGModelObject.h: Ditto.
        * rendering/RenderSVGResourceFilter.cpp: No need to call toSVGRenderBase() anymore, just grab the strokeBoundingBox() from the RenderObject.
        (WebCore::RenderSVGResourceFilter::applyResource):
        * rendering/RenderSVGText.h: Remove toSVGRenderBase() method.
        * rendering/SVGRenderSupport.h: Ditto. Remove markerBoundingBox() method, now combined with strokeBoundingBox().
        (WebCore::SVGRenderBase::strokeBoundingBox):
        * rendering/SVGRootInlineBox.h: Remove toSVGRenderBase() method.
        * rendering/style/SVGRenderStyle.h: Add hasMarkers() helper method, to avoid doing unnecessary work in RenderPath.
        (WebCore::SVGRenderStyle::hasMarkers):

2010-04-30  Nikolas Zimmermann  <nzimmermann@rim.com>

        Reviewed by Dirk Schulze.

        REGRESSION: RenderPath does not handle repaints correctly anymore if bounds changed
        https://bugs.webkit.org/show_bug.cgi?id=38385

        Add new test covering the repaint problem. Influences some marker results, that can be safely ignored.

        * platform/mac/svg/custom/circular-marker-reference-1-expected.txt:
        * platform/mac/svg/custom/circular-marker-reference-3-expected.txt:
        * platform/mac/svg/custom/circular-marker-reference-4-expected.txt:
        * platform/mac/svg/custom/repaint-stroke-width-changes-expected.checksum: Added.
        * platform/mac/svg/custom/repaint-stroke-width-changes-expected.png: Added.
        * platform/mac/svg/custom/repaint-stroke-width-changes-expected.txt: Added.
        * svg/custom/repaint-stroke-width-changes.svg: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@58570 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent c1b94711
2010-04-30 Nikolas Zimmermann <nzimmermann@rim.com>
Reviewed by Dirk Schulze.
REGRESSION: RenderPath does not handle repaints correctly anymore if bounds changed
https://bugs.webkit.org/show_bug.cgi?id=38385
Add new test covering the repaint problem. Influences some marker results, that can be safely ignored.
* platform/mac/svg/custom/circular-marker-reference-1-expected.txt:
* platform/mac/svg/custom/circular-marker-reference-3-expected.txt:
* platform/mac/svg/custom/circular-marker-reference-4-expected.txt:
* platform/mac/svg/custom/repaint-stroke-width-changes-expected.checksum: Added.
* platform/mac/svg/custom/repaint-stroke-width-changes-expected.png: Added.
* platform/mac/svg/custom/repaint-stroke-width-changes-expected.txt: Added.
* svg/custom/repaint-stroke-width-changes.svg: Added.
2010-04-30 Eric Uhrhane <ericu@chromium.org>
 
Reviewed by Dmitry Titov.
......
......@@ -4,5 +4,5 @@ layer at (0,0) size 800x600
RenderSVGRoot {svg} at (400,300) size 400x300
RenderSVGHiddenContainer {defs} at (0,0) size 0x0
RenderSVGResourceMarker {marker} [id="mark"] [markerUnits=strokeWidth] [ref at (4,4)] [angle=0.00]
RenderPath {path} at (280,240) size 210x60 [stroke={[type=SOLID] [color=#000000] [line cap=ROUND]}] [fill={[type=SOLID] [color=#000000]}] [start marker=mark] [middle marker=mark] [end marker=mark] [data="M-5.00,-2.00 L0.00,-2.00 L5.00,-2.00"]
RenderPath {path} at (100,240) size 480x150 [stroke={[type=SOLID] [color=#000000] [line cap=ROUND]}] [fill={[type=SOLID] [color=#000000]}] [start marker=mark] [middle marker=mark] [end marker=mark] [data="M-5.00,2.00 L0.00,2.00 L5.00,2.00"]
RenderPath {path} at (310,240) size 180x60 [stroke={[type=SOLID] [color=#000000] [line cap=ROUND]}] [fill={[type=SOLID] [color=#000000]}] [start marker=mark] [middle marker=mark] [end marker=mark] [data="M-5.00,-2.00 L0.00,-2.00 L5.00,-2.00"]
RenderPath {path} at (130,270) size 450x120 [stroke={[type=SOLID] [color=#000000] [line cap=ROUND]}] [fill={[type=SOLID] [color=#000000]}] [start marker=mark] [middle marker=mark] [end marker=mark] [data="M-5.00,2.00 L0.00,2.00 L5.00,2.00"]
......@@ -4,5 +4,5 @@ layer at (0,0) size 800x600
RenderSVGRoot {svg} at (400,300) size 400x300 [start marker=mark] [middle marker=mark] [end marker=mark]
RenderSVGHiddenContainer {defs} at (0,0) size 0x0 [start marker=mark] [middle marker=mark] [end marker=mark]
RenderSVGResourceMarker {marker} [id="mark"] [markerUnits=strokeWidth] [ref at (4,4)] [angle=0.00]
RenderPath {path} at (280,240) size 210x60 [stroke={[type=SOLID] [color=#000000] [line cap=ROUND]}] [fill={[type=SOLID] [color=#000000]}] [start marker=mark] [middle marker=mark] [end marker=mark] [data="M-5.00,-2.00 L0.00,-2.00 L5.00,-2.00"]
RenderPath {path} at (100,240) size 480x150 [stroke={[type=SOLID] [color=#000000] [line cap=ROUND]}] [fill={[type=SOLID] [color=#000000]}] [start marker=mark] [middle marker=mark] [end marker=mark] [data="M-5.00,2.00 L0.00,2.00 L5.00,2.00"]
RenderPath {path} at (310,240) size 180x60 [stroke={[type=SOLID] [color=#000000] [line cap=ROUND]}] [fill={[type=SOLID] [color=#000000]}] [start marker=mark] [middle marker=mark] [end marker=mark] [data="M-5.00,-2.00 L0.00,-2.00 L5.00,-2.00"]
RenderPath {path} at (130,270) size 450x120 [stroke={[type=SOLID] [color=#000000] [line cap=ROUND]}] [fill={[type=SOLID] [color=#000000]}] [start marker=mark] [middle marker=mark] [end marker=mark] [data="M-5.00,2.00 L0.00,2.00 L5.00,2.00"]
......@@ -3,7 +3,7 @@ layer at (0,0) size 800x600
layer at (0,0) size 800x600
RenderSVGRoot {svg} at (400,300) size 400x300
RenderSVGResourceMarker {marker} [id="mark1"] [markerUnits=strokeWidth] [ref at (4,4)] [angle=0.00]
RenderPath {path} at (280,240) size 210x60 [stroke={[type=SOLID] [color=#000000] [line cap=ROUND]}] [fill={[type=SOLID] [color=#000000]}] [start marker=mark2] [middle marker=mark2] [end marker=mark2] [data="M-5.00,-2.00 L0.00,-2.00 L5.00,-2.00"]
RenderPath {path} at (310,240) size 180x60 [stroke={[type=SOLID] [color=#000000] [line cap=ROUND]}] [fill={[type=SOLID] [color=#000000]}] [start marker=mark2] [middle marker=mark2] [end marker=mark2] [data="M-5.00,-2.00 L0.00,-2.00 L5.00,-2.00"]
RenderSVGResourceMarker {marker} [id="mark2"] [markerUnits=strokeWidth] [ref at (4,4)] [angle=0.00]
RenderPath {path} at (280,270) size 210x90 [stroke={[type=SOLID] [color=#000000] [line cap=ROUND]}] [fill={[type=SOLID] [color=#000000]}] [start marker=mark1] [middle marker=mark1] [end marker=mark1] [data="M-5.00,2.00 L0.00,2.00 L5.00,2.00"]
RenderPath {path} at (70,270) size 510x120 [stroke={[type=SOLID] [color=#000000] [line cap=ROUND]}] [fill={[type=SOLID] [color=#000000]}] [start marker=mark1] [middle marker=mark1] [end marker=mark1] [data="M-5.00,2.00 L0.00,2.00 L5.00,2.00"]
RenderPath {path} at (130,270) size 450x120 [stroke={[type=SOLID] [color=#000000] [line cap=ROUND]}] [fill={[type=SOLID] [color=#000000]}] [start marker=mark1] [middle marker=mark1] [end marker=mark1] [data="M-5.00,2.00 L0.00,2.00 L5.00,2.00"]
a62e363ff56573099de51946d98f723a
\ No newline at end of file
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
RenderSVGRoot {svg} at (0,0) size 800x600
RenderPath {rect} at (19,19) size 442x322 [stroke={[type=SOLID] [color=#FF0000]}] [data="M20.00,20.00 L460.00,20.00 L460.00,340.00 L20.00,340.00 Z"]
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewbox="0 0 480 360">
<rect x="20" y="20" width="440" height="320" stroke-width="20" fill="none" stroke="red"/>
<script>
var rect = document.getElementsByTagName('rect')[0];
rect.onclick = function() {
window.setTimeout(function() {
// Show differences, makes it easier to spot the repaint rect changes
if (window.layoutTestController)
layoutTestController.display();
rect.setAttribute("stroke-width", 1);
if (window.layoutTestController)
layoutTestController.notifyDone();
}, 0);
}
if (window.layoutTestController)
layoutTestController.waitUntilDone();
if (window.eventSender) {
eventSender.mouseMoveTo(25, 25);
eventSender.mouseDown();
eventSender.mouseUp();
}
</script>
</svg>
2010-04-30 Nikolas Zimmermann <nzimmermann@rim.com>
Reviewed by Dirk Schulze.
REGRESSION: RenderPath does not handle repaints correctly anymore if bounds changed
https://bugs.webkit.org/show_bug.cgi?id=38385
The last SVG performance patch broke repainting if bounds of a RenderPath get smaller.
It would only repaint the smaller part, not the original larger bounds.
Remove all lazy calculation of the repaint rects, instead calculate object/strokeBoundingBox and repaintRectInLocalCoordinates
once in layout - after LayoutRepainter grabbed the initial bounds, before calling repaintAfterLayout(). We can now inline
all these functions, and save a lot of m_path.isEmpty() checks, which are expensive. No need to store a seperated markerBoundingBox(),
combine with strokeBoundingBox() -> save one FloatRect per RenderPath. Move strokeBoundingBox() from SVGRenderBase to RenderObject,
right next to objectBoundingBox() - to save unnecessary toSVGRenderBase() calls. Completly remove this method.
Overall this is a regression fix, a performance improvement and saves memory. Something for everyone.
Tests: svg/custom/repaint-stroke-width-changes.svg
* rendering/RenderObject.cpp: Added strokeBoundingBox() here, to avoid the toSVGRenderBase() dance.
(WebCore::RenderObject::strokeBoundingBox):
* rendering/RenderObject.h: Ditto.
* rendering/RenderPath.cpp:
(WebCore::RenderPath::RenderPath):
(WebCore::RenderPath::layout): Fix regression, do repainting correctly, by recalculating the boundaries, if needed, instead of nulling them.
(WebCore::RenderPath::paint): Cache SVGRenderStyle in local variable, remove no longer valid FIXME.
(WebCore::RenderPath::calculateMarkerBoundsIfNeeded): Return a FloatRect, to avoid having to store the marker bounding box seperated.
(WebCore::RenderPath::styleWillChange): Mark boundaries as dirty.
(WebCore::RenderPath::updateCachedBoundaries): New function to (re-)calculate all cached boundaries, only called from layout().
* rendering/RenderPath.h: Rename cached rect variables to have more sensible names.
(WebCore::RenderPath::objectBoundingBox): Inlined, just returns the cached value - no more lazy creation. Huge speedup as this is hot code.
(WebCore::RenderPath::strokeBoundingBox): Ditto.
(WebCore::RenderPath::repaintRectInLocalCoordinates): Ditto.
* rendering/RenderSVGBlock.h: Remove toSVGRenderBase() method.
* rendering/RenderSVGImage.h: Ditto.
* rendering/RenderSVGInline.cpp: No need to call toSVGRenderBase() just to get the strokeBoundingBox(). Unifies code to retrieve bounding boxes.
(WebCore::RenderSVGInline::strokeBoundingBox):
* rendering/RenderSVGInline.h: Remove toSVGRenderBase() method.
* rendering/RenderSVGModelObject.h: Ditto.
* rendering/RenderSVGResourceFilter.cpp: No need to call toSVGRenderBase() anymore, just grab the strokeBoundingBox() from the RenderObject.
(WebCore::RenderSVGResourceFilter::applyResource):
* rendering/RenderSVGText.h: Remove toSVGRenderBase() method.
* rendering/SVGRenderSupport.h: Ditto. Remove markerBoundingBox() method, now combined with strokeBoundingBox().
(WebCore::SVGRenderBase::strokeBoundingBox):
* rendering/SVGRootInlineBox.h: Remove toSVGRenderBase() method.
* rendering/style/SVGRenderStyle.h: Add hasMarkers() helper method, to avoid doing unnecessary work in RenderPath.
(WebCore::SVGRenderStyle::hasMarkers):
2010-04-30 Eric Uhrhane <ericu@chromium.org>
 
Reviewed by Dmitry Titov.
......@@ -2491,19 +2491,19 @@ VisiblePosition RenderObject::createVisiblePosition(const Position& position)
}
#if ENABLE(SVG)
const SVGRenderBase* RenderObject::toSVGRenderBase() const
RenderSVGResourceContainer* RenderObject::toRenderSVGResourceContainer()
{
ASSERT_NOT_REACHED();
return 0;
}
RenderSVGResourceContainer* RenderObject::toRenderSVGResourceContainer()
FloatRect RenderObject::objectBoundingBox() const
{
ASSERT_NOT_REACHED();
return 0;
return FloatRect();
}
FloatRect RenderObject::objectBoundingBox() const
FloatRect RenderObject::strokeBoundingBox() const
{
ASSERT_NOT_REACHED();
return FloatRect();
......
......@@ -55,7 +55,6 @@ class TransformState;
class VisiblePosition;
#if ENABLE(SVG)
class RenderSVGResourceContainer;
class SVGRenderBase;
#endif
/*
......@@ -341,7 +340,6 @@ public:
virtual bool isSVGResourceContainer() const { return false; }
virtual bool isSVGShadowTreeRootContainer() const { return false; }
virtual const SVGRenderBase* toSVGRenderBase() const;
virtual RenderSVGResourceContainer* toRenderSVGResourceContainer();
// FIXME: Those belong into a SVG specific base-class for all renderers (see above)
......@@ -357,6 +355,7 @@ public:
// objectBoundingBox is returned local coordinates.
// The name objectBoundingBox is taken from the SVG 1.1 spec.
virtual FloatRect objectBoundingBox() const;
virtual FloatRect strokeBoundingBox() const;
// Returns the smallest rectangle enclosing all of the painted content
// respecting clipping, masking, filters, opacity, stroke-width and markers
......
......@@ -65,7 +65,7 @@ private:
RenderPath::RenderPath(SVGStyledTransformableElement* node)
: RenderSVGModelObject(node)
, m_needsBoundariesUpdate(false) // default is false, as this is only used when a RenderSVGResource tells us that the boundaries need to be recached
, m_needsBoundariesUpdate(false) // default is false, the cached rects are empty from the beginning
, m_needsPathUpdate(true) // default is true, so we grab a Path object once from SVGStyledTransformableElement
, m_needsTransformUpdate(true) // default is true, so we grab a AffineTransform object once from SVGStyledTransformableElement
{
......@@ -94,77 +94,6 @@ bool RenderPath::strokeContains(const FloatPoint& point, bool requiresStroke) co
return m_path.strokeContains(&strokeStyle, point);
}
FloatRect RenderPath::objectBoundingBox() const
{
if (m_path.isEmpty())
return FloatRect();
if (m_cachedLocalFillBBox.isEmpty())
m_cachedLocalFillBBox = m_path.boundingRect();
return m_cachedLocalFillBBox;
}
FloatRect RenderPath::strokeBoundingBox() const
{
if (m_path.isEmpty())
return FloatRect();
if (!m_cachedLocalStrokeBBox.isEmpty())
return m_cachedLocalStrokeBBox;
m_cachedLocalStrokeBBox = objectBoundingBox();
if (style()->svgStyle()->hasStroke()) {
BoundingRectStrokeStyleApplier strokeStyle(this, style());
m_cachedLocalStrokeBBox.unite(m_path.strokeBoundingRect(&strokeStyle));
}
return m_cachedLocalStrokeBBox;
}
FloatRect RenderPath::markerBoundingBox() const
{
if (m_path.isEmpty())
return FloatRect();
if (m_cachedLocalMarkerBBox.isEmpty())
calculateMarkerBoundsIfNeeded();
return m_cachedLocalMarkerBBox;
}
FloatRect RenderPath::repaintRectInLocalCoordinates() const
{
if (m_path.isEmpty())
return FloatRect();
// If we already have a cached repaint rect, return that
if (!m_cachedLocalRepaintRect.isEmpty())
return m_cachedLocalRepaintRect;
// FIXME: We need to be careful here. We assume that there is no filter,
// clipper, marker or masker if the rects are empty.
FloatRect rect = filterBoundingBoxForRenderer(this);
if (!rect.isEmpty())
m_cachedLocalRepaintRect = rect;
else {
m_cachedLocalRepaintRect = strokeBoundingBox();
m_cachedLocalRepaintRect.unite(markerBoundingBox());
}
rect = clipperBoundingBoxForRenderer(this);
if (!rect.isEmpty())
m_cachedLocalRepaintRect.intersect(rect);
rect = maskerBoundingBoxForRenderer(this);
if (!rect.isEmpty())
m_cachedLocalRepaintRect.intersect(rect);
style()->svgStyle()->inflateForShadow(m_cachedLocalRepaintRect);
return m_cachedLocalRepaintRect;
}
void RenderPath::layout()
{
LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout());
......@@ -173,15 +102,11 @@ void RenderPath::layout()
// We need to update the Path object whenever the underlying SVGStyledTransformableElement uses relative values
// as the viewport size may have changed. It would be nice to optimize this to detect these changes, and only
// update when needed, even when using relative values.
if (!m_needsPathUpdate && element->hasRelativeValues())
m_needsPathUpdate = true;
bool needsUpdate = m_needsPathUpdate || m_needsTransformUpdate || m_needsBoundariesUpdate;
if (m_needsBoundariesUpdate)
m_needsBoundariesUpdate = false;
bool needsPathUpdate = m_needsPathUpdate;
if (!needsPathUpdate && element->hasRelativeValues())
needsPathUpdate = true;
if (m_needsPathUpdate) {
if (needsPathUpdate) {
m_path = element->toPathData();
m_needsPathUpdate = false;
}
......@@ -191,8 +116,12 @@ void RenderPath::layout()
m_needsTransformUpdate = false;
}
if (needsUpdate)
invalidateCachedBoundaries();
// At this point LayoutRepainter already grabbed the old bounds,
// recalculate them now so repaintAfterLayout() uses the new bounds
if (needsPathUpdate || m_needsBoundariesUpdate) {
updateCachedBoundaries();
m_needsBoundariesUpdate = false;
}
repainter.repaintAfterLayout();
setNeedsLayout(false);
......@@ -222,10 +151,7 @@ void RenderPath::paint(PaintInfo& paintInfo, int, int)
FloatRect boundingBox = repaintRectInLocalCoordinates();
FloatRect nonLocalBoundingBox = m_localTransform.mapRect(boundingBox);
// FIXME: The empty rect check is to deal with incorrect initial clip in renderSubtreeToImage
// unfortunately fixing that problem is fairly complex unless we were willing to just futz the
// rect to something "close enough"
if (!nonLocalBoundingBox.intersects(paintInfo.rect) && !paintInfo.rect.isEmpty())
if (!nonLocalBoundingBox.intersects(paintInfo.rect))
return;
PaintInfo childPaintInfo(paintInfo);
......@@ -239,13 +165,16 @@ void RenderPath::paint(PaintInfo& paintInfo, int, int)
PaintInfo savedInfo(childPaintInfo);
if (prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter)) {
if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES)
const SVGRenderStyle* svgStyle = style()->svgStyle();
if (svgStyle->shapeRendering() == SR_CRISPEDGES)
childPaintInfo.context->setShouldAntialias(false);
fillAndStrokePath(m_path, childPaintInfo.context, this);
if (static_cast<SVGStyledElement*>(node())->supportsMarkers())
if (svgStyle->hasMarkers())
m_markerLayoutInfo.drawMarkers(childPaintInfo);
}
finishRenderSVGContent(this, childPaintInfo, filter, savedInfo.context);
}
......@@ -288,20 +217,22 @@ bool RenderPath::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result,
return false;
}
void RenderPath::calculateMarkerBoundsIfNeeded() const
FloatRect RenderPath::calculateMarkerBoundsIfNeeded()
{
Document* doc = document();
SVGElement* svgElement = static_cast<SVGElement*>(node());
ASSERT(svgElement && svgElement->document());
if (!svgElement->isStyled())
return;
return FloatRect();
SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement);
if (!styledElement->supportsMarkers())
return;
return FloatRect();
const SVGRenderStyle* svgStyle = style()->svgStyle();
ASSERT(svgStyle->hasMarkers());
AtomicString startMarkerId(svgStyle->markerStartResource());
AtomicString midMarkerId(svgStyle->markerMidResource());
AtomicString endMarkerId(svgStyle->markerEndResource());
......@@ -326,24 +257,63 @@ void RenderPath::calculateMarkerBoundsIfNeeded() const
endMarker->addClient(this);
if (!startMarker && !midMarker && !endMarker)
return;
return FloatRect();
float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, svgStyle->strokeWidth(), 1.0f);
m_cachedLocalMarkerBBox = m_markerLayoutInfo.calculateBoundaries(startMarker, midMarker, endMarker, strokeWidth, m_path);
return m_markerLayoutInfo.calculateBoundaries(startMarker, midMarker, endMarker, strokeWidth, m_path);
}
void RenderPath::invalidateCachedBoundaries()
void RenderPath::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
{
m_cachedLocalRepaintRect = FloatRect();
m_cachedLocalStrokeBBox = FloatRect();
m_cachedLocalFillBBox = FloatRect();
m_cachedLocalMarkerBBox = FloatRect();
setNeedsBoundariesUpdate();
RenderSVGModelObject::styleWillChange(diff, newStyle);
}
void RenderPath::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
void RenderPath::updateCachedBoundaries()
{
invalidateCachedBoundaries();
RenderSVGModelObject::styleWillChange(diff, newStyle);
if (m_path.isEmpty()) {
m_fillBoundingBox = FloatRect();
m_strokeAndMarkerBoundingBox = FloatRect();
m_repaintBoundingBox = FloatRect();
return;
}
// Cache _unclipped_ fill bounding box, used for calculations in resources
m_fillBoundingBox = m_path.boundingRect();
// Cache _unclipped_ stroke bounding box, used for calculations in resources (includes marker boundaries)
m_strokeAndMarkerBoundingBox = m_fillBoundingBox;
const SVGRenderStyle* svgStyle = style()->svgStyle();
if (svgStyle->hasStroke()) {
BoundingRectStrokeStyleApplier strokeStyle(this, style());
m_strokeAndMarkerBoundingBox.unite(m_path.strokeBoundingRect(&strokeStyle));
}
if (svgStyle->hasMarkers()) {
FloatRect markerBounds = calculateMarkerBoundsIfNeeded();
if (!markerBounds.isEmpty())
m_strokeAndMarkerBoundingBox.unite(markerBounds);
}
// Cache smallest possible repaint rectangle
// FIXME: We need to be careful here. We assume that there is no resource, if the rect is empty.
FloatRect rect = filterBoundingBoxForRenderer(this);
if (rect.isEmpty())
m_repaintBoundingBox = m_strokeAndMarkerBoundingBox;
else
m_repaintBoundingBox = rect;
rect = clipperBoundingBoxForRenderer(this);
if (!rect.isEmpty())
m_repaintBoundingBox.intersect(rect);
rect = maskerBoundingBoxForRenderer(this);
if (!rect.isEmpty())
m_repaintBoundingBox.intersect(rect);
svgStyle->inflateForShadow(m_repaintBoundingBox);
}
}
......
......@@ -50,11 +50,9 @@ private:
bool fillContains(const FloatPoint&, bool requiresFill = true) const;
bool strokeContains(const FloatPoint&, bool requiresStroke = true) const;
virtual FloatRect objectBoundingBox() const;
virtual FloatRect strokeBoundingBox() const;
virtual FloatRect markerBoundingBox() const;
virtual FloatRect repaintRectInLocalCoordinates() const;
virtual FloatRect objectBoundingBox() const { return m_fillBoundingBox; }
virtual FloatRect strokeBoundingBox() const { return m_strokeAndMarkerBoundingBox; }
virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; }
virtual const AffineTransform& localToParentTransform() const { return m_localTransform; }
virtual bool isRenderPath() const { return true; }
......@@ -67,8 +65,8 @@ private:
virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
virtual void styleWillChange(StyleDifference, const RenderStyle*);
void calculateMarkerBoundsIfNeeded() const;
void invalidateCachedBoundaries();
FloatRect calculateMarkerBoundsIfNeeded();
void updateCachedBoundaries();
private:
virtual AffineTransform localTransform() const { return m_localTransform; }
......@@ -78,11 +76,10 @@ private:
bool m_needsTransformUpdate : 1;
mutable Path m_path;
mutable FloatRect m_cachedLocalFillBBox;
mutable FloatRect m_cachedLocalStrokeBBox;
mutable FloatRect m_cachedLocalRepaintRect;
mutable FloatRect m_cachedLocalMarkerBBox;
mutable SVGMarkerLayoutInfo m_markerLayoutInfo;
FloatRect m_fillBoundingBox;
FloatRect m_strokeAndMarkerBoundingBox;
FloatRect m_repaintBoundingBox;
SVGMarkerLayoutInfo m_markerLayoutInfo;
AffineTransform m_localTransform;
};
......
......@@ -33,8 +33,6 @@ class RenderSVGBlock : public RenderBlock, protected SVGRenderBase {
public:
RenderSVGBlock(SVGElement*);
virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
private:
virtual void setStyle(PassRefPtr<RenderStyle>);
virtual void updateBoxModelInfoFromStyle();
......
......@@ -41,7 +41,6 @@ public:
virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
private:
virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
virtual const char* renderName() const { return "RenderSVGImage"; }
virtual bool isSVGImage() const { return true; }
......
......@@ -75,14 +75,10 @@ FloatRect RenderSVGInline::objectBoundingBox() const
FloatRect RenderSVGInline::strokeBoundingBox() const
{
const RenderObject* object = findTextRootObject(this);
ASSERT(object);
const SVGRenderBase* renderer = object->toSVGRenderBase();
if (!renderer)
return FloatRect();
if (const RenderObject* object = findTextRootObject(this))
return object->strokeBoundingBox();
return renderer->strokeBoundingBox();
return FloatRect();
}
FloatRect RenderSVGInline::repaintRectInLocalCoordinates() const
......
......@@ -35,8 +35,6 @@ class RenderSVGInline : public RenderInline, protected SVGRenderBase {
public:
RenderSVGInline(Node*);
virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
virtual const char* renderName() const { return "RenderSVGInline"; }
virtual bool requiresLayer() const { return false; }
......
......@@ -49,8 +49,6 @@ class RenderSVGModelObject : public RenderObject, protected SVGRenderBase {
public:
RenderSVGModelObject(SVGStyledElement*);
virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
virtual bool requiresLayer() const { return false; }
virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
......
......@@ -161,12 +161,7 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*,
if (!filterData->builder)
return false;
const SVGRenderBase* renderer = object->toSVGRenderBase();
if (!renderer)
return false;
FloatRect paintRect = renderer->strokeBoundingBox();
paintRect.unite(renderer->markerBoundingBox());
FloatRect paintRect = object->strokeBoundingBox();
// Calculate the scale factor for the use of filterRes.
// Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion
......
......@@ -42,8 +42,6 @@ public:
private:
virtual const char* renderName() const { return "RenderSVGText"; }
virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
virtual bool isSVGText() const { return true; }
virtual const AffineTransform& localToParentTransform() const { return m_localTransform; }
......
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