1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use pax_std::primitives::Image;
use piet::{ImageFormat, InterpolationMode, RenderContext};
use std::collections::HashMap;

use pax_core::pax_properties_coproduct::{PropertiesCoproduct, TypesCoproduct};
use pax_core::{
    unsafe_unwrap, HandlerRegistry, InstantiationArgs, PropertiesComputable, RenderNode,
    RenderNodePtr, RenderNodePtrList, RenderTreeContext,
};
use pax_message::ImagePatch;
use pax_runtime_api::CommonProperties;
use std::cell::RefCell;
use std::rc::Rc;
/// An Image (decoded by chassis), drawn to the bounds specified
/// by `size`, transformed by `transform`
pub struct ImageInstance<R: 'static + RenderContext> {
    pub handler_registry: Option<Rc<RefCell<HandlerRegistry<R>>>>,
    pub instance_id: u32,
    pub properties: Rc<RefCell<Image>>,
    pub common_properties: CommonProperties,
    last_patches: HashMap<Vec<u32>, pax_message::ImagePatch>,
    pub image: Option<<R as RenderContext>::Image>,
}

impl<R: 'static + RenderContext> RenderNode<R> for ImageInstance<R> {
    fn get_instance_id(&self) -> u32 {
        self.instance_id
    }
    fn get_common_properties(&self) -> &CommonProperties {
        &self.common_properties
    }

    fn get_rendering_children(&self) -> RenderNodePtrList<R> {
        Rc::new(RefCell::new(vec![]))
    }

    fn instantiate(args: InstantiationArgs<R>) -> Rc<RefCell<Self>>
    where
        Self: Sized,
    {
        let properties = unsafe_unwrap!(args.properties, PropertiesCoproduct, Image);
        let mut instance_registry = (*args.instance_registry).borrow_mut();
        let instance_id = instance_registry.mint_id();
        let ret = Rc::new(RefCell::new(ImageInstance {
            instance_id,
            properties: Rc::new(RefCell::new(properties)),
            common_properties: args.common_properties,
            handler_registry: args.handler_registry,
            last_patches: Default::default(),
            image: None,
        }));

        instance_registry.register(instance_id, Rc::clone(&ret) as RenderNodePtr<R>);
        ret
    }

    fn get_handler_registry(&self) -> Option<Rc<RefCell<HandlerRegistry<R>>>> {
        match &self.handler_registry {
            Some(registry) => Some(Rc::clone(registry)),
            _ => None,
        }
    }
    fn compute_properties(&mut self, rtc: &mut RenderTreeContext<R>) {
        let properties = &mut *self.properties.as_ref().borrow_mut();

        if let Some(path) = rtc.compute_vtable_value(properties.path._get_vtable_id()) {
            let new_value = if let TypesCoproduct::String(v) = path {
                v
            } else {
                unreachable!()
            };
            properties
                .path
                .set(pax_runtime_api::StringBox { string: new_value });
        }

        self.common_properties.compute_properties(rtc);
    }

    fn compute_native_patches(
        &mut self,
        rtc: &mut RenderTreeContext<R>,
        _computed_size: (f64, f64),
        _transform_coeffs: Vec<f64>,
        _z_index: u32,
        _subtree_depth: u32,
    ) {
        let mut new_message: ImagePatch = Default::default();
        new_message.id_chain = rtc.get_id_chain(self.instance_id);
        if !self.last_patches.contains_key(&new_message.id_chain) {
            let mut patch = ImagePatch::default();
            patch.id_chain = new_message.id_chain.clone();
            self.last_patches
                .insert(new_message.id_chain.clone(), patch);
        }
        let last_patch = self.last_patches.get_mut(&new_message.id_chain).unwrap();
        let mut has_any_updates = false;

        let properties = &mut *self.properties.as_ref().borrow_mut();
        let val = properties.path.get();
        let is_new_value = match &last_patch.path {
            Some(cached_value) => !val.string.eq(cached_value),
            None => true,
        };
        if is_new_value {
            new_message.path = Some(val.string.clone());
            last_patch.path = Some(val.string.clone());
            has_any_updates = true;
        }

        if has_any_updates {
            (*rtc.engine.runtime)
                .borrow_mut()
                .enqueue_native_message(pax_message::NativeMessage::ImageLoad(new_message));
        }
    }

    fn handle_render(&mut self, rtc: &mut RenderTreeContext<R>, rc: &mut R) {
        let transform = rtc.transform_scroller_reset;
        let bounding_dimens = rtc.bounds;
        let width = bounding_dimens.0;
        let height = bounding_dimens.1;

        let bounds = kurbo::Rect::new(0.0, 0.0, width, height);
        let top_left = transform * kurbo::Point::new(bounds.min_x(), bounds.min_y());
        let bottom_right = transform * kurbo::Point::new(bounds.max_x(), bounds.max_y());
        let transformed_bounds =
            kurbo::Rect::new(top_left.x, top_left.y, bottom_right.x, bottom_right.y);

        let _properties = (*self.properties).borrow();
        let id_chain = rtc.get_id_chain(self.instance_id);
        if rtc.engine.image_map.contains_key(&id_chain) && self.image.is_none() {
            let (bytes, width, height) = rtc.engine.image_map.get(&id_chain).unwrap();
            let image = rc
                .make_image(*width, *height, &*bytes, ImageFormat::RgbaSeparate)
                .unwrap();
            self.image = Some(image);
        }
        if let Some(image) = &self.image {
            rc.draw_image(&image, transformed_bounds, InterpolationMode::Bilinear);
        }
    }
}