mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-30 04:37:29 -06:00
Fix #3209: SVG export writes type sizes and spacing in CSS with px
With Styling set to Internal CSS, Inline Style or Style Entities, font-size and letter-spacing were written as bare numbers. Only presentation attributes take a bare number; in CSS a browser drops them, so the type was drawn at its default size. They are now written in px, SVG's user unit, and presentation attributes keep bare numbers.
This commit is contained in:
@@ -292,14 +292,18 @@ impl Writer<'_> {
|
||||
format!("matrix({} {} {} {} {} {})", self.num(c[0]), self.num(c[1]), self.num(c[2]), self.num(c[3]), self.num(c[4]), self.num(c[5]))
|
||||
}
|
||||
|
||||
/// How style properties are written: the styling option, but SVG Tiny has presentation
|
||||
/// attributes alone.
|
||||
pub(super) fn styling(&self) -> Styling {
|
||||
if self.tiny() { Styling::PresentationAttributes } else { self.opts.styling }
|
||||
}
|
||||
|
||||
/// Style properties as attributes, an inline style, or a CSS class, per the styling option.
|
||||
pub(super) fn attrs(&mut self, props: &Props) -> String {
|
||||
if props.is_empty() {
|
||||
return String::new();
|
||||
}
|
||||
// SVG Tiny has presentation attributes alone.
|
||||
let styling = if self.tiny() { Styling::PresentationAttributes } else { self.opts.styling };
|
||||
match styling {
|
||||
match self.styling() {
|
||||
Styling::PresentationAttributes => {
|
||||
// CSS-only properties go in a style attribute (SVG Tiny has none: left out).
|
||||
let (style, attrs): (Vec<_>, Vec<_>) = props.iter().partition(|(k, _)| {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use super::output::xml_text;
|
||||
use super::{
|
||||
Affine, AppearanceItem, Arc, BTreeSet, BezPath, BlendMode, CharStyle, FillRule, FontDb, FontFace, GradientKind, HashMap, Justify, Node, NodeId,
|
||||
NodeKind, Paint, PathData, Props, Rect, StrokeAlign, TextKind, TextObject, Writer, base64_encode, css, css_string, fmt_num, font_descriptor,
|
||||
xml_escape,
|
||||
NodeKind, Paint, PathData, Props, Rect, StrokeAlign, Styling, TextKind, TextObject, Writer, base64_encode, css, css_string, fmt_num,
|
||||
font_descriptor, xml_escape,
|
||||
};
|
||||
|
||||
/// `chars` (sorted) as a CSS `unicode-range` (`U+41-5A,U+61`).
|
||||
@@ -36,7 +36,10 @@ impl Writer<'_> {
|
||||
/// (as on the canvas).
|
||||
fn char_props(&mut self, st: &CharStyle, space: (Rect, Affine)) -> Props {
|
||||
let decimals = self.opts.decimals;
|
||||
let len = |v: f64| fmt_num(v, decimals);
|
||||
// Only presentation attributes take a bare number (in user units). Written as CSS, a
|
||||
// length needs its unit, a user unit being a `px`: a browser drops `font-size:8.6` (#3209).
|
||||
let unit = if self.styling() == Styling::PresentationAttributes { "" } else { "px" };
|
||||
let len = |v: f64| format!("{}{unit}", fmt_num(v, decimals));
|
||||
let mut p = css::font_props(st, &len);
|
||||
// Character paints resolve in the text's space (`to_user` maps it into user space).
|
||||
let (bounds, to_user) = space;
|
||||
|
||||
@@ -228,8 +228,16 @@ fn shared_properties_read_as_svg_export_writes_them() {
|
||||
let decl = format!("{k}:{v}").replace('"', """).replace('\'', "'");
|
||||
assert!(style.contains(&decl), "{decl} as in SVG export: {style}");
|
||||
}
|
||||
// Lengths are the same numbers, with units on the web.
|
||||
assert!(style.contains("font-size:18") && prop(&r, "font-size") == Some("18px"), "{style}");
|
||||
// Lengths are the same, with units: CSS takes a bare number only for 0, and a browser drops
|
||||
// `font-size:18`, leaving the type at its default size (#3209). Presentation attributes take
|
||||
// bare numbers (`text_layout`).
|
||||
let spacing = prop(&r, "letter-spacing").unwrap_or_default();
|
||||
assert!(prop(&r, "font-size") == Some("18px") && spacing.ends_with("px"), "{r:?}");
|
||||
for decl in ["font-size:18px".to_string(), format!("letter-spacing:{spacing}")] {
|
||||
assert!(style.contains(&decl), "{decl} as in SVG export: {style}");
|
||||
}
|
||||
let inline = export(&d, &ExportOptions { styling: Styling::InlineStyle, ..ExportOptions::default() });
|
||||
assert!(inline.contains("font-size:18px") && inline.contains(&format!("letter-spacing:{spacing}")), "{inline}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user