typst_batch/html/
document.rs1use typst::foundations::{Label, Selector};
4use typst::introspection::MetadataElem;
5use typst::utils::PicoStr;
6
7use super::HtmlElement;
8#[cfg(feature = "svg")]
9use super::HtmlFrame;
10
11#[cfg(all(feature = "svg", feature = "batch"))]
12use rayon::prelude::*;
13
14#[derive(Debug, Clone)]
18pub struct HtmlDocument(pub(crate) typst_html::HtmlDocument);
19
20impl HtmlDocument {
21 #[inline]
23 pub fn new(doc: typst_html::HtmlDocument) -> Self {
24 Self(doc)
25 }
26
27 #[inline]
29 pub fn root(&self) -> HtmlElement<'_> {
30 HtmlElement(&self.0.root)
31 }
32
33 pub fn query_metadata(&self, label: &str) -> Option<serde_json::Value> {
41 let label = Label::new(PicoStr::intern(label))?;
42 let elem = self
43 .0
44 .introspector
45 .query_unique(&Selector::Label(label))
46 .ok()?;
47 metadata_to_json(&elem)
48 }
49
50 pub fn query_metadata_all(&self, label: &str) -> Vec<serde_json::Value> {
64 let Some(label) = Label::new(PicoStr::intern(label)) else {
65 return Vec::new();
66 };
67
68 self.0
69 .introspector
70 .query(&Selector::Label(label))
71 .iter()
72 .filter_map(metadata_to_json)
73 .collect()
74 }
75
76 #[cfg(feature = "svg")]
78 pub(crate) fn render_frame_svg(&self, frame: &HtmlFrame<'_>) -> String {
79 self.render_raw_frame_svg(frame.0)
80 }
81
82 #[cfg(feature = "svg")]
84 #[inline]
85 fn render_raw_frame_svg(&self, frame: &typst_html::HtmlFrame) -> String {
86 typst_svg::svg_html_frame(
87 &frame.inner,
88 frame.text_size,
89 frame.id.as_deref(),
90 &frame.link_points,
91 &self.0.introspector,
92 )
93 }
94
95 #[cfg(feature = "svg")]
118 pub fn render_frames(&self, frames: &[HtmlFrame<'_>]) -> Vec<String> {
119 #[cfg(feature = "batch")]
120 {
121 frames
122 .par_iter()
123 .map(|frame| self.render_raw_frame_svg(frame.0))
124 .collect()
125 }
126
127 #[cfg(not(feature = "batch"))]
128 {
129 frames
130 .iter()
131 .map(|frame| self.render_raw_frame_svg(frame.0))
132 .collect()
133 }
134 }
135
136 #[inline]
138 pub fn into_inner(self) -> typst_html::HtmlDocument {
139 self.0
140 }
141
142 #[inline]
144 pub fn as_inner(&self) -> &typst_html::HtmlDocument {
145 &self.0
146 }
147}
148
149#[inline]
150fn metadata_to_json(elem: &typst::foundations::Content) -> Option<serde_json::Value> {
151 elem.to_packed::<MetadataElem>()
152 .and_then(|meta| serde_json::to_value(&meta.value).ok())
153}
154
155impl From<typst_html::HtmlDocument> for HtmlDocument {
156 fn from(doc: typst_html::HtmlDocument) -> Self {
157 Self::new(doc)
158 }
159}