Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit eb930ea

Browse files
committed
Bug 1903546 - fix non-scaling-stroke r=emilio
This implements w3c/svgwg#582 and therefore mostly reverts bug 1904891 Differential Revision: https://phabricator.services.mozilla.com/D216303
1 parent d0a28ff commit eb930ea

File tree

12 files changed

+46
-147
lines changed

12 files changed

+46
-147
lines changed

dom/svg/SVGContentUtils.cpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,9 @@ SVGViewportElement* SVGContentUtils::GetNearestViewportElement(
489489
return nullptr;
490490
}
491491

492-
static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM,
492+
enum class CTMType { NearestViewport, OuterViewport, Screen };
493+
494+
static gfx::Matrix GetCTMInternal(SVGElement* aElement, CTMType aCTMType,
493495
bool aHaveRecursed) {
494496
auto getLocalTransformHelper =
495497
[](SVGElement const* e, bool shouldIncludeChildToUserSpace) -> gfxMatrix {
@@ -530,7 +532,8 @@ static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM,
530532
!ancestor->IsSVGElement(nsGkAtoms::foreignObject)) {
531533
element = static_cast<SVGElement*>(ancestor);
532534
matrix *= getLocalTransformHelper(element, true);
533-
if (!aScreenCTM && SVGContentUtils::EstablishesViewport(element)) {
535+
if (aCTMType == CTMType::NearestViewport &&
536+
SVGContentUtils::EstablishesViewport(element)) {
534537
if (!element->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::symbol)) {
535538
NS_ERROR("New (SVG > 1.1) SVG viewport establishing element?");
536539
return gfx::Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
@@ -540,7 +543,7 @@ static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM,
540543
}
541544
ancestor = ancestor->GetFlattenedTreeParent();
542545
}
543-
if (!aScreenCTM) {
546+
if (aCTMType == CTMType::NearestViewport) {
544547
// didn't find a nearestViewportElement
545548
return gfx::Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
546549
}
@@ -568,13 +571,16 @@ static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM,
568571
int32_t appUnitsPerCSSPixel = AppUnitsPerCSSPixel();
569572
tm.PostTranslate(NSAppUnitsToFloatPixels(bp.left, appUnitsPerCSSPixel),
570573
NSAppUnitsToFloatPixels(bp.top, appUnitsPerCSSPixel));
574+
if (aCTMType == CTMType::OuterViewport) {
575+
return tm;
576+
}
571577
}
572578

573579
if (!ancestor || !ancestor->IsElement()) {
574580
return tm;
575581
}
576582
if (auto* ancestorSVG = SVGElement::FromNode(ancestor)) {
577-
return tm * GetCTMInternal(ancestorSVG, true, true);
583+
return tm * GetCTMInternal(ancestorSVG, aCTMType, true);
578584
}
579585
nsIFrame* parentFrame = frame->GetParent();
580586
if (!parentFrame) {
@@ -612,16 +618,20 @@ static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM,
612618
}
613619
return nearestSVGAncestor
614620
? tm * GetCTMInternal(static_cast<SVGElement*>(nearestSVGAncestor),
615-
true, true)
621+
aCTMType, true)
616622
: tm;
617623
}
618624

619625
gfx::Matrix SVGContentUtils::GetCTM(SVGElement* aElement) {
620-
return GetCTMInternal(aElement, false, false);
626+
return GetCTMInternal(aElement, CTMType::NearestViewport, false);
627+
}
628+
629+
gfx::Matrix SVGContentUtils::GetOuterViewportCTM(SVGElement* aElement) {
630+
return GetCTMInternal(aElement, CTMType::OuterViewport, false);
621631
}
622632

623633
gfx::Matrix SVGContentUtils::GetScreenCTM(SVGElement* aElement) {
624-
return GetCTMInternal(aElement, true, false);
634+
return GetCTMInternal(aElement, CTMType::Screen, false);
625635
}
626636

627637
void SVGContentUtils::RectilinearGetStrokeBounds(

dom/svg/SVGContentUtils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ class SVGContentUtils {
197197

198198
static Matrix GetCTM(dom::SVGElement* aElement);
199199

200+
static Matrix GetOuterViewportCTM(dom::SVGElement* aElement);
201+
200202
static Matrix GetScreenCTM(dom::SVGElement* aElement);
201203

202204
/**

dom/svg/SVGGeometryElement.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,7 @@ bool SVGGeometryElement::IsPointInStroke(const DOMPointInit& aPoint) {
201201
SVGGeometryProperty::DoForComputedStyle(this, [&](const ComputedStyle* s) {
202202
// Per spec, we should take vector-effect into account.
203203
if (s->StyleSVGReset()->HasNonScalingStroke()) {
204-
auto mat = s->StyleSVGReset()->mVectorEffect.IsScreen()
205-
? SVGContentUtils::GetScreenCTM(this)
206-
: SVGContentUtils::GetCTM(this);
204+
auto mat = SVGContentUtils::GetOuterViewportCTM(this);
207205
if (mat.HasNonTranslation()) {
208206
// We have non-scaling-stroke as well as a non-translation transform.
209207
// We should transform the path first then apply the stroke on the

layout/style/ServoBindings.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,8 +587,6 @@ cbindgen-types = [
587587
{ gecko = "StylePageOrientation", servo = "crate::values::generics::page::PageOrientation" },
588588
{ gecko = "StylePageSize", servo = "crate::values::computed::page::PageSize" },
589589
{ gecko = "StyleDProperty", servo = "crate::values::specified::svg::DProperty" },
590-
{ gecko = "StyleVectorEffectType", servo = "crate::values::specified::svg::VectorEffectType" },
591-
{ gecko = "StyleCoordinateSpace", servo = "crate::values::specified::svg::CoordinateSpace" },
592590
{ gecko = "StyleVectorEffect", servo = "crate::values::specified::svg::VectorEffect" },
593591
{ gecko = "StyleImageRendering", servo = "crate::values::computed::ImageRendering" },
594592
{ gecko = "StylePrintColorAdjust", servo = "crate::values::computed::PrintColorAdjust" },

layout/style/nsStyleStruct.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,7 @@ nsStyleSVGReset::nsStyleSVGReset()
909909
mLightingColor(StyleColor::White()),
910910
mStopOpacity(1.0f),
911911
mFloodOpacity(1.0f),
912+
mVectorEffect(StyleVectorEffect::NONE),
912913
mMaskType(StyleMaskType::Luminance),
913914
mD(StyleDProperty::None()) {
914915
MOZ_COUNT_CTOR(nsStyleSVGReset);

layout/style/test/property_database.js

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9787,18 +9787,8 @@ var gCSSProperties = {
97879787
applies_to_first_letter: true,
97889788
applies_to_first_line: true,
97899789
initial_values: ["none"],
9790-
other_values: [
9791-
"non-scaling-stroke",
9792-
"non-scaling-stroke viewport",
9793-
"non-scaling-stroke screen",
9794-
],
9795-
invalid_values: [
9796-
"none non-scaling-stroke",
9797-
"non-scaling-stroke viewport screen",
9798-
"none viewport",
9799-
"none screen",
9800-
"viewport non-scaling-stroke",
9801-
],
9790+
other_values: ["non-scaling-stroke"],
9791+
invalid_values: ["none non-scaling-stroke"],
98029792
},
98039793
"-moz-window-dragging": {
98049794
domProp: "MozWindowDragging",

layout/svg/SVGUtils.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,9 +1083,7 @@ bool SVGUtils::GetNonScalingStrokeTransform(const nsIFrame* aFrame,
10831083

10841084
SVGElement* content = static_cast<SVGElement*>(aFrame->GetContent());
10851085
*aUserToOuterSVG =
1086-
ThebesMatrix(aFrame->StyleSVGReset()->mVectorEffect.IsScreen()
1087-
? SVGContentUtils::GetScreenCTM(content)
1088-
: SVGContentUtils::GetCTM(content));
1086+
ThebesMatrix(SVGContentUtils::GetOuterViewportCTM(content));
10891087

10901088
return aUserToOuterSVG->HasNonTranslation() && !aUserToOuterSVG->IsSingular();
10911089
}

servo/components/style/values/specified/svg.rs

Lines changed: 4 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -420,104 +420,21 @@ impl Parse for DProperty {
420420
)]
421421
#[css(bitflags(single = "none", mixed = "non-scaling-stroke"))]
422422
#[repr(C)]
423-
/// Values for vector-effect:
424423
/// https://svgwg.org/svg2-draft/coords.html#VectorEffects
425-
pub struct VectorEffectType(u8);
424+
pub struct VectorEffect(u8);
426425
bitflags! {
427-
impl VectorEffectType: u8 {
426+
impl VectorEffect: u8 {
428427
/// `none`
429428
const NONE = 0;
430429
/// `non-scaling-stroke`
431430
const NON_SCALING_STROKE = 1 << 0;
432431
}
433432
}
434433

435-
#[allow(missing_docs)]
436-
impl VectorEffectType {
437-
pub fn is_none(&self) -> bool {
438-
*self == VectorEffectType::NONE
439-
}
440-
}
441-
442-
#[derive(
443-
Clone,
444-
Copy,
445-
Debug,
446-
Default,
447-
Eq,
448-
MallocSizeOf,
449-
Parse,
450-
PartialEq,
451-
SpecifiedValueInfo,
452-
ToComputedValue,
453-
ToCss,
454-
ToResolvedValue,
455-
ToShmem,
456-
)]
457-
#[repr(C)]
458-
/// co-ordinate space for vector-effect:
459-
/// https://svgwg.org/svg2-draft/coords.html#VectorEffects
460-
pub enum CoordinateSpace {
461-
#[default]
462-
/// `viewport`
463-
Viewport,
464-
/// `screen`
465-
Screen,
466-
}
467-
468-
#[allow(missing_docs)]
469-
impl CoordinateSpace {
470-
pub fn is_viewport(&self) -> bool {
471-
*self == Self::Viewport
472-
}
473-
}
474-
475-
#[derive(
476-
Clone,
477-
Copy,
478-
Debug,
479-
MallocSizeOf,
480-
PartialEq,
481-
SpecifiedValueInfo,
482-
ToCss,
483-
ToComputedValue,
484-
ToResolvedValue,
485-
ToShmem,
486-
)]
487-
#[repr(C)]
488-
/// Specified value for the vector-effect property.
489-
/// (The spec grammar gives
490-
/// `none | [ non-scaling-stroke | non-scaling-size | non-rotation | fixed-position ]+ [ viewport | screen ]?`.)
491-
/// https://svgwg.org/svg2-draft/coords.html#VectorEffects
492-
pub struct VectorEffect {
493-
/// none or non-scaling-stroke
494-
pub effect_type: VectorEffectType,
495-
/// screen or viewport
496-
#[css(skip_if = "CoordinateSpace::is_viewport")]
497-
pub coordinate_space: CoordinateSpace,
498-
}
499-
500-
#[allow(missing_docs)]
501434
impl VectorEffect {
435+
/// Returns the initial value of vector-effect
502436
#[inline]
503437
pub fn none() -> Self {
504-
Self {
505-
effect_type: VectorEffectType::NONE,
506-
coordinate_space: CoordinateSpace::Viewport,
507-
}
508-
}
509-
}
510-
511-
impl Parse for VectorEffect {
512-
fn parse<'i, 't>(
513-
context: &ParserContext,
514-
input: &mut Parser<'i, 't>,
515-
) -> Result<Self, ParseError<'i>> {
516-
let effect_type = VectorEffectType::parse(context, input)?;
517-
if effect_type.is_none() {
518-
return Ok(Self::none());
519-
}
520-
let coordinate_space = input.try_parse(CoordinateSpace::parse).unwrap_or(CoordinateSpace::Viewport);
521-
Ok(Self { effect_type, coordinate_space })
438+
Self::NONE
522439
}
523440
}

servo/ports/geckolib/cbindgen.toml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -557,12 +557,7 @@ renaming_overrides_prefixing = true
557557
"""
558558

559559
"VectorEffect" = """
560-
StyleVectorEffect()
561-
: effect_type(StyleVectorEffectType::NONE),
562-
coordinate_space(StyleCoordinateSpace::Viewport) {}
563-
564-
bool HasNonScalingStroke() const { return bool(effect_type & StyleVectorEffectType::NON_SCALING_STROKE); }
565-
bool IsScreen() const { return coordinate_space == StyleCoordinateSpace::Screen; }
560+
bool HasNonScalingStroke() const { return bool(*this & StyleVectorEffect::NON_SCALING_STROKE); }
566561
"""
567562

568563
# TODO(emilio): Add hooks to cbindgen to be able to generate [[nodiscard]]
Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!DOCTYPE html>
22
<html>
3-
<title>non-scaling-stroke with screen transform</title>
3+
<title>non-scaling-stroke with outer viewport transform</title>
44
<link rel="help" href="https://svgwg.org/svg2-draft/painting.html#PaintingVectorEffects" />
55
<link rel="match" href="green-100x100.svg" />
66
<body>
@@ -10,24 +10,30 @@
1010
margin: 0;
1111
width: 200px;
1212
height: 200px;
13-
transform: scale(0.5);
1413
}
1514
svg {
16-
width: 100px;
17-
height: 100px;
18-
transform: scale(2) translate(-25px, -25px);
1915
transform-origin: center;
2016
transform-bxox: fill-box;
2117
}
18+
#outer {
19+
width: 100px;
20+
height: 100px;
21+
transform: scale(2);
22+
}
23+
#inner {
24+
transform: scale(0.5);
25+
}
2226
rect {
2327
fill: red;
2428
stroke: green;
2529
stroke-width: 75px;
26-
vector-effect: non-scaling-stroke screen;
30+
vector-effect: non-scaling-stroke;
2731
}
2832
</style>
29-
<svg>
30-
<rect width="75" height="75"/>
33+
<svg id="outer">
34+
<svg id="inner">
35+
<rect width="75" height="75"/>
36+
</svg>
3137
</svg>
3238
</body>
3339
</html>

0 commit comments

Comments
 (0)