Commit 07b51916 authored by RazrFalcon's avatar RazrFalcon

Added 'letter-spacing' support.

Added 'word-spacing' support for Qt backend.
parent 39a90890
......@@ -9,6 +9,9 @@ This changelog also contains important changes in dependencies.
## [Unreleased]
### Added
- (resvg) Partial `baseline-shift` support.
- (resvg) `letter-spacing` support.
- (qt-backend) `word-spacing` support.
Does not work on the cairo backend.
- (resvg) Keep invisible shapes during *export by ID*.
Required for a proper bbox resolving.
......
......@@ -490,7 +490,7 @@ dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pango 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pangocairo 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"resvg-qt 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"resvg-qt 0.4.0 (git+https://github.com/RazrFalcon/libresvg-qt?rev=4dd0b40)",
"rgb 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"usvg 0.4.0",
......@@ -510,7 +510,7 @@ dependencies = [
[[package]]
name = "resvg-qt"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/RazrFalcon/libresvg-qt?rev=4dd0b40#4dd0b406574aaffd23104dbc772d4d33190b56f3"
dependencies = [
"cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -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=dc62f70#dc62f70353ca6154aec3af0c37af74ffc0c3162e"
source = "git+https://github.com/RazrFalcon/svgdom?rev=f53af72#f53af72283fbc6fdfc3ff00a3238f3e4b3e053c1"
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=dc62f70)",
"svgdom 0.15.0 (git+https://github.com/RazrFalcon/svgdom?rev=f53af72)",
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
......@@ -693,13 +693,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
"checksum rctree 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1817e0f0056f95bce0d6ab1a5be62ca24bd756b5547c20637ef47cc9a2065f4b"
"checksum redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a84bcd297b87a545980a2d25a0beb72a1f490c31f0a9fde52fca35bfbb1ceb70"
"checksum resvg-qt 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c2efacc41fc639ff3bf9c02c923a69a1cff354ef4fffbb772be45fbfdeb7f30"
"checksum resvg-qt 0.4.0 (git+https://github.com/RazrFalcon/libresvg-qt?rev=4dd0b40)" = "<none>"
"checksum rgb 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "002bebda58b24482d6911a59512e8a17fa1defecf5a2162521113b7cc5422dd1"
"checksum roxmltree 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "869a77456372218c6cd28ae457bedbc338af19866290e71d71965cc992e2654b"
"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=dc62f70)" = "<none>"
"checksum svgdom 0.15.0 (git+https://github.com/RazrFalcon/svgdom?rev=f53af72)" = "<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"
......
......@@ -40,7 +40,8 @@ pango = { version = "0.5", optional = true }
pangocairo = { version = "0.6", optional = true }
# qt backend
resvg-qt = { version = "0.4", optional = true }
#resvg-qt = { version = "0.4", optional = true }
resvg-qt = { git = "https://github.com/RazrFalcon/libresvg-qt", rev = "4dd0b40", optional = true }
[features]
cairo-backend = ["cairo-rs", "gdk-pixbuf", "pango", "pangocairo"]
......
......@@ -34,22 +34,21 @@
- `alignment-baseline`
- Nested `baseline-shift`
- `clip` (deprecated)
- `clip` (deprecated in the SVG 2)
- `color-interpolation`
- `color-profile`
- `color-rendering`
- `direction`
- `dominant-baseline`
- [`enable-background`](https://www.w3.org/TR/SVG11/filters.html#EnableBackgroundProperty) (deprecated)
- [`enable-background`](https://www.w3.org/TR/SVG11/filters.html#EnableBackgroundProperty) (deprecated in the SVG 2)
- `font`
- `font-size-adjust`
- `glyph-orientation-horizontal`
- `glyph-orientation-vertical`
- `glyph-orientation-horizontal` (removed in the SVG 2)
- `glyph-orientation-vertical` (deprecated in the SVG 2)
- [`in`](https://www.w3.org/TR/SVG11/filters.html#FilterPrimitiveInAttribute)
with `BackgroundImage`, `BackgroundAlpha`, `FillPaint`, `StrokePaint`
- `image-rendering`
- `kerning`
- `letter-spacing`
- `lighting-color`
- `marker-start`
- `marker-mid`
......@@ -57,7 +56,7 @@
- `shape-rendering`
- `text-rendering`
- `unicode-bidi`
- `word-spacing`
- `word-spacing` (unsupported only on the cairo backend)
- `writing-mode`
**Note:** this list does not include elements and attributes outside the
......
......@@ -418,7 +418,7 @@ fn _calc_node_bbox(
cr.new_path();
let context = text::init_pango_context(opt, cr);
let layout = text::init_pango_layout(&block.text, &block.font, &context);
let layout = text::init_pango_layout(&block, &context);
pc::layout_path(cr, &layout);
let path = cr.copy_path();
......
......@@ -25,16 +25,28 @@ use super::{
};
trait PangoScale {
fn scale(&self) -> f64;
trait FromPangoScale {
fn from_pango(&self) -> f64;
}
impl PangoScale for i32 {
fn scale(&self) -> f64 {
impl FromPangoScale for i32 {
fn from_pango(&self) -> f64 {
*self as f64 / pango::SCALE as f64
}
}
trait ToPangoScale {
fn to_pango(&self) -> i32;
}
impl ToPangoScale for f64 {
fn to_pango(&self) -> i32 {
(*self * pango::SCALE as f64) as i32
}
}
pub struct PangoFontMetrics {
layout: pango::Layout,
dpi: f64,
......@@ -50,8 +62,8 @@ impl PangoFontMetrics {
impl FontMetrics<pango::FontDescription> for PangoFontMetrics {
fn set_font(&mut self, font: &usvg::Font) {
let font = init_font(font, self.dpi);
self.layout.set_font_description(&font);
set_text_spacing(font.letter_spacing, &self.layout);
self.layout.set_font_description(&init_font(font, self.dpi));
}
fn font(&self) -> pango::FontDescription {
......@@ -60,16 +72,16 @@ impl FontMetrics<pango::FontDescription> for PangoFontMetrics {
fn width(&self, text: &str) -> f64 {
self.layout.set_text(text);
self.layout.get_size().0.scale()
self.layout.get_size().0.from_pango()
}
fn ascent(&self) -> f64 {
let mut layout_iter = self.layout.get_iter().unwrap();
layout_iter.get_baseline().scale()
layout_iter.get_baseline().from_pango()
}
fn height(&self) -> f64 {
self.layout.get_size().1.scale()
self.layout.get_size().1.from_pango()
}
}
......@@ -92,16 +104,29 @@ pub fn init_pango_context(opt: &Options, cr: &cairo::Context) -> pango::Context
}
pub fn init_pango_layout(
text: &str,
font: &pango::FontDescription,
block: &text::TextBlock<pango::FontDescription>,
context: &pango::Context,
) -> pango::Layout {
let layout = pango::Layout::new(&context);
layout.set_font_description(font);
layout.set_text(text);
layout.set_font_description(&block.font);
set_text_spacing(block.letter_spacing, &layout);
layout.set_text(&block.text);
layout
}
fn set_text_spacing(
letter_spacing: Option<f64>,
layout: &pango::Layout,
) {
let attr_list = pango::AttrList::new();
if let Some(letter_spacing) = letter_spacing {
attr_list.insert(pango::Attribute::new_letter_spacing(letter_spacing.to_pango()).unwrap());
}
layout.set_attributes(&attr_list);
}
fn draw_block(
tree: &usvg::Tree,
block: &text::TextBlock<pango::FontDescription>,
......@@ -109,7 +134,7 @@ fn draw_block(
cr: &cairo::Context,
) {
let context = init_pango_context(opt, cr);
let layout = init_pango_layout(&block.text, &block.font, &context);
let layout = init_pango_layout(&block, &context);
let fm = context.get_metrics(&block.font, None).unwrap();
......@@ -119,7 +144,8 @@ fn draw_block(
// so spaces around text are ignored.
let inner_bbox = get_layout_bbox(&layout, bbox.x, bbox.y);
let mut line_rect = Rect::new(bbox.x, 0.0, bbox.width, fm.get_underline_thickness().scale());
let underline_height = fm.get_underline_thickness().from_pango();
let mut line_rect = Rect::new(bbox.x, 0.0, bbox.width, underline_height);
let old_ts = cr.get_matrix();
if let Some(rotate) = block.rotate {
......@@ -131,7 +157,7 @@ fn draw_block(
//
// Should be drawn before/under text.
if let Some(ref style) = block.decoration.underline {
line_rect.y = bbox.y + block.font_ascent - fm.get_underline_position().scale();
line_rect.y = bbox.y + block.font_ascent - fm.get_underline_position().from_pango();
draw_line(tree, line_rect, &style.fill, &style.stroke, opt, cr);
}
......@@ -139,7 +165,7 @@ fn draw_block(
//
// Should be drawn before/under text.
if let Some(ref style) = block.decoration.overline {
line_rect.y = bbox.y + fm.get_underline_thickness().scale();
line_rect.y = bbox.y + underline_height;
draw_line(tree, line_rect, &style.fill, &style.stroke, opt, cr);
}
......@@ -160,8 +186,8 @@ fn draw_block(
//
// Should be drawn after/over text.
if let Some(ref style) = block.decoration.line_through {
line_rect.y = bbox.y + block.font_ascent - fm.get_strikethrough_position().scale();
line_rect.height = fm.get_strikethrough_thickness().scale();
line_rect.y = bbox.y + block.font_ascent - fm.get_strikethrough_position().from_pango();
line_rect.height = fm.get_strikethrough_thickness().from_pango();
draw_line(tree, line_rect, &style.fill, &style.stroke, opt, cr);
}
......@@ -214,7 +240,7 @@ fn init_font(dom_font: &usvg::Font, dpi: f64) -> pango::FontDescription {
};
font.set_stretch(font_stretch);
let font_size = dom_font.size.value() * (pango::SCALE as f64) / dpi * 72.0;
let font_size = dom_font.size.value().to_pango() as f64 / dpi * 72.0;
font.set_size(font_size as i32);
font
......@@ -224,10 +250,10 @@ pub fn get_layout_bbox(layout: &pango::Layout, x: f64, y: f64) -> Rect {
let (ink_rect, _) = layout.get_extents();
(
x + ink_rect.x.scale(),
y + ink_rect.y.scale(),
ink_rect.width.scale(),
ink_rect.height.scale(),
x + ink_rect.x.from_pango(),
y + ink_rect.y.from_pango(),
ink_rect.width.from_pango(),
ink_rect.height.from_pango(),
).into()
}
......
......@@ -157,6 +157,14 @@ fn init_font(dom_font: &usvg::Font) -> qt::Font {
};
font.set_stretch(font_stretch);
if let Some(letter_spacing) = dom_font.letter_spacing {
font.set_letter_spacing(letter_spacing);
}
if let Some(word_spacing) = dom_font.word_spacing {
font.set_word_spacing(word_spacing);
}
font.set_size(dom_font.size.value());
font
......
......@@ -18,6 +18,8 @@ pub struct TextBlock<Font> {
pub stroke: Option<usvg::Stroke>,
pub font: Font,
pub font_ascent: f64,
pub letter_spacing: Option<f64>,
pub word_spacing: Option<f64>,
pub decoration: usvg::TextDecoration,
}
......@@ -143,6 +145,8 @@ pub fn prepare_blocks<Font>(
stroke: tspan.stroke.clone(),
font: font_metrics.font(),
font_ascent,
letter_spacing: tspan.font.letter_spacing,
word_spacing: tspan.font.word_spacing,
decoration: tspan.decoration.clone(),
});
}
......
a-letter-spacing-001.svg
a-letter-spacing-002.svg
a-letter-spacing-003.svg
a-letter-spacing-004.svg
a-letter-spacing-005.svg
a-letter-spacing-006.svg
a-word-spacing-001.svg
a-word-spacing-002.svg
a-word-spacing-003.svg
a-word-spacing-004.svg
a-word-spacing-005.svg
a-word-spacing-006.svg
a-letter-spacing-001.svg
a-letter-spacing-002.svg
a-letter-spacing-003.svg
a-letter-spacing-004.svg
a-letter-spacing-005.svg
a-letter-spacing-006.svg
a-word-spacing-001.svg
a-word-spacing-002.svg
a-word-spacing-003.svg
a-word-spacing-004.svg
a-word-spacing-005.svg
a-word-spacing-006.svg
......@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added
- Implement `FuzzyEq` for `Rect`, `Size` and `Point`.
- `StrokeMiterlimit` and `FontSize` wrappers for `f64`.
- `letter-spacing` and `word-spacing` support.
- Partial `baseline-shift` support.
- `TextSpan::baseline_shift`.
......
......@@ -18,7 +18,7 @@ libflate = "0.1"
log = "0.4"
lyon_geom = "0.12"
rctree = "0.2.1"
svgdom = { git = "https://github.com/RazrFalcon/svgdom", rev = "dc62f70" }
svgdom = { git = "https://github.com/RazrFalcon/svgdom", rev = "f53af72" }
#svgdom = { path = "../../svgdom" }
unicode-segmentation = "1.2.1"
......
......@@ -158,8 +158,8 @@ 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>>, `baseline-shift`, `text-decoration`,
`visibility` and `clip-rule` (when inside the `clipPath`) attributes.
<<stroke_attrs,stroking>>, <<font_attrs,font>>, `baseline-shift`, `letter-spacing`, `word-spacing`,
`text-decoration`, `visibility` and `clip-rule` (when inside the `clipPath`) attributes.
* `id` is optional but never empty.
......
......@@ -79,14 +79,16 @@ fn convert_chunks(
let fill = fill::convert(tree, attrs, true);
let stroke = stroke::convert(tree, attrs, true);
let font = conv_font(attrs, opt);
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: conv_font(attrs, opt),
font,
baseline_shift,
decoration,
text,
......@@ -289,6 +291,9 @@ fn conv_font(attrs: &svgdom::Attributes, opt: &Options) -> tree::Font {
_ => tree::FontStretch::Normal,
};
let letter_spacing = attrs.get_number(AId::LetterSpacing);
let word_spacing = attrs.get_number(AId::WordSpacing);
// TODO: what to do when <= 0?
let size = attrs.get_number_or(AId::FontSize, opt.font_size);
let size = if !(size > 0.0) { opt.font_size } else { size };
......@@ -303,5 +308,7 @@ fn conv_font(attrs: &svgdom::Attributes, opt: &Options) -> tree::Font {
variant,
weight,
stretch,
letter_spacing,
word_spacing,
}
}
......@@ -19,6 +19,8 @@ fn resolve_inherit(parent: &Node, opt: &Options) {
resolve(&mut node, AId::FontVariant);
resolve(&mut node, AId::FontWeight);
resolve(&mut node, AId::TextAnchor);
resolve(&mut node, AId::LetterSpacing);
resolve(&mut node, AId::WordSpacing);
resolve_font_family(&mut node, opt);
}
......
......@@ -301,6 +301,16 @@ pub struct Font {
pub variant: FontVariant,
pub weight: FontWeight,
pub stretch: FontStretch,
/// Letter spacing.
///
/// None == `normal`
pub letter_spacing: Option<f64>,
/// Word spacing.
///
/// None == `normal`
pub word_spacing: Option<f64>,
}
......
......@@ -636,6 +636,9 @@ fn conv_font(
FontStretch::UltraExpanded => "ultra-expanded",
}
));
conv_text_spacing(font.letter_spacing, AId::LetterSpacing, node);
conv_text_spacing(font.word_spacing, AId::WordSpacing, node);
}
fn conv_baseline_shift(
......@@ -653,6 +656,19 @@ fn conv_baseline_shift(
node.set_attribute((AId::BaselineShift, av));
}
fn conv_text_spacing(
spacing: Option<f64>,
aid: AId,
node: &mut svgdom::Node,
) {
let spacing: AValue = match spacing {
Some(n) => n.into(),
None => "normal".into(),
};
node.set_attribute((aid, spacing));
}
fn conv_link(
tree: &Tree,
defs: &svgdom::Node,
......
......@@ -16,6 +16,8 @@ a-font-size-017,1088,UA dependent
a-font-size-019,649,bug
a-font-weight-003,484,chrome bug
a-font-weight-012,714,chrome bug
a-letter-spacing-005,2171,chrome bug
a-word-spacing-005,730,chrome bug
a-opacity-001,580
a-opacity-002,137
a-stroke-dasharray-012,244
......
This diff is collapsed.
......@@ -393,7 +393,9 @@ test!(preserve_id, false,
font-style='normal'
font-variant='normal'
font-weight='400'
visibility='visible'>Some text</tspan></tspan></text>
letter-spacing='normal'
visibility='visible'
word-spacing='normal'>Some text</tspan></tspan></text>
<text
id='text2'><tspan><tspan
fill='#000000'
......@@ -407,7 +409,9 @@ test!(preserve_id, false,
font-style='normal'
font-variant='normal'
font-weight='400'
visibility='visible'>Some text</tspan></tspan></text>
letter-spacing='normal'
visibility='visible'
word-spacing='normal'>Some text</tspan></tspan></text>
<image
id='image1'
visibility='visible'
......
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