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
33pub(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}