Bug 1074594 - Stop inverting the transform in nsSVGUtils::GetStrokeTransform, give it a more performant signature, and a better name. r=longsonr

This commit is contained in:
Jonathan Watt 2014-09-30 18:08:14 +01:00
parent 575724162a
commit aee9c12e6a
5 changed files with 57 additions and 50 deletions

View File

@ -263,13 +263,12 @@ nsSVGGradientFrame::GetPaintServerPattern(nsIFrame* aSource,
return nullptr;
}
// revert the vector effect transform so that the gradient appears unchanged
// revert any vector effect transform so that the gradient appears unchanged
if (aFillOrStroke == &nsStyleSVG::mStroke) {
gfxMatrix nonScalingStrokeTM = nsSVGUtils::GetStrokeTransform(aSource);
if (!nonScalingStrokeTM.Invert()) {
return nullptr;
gfxMatrix userToOuterSVG;
if (nsSVGUtils::GetNonScalingStrokeTransform(aSource, &userToOuterSVG)) {
patternMatrix *= userToOuterSVG;
}
patternMatrix *= nonScalingStrokeTM;
}
if (!patternMatrix.Invert()) {

View File

@ -302,18 +302,15 @@ nsSVGPathGeometryFrame::GetFrameForPoint(const gfxPoint& aPoint)
Point point = ToPoint(aPoint);
SVGContentUtils::AutoStrokeOptions stroke;
SVGContentUtils::GetStrokeOptions(&stroke, content, StyleContext(), nullptr);
Matrix nonScalingStrokeMatrix = ToMatrix(nsSVGUtils::GetStrokeTransform(this));
if (!nonScalingStrokeMatrix.IsIdentity()) {
gfxMatrix userToOuterSVG;
if (nsSVGUtils::GetNonScalingStrokeTransform(this, &userToOuterSVG)) {
// We need to transform the path back into the appropriate ancestor
// coordinate system in order for non-scaled stroke to be correct.
// Naturally we also need to transform the point into the same
// coordinate system in order to hit-test against the path.
if (!nonScalingStrokeMatrix.Invert()) {
return nullptr;
}
point = nonScalingStrokeMatrix * point;
point = ToMatrix(userToOuterSVG) * point;
RefPtr<PathBuilder> builder =
path->TransformedCopyToBuilder(nonScalingStrokeMatrix, fillRule);
path->TransformedCopyToBuilder(ToMatrix(userToOuterSVG), fillRule);
path = builder->Finish();
}
isHit = path->StrokeContainsPoint(stroke, point, Matrix());
@ -677,15 +674,15 @@ nsSVGPathGeometryFrame::Render(gfxContext* aContext,
if ((aRenderComponents & eRenderStroke) &&
nsSVGUtils::HasStroke(this, contextPaint)) {
// Account for vector-effect:non-scaling-stroke:
gfxMatrix strokeTransform = nsSVGUtils::GetStrokeTransform(this);
if (!strokeTransform.IsIdentity()) {
gfxMatrix userToOuterSVG;
if (nsSVGUtils::GetNonScalingStrokeTransform(this, &userToOuterSVG)) {
// We need to transform the path back into the appropriate ancestor
// coordinate system, and paint it it that coordinate system, in order
// for non-scaled stroke to paint correctly.
aContext->Multiply(strokeTransform);
Matrix moz2DstrokeTransform = ToMatrix(strokeTransform); // inverse of Thebes
moz2DstrokeTransform.Invert();
builder = path->TransformedCopyToBuilder(moz2DstrokeTransform, fillRule);
gfxMatrix outerSVGToUser = userToOuterSVG;
outerSVGToUser.Invert();
aContext->Multiply(outerSVGToUser);
builder = path->TransformedCopyToBuilder(ToMatrix(userToOuterSVG), fillRule);
path = builder->Finish();
}
GeneralPattern strokePattern;

View File

@ -325,12 +325,14 @@ nsSVGPatternFrame::PaintPattern(const DrawTarget* aDrawTarget,
// revert the vector effect transform so that the pattern appears unchanged
if (aFillOrStroke == &nsStyleSVG::mStroke) {
Matrix strokeTransform = ToMatrix(nsSVGUtils::GetStrokeTransform(aSource));
if (!strokeTransform.Invert()) {
NS_WARNING("Should we get here if the stroke transform is singular?");
return nullptr;
gfxMatrix userToOuterSVG;
if (nsSVGUtils::GetNonScalingStrokeTransform(aSource, &userToOuterSVG)) {
patternTransform *= ToMatrix(userToOuterSVG);
if (patternTransform.IsSingular()) {
NS_WARNING("Singular matrix painting non-scaling-stroke");
return nullptr;
}
}
patternTransform *= strokeTransform;
}
// Get the transformation matrix that we will hand to the renderer's pattern

View File

@ -1119,31 +1119,26 @@ nsSVGUtils::GetFirstNonAAncestorFrame(nsIFrame* aStartFrame)
return nullptr;
}
gfxMatrix
nsSVGUtils::GetStrokeTransform(nsIFrame *aFrame)
bool
nsSVGUtils::GetNonScalingStrokeTransform(nsIFrame *aFrame,
gfxMatrix* aUserToOuterSVG)
{
if (aFrame->GetContent()->IsNodeOfType(nsINode::eTEXT)) {
aFrame = aFrame->GetParent();
}
if (aFrame->StyleSVGReset()->mVectorEffect ==
NS_STYLE_VECTOR_EFFECT_NON_SCALING_STROKE) {
nsIContent *content = aFrame->GetContent();
NS_ABORT_IF_FALSE(content->IsSVG(), "bad cast");
// a non-scaling stroke is in the screen co-ordinate
// space rather so we need to invert the transform
// to the screen co-ordinate space to get there.
// See http://www.w3.org/TR/SVGTiny12/painting.html#NonScalingStroke
gfx::Matrix transform = SVGContentUtils::GetCTM(
static_cast<nsSVGElement*>(content), true);
if (!transform.IsSingular()) {
transform.Invert();
return ThebesMatrix(transform);
}
if (aFrame->StyleSVGReset()->mVectorEffect !=
NS_STYLE_VECTOR_EFFECT_NON_SCALING_STROKE) {
return false;
}
return gfxMatrix();
nsIContent *content = aFrame->GetContent();
NS_ABORT_IF_FALSE(content->IsSVG(), "bad cast");
*aUserToOuterSVG = ThebesMatrix(SVGContentUtils::GetCTM(
static_cast<nsSVGElement*>(content), true));
return !aUserToOuterSVG->IsIdentity();
}
// The logic here comes from _cairo_stroke_style_max_distance_from_path
@ -1156,7 +1151,13 @@ PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
double style_expansion =
aStyleExpansionFactor * nsSVGUtils::GetStrokeWidth(aFrame);
gfxMatrix matrix = aMatrix * nsSVGUtils::GetStrokeTransform(aFrame);
gfxMatrix matrix = aMatrix;
gfxMatrix outerSVGToUser;
if (nsSVGUtils::GetNonScalingStrokeTransform(aFrame, &outerSVGToUser)) {
outerSVGToUser.Invert();
matrix *= outerSVGToUser;
}
double dx = style_expansion * (fabs(matrix._11) + fabs(matrix._21));
double dy = style_expansion * (fabs(matrix._22) + fabs(matrix._12));
@ -1496,9 +1497,10 @@ nsSVGUtils::SetupCairoStrokeGeometry(nsIFrame* aFrame,
aContext->SetLineWidth(width);
// Apply any stroke-specific transform
gfxMatrix strokeTransform = GetStrokeTransform(aFrame);
if (!strokeTransform.IsIdentity()) {
aContext->Multiply(strokeTransform);
gfxMatrix outerSVGToUser;
if (GetNonScalingStrokeTransform(aFrame, &outerSVGToUser) &&
outerSVGToUser.Invert()) {
aContext->Multiply(outerSVGToUser);
}
const nsStyleSVG* style = aFrame->StyleSVG();

View File

@ -467,11 +467,18 @@ public:
static bool OuterSVGIsCallingReflowSVG(nsIFrame *aFrame);
static bool AnyOuterSVGIsCallingReflowSVG(nsIFrame *aFrame);
/*
* Get any additional transforms that apply only to stroking
* e.g. non-scaling-stroke
/**
* See https://svgwg.org/svg2-draft/painting.html#NonScalingStroke
*
* If the computed value of the 'vector-effect' property on aFrame is
* 'non-scaling-stroke', then this function will set aUserToOuterSVG to the
* transform from aFrame's SVG user space to the initial coordinate system
* established by the viewport of aFrame's outer-<svg>'s (the coordinate
* system in which the stroke is fixed). If aUserToOuterSVG is set to a
* non-identity matrix this function returns true, else it returns false.
*/
static gfxMatrix GetStrokeTransform(nsIFrame *aFrame);
static bool GetNonScalingStrokeTransform(nsIFrame *aFrame,
gfxMatrix* aUserToOuterSVG);
/**
* Compute the maximum possible device space stroke extents of a path given