Skip to content

Commit

Permalink
Implement text path map
Browse files Browse the repository at this point in the history
  • Loading branch information
LaurenzV committed Dec 5, 2023
1 parent cc98d68 commit 7245735
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 32 deletions.
9 changes: 6 additions & 3 deletions crates/resvg/tests/integration/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,17 @@ pub fn render(name: &str) -> usize {
let tree = {
let svg_data = std::fs::read(&svg_path).unwrap();
// TODO: Revert this
let db = GLOBAL_FONTDB.lock().unwrap();
let mut original_tree = usvg::Tree::from_data(&svg_data, &opt)
.unwrap();
original_tree.convert_text(&db);

let mut tree = usvg::Tree::from_str(
&usvg::Tree::from_data(&svg_data, &opt)
.unwrap()
&original_tree
.to_string(&XmlOptions::default()),
&opt,
)
.unwrap();
let db = GLOBAL_FONTDB.lock().unwrap();
tree.convert_text(&db);
tree
};
Expand Down
6 changes: 5 additions & 1 deletion crates/usvg-parser/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,11 @@ fn resolve_text_flow(node: SvgNode, state: &converter::State) -> Option<TextFlow
};

let id = linked_node.element_id().to_string();
Some(TextFlow::Path(Rc::new(TextPath { id, start_offset, path })))
Some(TextFlow::Path(Rc::new(TextPath {
id,
start_offset,
path,
})))
}

fn convert_font(node: SvgNode, state: &converter::State) -> Font {
Expand Down
6 changes: 5 additions & 1 deletion crates/usvg-tree/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1297,7 +1297,11 @@ impl NodeExt for Node {

fn calc_node_bbox(node: &Node, ts: Transform) -> Option<BBox> {
match *node.borrow() {
NodeKind::Path(ref path) => path.data.compute_tight_bounds()?.transform(ts).map(BBox::from),
NodeKind::Path(ref path) => path
.data
.compute_tight_bounds()?
.transform(ts)
.map(BBox::from),
NodeKind::Image(ref img) => img.view_box.rect.transform(ts).map(BBox::from),
NodeKind::Group(_) => {
let mut bbox = BBox::default();
Expand Down
1 change: 0 additions & 1 deletion crates/usvg/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,3 @@ impl TreeWriting for usvg_tree::Tree {
writer::convert(self, opt)
}
}

79 changes: 53 additions & 26 deletions crates/usvg/src/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ struct WriterContext<'a> {
next_linear_gradient_index: usize,
next_radial_gradient_index: usize,
next_pattern_index: usize,
next_path_index: usize,

text_path_map: HashMap<String, String>,
}

impl WriterContext<'_> {
Expand Down Expand Up @@ -129,6 +132,12 @@ impl WriterContext<'_> {
id
}

fn gen_path_id(&mut self) -> String {
let (new_index, id) = self.gen_id("path", self.next_path_index);
self.next_path_index = new_index;
id
}

fn push_defs_id<T>(&mut self, node: &Rc<T>, id: String) {
let key = Rc::as_ptr(node) as usize;
if !self.id_map.contains_key(&key) {
Expand Down Expand Up @@ -180,6 +189,8 @@ pub(crate) fn convert(tree: &Tree, opt: &XmlOptions) -> String {
next_linear_gradient_index: 0,
next_radial_gradient_index: 0,
next_pattern_index: 0,
next_path_index: 0,
text_path_map: HashMap::new(),
};
collect_ids(tree, &mut ctx);

Expand Down Expand Up @@ -722,6 +733,30 @@ fn conv_defs(tree: &Tree, ctx: &mut WriterContext, xml: &mut XmlWriter) {

xml.end_element();
}

if tree.has_text_nodes() {
// TODO: doesn't check for text in patterns and masks...
for node in tree.root.descendants() {
if let NodeKind::Text(ref text) = *node.borrow() {
for chunk in &text.chunks {
if let TextFlow::Path(ref text_path) = chunk.text_flow {
let path = Path {
id: ctx.gen_path_id(),
data: text_path.path.clone(),
visibility: Visibility::default(),
fill: None,
stroke: None,
rendering_mode: ShapeRendering::default(),
paint_order: PaintOrder::default(),
};
write_path(&path, false, Transform::default(), None, ctx, xml);
ctx.text_path_map
.insert(text_path.id.clone(), path.id.clone());
}
}
}
}
}
}

fn conv_elements(parent: &Node, is_clip_path: bool, ctx: &mut WriterContext, xml: &mut XmlWriter) {
Expand Down Expand Up @@ -893,19 +928,11 @@ fn conv_element(node: &Node, is_clip_path: bool, ctx: &mut WriterContext, xml: &
}

if !text.dx.is_empty() && text.dx.iter().any(|dx| *dx != 0.0) {
xml.write_numbers(
AId::Dx,
&text
.dx
);
xml.write_numbers(AId::Dx, &text.dx);
}

if !text.dy.is_empty() && text.dy.iter().any(|dy| *dy != 0.0) {
xml.write_numbers(
AId::Dy,
&text
.dy
);
xml.write_numbers(AId::Dy, &text.dy);
}

xml.set_preserve_whitespaces(true);
Expand All @@ -915,10 +942,10 @@ fn conv_element(node: &Node, is_clip_path: bool, ctx: &mut WriterContext, xml: &
xml.start_svg_element(EId::TextPath);

xml.write_attribute_raw("xlink:href", |buf| {
// let ref_path = writer_context.text_path_map.pop().unwrap();
// let prefix = writer_context.opt.id_prefix.as_deref().unwrap_or_default();
// let url = format!("#{}{}", prefix, ref_path);
// buf.extend_from_slice(url.as_bytes());
let ref_path = ctx.text_path_map.get(&text_path.id).unwrap();
let prefix = ctx.opt.id_prefix.as_deref().unwrap_or_default();
let url = format!("#{}{}", prefix, ref_path);
buf.extend_from_slice(url.as_bytes());
});

if text_path.start_offset != 0.0 {
Expand Down Expand Up @@ -964,11 +991,11 @@ fn conv_element(node: &Node, is_clip_path: bool, ctx: &mut WriterContext, xml: &
("line-through", &span.decoration.line_through),
("overline", &span.decoration.overline),
]
.iter()
.filter_map(|&(key, option_value)| {
option_value.as_ref().map(|value| (key, value))
})
.collect();
.iter()
.filter_map(|&(key, option_value)| {
option_value.as_ref().map(|value| (key, value))
})
.collect();

for (deco_name, deco) in &decorations {
xml.start_svg_element(EId::Tspan);
Expand Down Expand Up @@ -1656,25 +1683,25 @@ fn write_span(
DominantBaseline::Alphabetic => "alphabetic",
DominantBaseline::Hanging => "hanging",
DominantBaseline::Mathematical => "mathematical",
DominantBaseline::Auto => unreachable!()
DominantBaseline::Auto => unreachable!(),
};
xml.write_svg_attribute(AId::DominantBaseline, name);
}

if span.alignment_baseline != AlignmentBaseline::Auto {
let name = match span.alignment_baseline {
AlignmentBaseline::Baseline => "baseline",
AlignmentBaseline::Baseline => "baseline",
AlignmentBaseline::BeforeEdge => "before-edge",
AlignmentBaseline::TextBeforeEdge => "text-before-edge",
AlignmentBaseline::Middle => "middle",
AlignmentBaseline::Central => "central",
AlignmentBaseline::TextBeforeEdge => "text-before-edge",
AlignmentBaseline::Middle => "middle",
AlignmentBaseline::Central => "central",
AlignmentBaseline::AfterEdge => "after-edge",
AlignmentBaseline::TextAfterEdge => "text-after-edge",
AlignmentBaseline::Ideographic => "ideographic",
AlignmentBaseline::Alphabetic => "alphabetic",
AlignmentBaseline::Hanging => "hanging",
AlignmentBaseline::Hanging => "hanging",
AlignmentBaseline::Mathematical => "mathematical",
AlignmentBaseline::Auto => unreachable!()
AlignmentBaseline::Auto => unreachable!(),
};
xml.write_svg_attribute(AId::AlignmentBaseline, name);
}
Expand Down

0 comments on commit 7245735

Please sign in to comment.