blitz-pdf 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -0
- package/THIRD_PARTY_NOTICES.md +5 -2
- package/docs/layout-regressions.md +65 -0
- package/docs/pagination-regressions.md +89 -0
- package/package.json +2 -1
- package/vendor/README.md +35 -0
- package/vendor/blitz-dom/Cargo.toml +113 -0
- package/vendor/blitz-dom/LICENSE-APACHE +176 -0
- package/vendor/blitz-dom/LICENSE-MIT +23 -0
- package/vendor/blitz-dom/assets/default.css +1142 -0
- package/vendor/blitz-dom/assets/moz-bullet-font.otf +0 -0
- package/vendor/blitz-dom/src/accessibility.rs +255 -0
- package/vendor/blitz-dom/src/config.rs +97 -0
- package/vendor/blitz-dom/src/cssom.rs +971 -0
- package/vendor/blitz-dom/src/debug.rs +206 -0
- package/vendor/blitz-dom/src/document.rs +3395 -0
- package/vendor/blitz-dom/src/events/driver.rs +427 -0
- package/vendor/blitz-dom/src/events/focus.rs +40 -0
- package/vendor/blitz-dom/src/events/ime.rs +31 -0
- package/vendor/blitz-dom/src/events/keyboard.rs +174 -0
- package/vendor/blitz-dom/src/events/mod.rs +315 -0
- package/vendor/blitz-dom/src/events/pointer.rs +849 -0
- package/vendor/blitz-dom/src/font_metrics.rs +177 -0
- package/vendor/blitz-dom/src/form.rs +463 -0
- package/vendor/blitz-dom/src/html.rs +38 -0
- package/vendor/blitz-dom/src/iframe.rs +186 -0
- package/vendor/blitz-dom/src/layout/construct.rs +1328 -0
- package/vendor/blitz-dom/src/layout/damage.rs +642 -0
- package/vendor/blitz-dom/src/layout/inline.rs +1160 -0
- package/vendor/blitz-dom/src/layout/list.rs +237 -0
- package/vendor/blitz-dom/src/layout/mod.rs +969 -0
- package/vendor/blitz-dom/src/layout/paint_tree.rs +462 -0
- package/vendor/blitz-dom/src/layout/replaced.rs +439 -0
- package/vendor/blitz-dom/src/layout/table.rs +967 -0
- package/vendor/blitz-dom/src/layout/text_transform.rs +979 -0
- package/vendor/blitz-dom/src/layout/writing_mode.rs +437 -0
- package/vendor/blitz-dom/src/lib.rs +160 -0
- package/vendor/blitz-dom/src/mutator.rs +1818 -0
- package/vendor/blitz-dom/src/net.rs +649 -0
- package/vendor/blitz-dom/src/node/attributes.rs +60 -0
- package/vendor/blitz-dom/src/node/custom_widget.rs +178 -0
- package/vendor/blitz-dom/src/node/element.rs +1106 -0
- package/vendor/blitz-dom/src/node/mod.rs +30 -0
- package/vendor/blitz-dom/src/node/node.rs +2036 -0
- package/vendor/blitz-dom/src/node/scrollbar.rs +237 -0
- package/vendor/blitz-dom/src/node/serialize.rs +225 -0
- package/vendor/blitz-dom/src/node/stylo_data.rs +142 -0
- package/vendor/blitz-dom/src/node/svg.rs +265 -0
- package/vendor/blitz-dom/src/node/text.rs +804 -0
- package/vendor/blitz-dom/src/query_selector.rs +275 -0
- package/vendor/blitz-dom/src/resolve.rs +474 -0
- package/vendor/blitz-dom/src/resolved_style.rs +797 -0
- package/vendor/blitz-dom/src/scrolling.rs +780 -0
- package/vendor/blitz-dom/src/selection.rs +122 -0
- package/vendor/blitz-dom/src/stylo.rs +1518 -0
- package/vendor/blitz-dom/src/stylo_device.rs +88 -0
- package/vendor/blitz-dom/src/stylo_to_cursor_icon.rs +49 -0
- package/vendor/blitz-dom/src/stylo_to_kurbo.rs +129 -0
- package/vendor/blitz-dom/src/stylo_to_parley.rs +655 -0
- package/vendor/blitz-dom/src/traversal.rs +600 -0
- package/vendor/blitz-dom/src/tree.rs +136 -0
- package/vendor/blitz-dom/src/url.rs +63 -0
- package/vendor/blitz-dom/src/util.rs +256 -0
- package/wasm/blitz_pdf_bg.wasm +0 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
use blitz_traits::node_id::NodeId;
|
|
2
|
+
use markup5ever::local_name;
|
|
3
|
+
use parley::FontFamily;
|
|
4
|
+
use style::computed_values::list_style_type::T as ListStyleType;
|
|
5
|
+
use style::{
|
|
6
|
+
computed_values::list_style_position::T as ListStylePosition, counter_style::CounterStyle,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
use crate::{
|
|
10
|
+
BaseDocument,
|
|
11
|
+
node::{ListItemLayout, ListItemLayoutPosition, Marker},
|
|
12
|
+
stylo_to_parley,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
pub(super) const BULLET_FONT_FAMILY: &str = "Bullet, monospace, sans-serif";
|
|
16
|
+
|
|
17
|
+
pub(super) fn collect_list_item_children(
|
|
18
|
+
doc: &mut BaseDocument,
|
|
19
|
+
index: &mut usize,
|
|
20
|
+
reversed: bool,
|
|
21
|
+
node_id: NodeId,
|
|
22
|
+
) {
|
|
23
|
+
let mut children = doc.nodes[node_id].children.clone();
|
|
24
|
+
if reversed {
|
|
25
|
+
children.reverse();
|
|
26
|
+
}
|
|
27
|
+
for child in children.into_iter() {
|
|
28
|
+
if let Some(layout) = node_list_item_child(doc, child, *index) {
|
|
29
|
+
let node = &mut doc.nodes[child];
|
|
30
|
+
node.element_data_mut().unwrap().list_item_data = Some(Box::new(layout));
|
|
31
|
+
*index += 1;
|
|
32
|
+
collect_list_item_children(doc, index, reversed, child);
|
|
33
|
+
} else {
|
|
34
|
+
// Unset marker in case it was previously set
|
|
35
|
+
let node = &mut doc.nodes[child];
|
|
36
|
+
if let Some(element_data) = node.element_data_mut() {
|
|
37
|
+
element_data.list_item_data = None;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Return a child node which is of display: list-item
|
|
44
|
+
fn node_list_item_child(
|
|
45
|
+
doc: &mut BaseDocument,
|
|
46
|
+
child_id: NodeId,
|
|
47
|
+
index: usize,
|
|
48
|
+
) -> Option<ListItemLayout> {
|
|
49
|
+
let node = &doc.nodes[child_id];
|
|
50
|
+
|
|
51
|
+
// We only care about elements with display: list-item (li's have this automatically)
|
|
52
|
+
if !node
|
|
53
|
+
.primary_styles()
|
|
54
|
+
.is_some_and(|style| style.get_box().display.is_list_item())
|
|
55
|
+
{
|
|
56
|
+
return None;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//Break on container elements when already in a list
|
|
60
|
+
if node
|
|
61
|
+
.element_data()
|
|
62
|
+
.map(|element_data| {
|
|
63
|
+
matches!(
|
|
64
|
+
element_data.name.local,
|
|
65
|
+
local_name!("ol") | local_name!("ul"),
|
|
66
|
+
)
|
|
67
|
+
})
|
|
68
|
+
.unwrap_or(false)
|
|
69
|
+
{
|
|
70
|
+
return None;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
let styles = node.primary_styles().unwrap();
|
|
74
|
+
let list_style_type = styles.clone_list_style_type();
|
|
75
|
+
let list_style_position = styles.clone_list_style_position();
|
|
76
|
+
let marker = marker_for_style(list_style_type.clone(), index)?;
|
|
77
|
+
|
|
78
|
+
let position = match list_style_position {
|
|
79
|
+
ListStylePosition::Inside => ListItemLayoutPosition::Inside,
|
|
80
|
+
ListStylePosition::Outside => {
|
|
81
|
+
let mut parley_style = stylo_to_parley::style(child_id, &styles);
|
|
82
|
+
|
|
83
|
+
if let Some(font_family) = font_for_bullet_style(list_style_type) {
|
|
84
|
+
parley_style.font_family = font_family;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Create a parley tree builder
|
|
88
|
+
let mut font_ctx = doc.font_ctx.lock().unwrap();
|
|
89
|
+
let mut builder = doc.layout_ctx.tree_builder(
|
|
90
|
+
&mut font_ctx,
|
|
91
|
+
doc.viewport.scale(),
|
|
92
|
+
true,
|
|
93
|
+
&parley_style,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
match &marker {
|
|
97
|
+
Marker::Char(char) => {
|
|
98
|
+
let mut buf = [0u8; 4];
|
|
99
|
+
builder.push_text(char.encode_utf8(&mut buf));
|
|
100
|
+
}
|
|
101
|
+
Marker::String(str) => builder.push_text(str),
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
let mut layout = builder.build().0;
|
|
105
|
+
let width = layout.calculate_content_widths().max;
|
|
106
|
+
layout.break_all_lines(Some(width));
|
|
107
|
+
|
|
108
|
+
ListItemLayoutPosition::Outside(Box::new(layout))
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
Some(ListItemLayout { marker, position })
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Determine the marker to render for a given list style type
|
|
116
|
+
fn marker_for_style(list_style_type: ListStyleType, index: usize) -> Option<Marker> {
|
|
117
|
+
Some(match list_style_type.0 {
|
|
118
|
+
CounterStyle::None => return None,
|
|
119
|
+
CounterStyle::Name(name) => match &*name.0 {
|
|
120
|
+
"lower-alpha" => {
|
|
121
|
+
let mut marker = String::new();
|
|
122
|
+
build_alpha_marker(index, &mut marker);
|
|
123
|
+
Marker::String(format!("{marker}. "))
|
|
124
|
+
}
|
|
125
|
+
"upper-alpha" => {
|
|
126
|
+
let mut marker = String::new();
|
|
127
|
+
build_alpha_marker(index, &mut marker);
|
|
128
|
+
Marker::String(format!("{}. ", marker.to_ascii_uppercase()))
|
|
129
|
+
}
|
|
130
|
+
"decimal" => Marker::String(format!("{}. ", index + 1)),
|
|
131
|
+
"disc" => Marker::Char('•'),
|
|
132
|
+
"circle" => Marker::Char('◦'),
|
|
133
|
+
"square" => Marker::Char('▪'),
|
|
134
|
+
"disclosure-open" => Marker::Char('▾'),
|
|
135
|
+
"disclosure-closed" => Marker::Char('▸'),
|
|
136
|
+
_ => Marker::Char('□'),
|
|
137
|
+
},
|
|
138
|
+
CounterStyle::String(atom_string) => Marker::String(atom_string.as_ref().to_string()),
|
|
139
|
+
CounterStyle::Symbols { symbols, .. } => {
|
|
140
|
+
// Use symbols from counter-style definition
|
|
141
|
+
let syms = &symbols.0;
|
|
142
|
+
let len = syms.len();
|
|
143
|
+
if len == 0 {
|
|
144
|
+
Marker::Char('•')
|
|
145
|
+
} else {
|
|
146
|
+
// Cycle through symbols based on index: 1st, 2nd, 1st, 2nd, etc.
|
|
147
|
+
let idx = if len > 1 { index % len } else { 0 };
|
|
148
|
+
// Symbol is String or Ident variant, extract the string value
|
|
149
|
+
let sym = &syms[idx];
|
|
150
|
+
let marker_str = match sym {
|
|
151
|
+
style::counter_style::Symbol::String(s) => s.to_string(),
|
|
152
|
+
style::counter_style::Symbol::Ident(id) => id.0.to_string(),
|
|
153
|
+
};
|
|
154
|
+
Marker::String(marker_str)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Override the font to our specific bullet font when rendering bullets
|
|
161
|
+
fn font_for_bullet_style(list_style_type: ListStyleType) -> Option<FontFamily<'static>> {
|
|
162
|
+
if list_style_type.0.is_bullet() {
|
|
163
|
+
return Some(BULLET_FONT_FAMILY.into());
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
None
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const ALPHABET: [char; 26] = [
|
|
170
|
+
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
|
|
171
|
+
't', 'u', 'v', 'w', 'x', 'y', 'z',
|
|
172
|
+
];
|
|
173
|
+
|
|
174
|
+
// Construct alphanumeric marker from index, appending characters when index exceeds powers of 26
|
|
175
|
+
fn build_alpha_marker(index: usize, str: &mut String) {
|
|
176
|
+
let rem = index % 26;
|
|
177
|
+
let sym = ALPHABET[rem];
|
|
178
|
+
str.insert(0, sym);
|
|
179
|
+
let rest = (index - rem) as i64 / 26 - 1;
|
|
180
|
+
if rest >= 0 {
|
|
181
|
+
build_alpha_marker(rest as usize, str);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
#[cfg(test)]
|
|
186
|
+
mod tests {
|
|
187
|
+
use crate::node::Marker;
|
|
188
|
+
use style::{
|
|
189
|
+
Atom,
|
|
190
|
+
counter_style::CounterStyle,
|
|
191
|
+
values::{CustomIdent, computed::ListStyleType},
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
use super::marker_for_style;
|
|
195
|
+
|
|
196
|
+
fn list_style(s: &str) -> ListStyleType {
|
|
197
|
+
ListStyleType(CounterStyle::Name(CustomIdent(Atom::from(s))))
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
#[test]
|
|
201
|
+
fn test_marker_for_disc() {
|
|
202
|
+
let result = marker_for_style(ListStyleType::disc(), 0);
|
|
203
|
+
assert_eq!(result, Some(Marker::Char('•')));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
#[test]
|
|
207
|
+
fn test_marker_for_decimal() {
|
|
208
|
+
let result_1 = marker_for_style(list_style("decimal"), 0);
|
|
209
|
+
let result_2 = marker_for_style(list_style("decimal"), 1);
|
|
210
|
+
assert_eq!(result_1, Some(Marker::String("1. ".to_string())));
|
|
211
|
+
assert_eq!(result_2, Some(Marker::String("2. ".to_string())));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
#[test]
|
|
215
|
+
fn test_marker_for_lower_alpha() {
|
|
216
|
+
let result_1 = marker_for_style(list_style("lower-alpha"), 0);
|
|
217
|
+
let result_2 = marker_for_style(list_style("lower-alpha"), 1);
|
|
218
|
+
let result_extended_1 = marker_for_style(list_style("lower-alpha"), 26);
|
|
219
|
+
let result_extended_2 = marker_for_style(list_style("lower-alpha"), 27);
|
|
220
|
+
assert_eq!(result_1, Some(Marker::String("a. ".to_string())));
|
|
221
|
+
assert_eq!(result_2, Some(Marker::String("b. ".to_string())));
|
|
222
|
+
assert_eq!(result_extended_1, Some(Marker::String("aa. ".to_string())));
|
|
223
|
+
assert_eq!(result_extended_2, Some(Marker::String("ab. ".to_string())));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
#[test]
|
|
227
|
+
fn test_marker_for_upper_alpha() {
|
|
228
|
+
let result_1 = marker_for_style(list_style("upper-alpha"), 0);
|
|
229
|
+
let result_2 = marker_for_style(list_style("upper-alpha"), 1);
|
|
230
|
+
let result_extended_1 = marker_for_style(list_style("upper-alpha"), 26);
|
|
231
|
+
let result_extended_2 = marker_for_style(list_style("upper-alpha"), 27);
|
|
232
|
+
assert_eq!(result_1, Some(Marker::String("A. ".to_string())));
|
|
233
|
+
assert_eq!(result_2, Some(Marker::String("B. ".to_string())));
|
|
234
|
+
assert_eq!(result_extended_1, Some(Marker::String("AA. ".to_string())));
|
|
235
|
+
assert_eq!(result_extended_2, Some(Marker::String("AB. ".to_string())));
|
|
236
|
+
}
|
|
237
|
+
}
|