зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1903361 - Make SVG paths respect zoom. r=longsonr
Differential Revision: https://phabricator.services.mozilla.com/D214175
This commit is contained in:
Родитель
7a0a28135d
Коммит
3eadcfef57
|
@ -884,7 +884,9 @@ already_AddRefed<gfx::Path> SVGContentUtils::GetPath(
|
|||
RefPtr<PathBuilder> builder =
|
||||
drawTarget->CreatePathBuilder(FillRule::FILL_WINDING);
|
||||
|
||||
return pathData.BuildPath(builder, StyleStrokeLinecap::Butt, 1);
|
||||
// This is called from canvas, so we don't need to get the effective zoom here
|
||||
// or so.
|
||||
return pathData.BuildPath(builder, StyleStrokeLinecap::Butt, 1, 1.0f);
|
||||
}
|
||||
|
||||
bool SVGContentUtils::ShapeTypeHasNoCorners(const nsIContent* aContent) {
|
||||
|
|
|
@ -232,7 +232,7 @@ void SVGMotionSMILAnimationFunction::RebuildPathAndVerticesFromPathAttr() {
|
|||
return;
|
||||
}
|
||||
|
||||
mPath = path.BuildPathForMeasuring();
|
||||
mPath = path.BuildPathForMeasuring(1.0f);
|
||||
bool ok = path.GetDistancesFromOriginToEndsOfVisibleSegments(&mPathVertices);
|
||||
if (!ok || !mPathVertices.Length()) {
|
||||
mPath = nullptr;
|
||||
|
|
|
@ -162,13 +162,15 @@ static void ApproximateZeroLengthSubpathSquareCaps(PathBuilder* aPB,
|
|||
|
||||
already_AddRefed<Path> SVGPathData::BuildPath(PathBuilder* aBuilder,
|
||||
StyleStrokeLinecap aStrokeLineCap,
|
||||
Float aStrokeWidth) const {
|
||||
return BuildPath(AsSpan(), aBuilder, aStrokeLineCap, aStrokeWidth);
|
||||
Float aStrokeWidth,
|
||||
float aZoom) const {
|
||||
return BuildPath(AsSpan(), aBuilder, aStrokeLineCap, aStrokeWidth, {}, {},
|
||||
aZoom);
|
||||
}
|
||||
|
||||
#undef MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS_TO_DT
|
||||
|
||||
already_AddRefed<Path> SVGPathData::BuildPathForMeasuring() const {
|
||||
already_AddRefed<Path> SVGPathData::BuildPathForMeasuring(float aZoom) 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
|
||||
// to pass something other than NS_STYLE_STROKE_LINECAP_SQUARE as
|
||||
|
@ -181,17 +183,17 @@ already_AddRefed<Path> SVGPathData::BuildPathForMeasuring() const {
|
|||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
RefPtr<PathBuilder> builder =
|
||||
drawTarget->CreatePathBuilder(FillRule::FILL_WINDING);
|
||||
return BuildPath(builder, StyleStrokeLinecap::Butt, 0);
|
||||
return BuildPath(builder, StyleStrokeLinecap::Butt, 0, aZoom);
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<Path> SVGPathData::BuildPathForMeasuring(
|
||||
Span<const StylePathCommand> aPath) {
|
||||
Span<const StylePathCommand> aPath, float aZoom) {
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
RefPtr<PathBuilder> builder =
|
||||
drawTarget->CreatePathBuilder(FillRule::FILL_WINDING);
|
||||
return BuildPath(aPath, builder, StyleStrokeLinecap::Butt, 0);
|
||||
return BuildPath(aPath, builder, StyleStrokeLinecap::Butt, 0, {}, {}, aZoom);
|
||||
}
|
||||
|
||||
static inline StyleCSSFloat GetRotate(const StyleCSSFloat& aAngle) {
|
||||
|
@ -525,8 +527,9 @@ ComputeSegAnglesAndCorrectRadii(const Point& aSegStart, const Point& aSegEnd,
|
|||
static_cast<float>(atan2(ty2, tx2))};
|
||||
}
|
||||
|
||||
void SVGPathData::GetMarkerPositioningData(nsTArray<SVGMark>* aMarks) const {
|
||||
return GetMarkerPositioningData(AsSpan(), aMarks);
|
||||
void SVGPathData::GetMarkerPositioningData(float aZoom,
|
||||
nsTArray<SVGMark>* aMarks) const {
|
||||
return GetMarkerPositioningData(AsSpan(), aZoom, aMarks);
|
||||
}
|
||||
|
||||
// Basically, this is identical to the above function, but replace |mData| with
|
||||
|
@ -535,6 +538,7 @@ void SVGPathData::GetMarkerPositioningData(nsTArray<SVGMark>* aMarks) const {
|
|||
// StylePathCommand for SVG d attribute in the future.
|
||||
/* static */
|
||||
void SVGPathData::GetMarkerPositioningData(Span<const StylePathCommand> aPath,
|
||||
float aZoom,
|
||||
nsTArray<SVGMark>* aMarks) {
|
||||
if (aPath.IsEmpty()) {
|
||||
return;
|
||||
|
@ -564,7 +568,7 @@ void SVGPathData::GetMarkerPositioningData(Span<const StylePathCommand> aPath,
|
|||
break;
|
||||
|
||||
case StylePathCommand::Tag::Move: {
|
||||
const Point& p = cmd.move.point.ToGfxPoint();
|
||||
const Point& p = cmd.move.point.ToGfxPoint() * aZoom;
|
||||
pathStart = segEnd = cmd.move.by_to == StyleByTo::To ? p : segStart + p;
|
||||
pathStartIndex = aMarks->Length();
|
||||
// If authors are going to specify multiple consecutive moveto commands
|
||||
|
@ -573,15 +577,15 @@ void SVGPathData::GetMarkerPositioningData(Span<const StylePathCommand> aPath,
|
|||
break;
|
||||
}
|
||||
case StylePathCommand::Tag::Line: {
|
||||
const Point& p = cmd.line.point.ToGfxPoint();
|
||||
const Point& p = cmd.line.point.ToGfxPoint() * aZoom;
|
||||
segEnd = cmd.line.by_to == StyleByTo::To ? p : segStart + p;
|
||||
segStartAngle = segEndAngle = AngleOfVector(segEnd, segStart);
|
||||
break;
|
||||
}
|
||||
case StylePathCommand::Tag::CubicCurve: {
|
||||
Point cp1 = cmd.cubic_curve.control1.ToGfxPoint();
|
||||
Point cp2 = cmd.cubic_curve.control2.ToGfxPoint();
|
||||
segEnd = cmd.cubic_curve.point.ToGfxPoint();
|
||||
Point cp1 = cmd.cubic_curve.control1.ToGfxPoint() * aZoom;
|
||||
Point cp2 = cmd.cubic_curve.control2.ToGfxPoint() * aZoom;
|
||||
segEnd = cmd.cubic_curve.point.ToGfxPoint() * aZoom;
|
||||
|
||||
if (cmd.cubic_curve.by_to == StyleByTo::By) {
|
||||
cp1 += segStart;
|
||||
|
@ -597,8 +601,8 @@ void SVGPathData::GetMarkerPositioningData(Span<const StylePathCommand> aPath,
|
|||
break;
|
||||
}
|
||||
case StylePathCommand::Tag::QuadCurve: {
|
||||
Point cp1 = cmd.quad_curve.control1.ToGfxPoint();
|
||||
segEnd = cmd.quad_curve.point.ToGfxPoint();
|
||||
Point cp1 = cmd.quad_curve.control1.ToGfxPoint() * aZoom;
|
||||
segEnd = cmd.quad_curve.point.ToGfxPoint() * aZoom;
|
||||
|
||||
if (cmd.quad_curve.by_to == StyleByTo::By) {
|
||||
cp1 += segStart;
|
||||
|
@ -612,12 +616,12 @@ void SVGPathData::GetMarkerPositioningData(Span<const StylePathCommand> aPath,
|
|||
}
|
||||
case StylePathCommand::Tag::Arc: {
|
||||
const auto& arc = cmd.arc;
|
||||
float rx = arc.radii.x;
|
||||
float ry = arc.radii.y;
|
||||
float rx = arc.radii.x * aZoom;
|
||||
float ry = arc.radii.y * aZoom;
|
||||
float angle = arc.rotate;
|
||||
bool largeArcFlag = arc.arc_size == StyleArcSize::Large;
|
||||
bool sweepFlag = arc.arc_sweep == StyleArcSweep::Cw;
|
||||
segEnd = arc.point.ToGfxPoint();
|
||||
segEnd = arc.point.ToGfxPoint() * aZoom;
|
||||
if (arc.by_to == StyleByTo::By) {
|
||||
segEnd += segStart;
|
||||
}
|
||||
|
@ -654,18 +658,18 @@ void SVGPathData::GetMarkerPositioningData(Span<const StylePathCommand> aPath,
|
|||
}
|
||||
case StylePathCommand::Tag::HLine: {
|
||||
if (cmd.h_line.by_to == StyleByTo::To) {
|
||||
segEnd = Point(cmd.h_line.x, segStart.y);
|
||||
segEnd = Point(cmd.h_line.x, segStart.y) * aZoom;
|
||||
} else {
|
||||
segEnd = segStart + Point(cmd.h_line.x, 0.0f);
|
||||
segEnd = segStart + Point(cmd.h_line.x, 0.0f) * aZoom;
|
||||
}
|
||||
segStartAngle = segEndAngle = AngleOfVector(segEnd, segStart);
|
||||
break;
|
||||
}
|
||||
case StylePathCommand::Tag::VLine: {
|
||||
if (cmd.v_line.by_to == StyleByTo::To) {
|
||||
segEnd = Point(segStart.x, cmd.v_line.y);
|
||||
segEnd = Point(segStart.x, cmd.v_line.y) * aZoom;
|
||||
} else {
|
||||
segEnd = segStart + Point(0.0f, cmd.v_line.y);
|
||||
segEnd = segStart + Point(0.0f, cmd.v_line.y) * aZoom;
|
||||
}
|
||||
segStartAngle = segEndAngle = AngleOfVector(segEnd, segStart);
|
||||
break;
|
||||
|
@ -674,8 +678,8 @@ void SVGPathData::GetMarkerPositioningData(Span<const StylePathCommand> aPath,
|
|||
const Point& cp1 = prevSeg && prevSeg->IsCubicType()
|
||||
? segStart * 2 - prevCP
|
||||
: segStart;
|
||||
Point cp2 = cmd.smooth_cubic.control2.ToGfxPoint();
|
||||
segEnd = cmd.smooth_cubic.point.ToGfxPoint();
|
||||
Point cp2 = cmd.smooth_cubic.control2.ToGfxPoint() * aZoom;
|
||||
segEnd = cmd.smooth_cubic.point.ToGfxPoint() * aZoom;
|
||||
|
||||
if (cmd.smooth_cubic.by_to == StyleByTo::By) {
|
||||
cp2 += segStart;
|
||||
|
@ -694,8 +698,8 @@ void SVGPathData::GetMarkerPositioningData(Span<const StylePathCommand> aPath,
|
|||
? segStart * 2 - prevCP
|
||||
: segStart;
|
||||
segEnd = cmd.smooth_quad.by_to == StyleByTo::To
|
||||
? cmd.smooth_quad.point.ToGfxPoint()
|
||||
: segStart + cmd.smooth_quad.point.ToGfxPoint();
|
||||
? cmd.smooth_quad.point.ToGfxPoint() * aZoom
|
||||
: segStart + cmd.smooth_quad.point.ToGfxPoint() * aZoom;
|
||||
|
||||
prevCP = cp1;
|
||||
segStartAngle = AngleOfVector(cp1 == segStart ? segEnd : cp1, segStart);
|
||||
|
@ -738,7 +742,7 @@ void SVGPathData::GetMarkerPositioningData(Span<const StylePathCommand> aPath,
|
|||
prevSegEndAngle = segEndAngle;
|
||||
}
|
||||
|
||||
if (aMarks->Length()) {
|
||||
if (!aMarks->IsEmpty()) {
|
||||
if (!(prevSeg && prevSeg->IsClose())) {
|
||||
aMarks->LastElement().angle = prevSegEndAngle;
|
||||
}
|
||||
|
|
|
@ -119,11 +119,10 @@ class SVGPathData {
|
|||
static uint32_t GetPathSegAtLength(Span<const StylePathCommand> aPath,
|
||||
float aDistance);
|
||||
|
||||
void GetMarkerPositioningData(nsTArray<SVGMark>* aMarks) const;
|
||||
void GetMarkerPositioningData(float aZoom, nsTArray<SVGMark>* aMarks) const;
|
||||
|
||||
static void GetMarkerPositioningData(Span<const StylePathCommand> aPath,
|
||||
nsTArray<SVGMark>* aMarks);
|
||||
|
||||
float aZoom, nsTArray<SVGMark>* aMarks);
|
||||
/**
|
||||
* Returns true, except on OOM, in which case returns false.
|
||||
*/
|
||||
|
@ -141,14 +140,14 @@ class SVGPathData {
|
|||
* ApproximateZeroLengthSubpathSquareCaps can insert if we have square-caps.
|
||||
* See the comment for that function for more info on that.
|
||||
*/
|
||||
already_AddRefed<Path> BuildPathForMeasuring() const;
|
||||
already_AddRefed<Path> BuildPathForMeasuring(float aZoom) const;
|
||||
|
||||
already_AddRefed<Path> BuildPath(PathBuilder* aBuilder,
|
||||
StyleStrokeLinecap aStrokeLineCap,
|
||||
Float aStrokeWidth) const;
|
||||
Float aStrokeWidth, float aZoom) const;
|
||||
|
||||
static already_AddRefed<Path> BuildPathForMeasuring(
|
||||
Span<const StylePathCommand> aPath);
|
||||
Span<const StylePathCommand> aPath, float aZoom);
|
||||
|
||||
/**
|
||||
* This function tries to build the path from an array of GenericShapeCommand,
|
||||
|
@ -157,11 +156,13 @@ class SVGPathData {
|
|||
* Note: |StylePathCommand| doesn't accept percentage values, so its |aBasis|
|
||||
* is empty by default.
|
||||
*/
|
||||
static already_AddRefed<Path> BuildPath(
|
||||
Span<const StylePathCommand> aPath, PathBuilder* aBuilder,
|
||||
StyleStrokeLinecap aStrokeLineCap, Float aStrokeWidth,
|
||||
const CSSSize& aBasis = {}, const gfx::Point& aOffset = gfx::Point(),
|
||||
float aZoomFactor = 1.0);
|
||||
static already_AddRefed<Path> BuildPath(Span<const StylePathCommand> aPath,
|
||||
PathBuilder* aBuilder,
|
||||
StyleStrokeLinecap aStrokeLineCap,
|
||||
Float aStrokeWidth,
|
||||
const CSSSize& aBasis = {},
|
||||
const gfx::Point& aOffset = {},
|
||||
float aZoomFactor = 1.0);
|
||||
static already_AddRefed<Path> BuildPath(
|
||||
Span<const StyleShapeCommand> aShape, PathBuilder* aBuilder,
|
||||
StyleStrokeLinecap aStrokeLineCap, Float aStrokeWidth,
|
||||
|
|
|
@ -88,9 +88,11 @@ already_AddRefed<Path> SVGPathElement::GetOrBuildPathForMeasuring() {
|
|||
if (d.IsNone()) {
|
||||
return;
|
||||
}
|
||||
path = SVGPathData::BuildPathForMeasuring(d.AsPath()._0.AsSpan());
|
||||
path = SVGPathData::BuildPathForMeasuring(d.AsPath()._0.AsSpan(),
|
||||
s->EffectiveZoom().ToFloat());
|
||||
});
|
||||
return success ? path.forget() : mD.GetAnimValue().BuildPathForMeasuring();
|
||||
return success ? path.forget()
|
||||
: mD.GetAnimValue().BuildPathForMeasuring(1.0f);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -108,7 +110,8 @@ void SVGPathElement::GetMarkPoints(nsTArray<SVGMark>* aMarks) {
|
|||
if (styleSVGReset->mD.IsPath()) {
|
||||
Span<const StylePathCommand> path =
|
||||
styleSVGReset->mD.AsPath()._0.AsSpan();
|
||||
SVGPathData::GetMarkerPositioningData(path, aMarks);
|
||||
SVGPathData::GetMarkerPositioningData(path, s->EffectiveZoom().ToFloat(),
|
||||
aMarks);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -116,7 +119,7 @@ void SVGPathElement::GetMarkPoints(nsTArray<SVGMark>* aMarks) {
|
|||
return;
|
||||
}
|
||||
|
||||
mD.GetAnimValue().GetMarkerPositioningData(aMarks);
|
||||
mD.GetAnimValue().GetMarkerPositioningData(1.0f, aMarks);
|
||||
}
|
||||
|
||||
void SVGPathElement::GetAsSimplePath(SimplePath* aSimplePath) {
|
||||
|
@ -162,7 +165,8 @@ already_AddRefed<Path> SVGPathElement::BuildPath(PathBuilder* aBuilder) {
|
|||
const auto& d = s->StyleSVGReset()->mD;
|
||||
if (d.IsPath()) {
|
||||
path = SVGPathData::BuildPath(d.AsPath()._0.AsSpan(), aBuilder,
|
||||
strokeLineCap, strokeWidth);
|
||||
strokeLineCap, strokeWidth, {}, {},
|
||||
s->EffectiveZoom().ToFloat());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -172,7 +176,8 @@ already_AddRefed<Path> SVGPathElement::BuildPath(PathBuilder* aBuilder) {
|
|||
}
|
||||
|
||||
// Fallback to use the d attribute if it exists.
|
||||
return mD.GetAnimValue().BuildPath(aBuilder, strokeLineCap, strokeWidth);
|
||||
return mD.GetAnimValue().BuildPath(aBuilder, strokeLineCap, strokeWidth,
|
||||
1.0f);
|
||||
}
|
||||
|
||||
bool SVGPathElement::GetDistancesFromOriginToEndsOfVisibleSegments(
|
||||
|
|
|
@ -4506,7 +4506,8 @@ already_AddRefed<Path> SVGTextFrame::GetTextPath(nsIFrame* aTextPathFrame) {
|
|||
if (tp->mPath.IsRendered()) {
|
||||
// This is just an attribute so there's no transform that can apply
|
||||
// so we can just return the path directly.
|
||||
return tp->mPath.GetAnimValue().BuildPathForMeasuring();
|
||||
return tp->mPath.GetAnimValue().BuildPathForMeasuring(
|
||||
aTextPathFrame->Style()->EffectiveZoom().ToFloat());
|
||||
}
|
||||
|
||||
SVGGeometryElement* geomElement =
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<svg width="320" height="200" style="background: #006AA7;">
|
||||
<path d="M120 0 L 120 320Z" stroke="#FECC02" stroke-width="40"/>
|
||||
<rect x="0" y="80" width="320" height="40" fill="#FECC02" />
|
||||
</svg>
|
|
@ -0,0 +1,9 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-viewport/#zoom-property">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1903361">
|
||||
<link rel="match" href="svg-path-ref.html">
|
||||
<svg width="160" height="100" style="zoom: 2; background: #006AA7;">
|
||||
<path d="M60 0 L 60 160Z" stroke="#FECC02" stroke-width="20"/>
|
||||
<rect x="0" y="40" width="160" height="20" fill="#FECC02" />
|
||||
</svg>
|
Загрузка…
Ссылка в новой задаче