Changeset 62238 in webkit


Ignore:
Timestamp:
Jul 1, 2010 1:33:13 AM (14 years ago)
Author:
Nikolas Zimmermann
Message:

2010-07-01 Nikolas Zimmermann <nzimmermann@rim.com>

Reviewed by Eric Seidel & Dirk Schulze.

Performance regression for setting content of <text> in SVG
https://bugs.webkit.org/show_bug.cgi?id=36564

Dramatically reducing the number of repaintRectInLocalCoordinates() calls needed while painting.
Do not pass the repaintRect to prepareToRenderSVGContent, only calculate it if opacity < 1 or -webkit-svg-shadow is set.
Most noticeable is that RenderSVGRoot had to visit all children, before actually painting, just to calculate the repaint rect.
And as RenderSVGRoot never carries shadow or opacity it was completly useless.

RenderSVGContainer also called repaintRectInLocalCoordinates, but the result is only needed when painting outlines, which is a rare case.
These modifications fix the performance regression and the number of repaintRectInLocalCoordinate calls for the complex example in
the bug report with 500 runs shrinks from 1.7 million calls to less than 105.000.

50 runs without the patch: ~ 520.8ms
50 runs with the patch : ~ 501.8ms

The test calls setTimeout(0) 50 times, that already accounts for the 500ms. So setting the content of a <text>
element withs clippers applied, is very cheap now.

Also remove the need to pass in a filter argument to prepareToRenderSVGContent/finishRenderSVGContent, it can easily be grabbed
of the cache - just like all other resources are handled, simplifying the code.

  • rendering/RenderPath.cpp: (WebCore::RenderPath::paint):
  • rendering/RenderSVGContainer.cpp: (WebCore::RenderSVGContainer::paint): (WebCore::RenderSVGContainer::repaintRectInLocalCoordinates):
  • rendering/RenderSVGImage.cpp: (WebCore::RenderSVGImage::paint):
  • rendering/RenderSVGRoot.cpp: (WebCore::RenderSVGRoot::paint):
  • rendering/SVGInlineFlowBox.cpp: (WebCore::SVGInlineFlowBox::paint):
  • rendering/SVGRenderSupport.cpp: (WebCore::SVGRenderSupport::prepareToRenderSVGContent): (WebCore::SVGRenderSupport::finishRenderSVGContent):
  • rendering/SVGRenderSupport.h:
  • rendering/SVGRootInlineBox.cpp: (WebCore::SVGRootInlineBox::paint):
Location:
trunk/WebCore
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r62235 r62238  
     12010-07-01  Nikolas Zimmermann  <nzimmermann@rim.com>
     2
     3        Reviewed by Eric Seidel & Dirk Schulze.
     4
     5        Performance regression for setting content of <text> in SVG
     6        https://bugs.webkit.org/show_bug.cgi?id=36564
     7
     8        Dramatically reducing the number of repaintRectInLocalCoordinates() calls needed while painting.
     9        Do not pass the repaintRect to prepareToRenderSVGContent, only calculate it if opacity < 1 or -webkit-svg-shadow is set.
     10        Most noticeable is that RenderSVGRoot had to visit all children, before actually painting, just to calculate the repaint rect.
     11        And as RenderSVGRoot never carries shadow or opacity it was completly useless.
     12
     13        RenderSVGContainer also called repaintRectInLocalCoordinates, but the result is only needed when painting outlines, which is a rare case.
     14        These modifications fix the performance regression and the number of repaintRectInLocalCoordinate calls for the complex example in
     15        the bug report with 500 runs shrinks from 1.7 million calls to less than 105.000.
     16
     17        50 runs without the patch: ~ 520.8ms
     18        50 runs with the patch   : ~ 501.8ms
     19
     20        The test calls setTimeout(0) 50 times, that already accounts for the 500ms. So setting the content of a <text>
     21        element withs clippers applied, is very cheap now.
     22
     23        Also remove the need to pass in a filter argument to prepareToRenderSVGContent/finishRenderSVGContent, it can easily be grabbed
     24        of the cache - just like all other resources are handled, simplifying the code.
     25
     26        * rendering/RenderPath.cpp:
     27        (WebCore::RenderPath::paint):
     28        * rendering/RenderSVGContainer.cpp:
     29        (WebCore::RenderSVGContainer::paint):
     30        (WebCore::RenderSVGContainer::repaintRectInLocalCoordinates):
     31        * rendering/RenderSVGImage.cpp:
     32        (WebCore::RenderSVGImage::paint):
     33        * rendering/RenderSVGRoot.cpp:
     34        (WebCore::RenderSVGRoot::paint):
     35        * rendering/SVGInlineFlowBox.cpp:
     36        (WebCore::SVGInlineFlowBox::paint):
     37        * rendering/SVGRenderSupport.cpp:
     38        (WebCore::SVGRenderSupport::prepareToRenderSVGContent):
     39        (WebCore::SVGRenderSupport::finishRenderSVGContent):
     40        * rendering/SVGRenderSupport.h:
     41        * rendering/SVGRootInlineBox.cpp:
     42        (WebCore::SVGRootInlineBox::paint):
     43
    1442010-07-01  Eric Seidel  <eric@webkit.org>
    245
  • trunk/WebCore/rendering/RenderPath.cpp

    r62118 r62238  
    3535#include "PointerEventsHitRules.h"
    3636#include "RenderSVGContainer.h"
    37 #include "RenderSVGResourceFilter.h"
    3837#include "RenderSVGResourceMarker.h"
    3938#include "StrokeStyleApplier.h"
     
    174173        childPaintInfo.context->save();
    175174        childPaintInfo.applyTransform(m_localTransform);
    176         RenderSVGResourceFilter* filter = 0;
    177175
    178176        if (childPaintInfo.phase == PaintPhaseForeground) {
    179177            PaintInfo savedInfo(childPaintInfo);
    180178
    181             if (SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter)) {
     179            if (SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo)) {
    182180                const SVGRenderStyle* svgStyle = style()->svgStyle();
    183181                if (svgStyle->shapeRendering() == SR_CRISPEDGES)
     
    190188            }
    191189
    192             SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, filter, savedInfo.context);
     190            SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, savedInfo.context);
    193191        }
    194192
  • trunk/WebCore/rendering/RenderSVGContainer.cpp

    r62118 r62238  
    8888
    8989    PaintInfo childPaintInfo(paintInfo);
    90 
    9190    childPaintInfo.context->save();
    9291
     
    9695    childPaintInfo.applyTransform(localToParentTransform());
    9796
    98     RenderSVGResourceFilter* filter = 0;
    99     FloatRect boundingBox = repaintRectInLocalCoordinates();
    100 
    10197    bool continueRendering = true;
    10298    if (childPaintInfo.phase == PaintPhaseForeground)
    103         continueRendering = SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
     99        continueRendering = SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo);
    104100
    105101    if (continueRendering) {
     
    110106
    111107    if (paintInfo.phase == PaintPhaseForeground)
    112         SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context);
     108        SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, paintInfo.context);
    113109
    114110    childPaintInfo.context->restore();
     
    119115    // FIXME: This means our focus ring won't share our rotation like it should.
    120116    // We should instead disable our clip during PaintPhaseOutline
    121     IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates()));
    122     if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE)
     117    if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) {
     118        IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates()));
    123119        paintOutline(paintInfo.context, paintRectInParent.x(), paintRectInParent.y(), paintRectInParent.width(), paintRectInParent.height());
     120    }
    124121}
    125122
     
    142139}
    143140
    144 // RenderSVGContainer is used for <g> elements which do not themselves have a
    145 // width or height, so we union all of our child rects as our repaint rect.
    146141FloatRect RenderSVGContainer::repaintRectInLocalCoordinates() const
    147142{
    148143    FloatRect repaintRect = strokeBoundingBox();
    149144    SVGRenderSupport::intersectRepaintRectWithResources(this, repaintRect);
    150 
    151145    return repaintRect;
    152146}
  • trunk/WebCore/rendering/RenderSVGImage.cpp

    r62118 r62238  
    8484
    8585    if (paintInfo.phase == PaintPhaseForeground) {
    86         RenderSVGResourceFilter* filter = 0;
    87 
    8886        PaintInfo savedInfo(paintInfo);
    8987
    90         if (SVGRenderSupport::prepareToRenderSVGContent(this, paintInfo, m_localBounds, filter)) {
     88        if (SVGRenderSupport::prepareToRenderSVGContent(this, paintInfo)) {
    9189            FloatRect destRect = m_localBounds;
    9290            FloatRect srcRect(0, 0, image()->width(), image()->height());
     
    9896            paintInfo.context->drawImage(image(), DeviceColorSpace, destRect, srcRect);
    9997        }
    100         SVGRenderSupport::finishRenderSVGContent(this, paintInfo, filter, savedInfo.context);
     98        SVGRenderSupport::finishRenderSVGContent(this, paintInfo, savedInfo.context);
    10199    }
    102100
  • trunk/WebCore/rendering/RenderSVGRoot.cpp

    r62142 r62238  
    172172    childPaintInfo.applyTransform(localToRepaintContainerTransform(parentOriginInContainer));
    173173
    174     RenderSVGResourceFilter* filter = 0;
    175     FloatRect boundingBox = repaintRectInLocalCoordinates();
    176 
    177174    bool continueRendering = true;
    178175    if (childPaintInfo.phase == PaintPhaseForeground)
    179         continueRendering = SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
     176        continueRendering = SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo);
    180177
    181178    if (continueRendering)
     
    183180
    184181    if (childPaintInfo.phase == PaintPhaseForeground)
    185         SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context);
     182        SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, paintInfo.context);
    186183
    187184    childPaintInfo.context->restore();
  • trunk/WebCore/rendering/SVGInlineFlowBox.cpp

    r62118 r62238  
    4242    childPaintInfo.context->save();
    4343
    44     RenderSVGResourceFilter* filter = 0;
    45     FloatRect repaintRect = boxRenderer->repaintRectInLocalCoordinates();
    46 
    47     if (SVGRenderSupport::prepareToRenderSVGContent(boxRenderer, childPaintInfo, repaintRect, filter)) {
     44    if (SVGRenderSupport::prepareToRenderSVGContent(boxRenderer, childPaintInfo)) {
    4845        for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
    4946            child->paint(childPaintInfo, 0, 0);
    5047    }
    5148
    52     SVGRenderSupport::finishRenderSVGContent(boxRenderer, childPaintInfo, filter, paintInfo.context);
     49    SVGRenderSupport::finishRenderSVGContent(boxRenderer, childPaintInfo, paintInfo.context);
    5350    childPaintInfo.context->restore();
    5451}
  • trunk/WebCore/rendering/SVGRenderSupport.cpp

    r62118 r62238  
    7575}
    7676
    77 bool SVGRenderSupport::prepareToRenderSVGContent(RenderObject* object, PaintInfo& paintInfo, const FloatRect& repaintRect, RenderSVGResourceFilter*& filter)
     77bool SVGRenderSupport::prepareToRenderSVGContent(RenderObject* object, PaintInfo& paintInfo)
    7878{
    7979#if !ENABLE(FILTERS)
     
    9292    ASSERT(svgStyle);
    9393
     94    FloatRect repaintRect;
     95
    9496    // Setup transparency layers before setting up SVG resources!
    95     float opacity = style->opacity();
    96     if (opacity < 1.0f) {
     97    float opacity = style->opacity();
     98    if (opacity < 1) {
     99        repaintRect = object->repaintRectInLocalCoordinates();
    97100        paintInfo.context->clip(repaintRect);
    98101        paintInfo.context->beginTransparencyLayer(opacity);
     
    100103
    101104    if (const ShadowData* shadow = svgStyle->shadow()) {
     105        // Eventually compute repaint rect, if not done so far.
     106        if (opacity >= 1)
     107            repaintRect = object->repaintRectInLocalCoordinates();
     108
    102109        paintInfo.context->clip(repaintRect);
    103110        paintInfo.context->setShadow(IntSize(shadow->x(), shadow->y()), shadow->blur(), shadow->color(), style->colorSpace());
    104         paintInfo.context->beginTransparencyLayer(1.0f);
     111        paintInfo.context->beginTransparencyLayer(1);
    105112    }
    106113
     
    113120                return false;
    114121        } else
    115             svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement);
     122            document->accessSVGExtensions()->addPendingResource(maskerId, styledElement);
    116123    }
    117124
     
    121128            clipper->applyResource(object, style, paintInfo.context, ApplyToDefaultMode);
    122129        else
    123             svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement);
     130            document->accessSVGExtensions()->addPendingResource(clipperId, styledElement);
    124131    }
    125132
     
    127134    if (svgStyle->hasFilter()) {
    128135        AtomicString filterId(svgStyle->filterResource());
    129         filter = getRenderSVGResourceById<RenderSVGResourceFilter>(document, filterId);
    130         if (filter) {
     136        if (RenderSVGResourceFilter* filter = getRenderSVGResourceById<RenderSVGResourceFilter>(document, filterId)) {
    131137            if (!filter->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
    132138                return false;
    133139        } else
    134             svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement);
     140            document->accessSVGExtensions()->addPendingResource(filterId, styledElement);
    135141    }
    136142#endif
     
    139145}
    140146
    141 void SVGRenderSupport::finishRenderSVGContent(RenderObject* object, PaintInfo& paintInfo, RenderSVGResourceFilter*& filter, GraphicsContext* savedContext)
     147void SVGRenderSupport::finishRenderSVGContent(RenderObject* object, PaintInfo& paintInfo, GraphicsContext* savedContext)
    142148{
    143149#if !ENABLE(FILTERS)
     
    151157    ASSERT(style);
    152158
     159    const SVGRenderStyle* svgStyle = style->svgStyle();
     160    ASSERT(svgStyle);
     161
    153162#if ENABLE(FILTERS)
    154     if (filter) {
    155         filter->postApplyResource(object, paintInfo.context, ApplyToDefaultMode);
    156         paintInfo.context = savedContext;
     163    if (svgStyle->hasFilter()) {
     164        AtomicString filterId(svgStyle->filterResource());
     165        if (RenderSVGResourceFilter* filter = getRenderSVGResourceById<RenderSVGResourceFilter>(object->document(), filterId)) {
     166            filter->postApplyResource(object, paintInfo.context, ApplyToDefaultMode);
     167            paintInfo.context = savedContext;
     168        }
    157169    }
    158170#endif
    159171
    160172    float opacity = style->opacity();   
    161     if (opacity < 1.0f)
     173    if (opacity < 1)
    162174        paintInfo.context->endTransparencyLayer();
    163175
    164176    // This needs to be done separately from opacity, because if both properties are set,
    165177    // then the transparency layers are nested.
    166     if (style->svgStyle()->shadow())
     178    if (svgStyle->shadow())
    167179        paintInfo.context->endTransparencyLayer();
    168180}
  • trunk/WebCore/rendering/SVGRenderSupport.h

    r62118 r62238  
    3838class RenderObject;
    3939class RenderStyle;
    40 class RenderSVGResourceFilter;
    4140class TransformState;
    4241
     
    4544public:
    4645    // Used by all SVG renderers who apply clip/filter/etc. resources to the renderer content
    47     static bool prepareToRenderSVGContent(RenderObject*, PaintInfo&, const FloatRect& boundingBox, RenderSVGResourceFilter*&);
    48     static void finishRenderSVGContent(RenderObject*, PaintInfo&, RenderSVGResourceFilter*&, GraphicsContext* savedContext);
     46    static bool prepareToRenderSVGContent(RenderObject*, PaintInfo&);
     47    static void finishRenderSVGContent(RenderObject*, PaintInfo&, GraphicsContext* savedContext);
    4948
    5049    // Shares child layouting code between RenderSVGRoot/RenderSVG(Hidden)Container
  • trunk/WebCore/rendering/SVGRootInlineBox.cpp

    r62118 r62238  
    2828#include "GraphicsContext.h"
    2929#include "RenderBlock.h"
    30 #include "RenderSVGResourceFilter.h"
    3130#include "SVGInlineFlowBox.h"
    3231#include "SVGInlineTextBox.h"
     
    5150    childPaintInfo.context->save();
    5251
    53     FloatRect repaintRect = boxRenderer->repaintRectInLocalCoordinates();
    54 
    55     RenderSVGResourceFilter* filter = 0;
    56     if (SVGRenderSupport::prepareToRenderSVGContent(boxRenderer, childPaintInfo, repaintRect, filter)) {
     52    if (SVGRenderSupport::prepareToRenderSVGContent(boxRenderer, childPaintInfo)) {
    5753        for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
    5854            child->paint(childPaintInfo, 0, 0);
    5955    }
    6056
    61     SVGRenderSupport::finishRenderSVGContent(boxRenderer, childPaintInfo, filter, paintInfo.context);
     57    SVGRenderSupport::finishRenderSVGContent(boxRenderer, childPaintInfo, paintInfo.context);
    6258    childPaintInfo.context->restore();
    6359}
Note: See TracChangeset for help on using the changeset viewer.