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