1use std::sync::atomic::{AtomicBool, Ordering};
4
5use inset_embedder::{Canvas, Color, Paint, Rect};
6use inset_painting::{Axis, FillRule, PathBuilder};
7
8use crate::box_::BoxConstraints;
9
10static DEBUG_PAINT_SIZE_ENABLED: AtomicBool = AtomicBool::new(false);
11static DEBUG_PAINT_BASELINES_ENABLED: AtomicBool = AtomicBool::new(false);
12static DEBUG_PAINT_TEXT_LAYOUT_BOXES: AtomicBool = AtomicBool::new(false);
13static DEBUG_PAINT_LAYER_BORDERS_ENABLED: AtomicBool = AtomicBool::new(false);
14static DEBUG_PAINT_POINTERS_ENABLED: AtomicBool = AtomicBool::new(false);
15static DEBUG_REPAINT_RAINBOW_ENABLED: AtomicBool = AtomicBool::new(false);
16static DEBUG_REPAINT_TEXT_RAINBOW_ENABLED: AtomicBool = AtomicBool::new(false);
17static DEBUG_PRINT_MARK_NEEDS_LAYOUT_STACKS: AtomicBool = AtomicBool::new(false);
18static DEBUG_PRINT_MARK_NEEDS_PAINT_STACKS: AtomicBool = AtomicBool::new(false);
19static DEBUG_PRINT_LAYOUTS: AtomicBool = AtomicBool::new(false);
20static DEBUG_CHECK_INTRINSIC_SIZES: AtomicBool = AtomicBool::new(false);
21static DEBUG_PROFILE_LAYOUTS_ENABLED: AtomicBool = AtomicBool::new(false);
22static DEBUG_PROFILE_PAINTS_ENABLED: AtomicBool = AtomicBool::new(false);
23static DEBUG_ENHANCE_LAYOUT_TIMELINE_ARGUMENTS: AtomicBool = AtomicBool::new(false);
24static DEBUG_ENHANCE_PAINT_TIMELINE_ARGUMENTS: AtomicBool = AtomicBool::new(false);
25static DEBUG_DISABLE_CLIP_LAYERS: AtomicBool = AtomicBool::new(false);
26static DEBUG_DISABLE_PHYSICAL_SHAPE_LAYERS: AtomicBool = AtomicBool::new(false);
27static DEBUG_DISABLE_OPACITY_LAYERS: AtomicBool = AtomicBool::new(false);
28
29macro_rules! debug_flag {
30 ($get:ident, $set:ident, $static:ident, $doc:expr) => {
31 #[doc = $doc]
32 pub fn $get() -> bool {
33 $static.load(Ordering::Relaxed)
34 }
35
36 #[doc = concat!("Sets [`", stringify!($get), "`].")]
37 pub fn $set(value: bool) {
38 $static.store(value, Ordering::Relaxed);
39 }
40 };
41}
42
43debug_flag!(
44 debug_paint_size_enabled,
45 set_debug_paint_size_enabled,
46 DEBUG_PAINT_SIZE_ENABLED,
47 "Causes each RenderBox to paint a box around its bounds."
48);
49debug_flag!(
50 debug_paint_baselines_enabled,
51 set_debug_paint_baselines_enabled,
52 DEBUG_PAINT_BASELINES_ENABLED,
53 "Causes each RenderBox to paint a line at each of its baselines."
54);
55debug_flag!(
56 debug_paint_text_layout_boxes,
57 set_debug_paint_text_layout_boxes,
58 DEBUG_PAINT_TEXT_LAYOUT_BOXES,
59 "Causes each RenderParagraph to paint the layout boxes of its text."
60);
61debug_flag!(
62 debug_paint_layer_borders_enabled,
63 set_debug_paint_layer_borders_enabled,
64 DEBUG_PAINT_LAYER_BORDERS_ENABLED,
65 "Causes each Layer to paint a box around its bounds."
66);
67debug_flag!(
68 debug_paint_pointers_enabled,
69 set_debug_paint_pointers_enabled,
70 DEBUG_PAINT_POINTERS_ENABLED,
71 "Causes objects like RenderPointerListener to flash while they are being tapped."
72);
73debug_flag!(
74 debug_repaint_rainbow_enabled,
75 set_debug_repaint_rainbow_enabled,
76 DEBUG_REPAINT_RAINBOW_ENABLED,
77 "Overlay a rotating set of colors when repainting layers in debug mode."
78);
79debug_flag!(
80 debug_repaint_text_rainbow_enabled,
81 set_debug_repaint_text_rainbow_enabled,
82 DEBUG_REPAINT_TEXT_RAINBOW_ENABLED,
83 "Overlay a rotating set of colors when repainting text in debug mode."
84);
85debug_flag!(
86 debug_print_mark_needs_layout_stacks,
87 set_debug_print_mark_needs_layout_stacks,
88 DEBUG_PRINT_MARK_NEEDS_LAYOUT_STACKS,
89 "Log the call stacks that mark render objects as needing layout."
90);
91debug_flag!(
92 debug_print_mark_needs_paint_stacks,
93 set_debug_print_mark_needs_paint_stacks,
94 DEBUG_PRINT_MARK_NEEDS_PAINT_STACKS,
95 "Log the call stacks that mark render objects as needing paint."
96);
97debug_flag!(
98 debug_print_layouts,
99 set_debug_print_layouts,
100 DEBUG_PRINT_LAYOUTS,
101 "Log the dirty render objects that are laid out each frame."
102);
103debug_flag!(
104 debug_check_intrinsic_sizes,
105 set_debug_check_intrinsic_sizes,
106 DEBUG_CHECK_INTRINSIC_SIZES,
107 "Check the intrinsic sizes of each RenderBox during layout."
108);
109debug_flag!(
110 debug_profile_layouts_enabled,
111 set_debug_profile_layouts_enabled,
112 DEBUG_PROFILE_LAYOUTS_ENABLED,
113 "Adds Timeline events for every RenderObject layout."
114);
115debug_flag!(
116 debug_profile_paints_enabled,
117 set_debug_profile_paints_enabled,
118 DEBUG_PROFILE_PAINTS_ENABLED,
119 "Adds Timeline events for every RenderObject painted."
120);
121debug_flag!(
122 debug_enhance_layout_timeline_arguments,
123 set_debug_enhance_layout_timeline_arguments,
124 DEBUG_ENHANCE_LAYOUT_TIMELINE_ARGUMENTS,
125 "Adds debugging information to Timeline events related to RenderObject layouts."
126);
127debug_flag!(
128 debug_enhance_paint_timeline_arguments,
129 set_debug_enhance_paint_timeline_arguments,
130 DEBUG_ENHANCE_PAINT_TIMELINE_ARGUMENTS,
131 "Adds debugging information to Timeline events related to RenderObject paints."
132);
133debug_flag!(
134 debug_disable_clip_layers,
135 set_debug_disable_clip_layers,
136 DEBUG_DISABLE_CLIP_LAYERS,
137 "Setting to true will cause all clipping effects from the layer tree to be ignored."
138);
139debug_flag!(
140 debug_disable_physical_shape_layers,
141 set_debug_disable_physical_shape_layers,
142 DEBUG_DISABLE_PHYSICAL_SHAPE_LAYERS,
143 "Setting to true will cause all physical modeling effects from the layer tree to be ignored."
144);
145debug_flag!(
146 debug_disable_opacity_layers,
147 set_debug_disable_opacity_layers,
148 DEBUG_DISABLE_OPACITY_LAYERS,
149 "Setting to true will cause all opacity effects from the layer tree to be ignored."
150);
151
152fn debug_draw_double_rect(canvas: &mut Canvas, outer_rect: Rect, inner_rect: Rect, color: Color) {
153 let mut path = PathBuilder::new();
154 path.rect(outer_rect.into());
155 path.rect(inner_rect.into());
156 let paint = Paint {
157 color: color.into(),
158 ..Paint::default()
159 };
160 canvas.draw_path(&path.build(), FillRule::EvenOdd, &paint);
161}
162
163pub fn debug_paint_padding(
165 canvas: &mut Canvas,
166 outer_rect: Rect,
167 inner_rect: Option<Rect>,
168 outline_width: f64,
169) {
170 if cfg!(debug_assertions) {
171 if let Some(inner_rect) = inner_rect.filter(|rect| !rect.is_empty()) {
172 debug_draw_double_rect(
173 canvas,
174 outer_rect,
175 inner_rect,
176 Color::from_argb(0x90, 0x00, 0x90, 0xFF),
177 );
178 debug_draw_double_rect(
179 canvas,
180 inner_rect.inflate(outline_width).intersect(outer_rect),
181 inner_rect,
182 Color::from_argb(0xFF, 0x00, 0x90, 0xFF),
183 );
184 } else {
185 let paint = Paint {
186 color: Color::from_argb(0x90, 0x90, 0x90, 0x90).into(),
187 ..Paint::default()
188 };
189 canvas.draw_rect(outer_rect, &paint);
190 }
191 }
192}
193
194pub fn debug_assert_all_render_vars_unset(
196 reason: &str,
197 debug_check_intrinsic_sizes_override: bool,
198) -> bool {
199 debug_assert!(
200 !(debug_paint_size_enabled()
201 || debug_paint_baselines_enabled()
202 || debug_paint_layer_borders_enabled()
203 || debug_paint_text_layout_boxes()
204 || debug_paint_pointers_enabled()
205 || debug_repaint_rainbow_enabled()
206 || debug_repaint_text_rainbow_enabled()
207 || debug_print_mark_needs_layout_stacks()
208 || debug_print_mark_needs_paint_stacks()
209 || debug_print_layouts()
210 || debug_check_intrinsic_sizes() != debug_check_intrinsic_sizes_override
211 || debug_profile_layouts_enabled()
212 || debug_profile_paints_enabled()
213 || debug_disable_clip_layers()
214 || debug_disable_physical_shape_layers()
215 || debug_disable_opacity_layers()),
216 "{reason}"
217 );
218 true
219}
220
221pub fn debug_check_has_bounded_axis(axis: Axis, constraints: BoxConstraints) -> bool {
224 debug_assert!(
225 constraints.has_bounded_height() && constraints.has_bounded_width(),
226 "{axis:?} viewport was given unbounded constraints: {constraints}"
227 );
228 true
229}