Bug 932762, part 2 - Make SVG elements cache their Moz2D path data to speed up rendering, hit-testing, clipPath clipping, bbox calculations and animation/text along a path. r=longsonr

This commit is contained in:
Jonathan Watt 2014-10-04 12:13:30 +01:00
parent a59360db7f
commit 799ef86fc1
21 changed files with 196 additions and 58 deletions

View File

@ -180,7 +180,6 @@ DOMSVGPathSeg::IndexIsValid()
} \
AutoChangePathSegNotifier notifier(this); \
InternalItem()[1+index] = float(a##propName); \
InvalidateCachedList(); \
} else { \
mArgs[index] = float(a##propName); \
} \

View File

@ -209,10 +209,6 @@ protected:
*/
float* InternalItem();
void InvalidateCachedList() {
mList->InternalList().mCachedPath = nullptr;
}
virtual float* PtrToMemberArgs() = 0;
#ifdef DEBUG

View File

@ -383,7 +383,6 @@ DOMSVGPathSegList::InsertItemBefore(DOMSVGPathSeg& aNewItem,
domItem->ToSVGPathSegEncodedData(segAsRaw);
InternalList().mData.InsertElementsAt(internalIndex, segAsRaw, 1 + argCount);
InternalList().mCachedPath = nullptr;
mItems.InsertElementAt(aIndex, ItemProxy(domItem.get(), internalIndex));
// This MUST come after the insertion into InternalList(), or else under the
@ -440,7 +439,6 @@ DOMSVGPathSegList::ReplaceItem(DOMSVGPathSeg& aNewItem,
bool ok = !!InternalList().mData.ReplaceElementsAt(
internalIndex, 1 + oldArgCount,
segAsRaw, 1 + newArgCount);
InternalList().mCachedPath = nullptr;
if (!ok) {
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
@ -495,7 +493,6 @@ DOMSVGPathSegList::RemoveItem(uint32_t aIndex,
MaybeRemoveItemFromAnimValListAt(aIndex, argCount);
InternalList().mData.RemoveElementsAt(internalIndex, 1 + argCount);
InternalList().mCachedPath = nullptr;
mItems.RemoveElementAt(aIndex);
UpdateListIndicesFromIndex(aIndex, -(argCount + 1));

View File

@ -227,7 +227,7 @@ SVGMotionSMILAnimationFunction::
bool ok =
path.GetDistancesFromOriginToEndsOfVisibleSegments(&mPathVertices);
if (ok && mPathVertices.Length()) {
mPath = pathElem->GetPathForLengthOrPositionMeasuring();
mPath = pathElem->GetOrBuildPathForMeasuring();
}
}
}
@ -252,7 +252,7 @@ SVGMotionSMILAnimationFunction::RebuildPathAndVerticesFromPathAttr()
return;
}
mPath = path.ToPathForLengthOrPositionMeasuring();
mPath = path.BuildPathForMeasuring();
bool ok = path.GetDistancesFromOriginToEndsOfVisibleSegments(&mPathVertices);
if (!ok || !mPathVertices.Length()) {
mPath = nullptr;

View File

@ -37,7 +37,6 @@ SVGPathData::CopyFrom(const SVGPathData& rhs)
// Yes, we do want fallible alloc here
return NS_ERROR_OUT_OF_MEMORY;
}
mCachedPath = nullptr;
mData = rhs.mData;
return NS_OK;
}
@ -72,7 +71,6 @@ SVGPathData::SetValueFromString(const nsAString& aValue)
// the first error. We still return any error though so that callers know if
// there's a problem.
mCachedPath = nullptr;
nsSVGPathDataParser pathParser(aValue, this);
return pathParser.Parse() ? NS_OK : NS_ERROR_DOM_SYNTAX_ERR;
}
@ -85,7 +83,6 @@ SVGPathData::AppendSeg(uint32_t aType, ...)
if (!mData.SetLength(newLength)) {
return NS_ERROR_OUT_OF_MEMORY;
}
mCachedPath = nullptr;
mData[oldLength] = SVGPathSegUtils::EncodeType(aType);
va_list args;
@ -510,7 +507,7 @@ SVGPathData::BuildPath(PathBuilder* builder,
}
TemporaryRef<Path>
SVGPathData::ToPathForLengthOrPositionMeasuring() const
SVGPathData::BuildPathForMeasuring() const
{
// Since the path that we return will not be used for painting it doesn't
// matter what we pass to CreatePathBuilder as aFillRule. Hawever, we do want
@ -520,15 +517,11 @@ SVGPathData::ToPathForLengthOrPositionMeasuring() const
// pass as aStrokeWidth doesn't matter (since it's only used to determine the
// length of those extra little lines).
if (!mCachedPath) {
RefPtr<DrawTarget> drawTarget =
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
RefPtr<PathBuilder> builder =
drawTarget->CreatePathBuilder(FillRule::FILL_WINDING);
mCachedPath = BuildPath(builder, NS_STYLE_STROKE_LINECAP_BUTT, 0);
}
return mCachedPath;
RefPtr<DrawTarget> drawTarget =
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
RefPtr<PathBuilder> builder =
drawTarget->CreatePathBuilder(FillRule::FILL_WINDING);
return BuildPath(builder, NS_STYLE_STROKE_LINECAP_BUTT, 0);
}
static double

View File

@ -163,7 +163,7 @@ public:
* ApproximateZeroLengthSubpathSquareCaps can insert if we have square-caps.
* See the comment for that function for more info on that.
*/
TemporaryRef<Path> ToPathForLengthOrPositionMeasuring() const;
TemporaryRef<Path> BuildPathForMeasuring() const;
TemporaryRef<Path> BuildPath(PathBuilder* aBuilder,
uint8_t aCapStyle,
@ -193,7 +193,6 @@ protected:
nsresult CopyFrom(const SVGPathData& rhs);
float& operator[](uint32_t aIndex) {
mCachedPath = nullptr;
return mData[aIndex];
}
@ -202,14 +201,12 @@ protected:
* increased, in which case the list will be left unmodified.
*/
bool SetLength(uint32_t aLength) {
mCachedPath = nullptr;
return mData.SetLength(aLength);
}
nsresult SetValueFromString(const nsAString& aValue);
void Clear() {
mCachedPath = nullptr;
mData.Clear();
}
@ -223,11 +220,10 @@ protected:
nsresult AppendSeg(uint32_t aType, ...); // variable number of float args
iterator begin() { mCachedPath = nullptr; return mData.Elements(); }
iterator end() { mCachedPath = nullptr; return mData.Elements() + mData.Length(); }
iterator begin() { return mData.Elements(); }
iterator end() { return mData.Elements() + mData.Length(); }
FallibleTArray<float> mData;
mutable RefPtr<gfx::Path> mCachedPath;
};

View File

@ -70,14 +70,14 @@ SVGPathElement::PathLength()
float
SVGPathElement::GetTotalLength()
{
RefPtr<Path> flat = GetPathForLengthOrPositionMeasuring();
RefPtr<Path> flat = GetOrBuildPathForMeasuring();
return flat ? flat->ComputeLength() : 0.f;
}
already_AddRefed<nsISVGPoint>
SVGPathElement::GetPointAtLength(float distance, ErrorResult& rv)
{
RefPtr<Path> path = GetPathForLengthOrPositionMeasuring();
RefPtr<Path> path = GetOrBuildPathForMeasuring();
if (!path) {
rv.Throw(NS_ERROR_FAILURE);
return nullptr;
@ -305,9 +305,9 @@ SVGPathElement::IsAttributeMapped(const nsIAtom* name) const
}
TemporaryRef<Path>
SVGPathElement::GetPathForLengthOrPositionMeasuring()
SVGPathElement::GetOrBuildPathForMeasuring()
{
return mD.GetAnimValue().ToPathForLengthOrPositionMeasuring();
return mD.GetAnimValue().BuildPathForMeasuring();
}
//----------------------------------------------------------------------
@ -340,7 +340,7 @@ SVGPathElement::GetPathLengthScale(PathLengthScaleForType aFor)
if (mPathLength.IsExplicitlySet()) {
float authorsPathLengthEstimate = mPathLength.GetAnimValue();
if (authorsPathLengthEstimate > 0) {
RefPtr<Path> path = GetPathForLengthOrPositionMeasuring();
RefPtr<Path> path = GetOrBuildPathForMeasuring();
if (!path) {
// The path is empty or invalid so its length must be zero and
// we know that 0 / authorsPathLengthEstimate = 0.

View File

@ -57,8 +57,7 @@ public:
* ApproximateZeroLengthSubpathSquareCaps can insert if we have square-caps.
* See the comment for that function for more info on that.
*/
virtual TemporaryRef<Path>
GetPathForLengthOrPositionMeasuring() MOZ_OVERRIDE;
virtual TemporaryRef<Path> GetOrBuildPathForMeasuring() MOZ_OVERRIDE;
// nsIContent interface
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;

View File

@ -15,6 +15,7 @@
#include "nsICSSDeclaration.h"
#include "nsIDocument.h"
#include "nsIDOMMutationEvent.h"
#include "nsSVGPathGeometryElement.h"
#include "mozilla/InternalMutationEvent.h"
#include "nsError.h"
#include "nsIPresShell.h"
@ -1605,6 +1606,8 @@ nsSVGElement::DidChangeLength(uint8_t aAttrEnum,
void
nsSVGElement::DidAnimateLength(uint8_t aAttrEnum)
{
ClearAnyCachedPath();
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
@ -1850,6 +1853,8 @@ nsSVGElement::DidAnimatePointList()
NS_ABORT_IF_FALSE(GetPointListAttrName(),
"Animating non-existent path data?");
ClearAnyCachedPath();
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
@ -1885,6 +1890,8 @@ nsSVGElement::DidAnimatePathSegList()
NS_ABORT_IF_FALSE(GetPathDataAttrName(),
"Animating non-existent path data?");
ClearAnyCachedPath();
nsIFrame* frame = GetPrimaryFrame();
if (frame) {

View File

@ -33,6 +33,7 @@ class nsSVGIntegerPair;
class nsSVGLength2;
class nsSVGNumber2;
class nsSVGNumberPair;
class nsSVGPathGeometryElement;
class nsSVGString;
class nsSVGViewBox;
@ -313,6 +314,7 @@ public:
return mClassAnimAttr;
}
virtual void ClearAnyCachedPath() {}
virtual nsIDOMNode* AsDOMNode() MOZ_FINAL MOZ_OVERRIDE { return this; }
virtual bool IsTransformable() { return false; }

View File

@ -8,6 +8,7 @@
#include "gfxPlatform.h"
#include "mozilla/gfx/2D.h"
#include "nsComputedDOMStyle.h"
#include "nsSVGUtils.h"
#include "nsSVGLength2.h"
#include "SVGContentUtils.h"
@ -22,6 +23,19 @@ nsSVGPathGeometryElement::nsSVGPathGeometryElement(already_AddRefed<mozilla::dom
{
}
nsresult
nsSVGPathGeometryElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValue* aValue, bool aNotify)
{
if (mCachedPath &&
aNamespaceID == kNameSpaceID_None &&
AttributeDefinesGeometry(aName)) {
mCachedPath = nullptr;
}
return nsSVGPathGeometryElementBase::AfterSetAttr(aNamespaceID, aName,
aValue, aNotify);
}
bool
nsSVGPathGeometryElement::AttributeDefinesGeometry(const nsIAtom *aName)
{
@ -61,7 +75,30 @@ nsSVGPathGeometryElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks)
}
TemporaryRef<Path>
nsSVGPathGeometryElement::GetPathForLengthOrPositionMeasuring()
nsSVGPathGeometryElement::GetOrBuildPath(const DrawTarget& aDrawTarget,
FillRule aFillRule)
{
// We only cache the path if it matches the backend used for screen painting:
bool cacheable = aDrawTarget.GetBackendType() ==
gfxPlatform::GetPlatform()->GetContentBackend();
// Checking for and returning mCachedPath before checking the pref means
// that the pref is only live on page reload (or app restart for SVG in
// chrome). The benefit is that we avoid causing a CPU memory cache miss by
// looking at the global variable that the pref's stored in.
if (cacheable && mCachedPath) {
return mCachedPath;
}
RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder(aFillRule);
RefPtr<Path> path = BuildPath(builder);
if (cacheable && NS_SVGPathCachingEnabled()) {
mCachedPath = path;
}
return path.forget();
}
TemporaryRef<Path>
nsSVGPathGeometryElement::GetOrBuildPathForMeasuring()
{
return nullptr;
}

View File

@ -31,6 +31,7 @@ typedef mozilla::dom::SVGGraphicsElement nsSVGPathGeometryElementBase;
class nsSVGPathGeometryElement : public nsSVGPathGeometryElementBase
{
protected:
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef mozilla::gfx::FillRule FillRule;
typedef mozilla::gfx::Float Float;
typedef mozilla::gfx::Path Path;
@ -39,6 +40,17 @@ protected:
public:
explicit nsSVGPathGeometryElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValue* aValue, bool aNotify) MOZ_OVERRIDE;
/**
* Causes this element to discard any Path object that GetOrBuildPath may
* have cached.
*/
virtual void ClearAnyCachedPath() MOZ_OVERRIDE MOZ_FINAL {
mCachedPath = nullptr;
}
virtual bool AttributeDefinesGeometry(const nsIAtom *aName);
/**
@ -57,17 +69,44 @@ public:
/**
* Returns a Path that can be used to paint, hit-test or calculate bounds for
* this element. May return nullptr if there is no [valid] path. The path
* that is created may be cached and returned on subsequent calls.
*/
virtual mozilla::TemporaryRef<Path> GetOrBuildPath(const DrawTarget& aDrawTarget,
FillRule fillRule);
/**
* The same as GetOrBuildPath, but bypasses the cache (neither returns any
* previously cached Path, nor caches the Path that in does return).
* this element. May return nullptr if there is no [valid] path.
*/
virtual mozilla::TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) = 0;
virtual mozilla::TemporaryRef<Path> BuildPath(PathBuilder* aBuilder) = 0;
virtual mozilla::TemporaryRef<Path> GetPathForLengthOrPositionMeasuring();
/**
* Returns a Path that can be used to measure the length of this elements
* path, or to find the position at a given distance along it.
*
* This is currently equivalent to calling GetOrBuildPath, but it may not be
* in the future. The reason for this function to be separate from
* GetOrBuildPath is because SVGPathData::BuildPath inserts small lines into
* the path if zero length subpaths are encountered, in order to implement
* the SVG specifications requirements that zero length subpaths should
* render circles/squares if stroke-linecap is round/square, respectively.
* In principle these inserted lines could interfere with path measurement,
* so we keep callers that are looking to do measurement separate in case we
* run into problems with the inserted lines negatively affecting measuring
* for content.
*/
virtual mozilla::TemporaryRef<Path> GetOrBuildPathForMeasuring();
/**
* Returns the current computed value of the CSS property 'fill-rule' for
* this element.
*/
FillRule GetFillRule();
protected:
mutable mozilla::RefPtr<Path> mCachedPath;
};
#endif

View File

@ -0,0 +1,20 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<title>Reference for dynamic changes to fill-rule</title>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=932762 -->
<!-- for p1 -->
<rect x="50" y="100" width="150" height="50"/>
<rect x="100" y="50" width="50" height="150"/>
<!-- for p2 -->
<rect x="250" y="100" width="50" height="50"/>
<rect x="350" y="100" width="50" height="50"/>
<rect x="300" y="50" width="50" height="50"/>
<rect x="300" y="150" width="50" height="50"/>
</svg>

After

Width:  |  Height:  |  Size: 641 B

View File

@ -0,0 +1,25 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" class="reftest-wait">
<title>Testcase for dynamic changes to fill-rule</title>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=932762 -->
<script>
function doTest() {
document.getElementById("p1").removeAttribute("style");
document.getElementById("p2").setAttribute("style", "fill-rule: evenodd;");
document.documentElement.removeAttribute("class");
}
window.addEventListener("MozReftestInvalidate", doTest, false);
window.setTimeout(doTest, 4000); // fallback for running outside reftest
</script>
<path id="p1" style="fill-rule: evenodd;"
d="M100,50 l0,150 50,0 0,-100 -100,0 0,50 150,0 0,-50 -50,0 0,-50 z"/>
<path id="p2"
d="M300,50 l0,150 50,0 0,-100 -100,0 0,50 150,0 0,-50 -50,0 0,-50 z"/>
</svg>

After

Width:  |  Height:  |  Size: 921 B

View File

@ -78,6 +78,7 @@ fuzzy-if(Android,4,87) == dynamic-clipPath-01.svg pass.svg
== dynamic-feFlood-01.svg pass.svg
asserts(0-1) == dynamic-feImage-01.svg pass.svg # intermittent assertions (bug 886080)
== dynamic-fill-01.svg dynamic-fill-01-ref.svg
== dynamic-fill-rule-01.svg dynamic-fill-rule-01-ref.svg
fuzzy-if(d2d,1,10000) == dynamic-filter-contents-01a.svg dynamic-filter-contents-01-ref.svg
fuzzy-if(d2d,1,10000) == dynamic-filter-contents-01b.svg dynamic-filter-contents-01-ref.svg
== dynamic-gradient-contents-01.svg pass.svg

View File

@ -4805,7 +4805,7 @@ SVGTextFrame::GetTextPath(nsIFrame* aTextPathFrame)
nsSVGPathGeometryElement *element =
static_cast<nsSVGPathGeometryElement*>(pathFrame->GetContent());
RefPtr<Path> path = element->GetPathForLengthOrPositionMeasuring();
RefPtr<Path> path = element->GetOrBuildPathForMeasuring();
if (!path) {
return nullptr;
}

View File

@ -66,10 +66,8 @@ nsSVGClipPathFrame::ApplyClipOrPaintClipMask(nsRenderingContext* aContext,
gfx->CurrentMatrix().PreMultiply(toChildsUserSpace).NudgeToIntegers();
if (!newMatrix.IsSingular()) {
gfx->SetMatrix(newMatrix);
RefPtr<PathBuilder> builder =
gfx->GetDrawTarget()->CreatePathBuilder(
nsSVGUtils::ToFillRule(pathFrame->StyleSVG()->mClipRule));
clipPath = pathElement->BuildPath(builder);
clipPath = pathElement->GetOrBuildPath(*gfx->GetDrawTarget(),
nsSVGUtils::ToFillRule(pathFrame->StyleSVG()->mClipRule));
}
}
}

View File

@ -158,6 +158,25 @@ nsSVGPathGeometryFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
// nsDisplayOpacity display list item, so DLBI won't invalidate for us.
InvalidateFrame();
}
nsSVGPathGeometryElement* element =
static_cast<nsSVGPathGeometryElement*>(mContent);
if (aOldStyleContext->PeekStyleSVG()) {
if ((StyleSVG()->mStrokeLinecap !=
aOldStyleContext->PeekStyleSVG()->mStrokeLinecap) &&
element->Tag() == nsGkAtoms::path) {
// If the stroke-linecap changes to or from "butt" then our element
// needs to update its cached Moz2D Path, since SVGPathData::BuildPath
// decides whether or not to insert little lines into the path for zero
// length subpaths base on that property.
element->ClearAnyCachedPath();
} else if (StyleSVG()->mFillRule !=
aOldStyleContext->PeekStyleSVG()->mFillRule) {
// Moz2D Path objects are fill-rule specific.
element->ClearAnyCachedPath();
}
}
}
}
@ -288,9 +307,7 @@ nsSVGPathGeometryFrame::GetFrameForPoint(const gfxPoint& aPoint)
// so that we get more consistent/backwards compatible results?
RefPtr<DrawTarget> drawTarget =
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
RefPtr<PathBuilder> builder =
drawTarget->CreatePathBuilder(fillRule);
RefPtr<Path> path = content->BuildPath(builder);
RefPtr<Path> path = content->GetOrBuildPath(*drawTarget, fillRule);
if (!path) {
return nullptr; // no path, so we don't paint anything that can be hit
}
@ -410,6 +427,7 @@ nsSVGPathGeometryFrame::NotifySVGChanged(uint32_t aFlags)
// mRect.
if (static_cast<nsSVGPathGeometryElement*>(mContent)->GeometryDependsOnCoordCtx() ||
StyleSVG()->mStrokeWidth.HasPercent()) {
static_cast<nsSVGPathGeometryElement*>(mContent)->ClearAnyCachedPath();
nsSVGUtils::ScheduleReflowSVG(this);
}
}
@ -454,8 +472,7 @@ nsSVGPathGeometryFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
FillRule fillRule = StyleSVG()->mFillRule == NS_STYLE_FILL_RULE_NONZERO
? FillRule::FILL_WINDING : FillRule::FILL_EVEN_ODD;
RefPtr<PathBuilder> builder = tmpDT->CreatePathBuilder(fillRule);
RefPtr<Path> pathInUserSpace = element->BuildPath(builder);
RefPtr<Path> pathInUserSpace = element->GetOrBuildPath(*tmpDT, fillRule);
if (!pathInUserSpace) {
return bbox;
}
@ -463,7 +480,7 @@ nsSVGPathGeometryFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
if (aToBBoxUserspace.IsIdentity()) {
pathInBBoxSpace = pathInUserSpace;
} else {
builder =
RefPtr<PathBuilder> builder =
pathInUserSpace->TransformedCopyToBuilder(aToBBoxUserspace, fillRule);
pathInBBoxSpace = builder->Finish();
if (!pathInBBoxSpace) {
@ -663,13 +680,10 @@ nsSVGPathGeometryFrame::Render(gfxContext* aContext,
nsSVGUtils::ToFillRule(renderMode == SVGAutoRenderState::NORMAL ?
StyleSVG()->mFillRule : StyleSVG()->mClipRule);
RefPtr<PathBuilder> builder = drawTarget->CreatePathBuilder(fillRule);
if (!builder) {
return;
}
nsSVGPathGeometryElement* element =
static_cast<nsSVGPathGeometryElement*>(mContent);
RefPtr<Path> path =
static_cast<nsSVGPathGeometryElement*>(mContent)->BuildPath(builder);
RefPtr<Path> path = element->GetOrBuildPath(*drawTarget, fillRule);
if (!path) {
return;
}
@ -715,7 +729,8 @@ nsSVGPathGeometryFrame::Render(gfxContext* aContext,
gfxMatrix outerSVGToUser = userToOuterSVG;
outerSVGToUser.Invert();
aContext->Multiply(outerSVGToUser);
builder = path->TransformedCopyToBuilder(ToMatrix(userToOuterSVG), fillRule);
RefPtr<PathBuilder> builder =
path->TransformedCopyToBuilder(ToMatrix(userToOuterSVG), fillRule);
path = builder->Finish();
}
GeneralPattern strokePattern;

View File

@ -57,10 +57,17 @@ using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::gfx;
static bool sSVGPathCachingEnabled;
static bool sSVGDisplayListHitTestingEnabled;
static bool sSVGDisplayListPaintingEnabled;
static bool sSVGNewGetBBoxEnabled;
bool
NS_SVGPathCachingEnabled()
{
return sSVGPathCachingEnabled;
}
bool
NS_SVGDisplayListHitTestingEnabled()
{
@ -137,6 +144,9 @@ SVGAutoRenderState::IsPaintingToWindow(DrawTarget* aDrawTarget)
void
nsSVGUtils::Init()
{
Preferences::AddBoolVarCache(&sSVGPathCachingEnabled,
"svg.path-caching.enabled");
Preferences::AddBoolVarCache(&sSVGDisplayListHitTestingEnabled,
"svg.display-lists.hit-testing.enabled");

View File

@ -78,6 +78,7 @@ class SourceSurface;
#define SVG_HIT_TEST_CHECK_MRECT 0x04
bool NS_SVGPathCachingEnabled();
bool NS_SVGDisplayListHitTestingEnabled();
bool NS_SVGDisplayListPaintingEnabled();
bool NS_SVGNewGetBBoxEnabled();

View File

@ -2291,6 +2291,9 @@ pref("dom.ipc.plugins.unloadTimeoutSecs", 30);
pref("dom.ipc.processCount", 1);
// Enable caching of Moz2D Path objects for SVG geometry elements
pref("svg.path-caching.enabled", true);
// Enable the use of display-lists for SVG hit-testing and painting.
pref("svg.display-lists.hit-testing.enabled", true);
pref("svg.display-lists.painting.enabled", true);