mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-10-28 06:55:52 +02:00
Bug 1958768 - rollup patch of bug 1904891 and bug 1903546 to fix non-scaling-stroke in nested svg cases r=emilio a=diannaS
Differential Revision: https://phabricator.services.mozilla.com/D244710
This commit is contained in:
parent
22baf2b144
commit
08c68403f0
18 changed files with 140 additions and 23 deletions
|
|
@ -489,7 +489,9 @@ SVGViewportElement* SVGContentUtils::GetNearestViewportElement(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM,
|
||||
enum class CTMType { NearestViewport, OuterViewport, Screen };
|
||||
|
||||
static gfx::Matrix GetCTMInternal(SVGElement* aElement, CTMType aCTMType,
|
||||
bool aHaveRecursed) {
|
||||
auto getLocalTransformHelper =
|
||||
[](SVGElement const* e, bool shouldIncludeChildToUserSpace) -> gfxMatrix {
|
||||
|
|
@ -530,7 +532,8 @@ static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM,
|
|||
!ancestor->IsSVGElement(nsGkAtoms::foreignObject)) {
|
||||
element = static_cast<SVGElement*>(ancestor);
|
||||
matrix *= getLocalTransformHelper(element, true);
|
||||
if (!aScreenCTM && SVGContentUtils::EstablishesViewport(element)) {
|
||||
if (aCTMType == CTMType::NearestViewport &&
|
||||
SVGContentUtils::EstablishesViewport(element)) {
|
||||
if (!element->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::symbol)) {
|
||||
NS_ERROR("New (SVG > 1.1) SVG viewport establishing element?");
|
||||
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,
|
|||
}
|
||||
ancestor = ancestor->GetFlattenedTreeParent();
|
||||
}
|
||||
if (!aScreenCTM) {
|
||||
if (aCTMType == CTMType::NearestViewport) {
|
||||
// didn't find a nearestViewportElement
|
||||
return gfx::Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
|
||||
}
|
||||
|
|
@ -568,13 +571,16 @@ static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM,
|
|||
int32_t appUnitsPerCSSPixel = AppUnitsPerCSSPixel();
|
||||
tm.PostTranslate(NSAppUnitsToFloatPixels(bp.left, appUnitsPerCSSPixel),
|
||||
NSAppUnitsToFloatPixels(bp.top, appUnitsPerCSSPixel));
|
||||
if (aCTMType == CTMType::OuterViewport) {
|
||||
return tm;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ancestor || !ancestor->IsElement()) {
|
||||
return tm;
|
||||
}
|
||||
if (auto* ancestorSVG = SVGElement::FromNode(ancestor)) {
|
||||
return tm * GetCTMInternal(ancestorSVG, true, true);
|
||||
return tm * GetCTMInternal(ancestorSVG, aCTMType, true);
|
||||
}
|
||||
nsIFrame* parentFrame = frame->GetParent();
|
||||
if (!parentFrame) {
|
||||
|
|
@ -612,16 +618,20 @@ static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM,
|
|||
}
|
||||
return nearestSVGAncestor
|
||||
? tm * GetCTMInternal(static_cast<SVGElement*>(nearestSVGAncestor),
|
||||
true, true)
|
||||
aCTMType, true)
|
||||
: tm;
|
||||
}
|
||||
|
||||
gfx::Matrix SVGContentUtils::GetCTM(SVGElement* aElement) {
|
||||
return GetCTMInternal(aElement, false, false);
|
||||
return GetCTMInternal(aElement, CTMType::NearestViewport, false);
|
||||
}
|
||||
|
||||
gfx::Matrix SVGContentUtils::GetOuterViewportCTM(SVGElement* aElement) {
|
||||
return GetCTMInternal(aElement, CTMType::OuterViewport, false);
|
||||
}
|
||||
|
||||
gfx::Matrix SVGContentUtils::GetScreenCTM(SVGElement* aElement) {
|
||||
return GetCTMInternal(aElement, true, false);
|
||||
return GetCTMInternal(aElement, CTMType::Screen, false);
|
||||
}
|
||||
|
||||
void SVGContentUtils::RectilinearGetStrokeBounds(
|
||||
|
|
|
|||
|
|
@ -197,6 +197,8 @@ class SVGContentUtils {
|
|||
|
||||
static Matrix GetCTM(dom::SVGElement* aElement);
|
||||
|
||||
static Matrix GetOuterViewportCTM(dom::SVGElement* aElement);
|
||||
|
||||
static Matrix GetScreenCTM(dom::SVGElement* aElement);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ bool SVGGeometryElement::IsPointInStroke(const DOMPointInit& aPoint) {
|
|||
SVGGeometryProperty::DoForComputedStyle(this, [&](const ComputedStyle* s) {
|
||||
// Per spec, we should take vector-effect into account.
|
||||
if (s->StyleSVGReset()->HasNonScalingStroke()) {
|
||||
auto mat = SVGContentUtils::GetCTM(this);
|
||||
auto mat = SVGContentUtils::GetOuterViewportCTM(this);
|
||||
if (mat.HasNonTranslation()) {
|
||||
// We have non-scaling-stroke as well as a non-translation transform.
|
||||
// We should transform the path first then apply the stroke on the
|
||||
|
|
|
|||
|
|
@ -174,7 +174,6 @@ rusty-enums = [
|
|||
"mozilla::StyleMaskMode",
|
||||
"mozilla::StyleScrollBehavior",
|
||||
"mozilla::StyleColorInterpolation",
|
||||
"mozilla::StyleVectorEffect",
|
||||
"mozilla::StyleBackfaceVisibility",
|
||||
"mozilla::StyleBlend",
|
||||
"mozilla::StyleMaskComposite",
|
||||
|
|
@ -591,6 +590,7 @@ cbindgen-types = [
|
|||
{ gecko = "StylePageOrientation", servo = "crate::values::generics::page::PageOrientation" },
|
||||
{ gecko = "StylePageSize", servo = "crate::values::computed::page::PageSize" },
|
||||
{ gecko = "StyleDProperty", servo = "crate::values::specified::svg::DProperty" },
|
||||
{ gecko = "StyleVectorEffect", servo = "crate::values::specified::svg::VectorEffect" },
|
||||
{ gecko = "StyleImageRendering", servo = "crate::values::computed::ImageRendering" },
|
||||
{ gecko = "StylePrintColorAdjust", servo = "crate::values::computed::PrintColorAdjust" },
|
||||
{ gecko = "StyleForcedColorAdjust", servo = "crate::values::computed::ForcedColorAdjust" },
|
||||
|
|
|
|||
|
|
@ -549,9 +549,6 @@ enum class StyleColorInterpolation : uint8_t {
|
|||
Linearrgb = 2,
|
||||
};
|
||||
|
||||
// vector-effect
|
||||
enum class StyleVectorEffect : uint8_t { None = 0, NonScalingStroke = 1 };
|
||||
|
||||
// 3d Transforms - Backface visibility
|
||||
enum class StyleBackfaceVisibility : uint8_t { Hidden = 0, Visible = 1 };
|
||||
|
||||
|
|
|
|||
|
|
@ -907,7 +907,7 @@ nsStyleSVGReset::nsStyleSVGReset()
|
|||
mLightingColor(StyleColor::White()),
|
||||
mStopOpacity(1.0f),
|
||||
mFloodOpacity(1.0f),
|
||||
mVectorEffect(StyleVectorEffect::None),
|
||||
mVectorEffect(StyleVectorEffect::NONE),
|
||||
mMaskType(StyleMaskType::Luminance),
|
||||
mD(StyleDProperty::None()) {
|
||||
MOZ_COUNT_CTOR(nsStyleSVGReset);
|
||||
|
|
|
|||
|
|
@ -1910,7 +1910,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVGReset {
|
|||
bool HasMask() const;
|
||||
|
||||
bool HasNonScalingStroke() const {
|
||||
return mVectorEffect == mozilla::StyleVectorEffect::NonScalingStroke;
|
||||
return mVectorEffect.HasNonScalingStroke();
|
||||
}
|
||||
|
||||
// geometry properties
|
||||
|
|
|
|||
|
|
@ -9788,7 +9788,7 @@ var gCSSProperties = {
|
|||
applies_to_first_line: true,
|
||||
initial_values: ["none"],
|
||||
other_values: ["non-scaling-stroke"],
|
||||
invalid_values: [],
|
||||
invalid_values: ["none non-scaling-stroke"],
|
||||
},
|
||||
"-moz-window-dragging": {
|
||||
domProp: "MozWindowDragging",
|
||||
|
|
|
|||
|
|
@ -1078,8 +1078,9 @@ bool SVGUtils::GetNonScalingStrokeTransform(const nsIFrame* aFrame,
|
|||
|
||||
MOZ_ASSERT(aFrame->GetContent()->IsSVGElement(), "should be an SVG element");
|
||||
|
||||
*aUserToOuterSVG = ThebesMatrix(
|
||||
SVGContentUtils::GetCTM(static_cast<SVGElement*>(aFrame->GetContent())));
|
||||
SVGElement* content = static_cast<SVGElement*>(aFrame->GetContent());
|
||||
*aUserToOuterSVG =
|
||||
ThebesMatrix(SVGContentUtils::GetOuterViewportCTM(content));
|
||||
|
||||
return aUserToOuterSVG->HasNonTranslation() && !aUserToOuterSVG->IsSingular();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -617,6 +617,7 @@ class Longhand(Property):
|
|||
"TouchAction",
|
||||
"TransformStyle",
|
||||
"UserSelect",
|
||||
"VectorEffect",
|
||||
"WordBreak",
|
||||
"XSpan",
|
||||
"XTextScale",
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
|
||||
<%namespace name="helpers" file="/helpers.mako.rs" />
|
||||
|
||||
${helpers.single_keyword(
|
||||
${helpers.predefined_type(
|
||||
"vector-effect",
|
||||
"none non-scaling-stroke",
|
||||
"VectorEffect",
|
||||
"computed::VectorEffect::none()",
|
||||
engines="gecko",
|
||||
gecko_enum_prefix="StyleVectorEffect",
|
||||
animation_value_type="discrete",
|
||||
spec="https://svgwg.org/svg2-draft/coords.html#VectorEffects",
|
||||
affects="layout",
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ pub use self::rect::NonNegativeLengthOrNumberRect;
|
|||
pub use self::resolution::Resolution;
|
||||
pub use self::svg::{DProperty, MozContextProperties};
|
||||
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
|
||||
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
|
||||
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth, VectorEffect};
|
||||
pub use self::text::HyphenateCharacter;
|
||||
pub use self::text::TextUnderlinePosition;
|
||||
pub use self::text::{InitialLetter, LetterSpacing, LineBreak, TextIndent};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use crate::values::computed::{LengthPercentage, NonNegativeLengthPercentage, Opa
|
|||
use crate::values::generics::svg as generic;
|
||||
use crate::Zero;
|
||||
|
||||
pub use crate::values::specified::{DProperty, MozContextProperties, SVGPaintOrder};
|
||||
pub use crate::values::specified::{DProperty, MozContextProperties, SVGPaintOrder, VectorEffect};
|
||||
|
||||
/// Computed SVG Paint value
|
||||
pub type SVGPaint = generic::GenericSVGPaint<Color, ComputedUrl>;
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ pub use self::rect::NonNegativeLengthOrNumberRect;
|
|||
pub use self::resolution::Resolution;
|
||||
pub use self::svg::{DProperty, MozContextProperties};
|
||||
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint};
|
||||
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
|
||||
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth, VectorEffect};
|
||||
pub use self::svg_path::SVGPathData;
|
||||
pub use self::text::HyphenateCharacter;
|
||||
pub use self::text::RubyPosition;
|
||||
|
|
|
|||
|
|
@ -402,3 +402,39 @@ impl Parse for DProperty {
|
|||
Ok(DProperty::Path(path_data))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Eq,
|
||||
MallocSizeOf,
|
||||
Parse,
|
||||
PartialEq,
|
||||
SpecifiedValueInfo,
|
||||
ToComputedValue,
|
||||
ToCss,
|
||||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
#[css(bitflags(single = "none", mixed = "non-scaling-stroke"))]
|
||||
#[repr(C)]
|
||||
/// https://svgwg.org/svg2-draft/coords.html#VectorEffects
|
||||
pub struct VectorEffect(u8);
|
||||
bitflags! {
|
||||
impl VectorEffect: u8 {
|
||||
/// `none`
|
||||
const NONE = 0;
|
||||
/// `non-scaling-stroke`
|
||||
const NON_SCALING_STROKE = 1 << 0;
|
||||
}
|
||||
}
|
||||
|
||||
impl VectorEffect {
|
||||
/// Returns the initial value of vector-effect
|
||||
#[inline]
|
||||
pub fn none() -> Self {
|
||||
Self::NONE
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -300,6 +300,7 @@ include = [
|
|||
"ComputedLinearStop",
|
||||
"PiecewiseLinearFunction",
|
||||
"BeforeFlag",
|
||||
"VectorEffect",
|
||||
"XTextScale",
|
||||
"Zoom",
|
||||
"TransitionProperty",
|
||||
|
|
@ -547,6 +548,10 @@ renaming_overrides_prefixing = true
|
|||
inline bool IsRight() const;
|
||||
"""
|
||||
|
||||
"VectorEffect" = """
|
||||
bool HasNonScalingStroke() const { return bool(*this & StyleVectorEffect::NON_SCALING_STROKE); }
|
||||
"""
|
||||
|
||||
# TODO(emilio): Add hooks to cbindgen to be able to generate [[nodiscard]]
|
||||
# on the functions.
|
||||
"Owned" = """
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<title>non-scaling-stroke with outer viewport transform</title>
|
||||
<link rel="help" href="https://svgwg.org/svg2-draft/painting.html#PaintingVectorEffects" />
|
||||
<link rel="match" href="green-100x100.svg" />
|
||||
<body>
|
||||
<style>
|
||||
body {
|
||||
border: none;
|
||||
margin: 0;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
svg {
|
||||
transform-origin: center;
|
||||
transform-bxox: fill-box;
|
||||
}
|
||||
#outer {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
transform: scale(2);
|
||||
}
|
||||
#inner {
|
||||
transform: scale(0.5);
|
||||
}
|
||||
rect {
|
||||
fill: red;
|
||||
stroke: green;
|
||||
stroke-width: 75px;
|
||||
vector-effect: non-scaling-stroke;
|
||||
}
|
||||
</style>
|
||||
<svg id="outer">
|
||||
<svg id="inner">
|
||||
<rect width="75" height="75"/>
|
||||
</svg>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>vector-effect test: parsing vector-effect with invalid values</title>
|
||||
<link rel="help" href="https://www.w3.org/TR/SVG2/coords.html#VectorEffects">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_invalid_value("vector-effect", "none none");
|
||||
test_invalid_value("vector-effect", "none non-scaling-stroke");
|
||||
test_invalid_value("vector-effect", "non-scaling-stroke viewport screen");
|
||||
test_invalid_value("vector-effect", "none viewport");
|
||||
test_invalid_value("vector-effect", "none screen");
|
||||
test_invalid_value("vector-effect", "viewport");
|
||||
test_invalid_value("vector-effect", "screen");
|
||||
test_invalid_value("vector-effect", "screen non-scaling-stroke");
|
||||
// The following were removed by https://github.com/w3c/svgwg/issues/582
|
||||
test_invalid_value("vector-effect", "non-scaling-stroke viewport");
|
||||
test_invalid_value("vector-effect", "non-scaling-stroke screen");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in a new issue