1#![warn(missing_docs)]
5use super::items::*;
8use crate::graphics::{Color, FontRequest, Image, IntRect};
9use crate::item_tree::ItemTreeRc;
10use crate::item_tree::{ItemVisitor, ItemVisitorVTable, VisitChildrenResult};
11use crate::lengths::{
12 LogicalBorderRadius, LogicalLength, LogicalPoint, LogicalRect, LogicalSize, LogicalVector,
13};
14pub use crate::partial_renderer::CachedRenderingData;
15use crate::window::WindowAdapterRc;
16use crate::{Brush, SharedString};
17#[cfg(feature = "std")]
18use alloc::boxed::Box;
19#[cfg(feature = "std")]
20use core::cell::RefCell;
21use core::pin::Pin;
22#[cfg(feature = "std")]
23use std::collections::HashMap;
24use vtable::VRc;
25
26#[cfg(feature = "std")]
35pub struct ItemCache<T> {
36 map: RefCell<HashMap<*const vtable::Dyn, HashMap<u32, crate::graphics::CachedGraphicsData<T>>>>,
38 window_scale_factor_tracker: Pin<Box<crate::properties::PropertyTracker>>,
40}
41
42#[cfg(feature = "std")]
43impl<T> Default for ItemCache<T> {
44 fn default() -> Self {
45 Self { map: Default::default(), window_scale_factor_tracker: Box::pin(Default::default()) }
46 }
47}
48
49#[cfg(feature = "std")]
50impl<T: Clone> ItemCache<T> {
51 pub fn get_or_update_cache_entry(&self, item_rc: &ItemRc, update_fn: impl FnOnce() -> T) -> T {
55 let component = &(**item_rc.item_tree()) as *const _;
56 let mut borrowed = self.map.borrow_mut();
57 match borrowed.entry(component).or_default().entry(item_rc.index()) {
58 std::collections::hash_map::Entry::Occupied(mut entry) => {
59 let mut tracker = entry.get_mut().dependency_tracker.take();
60 drop(borrowed);
61 let maybe_new_data = tracker
62 .get_or_insert_with(|| Box::pin(Default::default()))
63 .as_ref()
64 .evaluate_if_dirty(update_fn);
65 let mut borrowed = self.map.borrow_mut();
66 let e = borrowed.get_mut(&component).unwrap().get_mut(&item_rc.index()).unwrap();
67 e.dependency_tracker = tracker;
68 if let Some(new_data) = maybe_new_data {
69 e.data = new_data.clone();
70 new_data
71 } else {
72 e.data.clone()
73 }
74 }
75 std::collections::hash_map::Entry::Vacant(_) => {
76 drop(borrowed);
77 let new_entry = crate::graphics::CachedGraphicsData::new(update_fn);
78 let data = new_entry.data.clone();
79 self.map
80 .borrow_mut()
81 .get_mut(&component)
82 .unwrap()
83 .insert(item_rc.index(), new_entry);
84 data
85 }
86 }
87 }
88
89 pub fn with_entry<U>(
92 &self,
93 item_rc: &ItemRc,
94 callback: impl FnOnce(&T) -> Option<U>,
95 ) -> Option<U> {
96 let component = &(**item_rc.item_tree()) as *const _;
97 self.map
98 .borrow()
99 .get(&component)
100 .and_then(|per_component_entries| per_component_entries.get(&item_rc.index()))
101 .and_then(|entry| callback(&entry.data))
102 }
103
104 pub fn clear_cache_if_scale_factor_changed(&self, window: &crate::api::Window) {
106 if self.window_scale_factor_tracker.is_dirty() {
107 self.window_scale_factor_tracker
108 .as_ref()
109 .evaluate_as_dependency_root(|| window.scale_factor());
110 self.clear_all();
111 }
112 }
113
114 pub fn clear_all(&self) {
116 self.map.borrow_mut().clear();
117 }
118
119 pub fn component_destroyed(&self, component: crate::item_tree::ItemTreeRef) {
123 let component_ptr: *const _ =
124 crate::item_tree::ItemTreeRef::as_ptr(component).cast().as_ptr();
125 self.map.borrow_mut().remove(&component_ptr);
126 }
127
128 pub fn release(&self, item_rc: &ItemRc) {
130 let component = &(**item_rc.item_tree()) as *const _;
131 if let Some(sub) = self.map.borrow_mut().get_mut(&component) {
132 sub.remove(&item_rc.index());
133 }
134 }
135
136 pub fn is_empty(&self) -> bool {
138 self.map.borrow().is_empty()
139 }
140}
141
142pub fn render_item_children(
144 renderer: &mut dyn ItemRenderer,
145 component: &ItemTreeRc,
146 index: isize,
147 window_adapter: &WindowAdapterRc,
148) {
149 let mut actual_visitor =
150 |component: &ItemTreeRc, index: u32, item: Pin<ItemRef>| -> VisitChildrenResult {
151 renderer.save_state();
152 let item_rc = ItemRc::new(component.clone(), index);
153
154 let (do_draw, item_geometry) = renderer.filter_item(&item_rc, window_adapter);
155
156 let item_origin = item_geometry.origin;
157 renderer.translate(item_origin.to_vector());
158
159 let render_result = if do_draw
162 || item.as_ref().clips_children()
163 || ItemRef::downcast_pin::<BoxShadow>(item).is_some()
165 || ItemRef::downcast_pin::<Transform>(item).is_some()
167 || ItemRef::downcast_pin::<Opacity>(item).is_some()
168 || ItemRef::downcast_pin::<Layer>(item).is_some()
169 {
170 item.as_ref().render(
171 &mut (renderer as &mut dyn ItemRenderer),
172 &item_rc,
173 item_geometry.size,
174 )
175 } else {
176 RenderingResult::ContinueRenderingChildren
177 };
178
179 if matches!(render_result, RenderingResult::ContinueRenderingChildren) {
180 render_item_children(renderer, component, index as isize, window_adapter);
181 }
182 renderer.restore_state();
183 VisitChildrenResult::CONTINUE
184 };
185 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
186 VRc::borrow_pin(component).as_ref().visit_children_item(
187 index,
188 crate::item_tree::TraversalOrder::BackToFront,
189 actual_visitor,
190 );
191}
192
193pub fn render_component_items(
196 component: &ItemTreeRc,
197 renderer: &mut dyn ItemRenderer,
198 origin: LogicalPoint,
199 window_adapter: &WindowAdapterRc,
200) {
201 renderer.save_state();
202 renderer.translate(origin.to_vector());
203
204 render_item_children(renderer, component, -1, window_adapter);
205
206 renderer.restore_state();
207}
208
209pub fn item_children_bounding_rect(
212 item_rc: &ItemRc,
213 window_adapter: &WindowAdapterRc,
214) -> LogicalRect {
215 item_children_bounding_rect_inner(item_rc, window_adapter, Default::default())
216}
217
218fn item_children_bounding_rect_inner(
219 item_rc: &ItemRc,
220 window_adapter: &WindowAdapterRc,
221 transform: crate::lengths::ItemTransform,
222) -> LogicalRect {
223 let mut bounding_rect = LogicalRect::zero();
224
225 let mut actual_visitor =
226 |component: &ItemTreeRc, index: u32, item: Pin<ItemRef>| -> VisitChildrenResult {
227 let item_rc = ItemRc::new(component.clone(), index);
228 let geom = ItemTreeRc::borrow_pin(component).as_ref().item_geometry(index);
229 let bounding = item_rc.bounding_rect(&geom, window_adapter);
230 let bounding = transform.outer_transformed_rect(&bounding.cast());
231 let children_transform = item_rc
232 .children_transform()
233 .unwrap_or_default()
234 .then_translate(bounding.origin.to_vector());
235
236 bounding_rect = bounding_rect.union(&bounding.cast());
237
238 if item.as_ref().clips_children() {
239 let clip = transform.outer_transformed_rect(&geom.cast()).cast();
240 if !bounding_rect.contains_rect(&clip) {
241 bounding_rect = bounding_rect.union(
242 &item_children_bounding_rect_inner(
243 &item_rc,
244 window_adapter,
245 transform.then(&children_transform),
246 )
247 .intersection(&clip)
248 .unwrap_or_default(),
249 );
250 }
251 } else {
252 bounding_rect = bounding_rect.union(&item_children_bounding_rect_inner(
253 &item_rc,
254 window_adapter,
255 transform.then(&children_transform),
256 ));
257 }
258 VisitChildrenResult::CONTINUE
259 };
260 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
261 VRc::borrow_pin(item_rc.item_tree()).as_ref().visit_children_item(
262 item_rc.index() as isize,
263 crate::item_tree::TraversalOrder::BackToFront,
264 actual_visitor,
265 );
266
267 bounding_rect
268}
269
270#[allow(missing_docs)]
272pub trait RenderRectangle {
273 fn background(self: Pin<&Self>) -> Brush;
274}
275
276#[allow(missing_docs)]
278pub trait RenderBorderRectangle {
279 fn background(self: Pin<&Self>) -> Brush;
280 fn border_width(self: Pin<&Self>) -> LogicalLength;
281 fn border_radius(self: Pin<&Self>) -> LogicalBorderRadius;
282 fn border_color(self: Pin<&Self>) -> Brush;
283}
284
285#[allow(missing_docs)]
287pub trait RenderImage {
288 fn target_size(self: Pin<&Self>) -> LogicalSize;
289 fn source(self: Pin<&Self>) -> Image;
290 fn source_clip(self: Pin<&Self>) -> Option<IntRect>;
291 fn image_fit(self: Pin<&Self>) -> ImageFit;
292 fn rendering(self: Pin<&Self>) -> ImageRendering;
293 fn colorize(self: Pin<&Self>) -> Brush;
294 fn alignment(self: Pin<&Self>) -> (ImageHorizontalAlignment, ImageVerticalAlignment);
295 fn tiling(self: Pin<&Self>) -> (ImageTiling, ImageTiling);
296}
297
298#[allow(missing_docs)]
300pub trait HasFont {
301 fn font_request(self: Pin<&Self>, self_rc: &crate::items::ItemRc) -> FontRequest;
302}
303
304#[allow(missing_docs)]
305pub enum PlainOrStyledText {
306 Plain(SharedString),
307 Styled(crate::styled_text::StyledText),
308}
309
310#[allow(missing_docs)]
312pub trait RenderString: HasFont {
313 fn text(self: Pin<&Self>) -> PlainOrStyledText;
314}
315
316#[allow(missing_docs)]
318pub trait RenderText: RenderString {
319 fn target_size(self: Pin<&Self>) -> LogicalSize;
320 fn color(self: Pin<&Self>) -> Brush;
321 fn alignment(self: Pin<&Self>) -> (TextHorizontalAlignment, TextVerticalAlignment);
322 fn wrap(self: Pin<&Self>) -> TextWrap;
323 fn overflow(self: Pin<&Self>) -> TextOverflow;
324 fn stroke(self: Pin<&Self>) -> (Brush, LogicalLength, TextStrokeStyle);
325 fn is_markdown(self: Pin<&Self>) -> bool;
326 fn link_color(self: Pin<&Self>) -> Color;
327}
328
329impl HasFont for (SharedString, Brush) {
330 fn font_request(self: Pin<&Self>, self_rc: &crate::items::ItemRc) -> FontRequest {
331 crate::items::WindowItem::resolved_font_request(
332 self_rc,
333 SharedString::default(),
334 0,
335 LogicalLength::default(),
336 LogicalLength::default(),
337 false,
338 )
339 }
340}
341
342impl RenderString for (SharedString, Brush) {
343 fn text(self: Pin<&Self>) -> PlainOrStyledText {
344 PlainOrStyledText::Plain(self.0.clone())
345 }
346}
347
348impl RenderText for (SharedString, Brush) {
349 fn target_size(self: Pin<&Self>) -> LogicalSize {
350 LogicalSize::default()
351 }
352
353 fn color(self: Pin<&Self>) -> Brush {
354 self.1.clone()
355 }
356
357 fn link_color(self: Pin<&Self>) -> Color {
358 Default::default()
359 }
360
361 fn alignment(
362 self: Pin<&Self>,
363 ) -> (crate::items::TextHorizontalAlignment, crate::items::TextVerticalAlignment) {
364 Default::default()
365 }
366
367 fn wrap(self: Pin<&Self>) -> crate::items::TextWrap {
368 Default::default()
369 }
370
371 fn overflow(self: Pin<&Self>) -> crate::items::TextOverflow {
372 Default::default()
373 }
374
375 fn stroke(self: Pin<&Self>) -> (Brush, LogicalLength, TextStrokeStyle) {
376 Default::default()
377 }
378
379 fn is_markdown(self: Pin<&Self>) -> bool {
380 false
381 }
382}
383
384#[allow(missing_docs)]
389pub trait ItemRenderer {
390 fn draw_rectangle(
391 &mut self,
392 rect: Pin<&dyn RenderRectangle>,
393 _self_rc: &ItemRc,
394 _size: LogicalSize,
395 _cache: &CachedRenderingData,
396 );
397 fn draw_border_rectangle(
398 &mut self,
399 rect: Pin<&dyn RenderBorderRectangle>,
400 _self_rc: &ItemRc,
401 _size: LogicalSize,
402 _cache: &CachedRenderingData,
403 );
404 fn draw_window_background(
405 &mut self,
406 rect: Pin<&dyn RenderRectangle>,
407 self_rc: &ItemRc,
408 size: LogicalSize,
409 cache: &CachedRenderingData,
410 );
411 fn draw_image(
412 &mut self,
413 image: Pin<&dyn RenderImage>,
414 _self_rc: &ItemRc,
415 _size: LogicalSize,
416 _cache: &CachedRenderingData,
417 );
418 fn draw_text(
419 &mut self,
420 text: Pin<&dyn RenderText>,
421 _self_rc: &ItemRc,
422 _size: LogicalSize,
423 _cache: &CachedRenderingData,
424 );
425 fn draw_text_input(
426 &mut self,
427 text_input: Pin<&TextInput>,
428 _self_rc: &ItemRc,
429 _size: LogicalSize,
430 );
431 #[cfg(feature = "std")]
432 fn draw_path(&mut self, path: Pin<&Path>, _self_rc: &ItemRc, _size: LogicalSize);
433 fn draw_box_shadow(
434 &mut self,
435 box_shadow: Pin<&BoxShadow>,
436 _self_rc: &ItemRc,
437 _size: LogicalSize,
438 );
439 fn visit_opacity(
440 &mut self,
441 opacity_item: Pin<&Opacity>,
442 _self_rc: &ItemRc,
443 _size: LogicalSize,
444 ) -> RenderingResult {
445 self.apply_opacity(opacity_item.opacity());
446 RenderingResult::ContinueRenderingChildren
447 }
448 fn visit_layer(
449 &mut self,
450 _layer_item: Pin<&Layer>,
451 _self_rc: &ItemRc,
452 _size: LogicalSize,
453 ) -> RenderingResult {
454 RenderingResult::ContinueRenderingChildren
456 }
457
458 fn visit_clip(
462 &mut self,
463 clip_item: Pin<&Clip>,
464 _item_rc: &ItemRc,
465 size: LogicalSize,
466 ) -> RenderingResult {
467 if clip_item.clip() {
468 let clip_region_valid = self.combine_clip(
469 LogicalRect::new(LogicalPoint::default(), size),
470 clip_item.logical_border_radius(),
471 clip_item.border_width(),
472 );
473
474 if !clip_region_valid {
477 return RenderingResult::ContinueRenderingWithoutChildren;
478 }
479 }
480 RenderingResult::ContinueRenderingChildren
481 }
482
483 fn combine_clip(
489 &mut self,
490 rect: LogicalRect,
491 radius: LogicalBorderRadius,
492 border_width: LogicalLength,
493 ) -> bool;
494 fn get_current_clip(&self) -> LogicalRect;
496
497 fn translate(&mut self, distance: LogicalVector);
498 fn translation(&self) -> LogicalVector {
499 unimplemented!()
500 }
501 fn rotate(&mut self, angle_in_degrees: f32);
502 fn scale(&mut self, scale_x_factor: f32, scale_y_factor: f32);
503 fn apply_opacity(&mut self, opacity: f32);
505
506 fn save_state(&mut self);
507 fn restore_state(&mut self);
508
509 fn scale_factor(&self) -> f32;
511
512 fn draw_cached_pixmap(
517 &mut self,
518 item_cache: &ItemRc,
519 update_fn: &dyn Fn(&mut dyn FnMut(u32, u32, &[u8])),
520 );
521
522 fn draw_string(&mut self, string: &str, color: crate::Color);
525
526 fn draw_image_direct(&mut self, image: crate::graphics::Image);
527
528 fn filter_item(
533 &mut self,
534 item: &ItemRc,
535 window_adapter: &WindowAdapterRc,
536 ) -> (bool, LogicalRect) {
537 let item_geometry = item.geometry();
538 let bounding_rect = crate::properties::evaluate_no_tracking(|| {
541 item.bounding_rect(&item_geometry, window_adapter)
542 });
543 (self.get_current_clip().intersects(&bounding_rect), item_geometry)
544 }
545
546 fn window(&self) -> &crate::window::WindowInner;
547
548 fn as_any(&mut self) -> Option<&mut dyn core::any::Any>;
550}
551
552pub trait ItemRendererFeatures {
554 const SUPPORTS_TRANSFORMATIONS: bool;
556}