1use std::{
4 any::Any,
5 borrow::Cow,
6 collections::HashMap,
7 rc::Rc,
8};
9
10use freya_core::{
11 data::{
12 AccessibilityData,
13 EffectData,
14 LayoutData,
15 StyleState,
16 TextStyleData,
17 },
18 diff_key::DiffKey,
19 element::{
20 Element,
21 ElementExt,
22 EventHandlerType,
23 },
24 events::name::EventName,
25 layers::Layer,
26 prelude::{
27 AccessibilityExt,
28 ContainerExt,
29 EventHandlersExt,
30 KeyExt,
31 LayerExt,
32 LayoutExt,
33 MaybeExt,
34 },
35 tree::DiffModifies,
36};
37use rustc_hash::FxHashMap;
38
39use crate::registry::{
40 WebViewConfig,
41 WebViewId,
42};
43
44#[derive(Clone)]
46pub struct WebViewElement {
47 pub accessibility: AccessibilityData,
48 pub layout: LayoutData,
49 pub event_handlers: FxHashMap<EventName, EventHandlerType>,
50 pub webview_id: WebViewId,
51 pub config: WebViewConfig,
52 pub relative_layer: Layer,
53 pub effect: Option<EffectData>,
54}
55
56impl PartialEq for WebViewElement {
57 fn eq(&self, other: &Self) -> bool {
58 self.accessibility == other.accessibility
59 && self.layout == other.layout
60 && self.webview_id == other.webview_id
61 && self.config == other.config
62 && self.relative_layer == other.relative_layer
63 && self.effect == other.effect
64 }
65}
66
67impl ElementExt for WebViewElement {
68 fn changed(&self, other: &Rc<dyn ElementExt>) -> bool {
69 let Some(webview) = (other.as_ref() as &dyn Any).downcast_ref::<WebViewElement>() else {
70 return false;
71 };
72 self != webview
73 }
74
75 fn diff(&self, other: &Rc<dyn ElementExt>) -> DiffModifies {
76 let Some(webview) = (other.as_ref() as &dyn Any).downcast_ref::<WebViewElement>() else {
77 return DiffModifies::all();
78 };
79
80 let mut diff = DiffModifies::empty();
81
82 if self.accessibility != webview.accessibility {
83 diff.insert(DiffModifies::ACCESSIBILITY);
84 }
85
86 if self.relative_layer != webview.relative_layer {
87 diff.insert(DiffModifies::LAYER);
88 }
89
90 if self.layout != webview.layout || self.config != webview.config {
91 diff.insert(DiffModifies::LAYOUT);
92 }
93
94 if self.effect != webview.effect {
95 diff.insert(DiffModifies::EFFECT);
96 }
97
98 diff
99 }
100
101 fn layout(&'_ self) -> Cow<'_, LayoutData> {
102 Cow::Borrowed(&self.layout)
103 }
104
105 fn effect(&'_ self) -> Option<Cow<'_, EffectData>> {
106 self.effect.as_ref().map(Cow::Borrowed)
107 }
108
109 fn style(&'_ self) -> Cow<'_, StyleState> {
110 Cow::Owned(StyleState::default())
111 }
112
113 fn text_style(&'_ self) -> Cow<'_, TextStyleData> {
114 Cow::Owned(TextStyleData::default())
115 }
116
117 fn accessibility(&'_ self) -> Cow<'_, AccessibilityData> {
118 Cow::Borrowed(&self.accessibility)
119 }
120
121 fn layer(&self) -> Layer {
122 self.relative_layer
123 }
124
125 fn should_measure_inner_children(&self) -> bool {
126 false
127 }
128
129 fn events_handlers(&'_ self) -> Option<Cow<'_, FxHashMap<EventName, EventHandlerType>>> {
130 Some(Cow::Borrowed(&self.event_handlers))
131 }
132}
133
134impl From<WebView> for Element {
135 fn from(value: WebView) -> Self {
136 Element::Element {
137 key: value.key,
138 element: Rc::new(value.element),
139 elements: vec![],
140 }
141 }
142}
143
144pub struct WebView {
148 pub(crate) key: DiffKey,
149 pub(crate) element: WebViewElement,
150}
151
152impl WebView {
153 pub fn try_downcast(element: &dyn ElementExt) -> Option<WebViewElement> {
155 (element as &dyn Any)
156 .downcast_ref::<WebViewElement>()
157 .cloned()
158 }
159
160 pub fn url(mut self, url: impl Into<String>) -> Self {
162 self.element.config.url = url.into();
163 self
164 }
165
166 pub fn transparent(mut self, transparent: bool) -> Self {
168 self.element.config.transparent = transparent;
169 self
170 }
171
172 pub fn user_agent(mut self, user_agent: impl Into<String>) -> Self {
174 self.element.config.user_agent = Some(user_agent.into());
175 self
176 }
177}
178
179impl KeyExt for WebView {
180 fn write_key(&mut self) -> &mut DiffKey {
181 &mut self.key
182 }
183}
184
185impl EventHandlersExt for WebView {
186 fn get_event_handlers(&mut self) -> &mut FxHashMap<EventName, EventHandlerType> {
187 &mut self.element.event_handlers
188 }
189}
190
191impl LayoutExt for WebView {
192 fn get_layout(&mut self) -> &mut LayoutData {
193 &mut self.element.layout
194 }
195}
196
197impl ContainerExt for WebView {}
198
199impl AccessibilityExt for WebView {
200 fn get_accessibility_data(&mut self) -> &mut AccessibilityData {
201 &mut self.element.accessibility
202 }
203}
204
205impl MaybeExt for WebView {}
206
207impl LayerExt for WebView {
208 fn get_layer(&mut self) -> &mut Layer {
209 &mut self.element.relative_layer
210 }
211}
212
213pub fn webview(url: impl Into<String>) -> WebView {
214 let mut accessibility = AccessibilityData::default();
215 accessibility.builder.set_role(accesskit::Role::WebView);
216
217 let webview_id = WebViewId::new();
218 let config = WebViewConfig {
219 url: url.into(),
220 transparent: false,
221 user_agent: None,
222 on_created: None,
223 };
224
225 WebView {
226 key: DiffKey::None,
227 element: WebViewElement {
228 accessibility,
229 layout: LayoutData::default(),
230 event_handlers: HashMap::default(),
231 webview_id,
232 config,
233 relative_layer: Layer::default(),
234 effect: None,
235 },
236 }
237}