Skip to content

Commit 47a6b59

Browse files
committed
view: Include data attributes on glyps
1 parent 2c52c4e commit 47a6b59

File tree

3 files changed

+80
-23
lines changed

3 files changed

+80
-23
lines changed

src/svg.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use allsorts::{tag, Font};
1414

1515
use crate::cli::SvgOpts;
1616
use crate::script;
17-
use crate::writer::{GlyfPost, SVGWriter};
17+
use crate::writer::{GlyfPost, SVGMode, SVGWriter};
1818
use crate::BoxError;
1919

2020
const FONT_SIZE: f32 = 1000.0;
@@ -63,7 +63,7 @@ pub fn main(opts: SvgOpts) -> Result<i32, BoxError> {
6363
{
6464
let cff_data = provider.read_table_data(tag::CFF)?;
6565
let mut cff = ReadScope::new(&cff_data).read::<CFF<'_>>()?;
66-
let writer = SVGWriter::new(Some(opts.testcase), transform);
66+
let writer = SVGWriter::new(SVGMode::TextRenderingTests(opts.testcase), transform);
6767
writer.glyphs_to_svg(&mut cff, &mut font, &infos, direction)?
6868
} else if font.glyph_table_flags.contains(GlyphTableFlags::GLYF) {
6969
let loca_data = provider.read_table_data(tag::LOCA)?;
@@ -79,7 +79,7 @@ pub fn main(opts: SvgOpts) -> Result<i32, BoxError> {
7979
.map(|data| ReadScope::new(data).read::<PostTable<'_>>())
8080
.transpose()?;
8181
let mut glyf_post = GlyfPost { glyf, post };
82-
let writer = SVGWriter::new(Some(opts.testcase), transform);
82+
let writer = SVGWriter::new(SVGMode::TextRenderingTests(opts.testcase), transform);
8383
writer.glyphs_to_svg(&mut glyf_post, &mut font, &infos, direction)?
8484
} else {
8585
eprintln!("no glyf or CFF table");

src/view.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use allsorts::tinyvec::tiny_vec;
1515

1616
use crate::cli::ViewOpts;
1717
use crate::script;
18-
use crate::writer::{GlyfPost, SVGWriter};
18+
use crate::writer::{GlyfPost, SVGMode, SVGWriter};
1919
use crate::BoxError;
2020

2121
const FONT_SIZE: f32 = 1000.0;
@@ -79,7 +79,7 @@ pub fn main(opts: ViewOpts) -> Result<i32, BoxError> {
7979
{
8080
let cff_data = provider.read_table_data(tag::CFF)?;
8181
let mut cff = ReadScope::new(&cff_data).read::<CFF<'_>>()?;
82-
let writer = SVGWriter::new(None, transform);
82+
let writer = SVGWriter::new(SVGMode::View, transform);
8383
writer.glyphs_to_svg(&mut cff, &mut font, &infos, direction)?
8484
} else if font.glyph_table_flags.contains(GlyphTableFlags::GLYF) {
8585
let loca_data = provider.read_table_data(tag::LOCA)?;
@@ -95,7 +95,7 @@ pub fn main(opts: ViewOpts) -> Result<i32, BoxError> {
9595
.map(|data| ReadScope::new(data).read::<PostTable<'_>>())
9696
.transpose()?;
9797
let mut glyf_post = GlyfPost { glyf, post };
98-
let writer = SVGWriter::new(None, transform);
98+
let writer = SVGWriter::new(SVGMode::View, transform);
9999
writer.glyphs_to_svg(&mut glyf_post, &mut font, &infos, direction)?
100100
} else {
101101
eprintln!("no glyf or CFF table");

src/writer.rs

+74-17
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
use std::borrow::Cow;
12
use std::collections::HashMap;
23

34
use allsorts::cff::CFF;
45
use allsorts::context::Glyph;
56
use allsorts::error::ParseError;
67
use allsorts::glyph_position::{GlyphLayout, GlyphPosition, TextDirection};
7-
use allsorts::gpos::Info;
8+
use allsorts::gpos::{Info, Placement};
9+
use allsorts::gsub::GlyphOrigin;
810
use allsorts::outline::{OutlineBuilder, OutlineSink};
911
use allsorts::pathfinder_geometry::line_segment::LineSegment2F;
1012
use allsorts::pathfinder_geometry::transform2d::Matrix2x2F;
@@ -64,8 +66,18 @@ impl<'a> OutlineBuilder for GlyfPost<'a> {
6466
}
6567
}
6668

69+
pub enum SVGMode {
70+
/// SVGs are being generated to comply with the expected output of the
71+
/// [Unicode text rendering tests](https://github.com/unicode-org/text-rendering-tests).
72+
///
73+
/// The String is the testcase name to be used as a prefix on ids.
74+
TextRenderingTests(String),
75+
/// SVGs are being generated for human viewing
76+
View,
77+
}
78+
6779
pub struct SVGWriter {
68-
id_prefix: Option<String>,
80+
mode: SVGMode,
6981
transform: Matrix2x2F,
7082
usage: Vec<(usize, Vector2F)>,
7183
}
@@ -76,9 +88,9 @@ struct Symbols<'info> {
7688
}
7789

7890
impl SVGWriter {
79-
pub fn new(id_prefix: Option<String>, transform: Matrix2x2F) -> Self {
91+
pub fn new(mode: SVGMode, transform: Matrix2x2F) -> Self {
8092
SVGWriter {
81-
id_prefix,
93+
mode,
8294
transform,
8395
usage: Vec::new(),
8496
}
@@ -188,9 +200,10 @@ impl SVGWriter {
188200
// Write symbols
189201
for symbol in &symbols.symbols {
190202
w.start_element("symbol");
191-
let id = SVGWriter::format_id(&self.id_prefix, &symbol.glyph_name);
192-
// let class = SVGWriter::class(&symbol.glyph_name);
193-
w.write_attribute("id", &id);
203+
w.write_attribute("id", &symbol.id(&self.mode));
204+
for (key, value) in symbol.data(&self.mode) {
205+
w.write_attribute(key, &value);
206+
}
194207
w.write_attribute("overflow", "visible");
195208
w.start_element("path");
196209
w.write_attribute("d", &symbol.path);
@@ -202,23 +215,14 @@ impl SVGWriter {
202215
for (symbol_index, point) in self.usage {
203216
w.start_element("use");
204217
let symbol = &symbols.symbols[symbol_index];
205-
let id = SVGWriter::format_id(&self.id_prefix, &symbol.glyph_name);
206-
let href = format!("#{}", id);
207-
w.write_attribute("xlink:href", &href);
218+
w.write_attribute("xlink:href", &format!("#{}", symbol.id(&self.mode)));
208219
w.write_attribute("x", &point.x().round());
209220
w.write_attribute("y", &point.y().round());
210221
w.end_element();
211222
}
212223

213224
w.end_document()
214225
}
215-
216-
fn format_id(id_prefix: &Option<String>, glyph_name: &str) -> String {
217-
match id_prefix {
218-
Some(id_prefix) => format!("{}.{}", id_prefix, glyph_name),
219-
None => glyph_name.to_owned(),
220-
}
221-
}
222226
}
223227

224228
impl<'info> Symbols<'info> {
@@ -241,6 +245,59 @@ impl<'info> Symbol<'info> {
241245
info,
242246
}
243247
}
248+
249+
fn id(&self, mode: &SVGMode) -> Cow<'_, str> {
250+
match mode {
251+
SVGMode::TextRenderingTests(id_prefix) => {
252+
format!("{}.{}", id_prefix, self.glyph_name).into()
253+
}
254+
SVGMode::View => Cow::from(&self.glyph_name),
255+
}
256+
}
257+
258+
fn data(&self, mode: &SVGMode) -> HashMap<&'static str, String> {
259+
match mode {
260+
SVGMode::TextRenderingTests(_) => HashMap::new(),
261+
SVGMode::View => {
262+
let bool_true = String::from("true");
263+
let mut data = HashMap::new();
264+
if matches!(
265+
self.info.placement,
266+
Placement::MarkAnchor(_, _, _) | Placement::MarkOverprint(_)
267+
) {
268+
data.insert("data-mark", bool_true.clone());
269+
}
270+
data.insert("data-glyph-index", self.info.glyph.glyph_index.to_string());
271+
data.insert(
272+
"data-liga-component-pos",
273+
self.info.glyph.liga_component_pos.to_string(),
274+
);
275+
data.insert(
276+
"data-glyph-origin",
277+
match self.info.glyph.glyph_origin {
278+
GlyphOrigin::Char(_) => String::from("char"),
279+
GlyphOrigin::Direct => String::from("direct"),
280+
},
281+
);
282+
if self.info.glyph.small_caps {
283+
data.insert("data-small-caps", bool_true.clone());
284+
}
285+
if self.info.glyph.multi_subst_dup {
286+
data.insert("data-multi-subst-dup", bool_true.clone());
287+
}
288+
if self.info.glyph.is_vert_alt {
289+
data.insert("data-is-vert-alt", bool_true.clone());
290+
}
291+
if self.info.glyph.fake_bold {
292+
data.insert("data-fake-bold", bool_true.clone());
293+
}
294+
if self.info.glyph.fake_italic {
295+
data.insert("data-fake-italic", bool_true.clone());
296+
}
297+
data
298+
}
299+
}
300+
}
244301
}
245302

246303
impl<'info> OutlineSink for Symbols<'info> {

0 commit comments

Comments
 (0)