Commit 3edb988f authored by RazrFalcon's avatar RazrFalcon

Added partial 'baseline-shift' support.

parent f1d271d3
......@@ -8,6 +8,7 @@ This changelog also contains important changes in dependencies.
## [Unreleased]
### Added
- (resvg) Partial `baseline-shift` support.
- (resvg) Keep invisible shapes during *export by ID*.
Required for a proper bbox resolving.
......
......@@ -547,7 +547,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "svgdom"
version = "0.15.0"
source = "git+https://github.com/RazrFalcon/svgdom?rev=f69fc2a#f69fc2aecc9cbf63a5bc37bf864d047a54e577d5"
source = "git+https://github.com/RazrFalcon/svgdom?rev=dc62f70#dc62f70353ca6154aec3af0c37af74ffc0c3162e"
dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"roxmltree 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -605,7 +605,7 @@ dependencies = [
"lyon_geom 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rctree 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"svgdom 0.15.0 (git+https://github.com/RazrFalcon/svgdom?rev=f69fc2a)",
"svgdom 0.15.0 (git+https://github.com/RazrFalcon/svgdom?rev=dc62f70)",
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
......@@ -699,7 +699,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum simplecss 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "135685097a85a64067df36e28a243e94a94f76d829087ce0be34eeb014260c0e"
"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d"
"checksum svgdom 0.15.0 (git+https://github.com/RazrFalcon/svgdom?rev=f69fc2a)" = "<none>"
"checksum svgdom 0.15.0 (git+https://github.com/RazrFalcon/svgdom?rev=dc62f70)" = "<none>"
"checksum svgtypes 0.3.0 (git+https://github.com/RazrFalcon/svgtypes?rev=3034692)" = "<none>"
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
"checksum time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "847da467bf0db05882a9e2375934a8a55cffdc9db0d128af1518200260ba1f6c"
......
......@@ -33,7 +33,7 @@
### Attributes
- `alignment-baseline`
- `baseline-shift`
- Nested `baseline-shift`
- `clip` (deprecated)
- `color-interpolation`
- `color-profile`
......
......@@ -115,9 +115,6 @@ fn draw_block(
let fm = context.get_metrics(&block.font, None).unwrap();
let mut layout_iter = layout.get_iter().unwrap();
let baseline_offset = layout_iter.get_baseline().scale();
let bbox = block.bbox;
// Contains only characters path bounding box,
......@@ -129,7 +126,7 @@ fn draw_block(
let old_ts = cr.get_matrix();
if !block.rotate.is_fuzzy_zero() {
let mut ts = usvg::Transform::default();
ts.rotate_at(block.rotate, bbox.x, bbox.y + baseline_offset);
ts.rotate_at(block.rotate, bbox.x, bbox.y + block.font_ascent);
cr.transform(ts.to_native());
}
......@@ -137,7 +134,7 @@ fn draw_block(
//
// Should be drawn before/under text.
if let Some(ref style) = block.decoration.underline {
line_rect.y = bbox.y + baseline_offset - fm.get_underline_position().scale();
line_rect.y = bbox.y + block.font_ascent - fm.get_underline_position().scale();
draw_line(tree, line_rect, &style.fill, &style.stroke, opt, cr);
}
......@@ -166,7 +163,7 @@ fn draw_block(
//
// Should be drawn after/over text.
if let Some(ref style) = block.decoration.line_through {
line_rect.y = bbox.y + baseline_offset - fm.get_strikethrough_position().scale();
line_rect.y = bbox.y + block.font_ascent - fm.get_strikethrough_position().scale();
line_rect.height = fm.get_strikethrough_thickness().scale();
draw_line(tree, line_rect, &style.fill, &style.stroke, opt, cr);
}
......
......@@ -77,7 +77,7 @@ fn draw_block(
if !block.rotate.is_fuzzy_zero() {
let mut ts = usvg::Transform::default();
ts.rotate_at(block.rotate, bbox.x, bbox.y + font_metrics.ascent());
ts.rotate_at(block.rotate, bbox.x, bbox.y + block.font_ascent);
p.apply_transform(&ts.to_native());
}
......
......@@ -114,14 +114,24 @@ pub fn prepare_blocks<Font>(
x = new_w;
} else {
let baseline_shift = match tspan.baseline_shift {
usvg::BaselineShift::Baseline => 0.0,
usvg::BaselineShift::Subscript => font_metrics.height() / 2.0,
usvg::BaselineShift::Superscript => -font_metrics.height() / 2.0,
usvg::BaselineShift::Percent(n) => -font_metrics.height() * (n / 100.0),
usvg::BaselineShift::Number(n) => -n,
};
let font_ascent = font_metrics.ascent();
let width = font_metrics.width(c);
let yy = y - font_metrics.ascent();
let yy = y - font_ascent + baseline_shift;
let height = font_metrics.height();
let bbox = Rect { x, y: yy, width, height };
x += width;
// TODO: rewrite, explain
let rotate = match text_kind.rotate {
Some(ref list) => { list[blocks.len()] }
Some(ref list) => list[blocks.len()],
None => 0.0,
};
......@@ -133,7 +143,7 @@ pub fn prepare_blocks<Font>(
fill: tspan.fill.clone(),
stroke: tspan.stroke.clone(),
font: font_metrics.font(),
font_ascent: font_metrics.ascent(),
font_ascent,
decoration: tspan.decoration.clone(),
});
}
......
a-baseline-shift-001.svg
a-baseline-shift-002.svg
a-baseline-shift-003.svg
a-baseline-shift-004.svg
a-baseline-shift-005.svg
a-baseline-shift-006.svg
a-baseline-shift-007.svg
a-baseline-shift-008.svg
a-baseline-shift-009.svg
a-baseline-shift-010.svg
a-baseline-shift-011.svg
a-baseline-shift-012.svg
a-baseline-shift-013.svg
a-baseline-shift-014.svg
a-baseline-shift-015.svg
a-baseline-shift-016.svg
a-baseline-shift-017.svg
a-baseline-shift-018.svg
a-baseline-shift-001.svg
a-baseline-shift-002.svg
a-baseline-shift-003.svg
a-baseline-shift-004.svg
a-baseline-shift-005.svg
a-baseline-shift-006.svg
a-baseline-shift-007.svg
a-baseline-shift-008.svg
a-baseline-shift-009.svg
a-baseline-shift-010.svg
a-baseline-shift-011.svg
a-baseline-shift-012.svg
a-baseline-shift-013.svg
a-baseline-shift-014.svg
a-baseline-shift-015.svg
a-baseline-shift-016.svg
a-baseline-shift-017.svg
a-baseline-shift-018.svg
......@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added
- Implement `FuzzyEq` for `Rect`, `Size` and `Point`.
- `StrokeMiterlimit` and `FontSize` wrappers for `f64`.
- Partial `baseline-shift` support.
- `TextSpan::baseline_shift`.
### Changed
- Shapes without fill and stroke will no longer be removed.
......
......@@ -18,8 +18,8 @@ libflate = "0.1"
log = "0.4"
lyon_geom = "0.12"
rctree = "0.2.1"
svgdom = { git = "https://github.com/RazrFalcon/svgdom", rev = "f69fc2a" }
#svgdom = { path = "../svgdom" }
svgdom = { git = "https://github.com/RazrFalcon/svgdom", rev = "dc62f70" }
#svgdom = { path = "../../svgdom" }
unicode-segmentation = "1.2.1"
[dev-dependencies]
......
......@@ -158,7 +158,7 @@ and `clip-path` (when inside the `clipPath`) attributes.
_Text chunk_ can have `x`, `y`, `dx`, `dy` and `text-anchor` attributes.
And the _text container_ can have <<fill_attrs, filling>>,
<<stroke_attrs,stroking>>, <<font_attrs,font>>, `text-decoration`,
<<stroke_attrs,stroking>>, <<font_attrs,font>>, `baseline-shift`, `text-decoration`,
`visibility` and `clip-rule` (when inside the `clipPath`) attributes.
* `id` is optional but never empty.
......
......@@ -81,11 +81,13 @@ fn convert_chunks(
let stroke = stroke::convert(tree, attrs, true);
let decoration = conv_tspan_decoration2(tree, text_elem, &tspan);
let visibility = super::convert_visibility(attrs);
let baseline_shift = conv_baseline_shift(attrs);
let span = tree::TextSpan {
visibility,
fill,
stroke,
font: convert_font(attrs, opt),
font: conv_font(attrs, opt),
baseline_shift,
decoration,
text,
};
......@@ -192,7 +194,50 @@ fn conv_text_anchor(attrs: &svgdom::Attributes) -> tree::TextAnchor {
}
}
fn convert_font(attrs: &svgdom::Attributes, opt: &Options) -> tree::Font {
fn conv_baseline_shift(attrs: &svgdom::Attributes) -> tree::BaselineShift {
let av = attrs.get_value(AId::BaselineShift);
match av {
Some(AValue::String(ref s)) => {
match s.as_str() {
"baseline" => tree::BaselineShift::Baseline,
"sub" => tree::BaselineShift::Subscript,
"super" => tree::BaselineShift::Superscript,
_ => {
warn!("An invalid 'baseline-shift' value: '{}'. Fallback to 'baseline'.", s);
tree::BaselineShift::Baseline
}
}
}
Some(AValue::Length(len)) => {
if len.num.is_fuzzy_zero() {
tree::BaselineShift::Baseline
} else {
match len.unit {
Unit::Percent => {
tree::BaselineShift::Percent(len.num)
}
_ => {
warn!("'baseline-shift' value must be a number or a percent.");
tree::BaselineShift::Baseline
}
}
}
}
Some(AValue::Number(n)) => {
tree::BaselineShift::Number(*n)
}
None => {
// Fallback to a default value.
tree::BaselineShift::Baseline
}
_ => {
warn!("An invalid 'baseline-shift' value: '{:?}'. Fallback to 'baseline'.", av);
tree::BaselineShift::Baseline
}
}
}
fn conv_font(attrs: &svgdom::Attributes, opt: &Options) -> tree::Font {
let style = attrs.get_str_or(AId::FontStyle, "normal");
let style = match style {
"normal" => tree::FontStyle::Normal,
......
......@@ -81,6 +81,11 @@ pub fn convert_units(svg: &mut Node, opt: &Options) {
} else if aid == AId::Offset && len.unit == Unit::Percent {
// The `offset` % value does not depend on viewBox.
len.num / 100.0
} else if aid == AId::BaselineShift && len.unit == Unit::Percent {
// `baseline-shift` should be kept as is, because it's % value
// corresponds to a fraction of the line height.
// And we don't know it.
continue;
} else {
// In other elements % units are depend on viewBox.
convert_len(len, aid, font_size)
......
......@@ -488,3 +488,15 @@ pub enum FeImageKind {
/// Not supported yet.
Use(String),
}
/// A baseline shift value.
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
pub enum BaselineShift {
Baseline,
Subscript,
Superscript,
Percent(f64),
Number(f64),
}
......@@ -363,6 +363,7 @@ fn conv_elements(
conv_fill(tree, &tspan.fill, defs, parent, &mut tspan_elem);
conv_stroke(tree, &tspan.stroke, defs, &mut tspan_elem);
conv_font(&tspan.font, &mut tspan_elem);
conv_baseline_shift(tspan.baseline_shift, &mut tspan_elem);
if tspan.text.contains(" ") {
is_preserve_required = true;
......@@ -637,6 +638,21 @@ fn conv_font(
));
}
fn conv_baseline_shift(
baseline_shift: BaselineShift,
node: &mut svgdom::Node,
) {
let av: AValue = match baseline_shift {
BaselineShift::Baseline => "baseline".into(),
BaselineShift::Subscript => "sub".into(),
BaselineShift::Superscript => "super".into(),
BaselineShift::Percent(n) => svgdom::Length::new(n, svgdom::LengthUnit::Percent).into(),
BaselineShift::Number(n) => n.into(),
};
node.set_attribute((AId::BaselineShift, av));
}
fn conv_link(
tree: &Tree,
defs: &svgdom::Node,
......
......@@ -189,6 +189,9 @@ pub struct TextSpan {
/// Font description.
pub font: Font,
/// Baseline shift.
pub baseline_shift: BaselineShift,
/// Text decoration.
///
/// Unlike `text-decoration` attribute from the SVG, this one has all styles resolved.
......
This diff is collapsed.
......@@ -386,6 +386,7 @@ test!(preserve_id, false,
fill-opacity='1'
fill-rule='nonzero'
stroke='none'
baseline-shift='baseline'
font-family='Times New Roman'
font-size='12'
font-stretch='normal'
......@@ -399,6 +400,7 @@ test!(preserve_id, false,
fill-opacity='1'
fill-rule='nonzero'
stroke='none'
baseline-shift='baseline'
font-family='Times New Roman'
font-size='12'
font-stretch='normal'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment