blitz-pdf 0.1.3 → 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.
Files changed (64) hide show
  1. package/README.md +6 -6
  2. package/THIRD_PARTY_NOTICES.md +5 -2
  3. package/docs/layout-regressions.md +65 -0
  4. package/docs/pagination-regressions.md +7 -6
  5. package/package.json +1 -1
  6. package/vendor/README.md +35 -0
  7. package/vendor/blitz-dom/Cargo.toml +113 -0
  8. package/vendor/blitz-dom/LICENSE-APACHE +176 -0
  9. package/vendor/blitz-dom/LICENSE-MIT +23 -0
  10. package/vendor/blitz-dom/assets/default.css +1142 -0
  11. package/vendor/blitz-dom/assets/moz-bullet-font.otf +0 -0
  12. package/vendor/blitz-dom/src/accessibility.rs +255 -0
  13. package/vendor/blitz-dom/src/config.rs +97 -0
  14. package/vendor/blitz-dom/src/cssom.rs +971 -0
  15. package/vendor/blitz-dom/src/debug.rs +206 -0
  16. package/vendor/blitz-dom/src/document.rs +3395 -0
  17. package/vendor/blitz-dom/src/events/driver.rs +427 -0
  18. package/vendor/blitz-dom/src/events/focus.rs +40 -0
  19. package/vendor/blitz-dom/src/events/ime.rs +31 -0
  20. package/vendor/blitz-dom/src/events/keyboard.rs +174 -0
  21. package/vendor/blitz-dom/src/events/mod.rs +315 -0
  22. package/vendor/blitz-dom/src/events/pointer.rs +849 -0
  23. package/vendor/blitz-dom/src/font_metrics.rs +177 -0
  24. package/vendor/blitz-dom/src/form.rs +463 -0
  25. package/vendor/blitz-dom/src/html.rs +38 -0
  26. package/vendor/blitz-dom/src/iframe.rs +186 -0
  27. package/vendor/blitz-dom/src/layout/construct.rs +1328 -0
  28. package/vendor/blitz-dom/src/layout/damage.rs +642 -0
  29. package/vendor/blitz-dom/src/layout/inline.rs +1160 -0
  30. package/vendor/blitz-dom/src/layout/list.rs +237 -0
  31. package/vendor/blitz-dom/src/layout/mod.rs +969 -0
  32. package/vendor/blitz-dom/src/layout/paint_tree.rs +462 -0
  33. package/vendor/blitz-dom/src/layout/replaced.rs +439 -0
  34. package/vendor/blitz-dom/src/layout/table.rs +967 -0
  35. package/vendor/blitz-dom/src/layout/text_transform.rs +979 -0
  36. package/vendor/blitz-dom/src/layout/writing_mode.rs +437 -0
  37. package/vendor/blitz-dom/src/lib.rs +160 -0
  38. package/vendor/blitz-dom/src/mutator.rs +1818 -0
  39. package/vendor/blitz-dom/src/net.rs +649 -0
  40. package/vendor/blitz-dom/src/node/attributes.rs +60 -0
  41. package/vendor/blitz-dom/src/node/custom_widget.rs +178 -0
  42. package/vendor/blitz-dom/src/node/element.rs +1106 -0
  43. package/vendor/blitz-dom/src/node/mod.rs +30 -0
  44. package/vendor/blitz-dom/src/node/node.rs +2036 -0
  45. package/vendor/blitz-dom/src/node/scrollbar.rs +237 -0
  46. package/vendor/blitz-dom/src/node/serialize.rs +225 -0
  47. package/vendor/blitz-dom/src/node/stylo_data.rs +142 -0
  48. package/vendor/blitz-dom/src/node/svg.rs +265 -0
  49. package/vendor/blitz-dom/src/node/text.rs +804 -0
  50. package/vendor/blitz-dom/src/query_selector.rs +275 -0
  51. package/vendor/blitz-dom/src/resolve.rs +474 -0
  52. package/vendor/blitz-dom/src/resolved_style.rs +797 -0
  53. package/vendor/blitz-dom/src/scrolling.rs +780 -0
  54. package/vendor/blitz-dom/src/selection.rs +122 -0
  55. package/vendor/blitz-dom/src/stylo.rs +1518 -0
  56. package/vendor/blitz-dom/src/stylo_device.rs +88 -0
  57. package/vendor/blitz-dom/src/stylo_to_cursor_icon.rs +49 -0
  58. package/vendor/blitz-dom/src/stylo_to_kurbo.rs +129 -0
  59. package/vendor/blitz-dom/src/stylo_to_parley.rs +655 -0
  60. package/vendor/blitz-dom/src/traversal.rs +600 -0
  61. package/vendor/blitz-dom/src/tree.rs +136 -0
  62. package/vendor/blitz-dom/src/url.rs +63 -0
  63. package/vendor/blitz-dom/src/util.rs +256 -0
  64. 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
+ }