Skip to content

Commit d335cf7

Browse files
sleepy-monaxLouciole
authored andcommitted
vaev-style: Update stroke handling in SVG rendering and add strokeOpacity property.
1 parent 1716d9d commit d335cf7

File tree

4 files changed

+61
-16
lines changed

4 files changed

+61
-16
lines changed

src/vaev-engine/layout/base/fragment.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ struct GroupFrag : SVG::Frag {
8181
e("(GroupFrag)");
8282
}
8383
};
84+
8485
} // namespace SVG
8586

8687
struct SVGRootFrag : SVG::GroupFrag {

src/vaev-engine/layout/svg.cpp

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -86,22 +86,22 @@ struct Rectangle {
8686
}
8787
};
8888

89-
Rc<Scene::Node> rectToSceneNode(Rectangle<f64> rect, Opt<Gfx::Fill> fill, Opt<Gfx::Fill> strokeColor, f64 strokeWidth) {
89+
Rc<Scene::Node> rectToSceneNode(Rectangle<f64> rect, Opt<Gfx::Fill> fill, Opt<Gfx::Stroke> const& stroke) {
9090
Gfx::Borders borders;
91-
if (strokeColor and strokeWidth > 0) {
91+
if (stroke) {
9292
borders = Gfx::Borders{
9393
Math::Radiif{},
94-
Math::Insetsf{strokeWidth},
95-
Array<Gfx::Fill, 4>::fill(*strokeColor),
94+
Math::Insetsf{stroke->width},
95+
Array<Gfx::Fill, 4>::fill(stroke->fill),
9696
Array<Gfx::BorderStyle, 4>::fill(Gfx::BorderStyle::SOLID),
9797
};
9898

9999
// FIXME: needed due to mismatch between SVG's and Scene's box model
100100
// svg's stroke's center is at the shape's edges
101-
rect.width += strokeWidth;
102-
rect.height += strokeWidth;
103-
rect.x -= strokeWidth / 2;
104-
rect.y -= strokeWidth / 2;
101+
rect.width += stroke->width;
102+
rect.height += stroke->width;
103+
rect.x -= stroke->width / 2;
104+
rect.y -= stroke->width / 2;
105105
}
106106

107107
return makeRc<Scene::Box>(
@@ -267,18 +267,33 @@ struct ShapeFrag : Frag {
267267
unreachable();
268268
}
269269

270+
Opt<Gfx::Stroke> _resolveStroke(SVGProps const& style, Gfx::Color currentColor) const {
271+
Opt<Gfx::Color> color = Vaev::Layout::resolve(style.stroke, currentColor);
272+
if (not color)
273+
return NONE;
274+
275+
if (Math::epsilonEq(style.strokeOpacity, 0.))
276+
return NONE;
277+
278+
color = color->withOpacity(style.strokeOpacity);
279+
280+
if (strokeWidth == 0_au)
281+
return NONE;
282+
283+
return Gfx::Stroke{*color, static_cast<f64>(strokeWidth)};
284+
}
285+
270286
Rc<Scene::Node> toSceneNode(Gfx::Color currentColor) const {
271-
Opt<Gfx::Color> resolvedFill = Vaev::Layout::resolve(box->style->svg->fill, currentColor).map([&](auto fill) {
272-
return fill.withOpacity(box->style->svg->fillOpacity);
287+
auto const& style = *box->style->svg;
288+
289+
Opt<Gfx::Color> resolvedFill = Vaev::Layout::resolve(style.fill, currentColor).map([&](auto fill) {
290+
return fill.withOpacity(style.fillOpacity);
273291
});
274-
Opt<Gfx::Color> resolvedStrokeColor = Vaev::Layout::resolve(box->style->svg->stroke, currentColor);
275-
Opt<Gfx::Stroke> resolvedStroke =
276-
resolvedStrokeColor
277-
? Opt<Gfx::Stroke>{{*resolvedStrokeColor, (f64)strokeWidth}}
278-
: NONE;
292+
293+
Opt<Gfx::Stroke> resolvedStroke = _resolveStroke(style, currentColor);
279294

280295
if (auto rect = shape.is<Rectangle<Au>>()) {
281-
return rectToSceneNode(rect->cast<f64>(), resolvedFill, resolvedStrokeColor, (f64)strokeWidth);
296+
return rectToSceneNode(rect->cast<f64>(), resolvedFill, resolvedStroke);
282297
} else if (auto circle = shape.is<Circle<Au>>()) {
283298
return circleToSceneNode(circle->cast<f64>(), resolvedFill, resolvedStroke);
284299
} else if (auto path = shape.is<Rc<Math::Path>>()) {

src/vaev-engine/style/props.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3369,6 +3369,33 @@ export struct SVGStrokeProp {
33693369
}
33703370
};
33713371

3372+
// https://svgwg.org/svg2-draft/painting.html#StrokeOpacity
3373+
export struct SvgStrokeOpacityProp {
3374+
Number value = initial();
3375+
3376+
static Str name() { return "stroke-opacity"; }
3377+
3378+
static f64 initial() { return 1; }
3379+
3380+
void apply(SpecifiedValues& c) const {
3381+
c.svg.cow().strokeOpacity = value;
3382+
}
3383+
3384+
static f64 load(SpecifiedValues const& c) {
3385+
return c.svg->strokeOpacity;
3386+
}
3387+
3388+
Res<> parse(Cursor<Css::Sst>& c) {
3389+
auto maybePercent = parseValue<Percent>(c);
3390+
if (maybePercent) {
3391+
value = maybePercent.unwrap().value() / 100;
3392+
} else {
3393+
value = try$(parseValue<Number>(c));
3394+
}
3395+
return Ok();
3396+
}
3397+
};
3398+
33723399
// https://svgwg.org/svg2-draft/painting.html#FillOpacity
33733400
export struct FillOpacityProp {
33743401
Number value = initial();
@@ -3671,6 +3698,7 @@ using _StyleProp = Union<
36713698
SVGFillProp,
36723699
SVGDProp,
36733700
SVGStrokeProp,
3701+
SvgStrokeOpacityProp,
36743702
SVGViewBoxProp,
36753703
FillOpacityProp,
36763704
StrokeWidthProp

src/vaev-engine/values/svg.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export struct SVGProps {
6464

6565
Number fillOpacity = 1;
6666
PercentOr<Length> strokeWidth = Length{1_au};
67+
Number strokeOpacity = 1;
6768
Union<String, None> d = NONE;
6869
Paint fill = Color{Gfx::BLACK};
6970
Paint stroke = NONE;

0 commit comments

Comments
 (0)