1#![allow(clippy::collapsible_if)]
5
6mod color;
7mod debug_overlay;
8mod filters;
9mod gradient;
10mod kurbo_css;
11mod layers;
12mod render;
13mod sizing;
14mod text;
15
16use std::collections::HashMap;
17
18use anyrender::{PaintScene, Scene};
19use apace_dom::{BaseDocument, NodeId, util::Color};
20use render::ApaceDomPainter;
21
22const FONT_EMBOLDEN_ENABLED: bool = cfg!(any(
23 feature = "font-embolden",
24 all(feature = "apple-font-embolden", target_os = "macos"),
25 all(feature = "apple-font-embolden", target_os = "ios"),
26));
27
28const SELECTION_COLOR: Color = Color::from_rgb8(180, 213, 255);
30
31type CustomWidgetSceneMap = HashMap<(usize, NodeId), Scene>;
33
34pub fn paint_scene(
44 scene: &mut impl PaintScene,
45 doc: &mut BaseDocument,
46 scale: f64,
47 width: u32,
48 height: u32,
49 x_offset: u32,
50 y_offset: u32,
51) {
52 #[allow(unused_mut)]
57 let mut custom_widget_scenes: CustomWidgetSceneMap = HashMap::new();
58 #[cfg(feature = "custom-widget")]
59 build_custom_widget_scenes(&mut custom_widget_scenes, doc, scene, scale);
60
61 let generator = ApaceDomPainter::new(
62 doc,
63 scale,
64 width,
65 height,
66 x_offset as f64,
67 y_offset as f64,
68 &custom_widget_scenes,
69 );
70 generator.paint_scene(scene);
71
72 }
79
80#[cfg(feature = "custom-widget")]
81fn build_custom_widget_scenes(
82 custom_widget_scenes: &mut CustomWidgetSceneMap,
83 doc: &mut BaseDocument,
84 render_ctx: &mut impl anyrender::RenderContext,
85 scale: f64,
86) {
87 let doc_id = doc.id();
88
89 let custom_widget_node_ids = doc.custom_widget_node_ids();
91 for node_id in custom_widget_node_ids.into_iter() {
92 if let Some(scene) = process_custom_widget_node(doc, render_ctx, node_id, scale) {
93 custom_widget_scenes.insert((doc_id, node_id), scene);
94 }
95 }
96
97 let sub_document_node_ids = doc.sub_document_node_ids();
99 for node_id in sub_document_node_ids.into_iter() {
100 if let Some(sub_doc) = doc.get_node_mut(node_id).and_then(|node| node.subdoc_mut()) {
101 let mut inner = sub_doc.inner_mut();
102 build_custom_widget_scenes(custom_widget_scenes, &mut inner, render_ctx, scale);
103 }
104 }
105}
106
107#[cfg(feature = "custom-widget")]
108fn process_custom_widget_node(
109 doc: &mut BaseDocument,
110 render_ctx: &mut impl anyrender::RenderContext,
111 node_id: NodeId,
112 scale: f64,
113) -> Option<Scene> {
114 use apace_dom::node::{CustomWidgetStatus, ProxyRenderContext};
115
116 let node = doc.get_node_mut(node_id)?;
117 let width = (node.final_layout().size.width as f64 * scale) as u32;
118 let height = (node.final_layout().size.height as f64 * scale) as u32;
119
120 if width == 0 || height == 0 {
121 return None;
122 }
123
124 let style = (*node.stylo_element_data().primary_styles()?).clone();
125 let element = node.data.downcast_element_mut()?;
126 let widget_data = element.custom_widget_data_mut()?;
127
128 let mut render_ctx = ProxyRenderContext {
129 inner: render_ctx,
130 resource_ids: &mut widget_data.active_resource_ids,
131 };
132
133 if widget_data.status == CustomWidgetStatus::Suspended {
134 widget_data.widget.can_create_surfaces(&mut render_ctx);
135 widget_data.status = CustomWidgetStatus::Active;
136 }
137
138 let widget_scene = widget_data
139 .widget
140 .paint(&mut render_ctx, &style, width, height, scale);
141
142 Some(widget_scene)
143}