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,186 @@
|
|
|
1
|
+
//! Loading of `<iframe>` elements into sub-documents.
|
|
2
|
+
|
|
3
|
+
use std::sync::Arc;
|
|
4
|
+
use std::sync::mpsc::Sender;
|
|
5
|
+
|
|
6
|
+
use blitz_traits::navigation::{NavigationOptions, NavigationProvider};
|
|
7
|
+
use blitz_traits::net::{AbortController, AbortSignal, Url};
|
|
8
|
+
use blitz_traits::node_id::NodeId;
|
|
9
|
+
use blitz_traits::shell::ShellProvider;
|
|
10
|
+
|
|
11
|
+
use crate::document::DocumentEvent;
|
|
12
|
+
use crate::net::{DocumentSrcHandler, ResourceHandler, stamped_request};
|
|
13
|
+
use crate::{BaseDocument, DocumentConfig, UserAgentStylesheet, local_name};
|
|
14
|
+
|
|
15
|
+
/// Maximum nesting depth of documents-within-documents. Iframes nested deeper
|
|
16
|
+
/// than this are not loaded (this guards against infinitely recursive
|
|
17
|
+
/// self-embedding pages).
|
|
18
|
+
pub(crate) const MAX_SUBDOCUMENT_DEPTH: usize = 10;
|
|
19
|
+
|
|
20
|
+
/// Per-iframe load state: the abort controller covering the current
|
|
21
|
+
/// "generation" of the iframe's content (the HTML fetch and, once loaded, the
|
|
22
|
+
/// sub-document's own sub-resource fetches), plus the id of the in-flight HTML
|
|
23
|
+
/// request (if any) so stale responses can be discarded.
|
|
24
|
+
pub(crate) struct IframeLoad {
|
|
25
|
+
pub(crate) request_id: Option<usize>,
|
|
26
|
+
pub(crate) abort_controller: AbortController,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/// A [`NavigationProvider`] given to iframe sub-documents. It routes
|
|
30
|
+
/// navigations (e.g. link clicks within the iframe) back to the parent
|
|
31
|
+
/// document, which reloads the iframe's sub-document with the new URL.
|
|
32
|
+
struct IframeNavigationProvider {
|
|
33
|
+
node_id: NodeId,
|
|
34
|
+
tx: Sender<DocumentEvent>,
|
|
35
|
+
shell_provider: Arc<dyn ShellProvider>,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
impl NavigationProvider for IframeNavigationProvider {
|
|
39
|
+
fn navigate_to(&self, options: NavigationOptions) {
|
|
40
|
+
let _ = self.tx.send(DocumentEvent::NavigateIframe {
|
|
41
|
+
node_id: self.node_id,
|
|
42
|
+
url: options.url,
|
|
43
|
+
});
|
|
44
|
+
self.shell_provider.request_redraw();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
impl BaseDocument {
|
|
49
|
+
/// Build the [`DocumentConfig`] for an iframe sub-document, inheriting
|
|
50
|
+
/// providers and settings from this (parent) document.
|
|
51
|
+
fn iframe_document_config(
|
|
52
|
+
&self,
|
|
53
|
+
node_id: NodeId,
|
|
54
|
+
base_url: Option<String>,
|
|
55
|
+
abort_signal: AbortSignal,
|
|
56
|
+
) -> DocumentConfig {
|
|
57
|
+
DocumentConfig {
|
|
58
|
+
viewport: None,
|
|
59
|
+
layout_viewport: None,
|
|
60
|
+
round_layout: self.round_layout,
|
|
61
|
+
base_url,
|
|
62
|
+
ua_stylesheets: vec![UserAgentStylesheet::default_sheet()],
|
|
63
|
+
net_provider: Some(self.net_provider.clone()),
|
|
64
|
+
navigation_provider: Some(Arc::new(IframeNavigationProvider {
|
|
65
|
+
node_id,
|
|
66
|
+
tx: self.tx.clone(),
|
|
67
|
+
shell_provider: self.shell_provider.clone(),
|
|
68
|
+
})),
|
|
69
|
+
shell_provider: Some(self.shell_provider.clone()),
|
|
70
|
+
html_parser_provider: Some(self.html_parser_provider.clone()),
|
|
71
|
+
font_ctx: Some(self.font_ctx.lock().unwrap().clone()),
|
|
72
|
+
media_type: Some(self.media_type.clone()),
|
|
73
|
+
style_threading: self.style_threading,
|
|
74
|
+
incremental: Some(self.incremental_layout),
|
|
75
|
+
abort_signal: Some(abort_signal),
|
|
76
|
+
subdocument_depth: self.subdocument_depth + 1,
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/// Abort the current generation of the iframe's content (in-flight HTML
|
|
81
|
+
/// fetch and/or the loaded sub-document's sub-resource fetches) and start
|
|
82
|
+
/// a new generation.
|
|
83
|
+
fn new_iframe_generation(&mut self, node_id: NodeId, request_id: Option<usize>) -> AbortSignal {
|
|
84
|
+
if let Some(load) = self.iframe_loads.remove(&node_id) {
|
|
85
|
+
load.abort_controller.abort();
|
|
86
|
+
}
|
|
87
|
+
let abort_controller = AbortController::default();
|
|
88
|
+
let signal = abort_controller.signal.clone();
|
|
89
|
+
self.iframe_loads.insert(
|
|
90
|
+
node_id,
|
|
91
|
+
IframeLoad {
|
|
92
|
+
request_id,
|
|
93
|
+
abort_controller,
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
signal
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// Parse `html` and attach the resulting document as `node_id`'s
|
|
100
|
+
/// sub-document.
|
|
101
|
+
pub(crate) fn attach_iframe_document(
|
|
102
|
+
&mut self,
|
|
103
|
+
node_id: NodeId,
|
|
104
|
+
html: &str,
|
|
105
|
+
base_url: Option<String>,
|
|
106
|
+
abort_signal: AbortSignal,
|
|
107
|
+
) {
|
|
108
|
+
let config = self.iframe_document_config(node_id, base_url, abort_signal);
|
|
109
|
+
let sub_doc = self
|
|
110
|
+
.html_parser_provider
|
|
111
|
+
.clone()
|
|
112
|
+
.parse_document(html, config);
|
|
113
|
+
self.set_sub_document(node_id, sub_doc);
|
|
114
|
+
self.shell_provider.request_redraw();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/// Attach a sub-document parsed from the iframe's `srcdoc` attribute.
|
|
118
|
+
/// Relative URLs within a `srcdoc` document resolve against the parent
|
|
119
|
+
/// document's base URL.
|
|
120
|
+
pub(crate) fn load_iframe_srcdoc(&mut self, node_id: NodeId, srcdoc: &str) {
|
|
121
|
+
let signal = self.new_iframe_generation(node_id, None);
|
|
122
|
+
let base_url = Some(self.url.to_string());
|
|
123
|
+
self.attach_iframe_document(node_id, srcdoc, base_url, signal);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/// Start fetching HTML for an iframe from `url`. The parsed document is
|
|
127
|
+
/// attached when the response arrives (via [`DocumentEvent::ResourceLoad`]).
|
|
128
|
+
pub(crate) fn start_iframe_load(&mut self, node_id: NodeId, url: Url) {
|
|
129
|
+
let handler = ResourceHandler::new(
|
|
130
|
+
self.tx.clone(),
|
|
131
|
+
self.id(),
|
|
132
|
+
Some(node_id),
|
|
133
|
+
self.shell_provider.clone(),
|
|
134
|
+
DocumentSrcHandler,
|
|
135
|
+
);
|
|
136
|
+
let signal = self.new_iframe_generation(node_id, Some(handler.request_id()));
|
|
137
|
+
self.net_provider.fetch(
|
|
138
|
+
self.id(),
|
|
139
|
+
stamped_request(url, Some(&signal)),
|
|
140
|
+
Box::new(handler),
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/// Handle a navigation originating from within an iframe's sub-document
|
|
145
|
+
/// (e.g. a link click) by loading the new URL into the iframe.
|
|
146
|
+
pub(crate) fn navigate_iframe(&mut self, node_id: NodeId, url: Url) {
|
|
147
|
+
let Some(node) = self.get_node(node_id) else {
|
|
148
|
+
return;
|
|
149
|
+
};
|
|
150
|
+
if !node.flags.is_in_document() {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
self.start_iframe_load(node_id, url);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/// Apply fetched iframe HTML, discarding stale responses (the iframe may
|
|
157
|
+
/// have been removed or re-navigated since the request was issued).
|
|
158
|
+
pub(crate) fn apply_iframe_html(
|
|
159
|
+
&mut self,
|
|
160
|
+
node_id: NodeId,
|
|
161
|
+
request_id: usize,
|
|
162
|
+
resolved_url: Option<String>,
|
|
163
|
+
html: &str,
|
|
164
|
+
) {
|
|
165
|
+
let is_current = self
|
|
166
|
+
.iframe_loads
|
|
167
|
+
.get(&node_id)
|
|
168
|
+
.is_some_and(|load| load.request_id == Some(request_id));
|
|
169
|
+
if !is_current {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
let load = self.iframe_loads.get_mut(&node_id).unwrap();
|
|
173
|
+
load.request_id = None;
|
|
174
|
+
let signal = load.abort_controller.signal.clone();
|
|
175
|
+
|
|
176
|
+
let node_is_iframe = self
|
|
177
|
+
.get_node(node_id)
|
|
178
|
+
.and_then(|node| node.element_data())
|
|
179
|
+
.is_some_and(|el| el.name.local == local_name!("iframe"));
|
|
180
|
+
if !node_is_iframe {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
self.attach_iframe_document(node_id, html, resolved_url, signal);
|
|
185
|
+
}
|
|
186
|
+
}
|