polyhorn_core/
render.rs

1use super::element::{ElementBuiltin, ElementComponent, ElementContext, ElementFragment};
2use super::{
3    CommandBuffer, Component, Compositor, Disposable, Effect, EffectLink, Element, EventLoop,
4    Instance, LayoutEffect, Manager, Platform,
5};
6use std::cell::RefCell;
7use std::ops::DerefMut;
8use std::rc::Rc;
9
10pub struct Render<P>
11where
12    P: Platform + ?Sized,
13{
14    renderer: Rc<Renderer<P>>,
15    buffer: P::CommandBuffer,
16    layout_effects: Vec<LayoutEffect<P>>,
17    effects: Vec<Effect<P>>,
18}
19
20impl<P> Render<P>
21where
22    P: Platform + ?Sized,
23{
24    fn new(renderer: Rc<Renderer<P>>) -> Render<P> {
25        let buffer = renderer
26            .compositor
27            .try_borrow_mut()
28            .expect("Couldn't acquire new command buffer from busy compositor.")
29            .buffer();
30
31        Render {
32            renderer,
33            buffer,
34            layout_effects: vec![],
35            effects: vec![],
36        }
37    }
38
39    fn rerender_builtin(&mut self, instance: &Rc<Instance<P>>, element: ElementBuiltin<P>) {
40        let container = instance.container();
41        let builtin = element.builtin;
42
43        self.buffer
44            .mutate(&[container], move |containers, environment| {
45                builtin.update(containers[0], environment);
46            });
47
48        self.rerender_edges(instance, vec![*element.children]);
49    }
50
51    fn rerender_component(&mut self, instance: &Rc<Instance<P>>, element: ElementComponent<P>) {
52        let (edges, (effects, layout_effects)) = {
53            let mut memory = instance.memory_mut();
54            let compositor = self
55                .renderer
56                .compositor
57                .try_borrow()
58                .expect("Couldn't borrow compositor.");
59            let bus = self
60                .renderer
61                .bus
62                .try_borrow()
63                .expect("Couldn't borrow bus.");
64            let mut manager = Manager::new(
65                &*compositor,
66                &*bus,
67                &mut memory,
68                instance.context(),
69                *element.children,
70                &instance,
71            );
72            (
73                vec![element.component.render(&mut manager)],
74                manager.into_effects(),
75            )
76        };
77
78        self.rerender_edges(instance, edges);
79
80        self.effects.extend(effects);
81        self.layout_effects.extend(layout_effects);
82    }
83
84    fn rerender_context(&mut self, instance: &Rc<Instance<P>>, element: ElementContext<P>) {
85        instance.context().insert_raw(element.value);
86
87        self.rerender_edges(instance, vec![*element.children])
88    }
89
90    fn rerender_fragment(&mut self, instance: &Rc<Instance<P>>, element: ElementFragment<P>) {
91        self.rerender_edges(instance, element.elements)
92    }
93
94    fn rerender_edges(&mut self, instance: &Rc<Instance<P>>, edges: Vec<Element<P>>) {
95        let mut topology = instance.topology_mut();
96        let topology = topology.deref_mut();
97
98        // Re-rendering looks a bit like mark and sweep. We start by collecting
99        // the set of keys of edges.
100        let mut keys = topology.keys();
101
102        for element in edges {
103            let key = element.key();
104
105            keys.remove(key);
106
107            if let Some(existing) = topology.edge(key) {
108                // The edge already exists. We replace its element and issue a
109                // re-render.
110                existing.topology_mut().deref_mut().update(element);
111                self.rerender(existing)
112            } else {
113                // The edge does not yet exist. We issue a fresh render and store
114                // the resulting instance in the topology of this instance.
115                let key = key.clone();
116                let instance = self.render(
117                    Some(instance.clone()),
118                    element,
119                    instance.container().clone(),
120                );
121                topology.add_edge(key, instance);
122            }
123        }
124
125        // Finally, we unmount all instances that correspond to edges that are
126        // no longer present.
127        for key in keys {
128            if let Some(instance) = topology.remove_edge(&key) {
129                self.unmount(&instance);
130            }
131        }
132    }
133
134    fn unmount(&mut self, instance: &Rc<Instance<P>>) {
135        for edge in instance.topology_mut().edges() {
136            self.unmount(&edge);
137        }
138
139        match instance.topology_mut().deref_mut().element() {
140            Element::Builtin(_) => {
141                self.buffer.unmount(instance.container());
142            }
143            _ => {}
144        }
145    }
146
147    /// This function is called when re-rendering an existing instance.
148    pub fn rerender(&mut self, instance: &Rc<Instance<P>>) {
149        let element = instance.topology_mut().element().clone();
150
151        match element {
152            Element::Builtin(element) => self.rerender_builtin(instance, element),
153            Element::Component(element) => self.rerender_component(instance, element),
154            Element::Context(element) => self.rerender_context(instance, element),
155            Element::Fragment(element) => self.rerender_fragment(instance, element),
156            Element::String(_text) => unimplemented!("Can't render string element directly."),
157        }
158    }
159
160    /// This function is called when rendering an element into a container for
161    /// the first time.
162    pub fn render(
163        &mut self,
164        parent: Option<Rc<Instance<P>>>,
165        element: Element<P>,
166        in_container: P::ContainerID,
167    ) -> Rc<Instance<P>> {
168        // We start by figuring out if we need to create a new container for this
169        // element or not.
170        let container = match &element {
171            Element::Builtin(element) => {
172                let builtin = element.builtin.clone();
173                let container = self.buffer.mount(in_container, move |parent, environment| {
174                    builtin.instantiate(parent, environment)
175                });
176
177                if let Some(reference) = &element.reference {
178                    reference.replace(Some(container));
179                }
180
181                container
182            }
183            _ => in_container,
184        };
185
186        let renderer = self.renderer.clone();
187
188        // Then, we create an instance for this element.
189        let instance = Rc::new(Instance::new(renderer, parent, element, container));
190
191        // Finally, we pretend that this is simply a re-render.
192        self.rerender(&instance);
193
194        instance
195    }
196
197    pub fn finish(mut self) {
198        self.buffer.layout();
199
200        // Finally, we apply the effects and we're done!
201        for effect in self.layout_effects.into_iter() {
202            let instance = effect.instance().clone();
203            let memory = instance.memory();
204            let link = EffectLink::new(&instance, &memory);
205
206            effect.invoke(&link, &mut self.buffer);
207        }
208
209        self.buffer.commit();
210
211        let effects = self.effects;
212
213        self.renderer.bus.borrow().queue_retain(async move {
214            for effect in effects.into_iter() {
215                let instance = effect.instance().clone();
216                let memory = instance.memory();
217                let link = EffectLink::new(&instance, &memory);
218
219                effect.invoke(&link);
220            }
221        });
222    }
223}
224
225pub struct Renderer<P>
226where
227    P: Platform + ?Sized,
228{
229    compositor: RefCell<P::Compositor>,
230    bus: RefCell<EventLoop>,
231}
232
233impl<P> Renderer<P>
234where
235    P: Platform + ?Sized,
236{
237    /// This function returns a new reference counted renderer with the given
238    /// compositor.
239    pub fn new(compositor: P::Compositor, bus: EventLoop) -> Rc<Renderer<P>> {
240        Rc::new(Renderer {
241            compositor: RefCell::new(compositor),
242            bus: RefCell::new(bus),
243        })
244    }
245
246    pub fn queue_rerender(self: &Rc<Self>, instance: &Rc<Instance<P>>) {
247        let renderer = self.clone();
248        let instance = instance.clone();
249
250        self.bus.borrow().queue_retain(async move {
251            let mut render = Render::new(renderer);
252            render.rerender(&instance);
253            render.finish();
254        });
255    }
256
257    pub fn render(
258        self: &Rc<Self>,
259        element: Element<P>,
260        container: P::ContainerID,
261    ) -> Rc<Instance<P>> {
262        let mut render = Render::new(self.clone());
263        let instance = render.render(None, element, container);
264        render.finish();
265
266        instance
267    }
268}
269
270/// This is the entry point of Polyhorn. This function renders an element into
271/// the given container. The returned instance must be retained. Once the
272/// returned is dropped, all UI will be unmounted.
273pub fn render<F, P>(element: F, container: P::Container) -> Disposable
274where
275    F: FnOnce() -> Element<P> + Send + 'static,
276    P: Platform + ?Sized,
277{
278    P::with_compositor(container, move |container_id, compositor, bus| {
279        // We've now switched to the render thread.
280        let renderer = Renderer::new(compositor, bus);
281        Disposable::new(renderer.render(element(), container_id))
282    })
283}