Skip to main content

freya_html/
element.rs

1use std::{
2    any::Any,
3    borrow::Cow,
4    cell::RefCell,
5    rc::Rc,
6};
7
8use freya_core::{
9    data::{
10        AccessibilityData,
11        LayoutData,
12    },
13    diff_key::DiffKey,
14    element::{
15        Element,
16        ElementExt,
17        EventHandlerType,
18        RenderContext,
19    },
20    events::name::EventName,
21    prelude::{
22        AccessibilityExt,
23        EventHandlersExt,
24        LayoutExt,
25    },
26    tree::DiffModifies,
27};
28use freya_engine::prelude::ClipOp;
29use rustc_hash::FxHashMap;
30
31use crate::state::BlitzState;
32
33/// Paints a Blitz document into the scene and forwards input events into it.
34pub(crate) struct HtmlElement {
35    pub layout: LayoutData,
36    pub accessibility: AccessibilityData,
37    pub event_handlers: FxHashMap<EventName, EventHandlerType>,
38    pub state: Rc<RefCell<BlitzState>>,
39}
40
41impl PartialEq for HtmlElement {
42    fn eq(&self, other: &Self) -> bool {
43        self.layout == other.layout
44            && self.accessibility == other.accessibility
45            && Rc::ptr_eq(&self.state, &other.state)
46    }
47}
48
49impl ElementExt for HtmlElement {
50    fn changed(&self, other: &Rc<dyn ElementExt>) -> bool {
51        let Some(other) = (other.as_ref() as &dyn Any).downcast_ref::<HtmlElement>() else {
52            return true;
53        };
54        self != other
55    }
56
57    fn diff(&self, other: &Rc<dyn ElementExt>) -> DiffModifies {
58        let Some(other) = (other.as_ref() as &dyn Any).downcast_ref::<HtmlElement>() else {
59            return DiffModifies::all();
60        };
61
62        let mut diff = DiffModifies::empty();
63        if self.layout != other.layout {
64            diff.insert(DiffModifies::LAYOUT);
65        }
66        if self.accessibility != other.accessibility {
67            diff.insert(DiffModifies::ACCESSIBILITY);
68        }
69        diff
70    }
71
72    fn layout(&'_ self) -> Cow<'_, LayoutData> {
73        Cow::Borrowed(&self.layout)
74    }
75
76    fn accessibility(&'_ self) -> Cow<'_, AccessibilityData> {
77        Cow::Borrowed(&self.accessibility)
78    }
79
80    fn events_handlers(&'_ self) -> Option<Cow<'_, FxHashMap<EventName, EventHandlerType>>> {
81        Some(Cow::Borrowed(&self.event_handlers))
82    }
83
84    fn should_measure_inner_children(&self) -> bool {
85        false
86    }
87
88    fn render(&self, context: RenderContext) {
89        let area = context.layout_node.visible_area();
90        let scale = context.scale_factor as f32;
91
92        context.canvas.save();
93        context
94            .canvas
95            .clip_rrect(self.render_rect(&area, scale), ClipOp::Intersect, true);
96
97        self.state.borrow_mut().paint(
98            context.canvas,
99            area.min_x(),
100            area.min_y(),
101            area.width().round() as u32,
102            area.height().round() as u32,
103            scale,
104        );
105
106        context.canvas.restore();
107    }
108}
109
110pub(crate) struct Html {
111    pub(crate) element: HtmlElement,
112}
113
114impl Html {
115    pub fn new(state: Rc<RefCell<BlitzState>>) -> Self {
116        Self {
117            element: HtmlElement {
118                layout: LayoutData::default(),
119                accessibility: AccessibilityData::default(),
120                event_handlers: FxHashMap::default(),
121                state,
122            },
123        }
124    }
125}
126
127impl From<Html> for Element {
128    fn from(value: Html) -> Self {
129        Element::Element {
130            key: DiffKey::None,
131            element: Rc::new(value.element),
132            elements: vec![],
133        }
134    }
135}
136
137impl LayoutExt for Html {
138    fn layout_mut(&mut self) -> &mut LayoutData {
139        &mut self.element.layout
140    }
141}
142
143impl AccessibilityExt for Html {
144    fn accessibility_data_mut(&mut self) -> &mut AccessibilityData {
145        &mut self.element.accessibility
146    }
147}
148
149impl EventHandlersExt for Html {
150    fn event_handlers_mut(&mut self) -> &mut FxHashMap<EventName, EventHandlerType> {
151        &mut self.element.event_handlers
152    }
153}