rive_rs/
artboard.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::cell::{Cell, Ref, RefCell};
6use std::collections::{HashMap, VecDeque};
7use std::iter;
8use std::rc::Rc;
9
10use crate::animation::{LinearAnimation, StateMachine};
11use crate::component::Component;
12use crate::component_dirt::ComponentDirt;
13use crate::container_component::ContainerComponent;
14use crate::core::{Core, CoreContext, Object, ObjectRef, OnAdded, Property};
15use crate::dependency_sorter::DependencySorter;
16use crate::draw_target::{DrawTarget, DrawTargetPlacement};
17use crate::drawable::Drawable;
18use crate::math::{self, Aabb, Mat};
19use crate::option_cell::OptionCell;
20use crate::renderer::Renderer;
21use crate::shapes::{CommandPath, CommandPathBuilder, ShapePaintContainer};
22use crate::status_code::StatusCode;
23
24#[derive(Clone, Debug)]
25pub struct ObjectsIter<T: Core> {
26    objects: Rc<RefCell<Vec<Object<T>>>>,
27    head: usize,
28    tail: usize,
29}
30
31impl<T: Core> ObjectsIter<T> {
32    fn new(objects: Rc<RefCell<Vec<Object<T>>>>) -> Self {
33        let len = objects.borrow().len();
34        Self { objects, head: 0, tail: len }
35    }
36}
37
38impl<T: Core> Iterator for ObjectsIter<T> {
39    type Item = Object<T>;
40
41    #[inline]
42    fn next(&mut self) -> Option<Self::Item> {
43        if self.head == self.tail {
44            return None;
45        }
46
47        let result = self.objects.borrow().iter().nth(self.head).cloned();
48
49        if result.is_some() {
50            self.head += 1;
51        }
52
53        result
54    }
55
56    #[inline]
57    fn size_hint(&self) -> (usize, Option<usize>) {
58        let len = self.tail - self.head;
59        (len, Some(len))
60    }
61
62    #[inline]
63    fn count(self) -> usize {
64        self.tail - self.head
65    }
66
67    #[inline]
68    fn nth(&mut self, n: usize) -> Option<Self::Item> {
69        self.objects.borrow().iter().nth(self.head + n).cloned()
70    }
71}
72
73impl<T: Core> DoubleEndedIterator for ObjectsIter<T> {
74    #[inline]
75    fn next_back(&mut self) -> Option<Self::Item> {
76        if self.head == self.tail {
77            return None;
78        }
79
80        let result = self.objects.borrow().iter().nth(self.tail - 1).cloned();
81
82        if result.is_some() {
83            self.tail -= 1;
84        }
85
86        result
87    }
88
89    #[inline]
90    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
91        if n >= self.tail {
92            return None;
93        }
94
95        self.objects.borrow().iter().nth(self.tail - 1 - n).cloned()
96    }
97}
98
99impl<T: Core> ExactSizeIterator for ObjectsIter<T> {
100    #[inline]
101    fn len(&self) -> usize {
102        self.tail - self.head
103    }
104}
105
106#[derive(Debug, Default)]
107struct ArtboardInner {
108    objects: RefCell<Vec<Object>>,
109    animations: Rc<RefCell<Vec<Object<LinearAnimation>>>>,
110    state_machines: Rc<RefCell<Vec<Object<StateMachine>>>>,
111    dependency_order: RefCell<VecDeque<Object<Component>>>,
112    drawables: RefCell<Vec<Object<Drawable>>>,
113    draw_targets: RefCell<Vec<Object<DrawTarget>>>,
114    dirt_depth: Cell<usize>,
115    background_path: RefCell<Option<CommandPath>>,
116    clip_path: RefCell<Option<CommandPath>>,
117    first_drawable: OptionCell<Object<Drawable>>,
118    root: OptionCell<Rc<dyn Core>>,
119}
120
121fn objects_of<T: Core>(objects: &[Object]) -> impl Iterator<Item = Object<T>> + '_ {
122    objects.iter().cloned().filter_map(|object| object.try_cast())
123}
124
125impl ArtboardInner {
126    pub fn initialize(&self) -> StatusCode {
127        for object in self.objects.borrow().iter() {
128            let code = object.as_ref().on_added_dirty(self);
129            if code != StatusCode::Ok {
130                return code;
131            }
132        }
133
134        for object in self.animations.borrow().iter() {
135            let code = object.as_ref().on_added_dirty(self);
136            if code != StatusCode::Ok {
137                return code;
138            }
139        }
140
141        for object in self.state_machines.borrow().iter() {
142            let code = object.as_ref().on_added_dirty(self);
143            if code != StatusCode::Ok {
144                return code;
145            }
146        }
147
148        let mut component_draw_rules = HashMap::new();
149
150        for object in self.objects.borrow().iter() {
151            let code = object.as_ref().on_added_clean(self);
152            if code != StatusCode::Ok {
153                return code;
154            }
155
156            if let Some(draw_rules) = object.try_cast() {
157                if let Some(component) = self
158                    .resolve(draw_rules.cast::<Component>().as_ref().parent_id() as usize)
159                    .and_then(|core| core.try_cast())
160                {
161                    component_draw_rules.insert(component, draw_rules);
162                } else {
163                    return StatusCode::MissingObject;
164                }
165            }
166        }
167
168        for object in self.animations.borrow().iter() {
169            let code = object.as_ref().on_added_clean(self);
170            if code != StatusCode::Ok {
171                return code;
172            }
173        }
174
175        for object in self.state_machines.borrow().iter() {
176            let code = object.as_ref().on_added_clean(self);
177            if code != StatusCode::Ok {
178                return code;
179            }
180        }
181
182        for component in objects_of::<Component>(self.objects.borrow().as_slice()) {
183            component.as_ref().build_dependencies();
184        }
185
186        for drawable in objects_of::<Drawable>(self.objects.borrow().as_slice()) {
187            self.drawables.borrow_mut().push(drawable.clone());
188
189            let parents = iter::once(drawable.cast::<ContainerComponent>())
190                .chain(drawable.cast::<Component>().as_ref().parents());
191
192            for parent in parents {
193                if let Some(draw_rules) = component_draw_rules.get(&parent) {
194                    drawable.as_ref().flattened_draw_rules.set(Some(draw_rules.clone()));
195                    break;
196                }
197            }
198        }
199
200        self.sort_dependencies();
201
202        let root: Rc<dyn Core> = Rc::new(DrawTarget::default());
203        self.root.set(Some(Rc::clone(&root)));
204        let root = Object::new(&root);
205
206        for draw_target in objects_of::<DrawTarget>(self.objects.borrow().as_slice()) {
207            root.cast::<Component>().as_ref().push_dependent(draw_target.cast());
208
209            if let Some(dependent_rules) = draw_target
210                .as_ref()
211                .drawable()
212                .expect("DrawTarget has no Drawable set")
213                .as_ref()
214                .flattened_draw_rules
215                .get()
216            {
217                for dependent_target in objects_of::<DrawTarget>(self.objects.borrow().as_slice()) {
218                    let dependent_target = dependent_target.cast::<Component>();
219                    let dependent_target = dependent_target.as_ref();
220                    if let Some(parent) = dependent_target.parent() {
221                        if parent.ptr_eq(&dependent_rules) {
222                            dependent_target.push_dependent(draw_target.cast());
223                        }
224                    }
225                }
226            }
227        }
228
229        let mut sorter = DependencySorter::default();
230        let mut draw_target_order = VecDeque::new();
231
232        sorter.sort(root, &mut draw_target_order);
233
234        self.draw_targets
235            .borrow_mut()
236            .extend(draw_target_order.into_iter().map(|component| component.cast()));
237
238        StatusCode::Ok
239    }
240
241    pub fn sort_draw_order(&self) {
242        for target in &*self.draw_targets.borrow() {
243            let target = target.as_ref();
244            target.first.set(None);
245            target.last.set(None);
246        }
247
248        self.first_drawable.set(None);
249        let mut last_drawable = None;
250
251        for drawable in &*self.drawables.borrow() {
252            let drawable_ref = drawable.as_ref();
253            if let Some(target) = drawable_ref
254                .flattened_draw_rules
255                .get()
256                .and_then(|rules| rules.as_ref().active_target())
257            {
258                let target = target.as_ref();
259                if let (Some(_), Some(last)) = (target.first.get(), target.last.get()) {
260                    last.as_ref().next.set(Some(drawable.clone()));
261                    drawable_ref.prev.set(Some(last));
262                    target.last.set(Some(drawable.clone()));
263                } else {
264                    target.first.set(Some(drawable.clone()));
265                    target.last.set(Some(drawable.clone()));
266                    drawable_ref.prev.set(None);
267                }
268                drawable_ref.next.set(None);
269            } else {
270                drawable_ref.prev.set(last_drawable.clone());
271                drawable_ref.next.set(None);
272
273                if let Some(ref last_drawable_ref) = last_drawable {
274                    last_drawable_ref.as_ref().next.set(Some(drawable.clone()));
275                    last_drawable = Some(drawable.clone());
276                } else {
277                    last_drawable = Some(drawable.clone());
278                    self.first_drawable.set(Some(drawable.clone()));
279                }
280            }
281        }
282
283        for rule in &*self.draw_targets.borrow() {
284            let rule = rule.as_ref();
285            if let (Some(ref rule_first), Some(ref rule_last)) = (rule.first.get(), rule.last.get())
286            {
287                let rule_last_ref = rule_last.as_ref();
288                if let Some(ref target_drawable) = rule.drawable() {
289                    let target_drawable_ref = target_drawable.as_ref();
290                    match rule.placement() {
291                        DrawTargetPlacement::Before => {
292                            if let Some(prev) = target_drawable_ref.prev.get() {
293                                prev.as_ref().next.set(Some(rule_first.clone()));
294                                rule_first.as_ref().prev.set(Some(prev));
295                            }
296
297                            if Some(target_drawable) == self.first_drawable.get().as_ref() {
298                                self.first_drawable.set(Some(rule_first.clone()));
299                            }
300
301                            target_drawable_ref.prev.set(Some(rule_last.clone()));
302                            rule_last_ref.next.set(Some(target_drawable.clone()));
303                        }
304                        DrawTargetPlacement::After => {
305                            if let Some(next) = target_drawable_ref.next.get() {
306                                next.as_ref().prev.set(Some(rule_last.clone()));
307                                rule_last_ref.next.set(target_drawable_ref.next.get());
308                            }
309
310                            if Some(target_drawable) == last_drawable.as_ref() {
311                                last_drawable = Some(rule_last.clone());
312                            }
313
314                            target_drawable_ref.next.set(Some(rule_first.clone()));
315                            rule_last_ref.prev.set(Some(target_drawable.clone()));
316                        }
317                    }
318                }
319            }
320        }
321
322        self.first_drawable.set(last_drawable);
323    }
324
325    fn component(&self) -> Object<Component> {
326        self.objects.borrow()[0].try_cast().expect("first object in Artboard must be itself")
327    }
328
329    fn sort_dependencies(&self) {
330        let mut sorter = DependencySorter::default();
331
332        let component = self.component();
333        sorter.sort(component.clone(), &mut *self.dependency_order.borrow_mut());
334
335        for (component, graph_order) in self.dependency_order.borrow().iter().zip(0..) {
336            component.as_ref().graph_order.set(graph_order);
337        }
338
339        component.as_ref().dirt.set(component.as_ref().dirt.get() | ComponentDirt::COMPONENTS);
340    }
341
342    pub fn push_object(&self, object: Object) {
343        self.objects.borrow_mut().push(object);
344    }
345
346    pub fn push_animation(&self, animation: Object<LinearAnimation>) {
347        self.animations.borrow_mut().push(animation);
348    }
349
350    pub fn push_state_machine(&self, state_machine: Object<StateMachine>) {
351        self.state_machines.borrow_mut().push(state_machine);
352    }
353
354    pub fn on_component_dirty(&self, component: &Component) {
355        let this_component = self.component();
356        let this_component = this_component.as_ref();
357        this_component.dirt.set(this_component.dirt.get() | ComponentDirt::COMPONENTS);
358
359        self.dirt_depth.set(self.dirt_depth.get().min(component.graph_order.get()));
360    }
361
362    pub fn update_components(&self, component: ObjectRef<'_, Component>) -> bool {
363        let mut step = 0;
364        while component.has_dirt(ComponentDirt::COMPONENTS) && step < 100 {
365            for (i, component) in self.dependency_order.borrow().iter().enumerate() {
366                self.dirt_depth.set(i);
367
368                let component = component.as_ref();
369                let dirt = component.dirt.get();
370                if dirt.is_empty() {
371                    continue;
372                }
373
374                component.dirt.set(ComponentDirt::empty());
375                component.update(dirt);
376
377                if self.dirt_depth.get() < i {
378                    break;
379                }
380            }
381
382            step += 1;
383        }
384
385        false
386    }
387}
388
389#[derive(Debug, Default)]
390pub struct Artboard {
391    container_component: ContainerComponent,
392    shape_paint_container: ShapePaintContainer,
393    width: Property<f32>,
394    height: Property<f32>,
395    x: Property<f32>,
396    y: Property<f32>,
397    origin_x: Property<f32>,
398    origin_y: Property<f32>,
399    inner: ArtboardInner,
400}
401
402impl ObjectRef<'_, Artboard> {
403    pub fn width(&self) -> f32 {
404        self.width.get()
405    }
406
407    pub fn set_width(&self, width: f32) {
408        self.width.set(width);
409    }
410
411    pub fn height(&self) -> f32 {
412        self.height.get()
413    }
414
415    pub fn set_height(&self, height: f32) {
416        self.height.set(height);
417    }
418
419    pub fn x(&self) -> f32 {
420        self.x.get()
421    }
422
423    pub fn set_x(&self, x: f32) {
424        self.x.set(x);
425    }
426
427    pub fn y(&self) -> f32 {
428        self.y.get()
429    }
430
431    pub fn set_y(&self, y: f32) {
432        self.y.set(y);
433    }
434
435    pub fn origin_x(&self) -> f32 {
436        self.origin_x.get()
437    }
438
439    pub fn set_origin_x(&self, origin_x: f32) {
440        self.origin_x.set(origin_x);
441    }
442
443    pub fn origin_y(&self) -> f32 {
444        self.origin_y.get()
445    }
446
447    pub fn set_origin_y(&self, origin_y: f32) {
448        self.origin_y.set(origin_y);
449    }
450}
451
452impl ObjectRef<'_, Artboard> {
453    pub fn initialize(&self) -> StatusCode {
454        self.inner.initialize()
455    }
456
457    pub fn push_object(&self, object: Object) {
458        self.inner.push_object(object);
459    }
460
461    pub(crate) fn objects(&self) -> Ref<'_, [Object]> {
462        Ref::map(self.inner.objects.borrow(), |objects| objects.as_slice())
463    }
464
465    pub fn push_animation(&self, animation: Object<LinearAnimation>) {
466        self.inner.push_animation(animation);
467    }
468
469    pub fn push_state_machine(&self, state_machine: Object<StateMachine>) {
470        self.inner.push_state_machine(state_machine);
471    }
472
473    pub fn on_component_dirty(&self, component: &Component) {
474        self.inner.on_component_dirty(component);
475    }
476
477    fn as_component(&self) -> ObjectRef<'_, Component> {
478        self.cast()
479    }
480
481    pub fn on_dirty(&self, _dirt: ComponentDirt) {
482        let dirt = &self.as_component().dirt;
483        dirt.set(dirt.get() | ComponentDirt::COMPONENTS);
484    }
485
486    pub fn update(&self, value: ComponentDirt) {
487        if Component::value_has_dirt(value, ComponentDirt::DRAW_ORDER) {
488            self.inner.sort_draw_order();
489        }
490
491        if Component::value_has_dirt(value, ComponentDirt::PATH) {
492            let mut builder = CommandPathBuilder::new();
493
494            builder.rect(math::Vec::new(0.0, 0.0), math::Vec::new(self.width(), self.height()));
495
496            *self.inner.clip_path.borrow_mut() = Some(builder.build());
497
498            let mut builder = CommandPathBuilder::new();
499
500            builder.rect(
501                math::Vec::new(-self.width() * self.origin_x(), -self.height() * self.origin_y()),
502                math::Vec::new(self.width(), self.height()),
503            );
504
505            *self.inner.background_path.borrow_mut() = Some(builder.build());
506        }
507    }
508
509    pub fn update_components(&self) -> bool {
510        let component = self.as_component();
511        if component.has_dirt(ComponentDirt::COMPONENTS) {
512            return self.inner.update_components(component);
513        }
514
515        false
516    }
517
518    pub fn advance(&self, _elapsed_seconds: f32) -> bool {
519        self.update_components()
520    }
521
522    pub fn draw(&self, renderer: &mut impl Renderer, transform: Mat) {
523        let mut artboard_transform = Mat {
524            translate_x: self.width() * self.origin_x(),
525            translate_y: self.height() * self.origin_y(),
526            ..Default::default()
527        };
528
529        artboard_transform = artboard_transform * transform;
530
531        for shape_paint in self.cast::<ShapePaintContainer>().shape_paints() {
532            shape_paint.as_ref().draw(
533                renderer,
534                self.inner
535                    .background_path
536                    .borrow()
537                    .as_ref()
538                    .expect("background_path should already be set in Artboard"),
539                artboard_transform,
540            );
541        }
542
543        let drawables = iter::successors(self.inner.first_drawable.get(), |drawable| {
544            drawable.as_ref().prev.get()
545        });
546
547        for drawable in drawables {
548            drawable.as_ref().draw(renderer, artboard_transform);
549        }
550    }
551
552    pub fn bounds(&self) -> Aabb {
553        Aabb::new(0.0, 0.0, self.width(), self.height())
554    }
555
556    pub fn animations(&self) -> ObjectsIter<LinearAnimation> {
557        ObjectsIter::new(self.inner.animations.clone())
558    }
559
560    pub fn state_machines(&self) -> ObjectsIter<StateMachine> {
561        ObjectsIter::new(self.inner.state_machines.clone())
562    }
563}
564
565impl Core for Artboard {
566    parent_types![
567        (container_component, ContainerComponent),
568        (shape_paint_container, ShapePaintContainer),
569    ];
570
571    properties![
572        (7, width, set_width),
573        (8, height, set_height),
574        (9, x, set_x),
575        (10, y, set_y),
576        (11, origin_x, set_origin_x),
577        (12, origin_y, set_origin_y),
578        container_component,
579    ];
580}
581
582impl OnAdded for ObjectRef<'_, Artboard> {
583    on_added!(ContainerComponent);
584}
585
586impl CoreContext for ArtboardInner {
587    fn resolve(&self, id: usize) -> Option<Object> {
588        self.objects.borrow().get(id).cloned()
589    }
590}
591
592impl CoreContext for Artboard {
593    fn resolve(&self, id: usize) -> Option<Object> {
594        self.inner.resolve(id)
595    }
596}