Bug 1092125 - Part 1: Add non-scaling-stroke support to nsSVGPathGeometryElement::GetGeometryBounds (except line). r=jwatt

This commit is contained in:
Tom Klein 2015-09-01 06:17:00 -04:00
parent 28b858ab4a
commit 033cb8c72b
18 changed files with 228 additions and 64 deletions

View File

@ -83,26 +83,38 @@ SVGCircleElement::GetLengthInfo()
// nsSVGPathGeometryElement methods
bool
SVGCircleElement::GetGeometryBounds(
Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aTransform)
SVGCircleElement::GetGeometryBounds(Rect* aBounds,
const StrokeOptions& aStrokeOptions,
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace)
{
float x, y, r;
GetAnimatedLengthValues(&x, &y, &r, nullptr);
if (r <= 0.f) {
// Rendering of the element is disabled
*aBounds = Rect(aTransform * Point(x, y), Size());
*aBounds = Rect(aToBoundsSpace * Point(x, y), Size());
return true;
}
if (aTransform.IsRectilinear()) {
if (aToBoundsSpace.IsRectilinear()) {
// Optimize the case where we can treat the circle as a rectangle and
// still get tight bounds.
if (aStrokeOptions.mLineWidth > 0.f) {
if (aToNonScalingStrokeSpace) {
if (aToNonScalingStrokeSpace->IsRectilinear()) {
Rect userBounds(x - r, y - r, 2 * r, 2 * r);
SVGContentUtils::RectilinearGetStrokeBounds(
userBounds, aToBoundsSpace, *aToNonScalingStrokeSpace,
aStrokeOptions.mLineWidth, aBounds);
return true;
}
return false;
}
r += aStrokeOptions.mLineWidth / 2.f;
}
Rect rect(x - r, y - r, 2 * r, 2 * r);
*aBounds = aTransform.TransformBounds(rect);
*aBounds = aToBoundsSpace.TransformBounds(rect);
return true;
}

View File

@ -32,7 +32,8 @@ public:
// nsSVGPathGeometryElement methods:
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
const Matrix& aTransform) override;
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace = nullptr) override;
virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;

View File

@ -464,6 +464,45 @@ SVGContentUtils::GetCTM(nsSVGElement *aElement, bool aScreenCTM)
return GetCTMInternal(aElement, aScreenCTM, false);
}
void
SVGContentUtils::RectilinearGetStrokeBounds(const Rect& aRect,
const Matrix& aToBoundsSpace,
const Matrix& aToNonScalingStrokeSpace,
float aStrokeWidth,
Rect* aBounds)
{
MOZ_ASSERT(aToBoundsSpace.IsRectilinear(),
"aToBoundsSpace must be rectilinear");
MOZ_ASSERT(aToNonScalingStrokeSpace.IsRectilinear(),
"aToNonScalingStrokeSpace must be rectilinear");
Matrix nonScalingToSource = aToNonScalingStrokeSpace.Inverse();
Matrix nonScalingToBounds = nonScalingToSource * aToBoundsSpace;
*aBounds = aToBoundsSpace.TransformBounds(aRect);
// Compute the amounts dx and dy that nonScalingToBounds scales a half-width
// stroke in the x and y directions, and then inflate aBounds by those amounts
// so that when aBounds is transformed back to non-scaling-stroke space
// it will map onto the correct stroked bounds.
Float dx = 0.0f;
Float dy = 0.0f;
// nonScalingToBounds is rectilinear, so either _12 and _21 are zero or _11
// and _22 are zero, and in each case the non-zero entries (from among _11,
// _12, _21, _22) simply scale the stroke width in the x and y directions.
if (FuzzyEqual(nonScalingToBounds._12, 0) &&
FuzzyEqual(nonScalingToBounds._21, 0)) {
dx = (aStrokeWidth / 2.0f) * std::abs(nonScalingToBounds._11);
dy = (aStrokeWidth / 2.0f) * std::abs(nonScalingToBounds._22);
} else {
dx = (aStrokeWidth / 2.0f) * std::abs(nonScalingToBounds._21);
dy = (aStrokeWidth / 2.0f) * std::abs(nonScalingToBounds._12);
}
aBounds->Inflate(dx, dy);
}
double
SVGContentUtils::ComputeNormalizedHypotenuse(double aWidth, double aHeight)
{

View File

@ -63,6 +63,8 @@ class SVGContentUtils
{
public:
typedef mozilla::gfx::Float Float;
typedef mozilla::gfx::Matrix Matrix;
typedef mozilla::gfx::Rect Rect;
typedef mozilla::gfx::StrokeOptions StrokeOptions;
typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio;
typedef mozilla::SVGPreserveAspectRatio SVGPreserveAspectRatio;
@ -180,7 +182,23 @@ public:
const char16_t **aParams,
uint32_t aParamsLength);
static mozilla::gfx::Matrix GetCTM(nsSVGElement *aElement, bool aScreenCTM);
static Matrix GetCTM(nsSVGElement *aElement, bool aScreenCTM);
/**
* Gets the tight bounds-space stroke bounds of the non-scaling-stroked rect
* aRect.
* @param aToBoundsSpace transforms from source space to the space aBounds
* should be computed in. Must be rectilinear.
* @param aToNonScalingStrokeSpace transforms from source
* space to the space in which non-scaling stroke should be applied.
* Must be rectilinear.
*/
static void
RectilinearGetStrokeBounds(const Rect& aRect,
const Matrix& aToBoundsSpace,
const Matrix& aToNonScalingStrokeSpace,
float aStrokeWidth,
Rect* aBounds);
/**
* Check if this is one of the SVG elements that SVG 1.1 Full says
@ -205,13 +223,13 @@ public:
/* Generate a viewbox to viewport tranformation matrix */
static mozilla::gfx::Matrix
static Matrix
GetViewBoxTransform(float aViewportWidth, float aViewportHeight,
float aViewboxX, float aViewboxY,
float aViewboxWidth, float aViewboxHeight,
const SVGAnimatedPreserveAspectRatio &aPreserveAspectRatio);
static mozilla::gfx::Matrix
static Matrix
GetViewBoxTransform(float aViewportWidth, float aViewportHeight,
float aViewboxX, float aViewboxY,
float aViewboxWidth, float aViewboxHeight,

View File

@ -94,27 +94,39 @@ SVGEllipseElement::GetLengthInfo()
// nsSVGPathGeometryElement methods
bool
SVGEllipseElement::GetGeometryBounds(
Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aTransform)
SVGEllipseElement::GetGeometryBounds(Rect* aBounds,
const StrokeOptions& aStrokeOptions,
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace)
{
float x, y, rx, ry;
GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
if (rx <= 0.f || ry <= 0.f) {
// Rendering of the element is disabled
*aBounds = Rect(aTransform * Point(x, y), Size());
*aBounds = Rect(aToBoundsSpace * Point(x, y), Size());
return true;
}
if (aTransform.IsRectilinear()) {
if (aToBoundsSpace.IsRectilinear()) {
// Optimize the case where we can treat the ellipse as a rectangle and
// still get tight bounds.
if (aStrokeOptions.mLineWidth > 0.f) {
if (aToNonScalingStrokeSpace) {
if (aToNonScalingStrokeSpace->IsRectilinear()) {
Rect userBounds(x - rx, y - ry, 2 * rx, 2 * ry);
SVGContentUtils::RectilinearGetStrokeBounds(
userBounds, aToBoundsSpace, *aToNonScalingStrokeSpace,
aStrokeOptions.mLineWidth, aBounds);
return true;
}
return false;
}
rx += aStrokeOptions.mLineWidth / 2.f;
ry += aStrokeOptions.mLineWidth / 2.f;
}
Rect rect(x - rx, y - ry, 2 * rx, 2 * ry);
*aBounds = aTransform.TransformBounds(rect);
*aBounds = aToBoundsSpace.TransformBounds(rect);
return true;
}

View File

@ -32,7 +32,8 @@ public:
// nsSVGPathGeometryElement methods:
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
const Matrix& aTransform) override;
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace = nullptr) override;
virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;

View File

@ -226,8 +226,10 @@ SVGImageElement::IsAttributeMapped(const nsIAtom* name) const
/* For the purposes of the update/invalidation logic pretend to
be a rectangle. */
bool
SVGImageElement::GetGeometryBounds(
Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aTransform)
SVGImageElement::GetGeometryBounds(Rect* aBounds,
const StrokeOptions& aStrokeOptions,
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace)
{
Rect rect;
GetAnimatedLengthValues(&rect.x, &rect.y, &rect.width,
@ -238,7 +240,7 @@ SVGImageElement::GetGeometryBounds(
rect.SetEmpty(); // Make sure width/height are zero and not negative
}
*aBounds = aTransform.TransformBounds(rect);
*aBounds = aToBoundsSpace.TransformBounds(rect);
return true;
}

View File

@ -55,7 +55,8 @@ public:
// nsSVGPathGeometryElement methods:
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
const Matrix& aTransform) override;
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace = nullptr) override;
virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
// nsSVGSVGElement methods:

View File

@ -148,27 +148,33 @@ SVGLineElement::BuildPath(PathBuilder* aBuilder)
}
bool
SVGLineElement::GetGeometryBounds(
Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aTransform)
SVGLineElement::GetGeometryBounds(Rect* aBounds,
const StrokeOptions& aStrokeOptions,
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace)
{
if (aToNonScalingStrokeSpace) {
return false;
}
float x1, y1, x2, y2;
GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
if (aStrokeOptions.mLineWidth <= 0) {
*aBounds = Rect(aTransform * Point(x1, y1), Size());
aBounds->ExpandToEnclose(aTransform * Point(x2, y2));
*aBounds = Rect(aToBoundsSpace * Point(x1, y1), Size());
aBounds->ExpandToEnclose(aToBoundsSpace * Point(x2, y2));
return true;
}
if (aStrokeOptions.mLineCap == CapStyle::ROUND) {
if (!aTransform.IsRectilinear()) {
if (!aToBoundsSpace.IsRectilinear()) {
// TODO: handle this case.
return false;
}
Rect bounds(Point(x1, y1), Size());
bounds.ExpandToEnclose(Point(x2, y2));
bounds.Inflate(aStrokeOptions.mLineWidth / 2.f);
*aBounds = aTransform.TransformBounds(bounds);
*aBounds = aToBoundsSpace.TransformBounds(bounds);
return true;
}
@ -201,9 +207,9 @@ SVGLineElement::GetGeometryBounds(
points[2] = Point(x2 + xDelta, y2 + yDelta);
points[3] = Point(x2 - xDelta, y2 - yDelta);
*aBounds = Rect(aTransform * points[0], Size());
*aBounds = Rect(aToBoundsSpace * points[0], Size());
for (uint32_t i = 1; i < 4; ++i) {
aBounds->ExpandToEnclose(aTransform * points[i]);
aBounds->ExpandToEnclose(aToBoundsSpace * points[i]);
}
return true;
}

View File

@ -40,7 +40,8 @@ public:
virtual void GetAsSimplePath(SimplePath* aSimplePath) override;
virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
const Matrix& aTransform) override;
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace = nullptr) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;

View File

@ -112,8 +112,10 @@ SVGRectElement::GetLengthInfo()
// nsSVGPathGeometryElement methods
bool
SVGRectElement::GetGeometryBounds(
Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aTransform)
SVGRectElement::GetGeometryBounds(Rect* aBounds,
const StrokeOptions& aStrokeOptions,
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace)
{
Rect rect;
Float rx, ry;
@ -124,11 +126,11 @@ SVGRectElement::GetGeometryBounds(
// Rendering of the element disabled
rect.SetEmpty(); // Make sure width/height are zero and not negative
// We still want the x/y position from 'rect'
*aBounds = aTransform.TransformBounds(rect);
*aBounds = aToBoundsSpace.TransformBounds(rect);
return true;
}
if (!aTransform.IsRectilinear()) {
if (!aToBoundsSpace.IsRectilinear()) {
// We can't ignore the radii in this case if we want tight bounds
rx = std::max(rx, 0.0f);
ry = std::max(ry, 0.0f);
@ -139,10 +141,28 @@ SVGRectElement::GetGeometryBounds(
}
if (aStrokeOptions.mLineWidth > 0.f) {
if (aToNonScalingStrokeSpace) {
if (aToNonScalingStrokeSpace->IsRectilinear()) {
rect = aToNonScalingStrokeSpace->TransformBounds(rect);
// Note that, in principle, an author could cause the corners of the
// rect to be beveled by specifying stroke-linejoin or setting
// stroke-miterlimit to be less than sqrt(2). In that very unlikely
// event the bounds that we calculate here may be too big if
// aToBoundsSpace is non-rectilinear. This is likely to be so rare it's
// not worth handling though.
rect.Inflate(aStrokeOptions.mLineWidth / 2.f);
Matrix nonScalingToBounds =
aToNonScalingStrokeSpace->Inverse() * aToBoundsSpace;
*aBounds = nonScalingToBounds.TransformBounds(rect);
return true;
}
return false;
}
// The "beveled" comment above applies here too
rect.Inflate(aStrokeOptions.mLineWidth / 2.f);
}
*aBounds = aTransform.TransformBounds(rect);
*aBounds = aToBoundsSpace.TransformBounds(rect);
return true;
}

View File

@ -32,7 +32,8 @@ public:
// nsSVGPathGeometryElement methods:
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
const Matrix& aTransform) override;
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace = nullptr) override;
virtual void GetAsSimplePath(SimplePath* aSimplePath) override;
virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder = nullptr) override;

View File

@ -76,9 +76,18 @@ public:
* GetStrokedBounds on it. It also helps us avoid rounding error for simple
* shapes and simple transforms where the Moz2D Path backends can fail to
* produce the clean integer bounds that content authors expect in some cases.
*
* If |aToNonScalingStrokeSpace| is non-null then |aBounds|, which is computed
* in bounds space, has the property that it's the smallest (axis-aligned)
* rectangular bound containing the image of this shape as stroked in
* non-scaling-stroke space. (When all transforms involved are rectilinear
* the bounds of the image of |aBounds| in non-scaling-stroke space will be
* tight, but if there are non-rectilinear transforms involved then that may
* be impossible and this method will return false).
*/
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
const Matrix& aTransform) {
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace = nullptr) {
return false;
}

View File

@ -122,8 +122,10 @@ nsSVGPolyElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks)
}
bool
nsSVGPolyElement::GetGeometryBounds(
Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aTransform)
nsSVGPolyElement::GetGeometryBounds(Rect* aBounds,
const StrokeOptions& aStrokeOptions,
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace)
{
const SVGPointList &points = mPoints.GetAnimValue();
@ -133,23 +135,23 @@ nsSVGPolyElement::GetGeometryBounds(
return true;
}
if (aStrokeOptions.mLineWidth > 0) {
// We don't handle stroke-miterlimit etc. yet
if (aStrokeOptions.mLineWidth > 0 || aToNonScalingStrokeSpace) {
// We don't handle non-scaling-stroke or stroke-miterlimit etc. yet
return false;
}
if (aTransform.IsRectilinear()) {
if (aToBoundsSpace.IsRectilinear()) {
// We can avoid transforming each point and just transform the result.
// Important for large point lists.
Rect bounds(points[0], Size());
for (uint32_t i = 1; i < points.Length(); ++i) {
bounds.ExpandToEnclose(points[i]);
}
*aBounds = aTransform.TransformBounds(bounds);
*aBounds = aToBoundsSpace.TransformBounds(bounds);
} else {
*aBounds = Rect(aTransform * points[0], Size());
*aBounds = Rect(aToBoundsSpace * points[0], Size());
for (uint32_t i = 1; i < points.Length(); ++i) {
aBounds->ExpandToEnclose(aTransform * points[i]);
aBounds->ExpandToEnclose(aToBoundsSpace * points[i]);
}
}
return true;

View File

@ -47,7 +47,8 @@ public:
virtual bool IsMarkable() override { return true; }
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) override;
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
const Matrix& aTransform) override;
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace = nullptr) override;
// WebIDL
already_AddRefed<mozilla::DOMSVGPointList> Points();

View File

@ -39,5 +39,13 @@ text { font: 20px monospace; }
<rect x="100" y="100" width="50" height="50" fill="pink"/>
<text x="200" y="200"/>
</g>
<circle id="nonScalingStrokedCircle1" cx="0" cy="0" r="10"
transform="translate(45 130) scale(3 -2)"
fill="none" stroke="gray" stroke-width="10"
vector-effect="non-scaling-stroke"/>
<ellipse id="nonScalingStrokedEllipse1" cx="20" cy="-10" rx="5" ry="5"
transform="matrix(0 3 -2 0 0 0)"
fill="none" stroke="steelblue" stroke-width="10"
vector-effect="non-scaling-stroke" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -159,13 +159,10 @@ function runTest()
is(rect3aBounds.width, 108, "rect3a.getBoundingClientRect().width");
is(rect3aBounds.height, 108, "rect3a.getBoundingClientRect().height");
// Our PathExtentsToMaxStrokeExtents implementation considers the stroke
// width to be sqrt(2)*stroke-width in case the rect is rotated 45 degrees,
// so unfortunately we get slightly large results currently. Bug 1092125.
isWithAbsTolerance(rect3bBounds.left, 198, 1, "rect3b.getBoundingClientRect().left");
isWithAbsTolerance(rect3bBounds.top, 198, 1, "rect3b.getBoundingClientRect().top");
isWithAbsTolerance(rect3bBounds.width, 54, 2, "rect3b.getBoundingClientRect().width");
isWithAbsTolerance(rect3bBounds.height, 54, 2, "rect3b.getBoundingClientRect().height");
isWithAbsTolerance(rect3bBounds.left, 198, 0.1, "rect3b.getBoundingClientRect().left");
isWithAbsTolerance(rect3bBounds.top, 198, 0.1, "rect3b.getBoundingClientRect().top");
isWithAbsTolerance(rect3bBounds.width, 54, 0.1, "rect3b.getBoundingClientRect().width");
isWithAbsTolerance(rect3bBounds.height, 54, 0.1, "rect3b.getBoundingClientRect().height");
rect = new Rect(350 - 108 * sin45, 150 - 108 * sin45, 108 * sin45 * 2, 108 * sin45 * 2);
isWithAbsTolerance(rect4aBounds.left, rect.left, 0.1, "rect4a.getBoundingClientRect().left");
@ -203,6 +200,28 @@ function runTest()
is(gBounds.width, 50, "g2.getBoundingClientRect().width");
is(gBounds.height, 50, "g2.getBoundingClientRect().height");
var nonScalingStrokedCircle1Bounds =
doc.getElementById("nonScalingStrokedCircle1").getBoundingClientRect();
isWithAbsTolerance(nonScalingStrokedCircle1Bounds.left, 10, 0.15,
"nonScalingStrokedCircle1.getBoundingClientRect().left");
isWithAbsTolerance(nonScalingStrokedCircle1Bounds.top, 105, 0.15,
"nonScalingStrokedCircle1.getBoundingClientRect().top");
isWithAbsTolerance(nonScalingStrokedCircle1Bounds.width, 70, 0.15,
"nonScalingStrokedCircle1.getBoundingClientRect().width");
isWithAbsTolerance(nonScalingStrokedCircle1Bounds.height, 50, 0.15,
"nonScalingStrokedCircle1.getBoundingClientRect().height");
var nonScalingStrokedEllipse1Bounds =
doc.getElementById("nonScalingStrokedEllipse1").getBoundingClientRect();
isWithAbsTolerance(nonScalingStrokedEllipse1Bounds.left, 5, 0.15,
"nonScalingStrokedEllipse1.getBoundingClientRect().left");
isWithAbsTolerance(nonScalingStrokedEllipse1Bounds.top, 40, 0.15,
"nonScalingStrokedEllipse1.getBoundingClientRect().top");
isWithAbsTolerance(nonScalingStrokedEllipse1Bounds.width, 30, 0.15,
"nonScalingStrokedEllipse1.getBoundingClientRect().width");
isWithAbsTolerance(nonScalingStrokedEllipse1Bounds.height, 40, 0.15,
"nonScalingStrokedEllipse1.getBoundingClientRect().height");
SimpleTest.finish();
}

View File

@ -470,25 +470,36 @@ nsSVGPathGeometryFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
((aFlags & nsSVGUtils::eBBoxIncludeStroke) &&
nsSVGUtils::HasStroke(this));
bool gotSimpleBounds = false;
if (!StyleSVGReset()->HasNonScalingStroke()) {
SVGContentUtils::AutoStrokeOptions strokeOptions;
SVGContentUtils::AutoStrokeOptions strokeOptions;
if (getStroke) {
SVGContentUtils::GetStrokeOptions(&strokeOptions, element,
StyleContext(), nullptr,
SVGContentUtils::eIgnoreStrokeDashing);
} else {
// Override the default line width of 1.f so that when we call
// GetGeometryBounds below the result doesn't include stroke bounds.
strokeOptions.mLineWidth = 0.f;
if (getStroke) {
SVGContentUtils::GetStrokeOptions(&strokeOptions, element,
StyleContext(), nullptr,
SVGContentUtils::eIgnoreStrokeDashing);
}
Rect simpleBounds;
}
Rect simpleBounds;
bool gotSimpleBounds = false;
gfxMatrix userToOuterSVG;
if (getStroke &&
nsSVGUtils::GetNonScalingStrokeTransform(this, &userToOuterSVG)) {
Matrix moz2dUserToOuterSVG = ToMatrix(userToOuterSVG);
gotSimpleBounds = element->GetGeometryBounds(&simpleBounds,
strokeOptions,
aToBBoxUserspace,
&moz2dUserToOuterSVG);
} else {
gotSimpleBounds = element->GetGeometryBounds(&simpleBounds,
strokeOptions,
aToBBoxUserspace);
if (gotSimpleBounds) {
bbox = simpleBounds;
}
}
if (!gotSimpleBounds) {
if (gotSimpleBounds) {
bbox = simpleBounds;
} else {
// Get the bounds using a Moz2D Path object (more expensive):
RefPtr<DrawTarget> tmpDT;
#ifdef XP_WIN