1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
use svgdom::{
Length,
};
use super::prelude::*;
pub fn resolve_font_size(doc: &Document) {
_resolve_font_size(&doc.root());
}
// a-font-size-002.svg
// a-font-size-006.svg
pub fn _resolve_font_size(parent: &Node) {
for (_, mut node) in parent.children().svg() {
// We have to resolve 'font-size' for all elements
// and not only for 'text content' based,
// because it will be used during 'em'/'ex' units conversion.
//
// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-size
let font_size = match node.attributes().get(AId::FontSize) {
Some(v) => {
v.value.clone()
}
None => {
// If not set - lookup in parent nodes or use default.
let mut len = node.find_attribute(AId::FontSize)
.unwrap_or(Length::new_number(DEFAULT_FONT_SIZE));
// If 'font-size' is not set and the parent one is 'em' or 'ex'
// then the current 'font-size' is '1em' or '2ex' respectively.
// This way do not introduce an additional scaling.
//
// Example:
// <g font-size='12'>
// <g font-size='3em'>
// <g>
//
// The values are '12', '3em' and 'None'.
// And the expected results are '12', '36' and '36'.
// But if we simply copy the '3em' to the 'None' place we will
// get '12', '36' and '108'.
if len.unit == Unit::Em {
len.num = 1.0;
} else if len.unit == Unit::Ex {
// The same coefficient as in convert_units::convert.
len.num = 2.0;
}
AValue::Length(len)
}
};
let font_size = match font_size {
AValue::Length(len) => {
if len.unit == Unit::Percent {
process_percent_font_size(parent, len)
} else {
len
}
}
AValue::String(ref name) => {
process_named_font_size(parent, name, &font_size)
}
_ => {
warn!("Invalid 'font-size' value: {}.", font_size);
Length::new(DEFAULT_FONT_SIZE, Unit::None)
}
};
// We have to mark this attribute as invisible,
// otherwise it will break the 'use' resolving.
if !node.has_attribute(AId::FontSize) {
node.set_attribute(("resolved-font-size", 1));
}
node.set_attribute((AId::FontSize, font_size));
if node.has_children() {
_resolve_font_size(&node);
}
}
}
// If 'font-size' has percent units that it's value
// is relative to the parent node 'font-size'.
//
// a-font-size-003.svg
// a-font-size-004.svg
// a-font-size-007.svg
fn process_percent_font_size(parent: &Node, len: Length) -> Length {
if parent.is_root() {
Length::new(DEFAULT_FONT_SIZE, Unit::None)
} else {
let parent_len = parent.find_attribute(AId::FontSize)
.unwrap_or(Length::new_number(DEFAULT_FONT_SIZE));
let n = len.num * parent_len.num * 0.01;
Length::new(n, Unit::None)
}
}
// a-font-size-005.svg
// a-font-size-008.svg
fn process_named_font_size(parent: &Node, name: &str, font_size: &AValue) -> Length {
let factor = match name {
"xx-small" => -3,
"x-small" => -2,
"small" => -1,
"medium" => 0,
"large" => 1,
"x-large" => 2,
"xx-large" => 3,
"smaller" => -1,
"larger" => 1,
_ => {
warn!("Invalid 'font-size' value: {}.", font_size);
0
}
};
let parent_len = parent.find_attribute(AId::FontSize)
.unwrap_or(Length::new_number(DEFAULT_FONT_SIZE));
// 'On a computer screen a scaling factor of 1.2
// is suggested between adjacent indexes'
let n = parent_len.num * 1.2f64.powi(factor);
Length::new(n, Unit::None)
}