1pub mod border_path_iter;
9pub mod renderer;
10
11pub use border_path_iter::{BorderPath, BorderPathEvent};
12pub use renderer::Renderer;
13
14use floem_renderer::Renderer as FloemRenderer;
15use floem_renderer::gpu_resources::{GpuResourceError, GpuResources};
16use peniko::kurbo::{Affine, RoundedRect, Shape, Size};
17use std::ops::{Deref, DerefMut};
18use std::sync::Arc;
19use understory_box_tree::NodeFlags;
20use winit::window::Window;
21
22#[cfg(feature = "crossbeam")]
23use crossbeam::channel::Receiver;
24#[cfg(not(feature = "crossbeam"))]
25use std::sync::mpsc::Receiver;
26
27use crate::ElementId;
28use crate::style::FontSizeCx;
29use crate::view::ViewId;
30use crate::view::stacking::{StackingContextItem, collect_stacking_context_items_into};
31use crate::view::{paint_bg, paint_border, paint_outline};
32use crate::window::state::WindowState;
33
34std::thread_local! {
35 pub(crate) static CURRENT_DRAG_PAINTING_ID : std::cell::Cell<Option<ElementId>> = const { std::cell::Cell::new(None) };
42
43 static PAINT_ORDER_TRACKER: std::cell::RefCell<PaintOrderTracker> = const { std::cell::RefCell::new(PaintOrderTracker::new()) };
47}
48
49#[derive(Default)]
51pub struct PaintOrderTracker {
52 enabled: bool,
53 order: Vec<ViewId>,
54}
55
56impl PaintOrderTracker {
57 const fn new() -> Self {
58 Self {
59 enabled: false,
60 order: Vec::new(),
61 }
62 }
63
64 fn record(&mut self, id: ViewId) {
65 if self.enabled {
66 self.order.push(id);
67 }
68 }
69}
70
71pub fn enable_paint_order_tracking() {
73 PAINT_ORDER_TRACKER.with(|tracker| {
74 let mut t = tracker.borrow_mut();
75 t.enabled = true;
76 t.order.clear();
77 });
78}
79
80pub fn disable_paint_order_tracking() {
82 PAINT_ORDER_TRACKER.with(|tracker| {
83 tracker.borrow_mut().enabled = false;
84 });
85}
86
87pub fn clear_paint_order() {
89 PAINT_ORDER_TRACKER.with(|tracker| {
90 tracker.borrow_mut().order.clear();
91 });
92}
93
94pub fn get_paint_order() -> Vec<ViewId> {
96 PAINT_ORDER_TRACKER.with(|tracker| tracker.borrow().order.clone())
97}
98
99pub fn is_paint_order_tracking_enabled() -> bool {
101 PAINT_ORDER_TRACKER.with(|tracker| tracker.borrow().enabled)
102}
103
104#[inline]
106fn record_paint(id: ViewId) {
107 PAINT_ORDER_TRACKER.with(|tracker| {
108 tracker.borrow_mut().record(id);
109 });
110}
111
112pub struct GlobalPaintCx<'a> {
115 pub window_state: &'a mut WindowState,
116 pub(crate) paint_state: &'a mut PaintState,
117 pub gpu_resources: Option<GpuResources>,
118 pub window: Arc<dyn Window>,
119 pub(crate) record_paint_order: bool,
121}
122
123pub struct PaintCx<'a> {
126 pub window_state: &'a mut WindowState,
128 paint_state: &'a mut PaintState,
129 pub target_id: ElementId,
131 pub world_transform: Affine,
133 pub layout_rect_local: peniko::kurbo::Rect,
135 pub clip: Option<RoundedRect>,
137 pub font_size_cx: FontSizeCx,
138}
139
140pub(crate) enum PaintOrPost {
141 Paint(ElementId),
142 Post(ElementId),
143}
144
145pub(crate) fn collect_visual_order(
147 root_element_id: ElementId,
148 box_tree: &mut crate::BoxTree,
149 paint_order: &mut Vec<PaintOrPost>,
150 is_drag_preview: bool,
151 skip_element_id: Option<ElementId>,
152) {
153 enum TraversalStep {
154 Visit(ElementId),
155 Post(ElementId),
156 }
157
158 let should_paint = |element_id: ElementId, box_tree: &mut crate::BoxTree| {
160 if is_drag_preview {
161 return true;
162 }
163
164 box_tree
165 .world_bounds(element_id.0)
166 .is_none_or(|bounds| bounds.area() != 0.0)
167 };
168
169 let mut stack = Vec::new();
170 let mut stacking_scratch: Vec<StackingContextItem> = Vec::new();
171 stack.push(TraversalStep::Visit(root_element_id));
172
173 while let Some(step) = stack.pop() {
174 match step {
175 TraversalStep::Visit(element_id) => {
176 if !is_drag_preview && Some(element_id) == skip_element_id {
178 continue;
179 }
180
181 if box_tree
183 .flags(element_id.0)
184 .is_none_or(|f| !f.contains(NodeFlags::VISIBLE))
185 {
186 continue;
187 }
188
189 let paints_this_node = should_paint(element_id, box_tree);
190 if paints_this_node {
191 paint_order.push(PaintOrPost::Paint(element_id));
192 stack.push(TraversalStep::Post(element_id));
196 }
197
198 collect_stacking_context_items_into(element_id, box_tree, &mut stacking_scratch);
200 for item in stacking_scratch.iter().rev() {
201 stack.push(TraversalStep::Visit(item.element_id));
202 }
203 }
204 TraversalStep::Post(element_id) => paint_order.push(PaintOrPost::Post(element_id)),
205 }
206 }
207}
208
209impl GlobalPaintCx<'_> {
210 fn build_paint_order(
222 &self,
223 root: ElementId,
224 box_tree: &mut crate::BoxTree,
225 ) -> Vec<PaintOrPost> {
226 let mut paint_order = Vec::new();
227
228 let dragging_element_id = self
229 .window_state
230 .drag_tracker
231 .active_drag
232 .as_ref()
233 .and_then(|ad| ad.dragging_preview.as_ref().map(|p| p.element_id));
234 collect_visual_order(root, box_tree, &mut paint_order, false, dragging_element_id);
236
237 if let Some(preview) = self
239 .window_state
240 .drag_tracker
241 .active_drag
242 .as_ref()
243 .and_then(|ad| ad.dragging_preview.as_ref().map(|p| p.element_id))
244 {
245 crate::paint::collect_visual_order(preview, box_tree, &mut paint_order, true, None);
246 }
247
248 paint_order
249 }
250 pub(crate) fn paint_with_traversal(&mut self, root_id: ViewId) {
252 let root_element_id = root_id.get_element_id();
253 let mut box_tree = self.window_state.box_tree.borrow_mut();
254 let paint_order = self.build_paint_order(root_element_id, &mut box_tree);
255 drop(box_tree);
256
257 for id_or_pop in paint_order {
258 match id_or_pop {
259 PaintOrPost::Paint(element_id) => {
260 if self.record_paint_order {
262 record_paint(element_id.owning_id());
263 }
264
265 self.paint_visual_node(element_id, false);
267 }
268 PaintOrPost::Post(element_id) => {
269 self.paint_visual_node(element_id, true);
270 }
271 }
272 }
273 }
274
275 pub(crate) fn paint_visual_node(&mut self, element_id: ElementId, is_post: bool) {
277 let box_tree = self.window_state.box_tree.borrow_mut();
279 let world_transform = box_tree.world_transform(element_id.0).unwrap_or_default();
280 let layout_rect_local = box_tree.local_bounds(element_id.0).unwrap_or_default();
281 let clip = box_tree.clipped_local_clip(element_id.0);
282 drop(box_tree);
283
284 let device_transform = world_transform.then_scale(self.window_state.effective_scale());
286 self.paint_state
287 .renderer_mut()
288 .set_transform(device_transform);
289
290 let layout_rect = layout_rect_local;
291 let view_id = element_id.owning_id();
292 let view = view_id.view();
293 let view_state = view_id.state();
294
295 let mut cx = PaintCx {
297 window_state: self.window_state,
298 paint_state: self.paint_state,
299 target_id: element_id,
300 world_transform,
301 layout_rect_local,
302 clip,
303 font_size_cx: view_state.borrow().layout_props.font_size_cx(),
304 };
305
306 if !is_post {
307 if element_id.is_view() {
308 let state = view_state.borrow();
309 paint_bg(&mut cx, &state.view_style_props, layout_rect);
310 paint_border(
311 &mut cx,
312 &state.layout_props,
313 &state.view_style_props,
314 layout_rect,
315 );
316 drop(state);
317 if let Some(clip_shape) = clip {
319 cx.clip(&clip_shape);
320 }
321 }
322 view.borrow_mut().paint(&mut cx);
323 } else {
324 if element_id.is_view() && clip.is_some() {
325 cx.clear_clip();
326 }
327 view.borrow_mut().post_paint(&mut cx);
328 if element_id.is_view() {
329 let state = view_state.borrow();
330 paint_outline(&mut cx, &state.view_style_props, layout_rect);
331 }
332 }
333 }
334}
335
336impl PaintCx<'_> {
337 pub fn is_drag_paint(&self, id: impl Into<ElementId>) -> bool {
342 let id = id.into();
343 if let Some(dragging) = CURRENT_DRAG_PAINTING_ID.get() {
348 return dragging == id;
349 }
350 false
351 }
352
353 pub fn clip(&mut self, shape: &impl Shape) {
355 if self.paint_state.renderer().uses_layer_clip() {
356 use peniko::Mix;
357 self.push_layer(Mix::Normal, 1.0, Affine::IDENTITY, shape);
358 } else {
359 self.paint_state.renderer_mut().clip(shape);
360 }
361 }
362
363 pub fn clear_clip(&mut self) {
365 if self.paint_state.renderer().uses_layer_clip() {
366 self.pop_layer();
367 } else {
368 self.paint_state.renderer_mut().clear_clip();
369 }
370 }
371
372 }
375
376pub enum PaintState {
378 PendingGpuResources {
380 window: Arc<dyn Window>,
381 rx: Receiver<Result<(GpuResources, wgpu::Surface<'static>), GpuResourceError>>,
382 font_embolden: f32,
383 renderer: Renderer,
390 },
391 Initialized { renderer: Renderer },
393}
394
395impl PaintState {
396 pub fn new_pending(
397 window: Arc<dyn Window>,
398 rx: Receiver<Result<(GpuResources, wgpu::Surface<'static>), GpuResourceError>>,
399 size: Size,
400 font_embolden: f32,
401 ) -> Self {
402 Self::PendingGpuResources {
403 window,
404 rx,
405 font_embolden,
406 renderer: Renderer::Uninitialized { size },
407 }
408 }
409
410 pub fn new(
411 window: Arc<dyn Window>,
412 surface: wgpu::Surface<'static>,
413 gpu_resources: GpuResources,
414 scale: f64,
415 size: Size,
416 font_embolden: f32,
417 ) -> Self {
418 let renderer = Renderer::new(
419 window.clone(),
420 gpu_resources,
421 surface,
422 scale,
423 size,
424 font_embolden,
425 );
426 Self::Initialized { renderer }
427 }
428
429 #[cfg(feature = "skia")]
430 pub fn new_skia(window: Arc<dyn Window>, scale: f64, size: Size, font_embolden: f32) -> Self {
431 let renderer = Renderer::new_skia(window.clone(), scale, size, font_embolden);
432 Self::Initialized { renderer }
433 }
434
435 pub(crate) fn renderer(&self) -> &Renderer {
436 match self {
437 PaintState::PendingGpuResources { renderer, .. } => renderer,
438 PaintState::Initialized { renderer } => renderer,
439 }
440 }
441
442 pub(crate) fn renderer_mut(&mut self) -> &mut Renderer {
443 match self {
444 PaintState::PendingGpuResources { renderer, .. } => renderer,
445 PaintState::Initialized { renderer } => renderer,
446 }
447 }
448
449 pub(crate) fn resize(&mut self, scale: f64, size: Size) {
450 self.renderer_mut().resize(scale, size);
451 }
452
453 pub(crate) fn set_scale(&mut self, scale: f64) {
454 self.renderer_mut().set_scale(scale);
455 }
456}
457
458impl Deref for PaintCx<'_> {
459 type Target = Renderer;
460
461 fn deref(&self) -> &Self::Target {
462 self.paint_state.renderer()
463 }
464}
465
466impl DerefMut for PaintCx<'_> {
467 fn deref_mut(&mut self) -> &mut Self::Target {
468 self.paint_state.renderer_mut()
469 }
470}