1use super::*;
4
5#[derive(Clone, Debug)]
28pub struct Node {
29 pub(super) data: Arc<NodeData>,
30}
31
32#[derive(Clone, Debug)]
33pub(super) struct NodeData {
34 pub(super) time: Option<Time>,
35 pub(super) kind: NodeKind,
36 pub(super) placement: Placement,
37 pub(super) text_metrics: Option<(f64, Rect)>,
38 pub(super) filters: Vec<crate::Filter>,
39 pub(super) opacity: f64,
40 pub(super) blend_mode: BlendMode,
41 pub(super) clip: Option<crate::PathClip>,
42 pub(super) rect_clip: Option<crate::RectClip>,
43 pub(super) shape_clip: Option<crate::ShapeClip>,
44 pub(super) mask: Option<Box<NodeMask>>,
45 pub(super) z_index: i32,
46 pub(super) name: Option<Arc<str>>,
47
48 pub(super) shutter_sampled: bool,
49}
50
51#[derive(Clone, Debug)]
52pub(super) struct NodeMask {
53 pub(super) node: Node,
54 pub(super) mode: crate::drawing::MaskMode,
55}
56
57#[derive(Clone)]
58pub(super) enum NodeKind {
59 Empty,
60 Leaf(Arc<dyn Drawable>),
61 Group(Vec<Node>),
62 Accumulate(Vec<Node>),
63 Layout(Layout, Vec<Node>),
64 Relative(super::spatial::Relative),
65}
66
67impl std::fmt::Debug for NodeKind {
68 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 match self {
70 Self::Empty => formatter.write_str("Empty"),
71 Self::Leaf(_) => formatter.write_str("Leaf(..)"),
72 Self::Relative(relative) => formatter.debug_tuple("Relative").field(relative).finish(),
73 Self::Group(children) => formatter.debug_tuple("Group").field(children).finish(),
74 Self::Accumulate(children) => {
75 formatter.debug_tuple("Accumulate").field(children).finish()
76 }
77 Self::Layout(layout, children) => formatter
78 .debug_tuple("Layout")
79 .field(layout)
80 .field(children)
81 .finish(),
82 }
83 }
84}
85
86impl Default for Node {
87 fn default() -> Self {
88 Self::empty()
89 }
90}
91
92pub trait IntoNodeGroup<Kind> {
94 fn into_nodes(self) -> Vec<Node>;
96}
97
98pub struct IteratorGroup<Child>(std::marker::PhantomData<Child>);
100
101pub struct TupleGroup;
103
104impl<Child: Into<Node>, Children: IntoIterator<Item = Child>> IntoNodeGroup<IteratorGroup<Child>>
105 for Children
106{
107 fn into_nodes(self) -> Vec<Node> {
108 self.into_iter().map(Into::into).collect()
109 }
110}
111
112impl IntoNodeGroup<TupleGroup> for () {
113 fn into_nodes(self) -> Vec<Node> {
114 Vec::new()
115 }
116}
117
118impl From<()> for Node {
119 fn from(_: ()) -> Self {
120 Self::empty()
121 }
122}
123
124macro_rules! tuple_nodes {
125 (@impl $($kind:ident:$value:ident,)+) => {
126 impl<$($kind: Into<Node>),+> IntoNodeGroup<TupleGroup> for ($($kind,)+) {
127 fn into_nodes(self) -> Vec<Node> {
128 let ($($value,)+) = self;
129 vec![$($value.into()),+]
130 }
131 }
132 impl<$($kind: Into<Node>),+> From<($($kind,)+)> for Node {
133 fn from(values: ($($kind,)+)) -> Self {
134 Self::new(NodeKind::Group(IntoNodeGroup::<TupleGroup>::into_nodes(values)))
135 }
136 }
137 };
138 (@grow [$($kind:ident:$value:ident,)+] $next:ident:$next_value:ident $(,$tail:ident:$tail_value:ident)*) => {
139 tuple_nodes!(@impl $($kind:$value,)+ $next:$next_value,);
140 tuple_nodes!(@grow [$($kind:$value,)+ $next:$next_value,] $($tail:$tail_value),*);
141 };
142 (@grow [$($kind:ident:$value:ident,)+]) => {};
143 ($first:ident:$first_value:ident $(,$tail:ident:$tail_value:ident)*) => {
144 tuple_nodes!(@impl $first:$first_value,);
145 tuple_nodes!(@grow [$first:$first_value,] $($tail:$tail_value),*);
146 };
147}
148
149tuple_nodes!(First:first, Second:second, Third:third, Fourth:fourth, Fifth:fifth, Sixth:sixth, Seventh:seventh, Eighth:eighth, Ninth:ninth, Tenth:tenth, Eleventh:eleventh, Twelfth:twelfth, Thirteenth:thirteenth, Fourteenth:fourteenth, Fifteenth:fifteenth, Sixteenth:sixteenth);
150
151impl Node {
152 pub(crate) fn shutter_sampled(mut self) -> Self {
153 Arc::make_mut(&mut self.data).shutter_sampled = true;
154 self
155 }
156
157 pub(crate) fn contains_shutter(&self, depth: usize) -> bool {
158 if depth > 256 || self.data.shutter_sampled {
159 return true;
160 }
161 if self
162 .data
163 .mask
164 .as_ref()
165 .is_some_and(|mask| mask.node.contains_shutter(depth + 1))
166 {
167 return true;
168 }
169 match &self.data.kind {
170 NodeKind::Group(children)
171 | NodeKind::Accumulate(children)
172 | NodeKind::Layout(_, children) => children
173 .iter()
174 .any(|child| child.contains_shutter(depth + 1)),
175 NodeKind::Relative(relative) => {
176 relative.node.contains_shutter(depth + 1)
177 || relative.reference.contains_shutter(depth + 1)
178 }
179 _ => false,
180 }
181 }
182
183 pub fn with_scene_time(mut self, time: Time) -> Self {
185 Arc::make_mut(&mut self.data).time = Some(time);
186 self
187 }
188
189 pub(super) fn new(kind: NodeKind) -> Self {
190 Self {
191 data: Arc::new(NodeData {
192 time: None,
193 kind,
194 placement: Placement::default(),
195 text_metrics: None,
196 filters: Vec::new(),
197 opacity: 1.0,
198 blend_mode: BlendMode::SourceOver,
199 clip: None,
200 rect_clip: None,
201 shape_clip: None,
202 mask: None,
203 z_index: 0,
204 name: None,
205 shutter_sampled: false,
206 }),
207 }
208 }
209
210 pub fn empty() -> Self {
212 Self::new(NodeKind::Empty)
213 }
214
215 pub fn next_to(self, reference: &Node, side: Side, gap: f64) -> Self {
217 spatial::relative(self, reference.clone(), side, Some(gap))
218 }
219
220 pub fn align_to(self, reference: &Node, edge: Side) -> Self {
222 spatial::relative(self, reference.clone(), edge, None)
223 }
224
225 pub fn accumulate(samples: impl IntoIterator<Item = Node>) -> Result<Self, ValidationError> {
228 let samples = samples.into_iter().take(65).collect::<Vec<_>>();
229 let count = samples.len();
230 Self::weighted_sum(samples.into_iter().map(|node| (node, 1.0 / count as f64)))
231 }
232
233 pub fn weighted_sum(
236 samples: impl IntoIterator<Item = (Node, f64)>,
237 ) -> Result<Self, ValidationError> {
238 let samples = samples.into_iter().take(65).collect::<Vec<_>>();
239 if samples.is_empty()
240 || samples.len() > 64
241 || samples
242 .iter()
243 .any(|(_, weight)| !weight.is_finite() || !(0.0..=1.0).contains(weight))
244 {
245 return Err(ValidationError::invalid(
246 "accumulate",
247 "samples",
248 "Require 1..=64 samples and finite weights in 0..=1",
249 ));
250 }
251 Ok(Self::new(NodeKind::Accumulate(
252 samples
253 .into_iter()
254 .map(|(node, weight)| {
255 Node::group([node])
256 .opacity(weight)
257 .blend_mode(BlendMode::LinearPlus)
258 })
259 .collect(),
260 )))
261 }
262
263 pub fn with_text_metrics(mut self, baseline: f64, bounds: Rect) -> Self {
266 Arc::make_mut(&mut self.data).text_metrics = Some((baseline, bounds));
267 self
268 }
269
270 pub fn transformed(self, transform: crate::Transform) -> Self {
273 let mut group = Self::group([self]);
274 Arc::make_mut(&mut group.data).placement.affine = transform;
275 group
276 }
277
278 pub fn group<Kind>(children: impl IntoNodeGroup<Kind>) -> Self {
280 Self::new(NodeKind::Group(children.into_nodes()))
281 }
282
283 pub fn push(&mut self, child: impl Into<Node>) {
285 let child = child.into();
286 if let NodeKind::Group(children) = &mut Arc::make_mut(&mut self.data).kind {
287 children.push(child);
288 } else {
289 *self = Self::group([self.clone(), child]);
290 }
291 }
292
293 pub(super) fn layout<Child: Into<Node>>(
294 layout: Layout,
295 children: impl IntoIterator<Item = Child>,
296 ) -> Self {
297 Self::new(NodeKind::Layout(
298 layout,
299 children.into_iter().map(Into::into).collect(),
300 ))
301 }
302
303 pub fn measure(&self, limits: ValidationLimits) -> Result<Rect, ValidationError> {
310 self.measure_with(&DrawContext::default(), limits)
311 }
312
313 pub fn preflight_with(
316 &self,
317 context: &DrawContext,
318 limits: ValidationLimits,
319 ) -> Result<crate::SceneStats, ValidationError> {
320 let context = &context.clone().with_validation_limits(limits);
321 let mut state = ValidationState::new(limits)?;
322 self.measure_bounds("node", 1, &mut state, context)?;
323 Ok(state.stats)
324 }
325
326 pub fn measure_with(
331 &self,
332 context: &DrawContext,
333 limits: ValidationLimits,
334 ) -> Result<Rect, ValidationError> {
335 let context = &context.clone().with_validation_limits(limits);
336 let mut state = ValidationState::new(limits)?;
337 self.measure_bounds("node", 1, &mut state, context)?
338 .rect("node")
339 }
340
341 pub(super) fn measure_bounds(
342 &self,
343 path: &str,
344 depth: usize,
345 state: &mut ValidationState,
346 context: &DrawContext,
347 ) -> Result<Bounds, ValidationError> {
348 let context = &context
349 .clone()
350 .with_time(self.data.time.unwrap_or(context.time()));
351 let path = self
352 .data
353 .name
354 .as_ref()
355 .map_or_else(|| path.to_owned(), |name| format!("{path}(name={name})"));
356 state.enter(&path, depth)?;
357 self.validate_clip(&path, depth, state)?;
358 if !self.data.opacity.is_finite() || !(0.0..=1.0).contains(&self.data.opacity) {
359 return Err(ValidationError::invalid(
360 &path,
361 "opacity",
362 "Require finite opacity in 0..=1",
363 ));
364 }
365 if let Some(mask) = &self.data.mask {
366 mask.node
367 .measure_bounds(&format!("{path}.mask"), depth + 1, state, context)?;
368 }
369 let bounds = match &self.data.kind {
370 NodeKind::Empty => Bounds::Empty,
371 NodeKind::Relative(relative) => {
372 let subject = relative.node.measure_bounds(
373 &format!("{path}.subject"),
374 depth + 1,
375 state,
376 context,
377 )?;
378 let reference = relative.reference.measure_bounds(
379 &format!("{path}.reference"),
380 depth + 1,
381 state,
382 context,
383 )?;
384 let translation =
385 relative.translation(subject.rect(&path)?, reference.rect(&path)?)?;
386 subject.transformed(translation, &path)?
387 }
388 NodeKind::Leaf(drawable) => {
389 if let Some(resolved) = drawable.resolve_node(context)? {
390 resolved.measure_bounds(&path, depth + 1, state, context)?
391 } else {
392 let bounds = drawable.try_bounds(context)?;
393 crate::drawing::validate_rect(bounds, &path, "bounds")?;
394 Bounds::Known(bounds)
395 }
396 }
397 NodeKind::Group(children)
398 | NodeKind::Layout(_, children)
399 | NodeKind::Accumulate(children) => {
400 let mut geometry = Vec::new();
401 for (index, child) in children.iter().enumerate() {
402 geometry.push((
403 index,
404 child.measure_bounds(
405 &format!("{path}.children[{index}]"),
406 depth + 1,
407 state,
408 context,
409 )?,
410 ));
411 }
412 if let NodeKind::Layout(layout, _) = self.data.kind {
413 let baselines = layout.baselines(children, context, &path)?;
414 let placements = layout.placements(&geometry, &baselines, &path)?;
415 for ((_, bounds), placement) in geometry.iter_mut().zip(placements) {
416 if let Some((_, placed)) = placement {
417 *bounds = placed;
418 }
419 }
420 }
421 geometry
422 .into_iter()
423 .fold(Bounds::Empty, |bounds, (_, child)| bounds.union(child))
424 }
425 };
426 let placement = self.data.placement.resolve(bounds, &path)?;
427 bounds.transformed(placement.transform, &path)
428 }
429
430 pub(super) fn validate_clip(
431 &self,
432 path: &str,
433 depth: usize,
434 state: &mut ValidationState,
435 ) -> Result<(), ValidationError> {
436 for (index, filter) in self.data.filters.iter().enumerate() {
437 let path = format!("{path}.filters[{index}]");
438 filter.validate(&path)?;
439 for operation in 0..filter.structural_cost() {
440 state.enter_with(|| format!("{path}[{operation}]"), depth + 1)?;
441 }
442 }
443 if let Some(clip) = self.data.rect_clip {
444 let path = format!("{path}.rect_clip");
445 crate::display_list::mapped_bounds(clip.bounds, clip.transform, &path)?;
446 state.enter(&path, depth + 1)?;
447 }
448 if let Some(clip) = &self.data.shape_clip {
449 let path = format!("{path}.shape_clip");
450 let verbs = clip.validate(&path)?;
451 state.enter(&path, depth + 1)?;
452 for index in 0..verbs {
453 state.enter_with(|| format!("{path}.verbs[{index}]"), depth + 1)?;
454 }
455 }
456 if let Some(clip) = &self.data.clip {
457 let path = format!("{path}.clip");
458 crate::display_list::validate_path(&clip.path, clip.transform, &path)?;
459 for index in 0..clip.path.verbs().len() {
460 state.enter_with(|| format!("{path}.verbs[{index}]"), depth + 1)?;
461 }
462 }
463 Ok(())
464 }
465
466 pub(super) fn baseline(
467 &self,
468 context: &DrawContext,
469 path: &str,
470 ) -> Result<Option<f64>, ValidationError> {
471 let (baseline, local_bounds) = if let Some(metrics) = self.data.text_metrics {
472 metrics
473 } else {
474 let NodeKind::Leaf(drawable) = &self.data.kind else {
475 return Ok(None);
476 };
477 let Some(baseline) = drawable.baseline(context) else {
478 return Ok(None);
479 };
480 (baseline, drawable.try_bounds(context)?)
481 };
482 if !baseline.is_finite() {
483 return Err(ValidationError::invalid(
484 path,
485 "baseline",
486 "Text baseline must be finite",
487 ));
488 }
489 if self.data.placement.rotation != 0.0 || self.data.placement.scale.y <= 0.0 {
490 return Err(ValidationError::unsupported(
491 path,
492 "baseline",
493 "Baseline rows require horizontal, upright text",
494 ));
495 }
496 let bounds = Bounds::declared(local_bounds, path)?;
497 let placement = self.data.placement.resolve(bounds, path)?;
498 let baseline = placement.transform.apply(Point::new(0.0, baseline)).y;
499 if !baseline.is_finite() {
500 return Err(ValidationError::invalid(
501 path,
502 "baseline",
503 "Transformed baseline must be finite",
504 ));
505 }
506 Ok(Some(baseline))
507 }
508}
509
510impl<Content: Drawable + 'static> From<Content> for Node {
511 fn from(content: Content) -> Self {
512 Self::new(NodeKind::Leaf(Arc::new(content)))
513 }
514}
515
516impl From<Arc<dyn Drawable>> for Node {
517 fn from(content: Arc<dyn Drawable>) -> Self {
518 Self::new(NodeKind::Leaf(content))
519 }
520}
521
522impl<Value: Into<Node>> From<Option<Value>> for Node {
523 fn from(value: Option<Value>) -> Self {
524 value.map_or_else(Self::empty, Into::into)
525 }
526}
527
528impl FromIterator<Node> for Node {
529 fn from_iter<Iter: IntoIterator<Item = Node>>(iter: Iter) -> Self {
530 Self::group(iter)
531 }
532}