1use crate::{env::Env, layout::LayoutPosition, style::StyleManager};
2use float_pigment_css::typing::{
3 AlignContent, AlignItems, AlignSelf, BoxSizing, Direction, FlexDirection, FlexWrap,
4 JustifyContent, Overflow, Position, TextAlign, WritingMode,
5};
6
7use float_pigment_css::{length_num::*, typing::Display};
8use float_pigment_layout::{ComputedStyle, DefLength, LayoutNode};
9pub use float_pigment_layout::{OptionNum, OptionSize, Size};
10use lru::LruCache;
11
12use std::{
13 cell::{Cell, Ref, RefCell, RefMut, UnsafeCell},
14 ptr::{self},
15};
16
17pub type Len = float_pigment_css::fixed::FixedI32<float_pigment_css::fixed::types::extra::U10>;
18pub type Length = DefLength<Len>;
19pub type NodeId = usize;
20pub type NodePtr = *mut Node;
21
22#[inline(always)]
23pub fn convert_node_ref_to_ptr(node: &Node) -> NodePtr {
24 node as *const Node as *mut Node
25}
26
27#[inline(always)]
28#[allow(clippy::missing_safety_doc)]
29pub unsafe fn get_ref_from_node_ptr(node_ptr: NodePtr) -> &'static Node {
30 &*node_ptr
31}
32
33pub type ExternalHostPtr = *mut ();
34
35pub(crate) type MeasureMinWidth = Len;
36pub(crate) type MeasureMinHeight = Len;
37pub(crate) type MeasureMaxWidth = Len;
38pub(crate) type MeasureMaxHeight = Len;
39pub(crate) type MeasureMaxContentWidth = Len;
40pub(crate) type MeasureMaxContentHeight = Len;
41
42pub(crate) type MeasureFn<L> = dyn Fn(
43 NodePtr,
44 MeasureMaxWidth,
45 MeasureMode,
46 MeasureMaxHeight,
47 MeasureMode,
48 MeasureMinWidth,
49 MeasureMinHeight,
50 MeasureMaxContentWidth,
51 MeasureMaxContentHeight,
52) -> Size<L>;
53
54pub(crate) type BaselineFn<L> = dyn Fn(NodePtr, L, L) -> L;
55pub(crate) type ResolveCalcFn<L> = dyn Fn(i32, L) -> L;
56pub(crate) type DirtyCallbackFn = dyn Fn(NodePtr);
57
58pub(crate) type MeasureCacheKeyMinSize = OptionSize<<Len as LengthNum>::Hashable>;
59pub(crate) type MeasureCacheKeyMaxSize = OptionSize<<Len as LengthNum>::Hashable>;
60pub(crate) type MeasureCacheKeyMaxContent = OptionSize<<Len as LengthNum>::Hashable>;
61pub(crate) type MeasureCache = LruCache<
62 (
63 MeasureCacheKeyMinSize,
64 MeasureCacheKeyMaxSize,
65 MeasureCacheKeyMaxContent,
66 ),
67 Size<Len>,
68>;
69pub(crate) type BaselineCache = LruCache<Size<<Len as LengthNum>::Hashable>, Len>;
70
71const CACHE_SIZE: usize = 3;
72
73#[repr(C)]
74#[derive(Copy, Clone)]
75pub enum MeasureMode {
76 Undefined,
77 Exactly,
78 AtMost,
79}
80
81#[derive(Copy, Clone, Debug)]
82pub struct DumpOptions {
83 pub recursive: bool,
84 pub layout: bool,
85 pub style: DumpStyleMode,
86}
87
88#[derive(Copy, Clone, Debug)]
89pub enum DumpStyleMode {
90 None,
91 Full,
92 Mutation,
93}
94
95pub trait DumpNode {
96 unsafe fn dump_to_html(&self, options: DumpOptions, current_depth: u8) -> String;
97}
98
99impl DumpNode for Node {
100 unsafe fn dump_to_html(&self, options: DumpOptions, current_depth: u8) -> String {
101 let layout = options.layout.then_some(format!(
102 "left: {}, top: {}, width: {}, height: {}",
103 self.layout_position().left,
104 self.layout_position().top,
105 self.layout_position().width,
106 self.layout_position().height,
107 ));
108 let style = match options.style {
109 DumpStyleMode::None => None,
110 DumpStyleMode::Mutation => Some(self.style_manager().mutation_to_string()),
111 DumpStyleMode::Full => Some(self.style_manager().style_to_string()),
112 };
113 let children = (options.recursive && !self.children().is_empty()).then_some({
114 let mut children_str = String::new();
115 children_str.push('\n');
116 self.children().iter().for_each(|child| {
117 let child_str = child.dump_to_html(options, current_depth + 1);
118 let tabs = (0..current_depth).map(|_| " ").collect::<String>();
119 children_str.push_str(&tabs);
120 children_str.push_str(&child_str);
121 });
122 children_str.push('\n');
123 children_str.to_string()
124 });
125 let mut tag: String = match self.style_manager().display() {
126 Display::None => "None".into(),
127 Display::Block => "Block".into(),
128 Display::Flex => "Flex".into(),
129 Display::Inline => "Inline".into(),
130 Display::InlineBlock => "InlineBlock".into(),
131 Display::FlowRoot => "FlowRoot".into(),
132 Display::Grid => "Grid".into(),
133 Display::InlineFlex => "InlineFlex".into(),
134 };
135 if self.has_measure_func() {
136 tag = format!("Measurable{}", tag);
137 }
138 if let Some(children) = children {
139 if let Some(style) = style {
140 format!(
141 "<{}#{:p} layout=\"{}\", style=\"{}\">{}",
142 tag,
143 self,
144 layout.unwrap_or_default(),
145 style,
146 children,
147 )
148 } else {
149 format!(
150 "<{}#{:p} layout=\"{}\">{}",
151 tag,
152 self,
153 layout.unwrap_or_default(),
154 children,
155 )
156 }
157 } else if let Some(style) = style {
158 format!(
159 "<{}#{:p} layout=\"{}\", style=\"{}\"/>\n",
160 tag,
161 self,
162 layout.unwrap_or_default(),
163 style,
164 )
165 } else {
166 format!(
167 "<{}#{:p} layout=\"{}\"/>\n",
168 tag,
169 self,
170 layout.unwrap_or_default(),
171 )
172 }
173 }
174}
175#[repr(C)]
176#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
177pub enum NodeType {
178 Normal,
179 Text,
180 #[allow(unused)]
181 Image,
182}
183
184#[repr(C)]
185#[derive(Debug)]
186pub struct Node {
187 node_type: Cell<NodeType>,
188 is_dirty: Cell<bool>,
189 external_host: Cell<ExternalHostPtr>,
190 parent: Cell<NodePtr>,
191 children: RefCell<Vec<NodePtr>>,
192 style_manager: RefCell<StyleManager>,
193 pub(crate) layout_node: LayoutNode<Node>,
194 measure_cache: UnsafeCell<Option<Box<MeasureCache>>>,
195 baseline_cache: UnsafeCell<Option<Box<BaselineCache>>>,
196 baseline_func: UnsafeCell<Option<Box<BaselineFn<Len>>>>,
197 measure_func: UnsafeCell<Option<Box<MeasureFn<Len>>>>,
198 resolve_calc: UnsafeCell<Option<Box<ResolveCalcFn<Len>>>>,
199 dirty_callback: UnsafeCell<Option<Box<DirtyCallbackFn>>>,
200}
201
202impl Node {
203 pub fn new() -> Self {
204 Self {
205 node_type: Cell::new(NodeType::Normal),
206 external_host: Cell::new(std::ptr::null_mut()),
207 children: RefCell::new(Vec::with_capacity(0)),
208 parent: Cell::new(std::ptr::null_mut()),
209 style_manager: RefCell::new(StyleManager::new()),
210 layout_node: LayoutNode::new(),
211 is_dirty: Cell::new(true),
212 baseline_func: UnsafeCell::new(None),
213 measure_func: UnsafeCell::new(None),
214 resolve_calc: UnsafeCell::new(None),
215 dirty_callback: UnsafeCell::new(None),
216 measure_cache: UnsafeCell::new(None),
217 baseline_cache: UnsafeCell::new(None),
218 }
219 }
220 pub fn new_typed(node_type: NodeType) -> Self {
221 let ret = Self::new();
222 ret.node_type.set(node_type);
223 ret
224 }
225 pub fn new_ptr() -> NodePtr {
226 let self_node = Box::new(Self::new());
227 Box::into_raw(self_node)
228 }
229 pub unsafe fn parent(&self) -> Option<&Node> {
230 if self.parent.get().is_null() {
231 None
232 } else {
233 Some(&*self.parent.get())
234 }
235 }
236 pub fn set_parent(&self, parent: Option<NodePtr>) {
237 if let Some(parent) = parent {
238 self.parent.replace(parent);
239 } else {
240 self.parent.replace(std::ptr::null_mut());
241 }
242 }
243 pub fn parent_ptr(&self) -> Option<NodePtr> {
244 if self.parent.get().is_null() {
245 None
246 } else {
247 Some(self.parent.get())
248 }
249 }
250 pub unsafe fn children(&self) -> Vec<&Node> {
251 self.children
252 .borrow()
253 .iter()
254 .map(|node| &**node)
255 .collect::<Vec<_>>()
256 }
257 pub fn children_len(&self) -> usize {
258 self.children.borrow().len()
259 }
260 pub(crate) fn style_manager(&self) -> Ref<StyleManager> {
261 self.style_manager.borrow()
262 }
263 pub(crate) fn style_manager_mut(&self) -> RefMut<StyleManager> {
264 self.style_manager.borrow_mut()
265 }
266 pub(crate) fn computed_style(&self) -> ComputedStyle<Len> {
267 self.layout_node.computed_style()
268 }
269 pub unsafe fn set_node_type(&self, node_type: NodeType) {
270 if self.node_type.get() != node_type {
271 self.node_type.replace(node_type);
272 }
273 if node_type == NodeType::Text {
274 *self.measure_cache.get() = Some(Box::new(LruCache::new(CACHE_SIZE)));
275 *self.baseline_cache.get() = Some(Box::new(LruCache::new(CACHE_SIZE)));
276 }
277 }
278
279 #[inline(always)]
280 pub(crate) unsafe fn measure_cache(&self) -> Option<&mut MeasureCache> {
281 let ret: *mut _ = self.measure_cache.get();
282 (*ret).as_deref_mut()
283 }
284
285 pub(crate) unsafe fn clear_measure_cache(&self) {
286 if let Some(cache) = self.measure_cache() {
287 cache.clear();
288 }
289 }
290
291 #[inline(always)]
292 pub(crate) unsafe fn baseline_cache(&self) -> Option<&mut BaselineCache> {
293 let ret: *mut _ = self.baseline_cache.get();
294 (*ret).as_deref_mut()
295 }
296
297 pub(crate) unsafe fn clear_baseline_cache(&self) {
298 if let Some(cache) = self.baseline_cache() {
299 cache.clear();
300 }
301 }
302 pub(crate) fn node_type(&self) -> NodeType {
303 self.node_type.get()
304 }
305 pub(crate) unsafe fn baseline_func(&self) -> Option<&BaselineFn<Len>> {
306 (*self.baseline_func.get()).as_deref()
307 }
308 pub unsafe fn set_baseline_func(&self, baseline_func: Option<Box<BaselineFn<Len>>>) {
309 drop(std::mem::replace(
310 &mut *self.baseline_func.get(),
311 baseline_func,
312 ));
313 }
314 pub unsafe fn has_baseline_func(&self) -> bool {
315 (*self.baseline_func.get()).is_some()
316 }
317 pub(crate) unsafe fn measure_func(&self) -> Option<&MeasureFn<Len>> {
318 (*self.measure_func.get()).as_deref()
319 }
320 pub fn set_measure_func(&self, measure_func: Option<Box<MeasureFn<Len>>>) {
321 drop(std::mem::replace(
322 unsafe { &mut *self.measure_func.get() },
323 measure_func,
324 ));
325 }
326 pub fn has_measure_func(&self) -> bool {
327 unsafe { (*self.measure_func.get()).is_some() }
328 }
329 pub(crate) fn resolve_calc(&self) -> Option<&ResolveCalcFn<Len>> {
330 unsafe { (*self.resolve_calc.get()).as_deref() }
331 }
332 pub fn set_resolve_calc(&self, resolve_calc: Option<Box<ResolveCalcFn<Len>>>) {
333 drop(std::mem::replace(
334 unsafe { &mut *self.resolve_calc.get() },
335 resolve_calc,
336 ))
337 }
338 pub fn set_dirty_callback(&self, dirty_callback: Option<Box<DirtyCallbackFn>>) {
339 drop(std::mem::replace(
340 unsafe { &mut *self.dirty_callback.get() },
341 dirty_callback,
342 ));
343 }
344 pub fn has_dirty_callback(&self) -> bool {
345 unsafe { (*self.dirty_callback.get()).is_some() }
346 }
347 pub(crate) fn dirty_callback(&self) -> Option<&DirtyCallbackFn> {
348 unsafe { (*self.dirty_callback.get()).as_deref() }
349 }
350 pub fn external_host(&self) -> Option<ExternalHostPtr> {
351 if self.external_host.get().is_null() {
352 None
353 } else {
354 Some(self.external_host.get())
355 }
356 }
357 pub fn set_external_host(&self, external_host: Option<ExternalHostPtr>) {
358 if let Some(external_host) = external_host {
359 self.external_host.replace(external_host);
360 } else {
361 self.external_host.replace(std::ptr::null_mut());
362 }
363 }
364 pub(crate) fn is_dirty(&self) -> bool {
365 self.is_dirty.get()
366 }
367 pub(crate) fn clear_dirty(&self) {
368 self.is_dirty.set(false)
369 }
370 pub(crate) unsafe fn clear_dirty_recursive(&self) {
371 if self.is_dirty() {
372 self.clear_dirty();
373 self.children()
374 .iter()
375 .for_each(|child| child.clear_dirty_recursive());
376 }
377 }
378 pub unsafe fn mark_self_dirty(&self) {
379 if self.is_dirty() {
380 return;
381 }
382 self.is_dirty.set(true);
383 if self.node_type() == NodeType::Text {
384 self.clear_measure_cache();
385 self.clear_baseline_cache();
386 }
387 if let Some(dirty_callback) = self.dirty_callback() {
388 dirty_callback(convert_node_ref_to_ptr(self))
389 }
390 self.layout_node.mark_dirty(self);
391 }
392 pub unsafe fn mark_dirty_propagate_to_descendants(&self) {
393 self.mark_self_dirty();
394 unsafe {
395 self.children
396 .borrow()
397 .iter()
398 .for_each(|node| (**node).mark_dirty_propagate_to_descendants())
399 }
400 }
401 pub unsafe fn mark_dirty_propagate(&self) {
402 if !self.is_dirty() {
403 self.mark_self_dirty();
404 if let Some(parent) = self.parent() {
405 parent.mark_dirty_propagate()
406 }
407 }
408 }
409 pub fn dry_layout(
410 &self,
411 available_size: OptionSize<Len>,
412 viewport_size: float_pigment_layout::Size<Len>,
413 ) {
414 self.layout_node.update_with_containing_size(
416 &mut Env {
417 screen_width: viewport_size.width,
418 screen_height: viewport_size.height,
419 },
420 self,
421 available_size,
422 available_size,
423 );
424 }
425 pub unsafe fn layout(
426 &self,
427 available_size: OptionSize<Len>,
428 viewport_size: float_pigment_layout::Size<Len>,
429 ) {
430 self.layout_node.update_with_containing_size(
432 &mut Env {
433 screen_width: viewport_size.width,
434 screen_height: viewport_size.height,
435 },
436 self,
437 available_size,
438 available_size,
439 );
440 self.clear_dirty_recursive();
441 }
442
443 pub unsafe fn layout_with_containing_size(
444 &self,
445 available_size: OptionSize<Len>,
446 viewport_size: float_pigment_layout::Size<Len>,
447 containing_size: OptionSize<Len>,
448 ) {
449 self.layout_node.update_with_containing_size(
450 &mut Env {
451 screen_width: viewport_size.width,
452 screen_height: viewport_size.height,
453 },
454 self,
455 available_size,
456 containing_size,
457 );
458 self.clear_dirty_recursive();
459 }
460
461 pub fn layout_position(&self) -> LayoutPosition {
462 let layout = self.layout_node.result();
463 LayoutPosition {
464 left: layout.origin.x,
465 top: layout.origin.y,
466 width: layout.size.width,
467 height: layout.size.height,
468 }
469 }
470}
471
472impl Default for Node {
473 fn default() -> Self {
474 Self::new()
475 }
476}
477pub trait ChildOperation {
478 unsafe fn get_child_at(&self, idx: usize) -> Option<&Node>;
479 unsafe fn get_child_ptr_at(&self, idx: usize) -> Option<NodePtr>;
480 unsafe fn get_child_index(&self, child: NodePtr) -> Option<usize>;
481 unsafe fn append_child(&self, child: NodePtr);
482 unsafe fn insert_child_at(&self, child: NodePtr, idx: usize);
483 unsafe fn insert_child_before(&self, child: NodePtr, pivot: NodePtr);
484 unsafe fn remove_child(&self, child: NodePtr);
485 unsafe fn remove_child_at(&self, idx: usize);
486 unsafe fn remove_all_children(&self);
487 unsafe fn for_each_child_node<'a, 'b: 'a, F>(&'b self, func: F)
488 where
489 F: FnMut(&'a Self, usize);
490}
491
492impl ChildOperation for Node {
493 unsafe fn get_child_at(&self, idx: usize) -> Option<&Node> {
494 self.children().get(idx).copied()
495 }
496 unsafe fn get_child_ptr_at(&self, idx: usize) -> Option<NodePtr> {
497 self.children.borrow().get(idx).copied()
498 }
499 unsafe fn get_child_index(&self, child: NodePtr) -> Option<usize> {
500 self.children()
501 .iter()
502 .position(|node| ptr::eq(*node, child))
503 }
504 #[allow(clippy::not_unsafe_ptr_arg_deref)]
505 unsafe fn append_child(&self, child: NodePtr) {
506 (*child).set_parent(Some(convert_node_ref_to_ptr(self)));
507 self.children.borrow_mut().push(child);
508 self.mark_dirty_propagate()
509 }
510 #[allow(clippy::not_unsafe_ptr_arg_deref)]
511 unsafe fn insert_child_at(&self, child: NodePtr, idx: usize) {
512 (*child).set_parent(Some(convert_node_ref_to_ptr(self)));
513 self.children.borrow_mut().insert(idx, child);
514 self.mark_dirty_propagate()
515 }
516 #[allow(clippy::not_unsafe_ptr_arg_deref)]
517 unsafe fn insert_child_before(&self, child: NodePtr, pivot: NodePtr) {
518 (*child).set_parent(Some(convert_node_ref_to_ptr(self)));
519 let idx = self
520 .children
521 .borrow()
522 .iter()
523 .position(|node| std::ptr::eq(*node, pivot));
524 if let Some(idx) = idx {
525 self.children.borrow_mut().insert(idx, child)
526 }
527 self.mark_dirty_propagate();
528 }
529 unsafe fn remove_child(&self, child: NodePtr) {
530 if self.children_len() == 0 {
531 return;
532 }
533 if let Some((idx, node)) = self
534 .children
535 .borrow()
536 .iter()
537 .enumerate()
538 .find(|(_, node)| std::ptr::eq(**node, child))
539 {
540 (**node).set_parent(None);
541 (*self.children.as_ptr()).remove(idx);
542 }
543 self.mark_dirty_propagate();
544 }
545 unsafe fn remove_child_at(&self, idx: usize) {
546 let len = self.children_len();
547 if len == 0 || idx >= len {
548 return;
549 }
550 if let Some(node) = self.children.borrow().get(idx) {
551 (**node).set_parent(None);
552 }
553 self.children.borrow_mut().remove(idx);
554 self.mark_dirty_propagate();
555 }
556 unsafe fn remove_all_children(&self) {
557 self.for_each_child_node(|node, _| {
558 (*node).set_parent(None);
559 });
560 self.children.borrow_mut().clear();
561 self.mark_dirty_propagate()
562 }
563 unsafe fn for_each_child_node<'a, 'b: 'a, F>(&'b self, func: F)
564 where
565 F: FnMut(&'a Self, usize),
566 {
567 let mut func = func;
568 self.children
569 .borrow_mut()
570 .iter_mut()
571 .enumerate()
572 .for_each(|(idx, node)| func(&**node, idx))
573 }
574}
575
576pub trait StyleSetter {
577 unsafe fn set_display(&self, value: Display);
578 unsafe fn set_box_sizing(&self, value: BoxSizing);
579 unsafe fn set_direction(&self, value: Direction);
580 unsafe fn set_writing_mode(&self, value: WritingMode);
581 unsafe fn set_position(&self, value: Position);
582 unsafe fn set_left(&self, value: Length);
583 unsafe fn set_top(&self, value: Length);
584 unsafe fn set_right(&self, value: Length);
585 unsafe fn set_bottom(&self, value: Length);
586 unsafe fn set_overflow_x(&self, value: Overflow);
587 unsafe fn set_overflow_y(&self, value: Overflow);
588 unsafe fn set_width(&self, value: Length);
589 unsafe fn set_height(&self, value: Length);
590 unsafe fn set_min_width(&self, value: Length);
591 unsafe fn set_min_height(&self, value: Length);
592 unsafe fn set_max_width(&self, value: Length);
593 unsafe fn set_max_height(&self, value: Length);
594 unsafe fn set_margin(&self, value: Length);
595 unsafe fn set_margin_left(&self, value: Length);
596 unsafe fn set_margin_top(&self, value: Length);
597 unsafe fn set_margin_right(&self, value: Length);
598 unsafe fn set_margin_bottom(&self, value: Length);
599 unsafe fn set_padding(&self, value: Length);
600 unsafe fn set_padding_left(&self, value: Length);
601 unsafe fn set_padding_top(&self, value: Length);
602 unsafe fn set_padding_right(&self, value: Length);
603 unsafe fn set_padding_bottom(&self, value: Length);
604 unsafe fn set_border(&self, value: Length);
605 unsafe fn set_border_left(&self, value: Length);
606 unsafe fn set_border_top(&self, value: Length);
607 unsafe fn set_border_right(&self, value: Length);
608 unsafe fn set_border_bottom(&self, value: Length);
609 unsafe fn set_flex_grow(&self, value: f32);
610 unsafe fn set_flex_shrink(&self, value: f32);
611 unsafe fn set_flex_basis(&self, value: Length);
612 unsafe fn set_flex_direction(&self, value: FlexDirection);
613 unsafe fn set_flex_wrap(&self, value: FlexWrap);
614 unsafe fn set_justify_content(&self, value: JustifyContent);
615 unsafe fn set_align_content(&self, value: AlignContent);
616 unsafe fn set_align_items(&self, value: AlignItems);
617 unsafe fn set_align_self(&self, value: AlignSelf);
618 unsafe fn set_aspect_ratio(&self, value: Option<f32>);
619 unsafe fn set_order(&self, value: i32);
620 unsafe fn set_text_align(&self, value: TextAlign);
621 unsafe fn set_row_gap(&self, value: Length);
622 unsafe fn set_column_gap(&self, value: Length);
623}
624
625impl StyleSetter for Node {
626 unsafe fn set_flex_direction(&self, flex_direction: FlexDirection) {
627 if self.style_manager_mut().set_flex_direction(flex_direction) {
628 self.mark_dirty_propagate();
629 }
630 }
631 unsafe fn set_direction(&self, direction: Direction) {
632 if self.style_manager_mut().set_direction(direction) {
633 self.mark_dirty_propagate();
634 }
635 }
636 unsafe fn set_align_content(&self, align_content: AlignContent) {
637 if self.style_manager_mut().set_align_content(align_content) {
638 self.mark_dirty_propagate();
639 }
640 }
641 unsafe fn set_align_items(&self, align_items: AlignItems) {
642 if self.style_manager_mut().set_align_items(align_items) {
643 self.mark_dirty_propagate();
644 }
645 }
646 unsafe fn set_align_self(&self, align_self: AlignSelf) {
647 if self.style_manager_mut().set_align_self(align_self) {
648 self.mark_dirty_propagate();
649 }
650 }
651 unsafe fn set_aspect_ratio(&self, aspect_ratio: Option<f32>) {
652 if self.style_manager_mut().set_aspect_ratio(aspect_ratio) {
653 self.mark_dirty_propagate();
654 }
655 }
656 unsafe fn set_border(&self, border: Length) {
657 let top_changed = self.style_manager_mut().set_border_top(border);
658 let right_changed = self.style_manager_mut().set_border_right(border);
659 let bottom_changed = self.style_manager_mut().set_border_bottom(border);
660 let left_changed = self.style_manager_mut().set_border_left(border);
661 if top_changed || right_changed || bottom_changed || left_changed {
662 self.mark_dirty_propagate();
663 }
664 }
665 unsafe fn set_border_left(&self, border_left: Length) {
666 if self.style_manager_mut().set_border_left(border_left) {
667 self.mark_dirty_propagate();
668 }
669 }
670 unsafe fn set_border_right(&self, border_right: Length) {
671 if self.style_manager_mut().set_border_right(border_right) {
672 self.mark_dirty_propagate();
673 }
674 }
675 unsafe fn set_border_top(&self, border_top: Length) {
676 if self.style_manager_mut().set_border_top(border_top) {
677 self.mark_dirty_propagate();
678 }
679 }
680 unsafe fn set_border_bottom(&self, border_bottom: Length) {
681 if self.style_manager_mut().set_border_bottom(border_bottom) {
682 self.mark_dirty_propagate();
683 }
684 }
685 unsafe fn set_box_sizing(&self, box_sizing: BoxSizing) {
686 if self.style_manager_mut().set_box_sizing(box_sizing) {
687 self.mark_dirty_propagate();
688 }
689 }
690 unsafe fn set_display(&self, display: Display) {
691 if self.style_manager_mut().set_display(display) {
692 self.mark_dirty_propagate();
693 }
694 }
695 unsafe fn set_height(&self, height: Length) {
696 if self.style_manager_mut().set_height(height) {
697 self.mark_dirty_propagate();
698 }
699 }
700 unsafe fn set_width(&self, width: Length) {
701 if self.style_manager_mut().set_width(width) {
702 self.mark_dirty_propagate();
703 }
704 }
705 unsafe fn set_left(&self, left: Length) {
706 if self.style_manager_mut().set_left(left) {
707 self.mark_dirty_propagate();
708 }
709 }
710 unsafe fn set_right(&self, right: Length) {
711 if self.style_manager_mut().set_right(right) {
712 self.mark_dirty_propagate();
713 }
714 }
715 unsafe fn set_top(&self, top: Length) {
716 if self.style_manager_mut().set_top(top) {
717 self.mark_dirty_propagate();
718 }
719 }
720 unsafe fn set_bottom(&self, bottom: Length) {
721 if self.style_manager_mut().set_bottom(bottom) {
722 self.mark_dirty_propagate();
723 }
724 }
725 unsafe fn set_flex_shrink(&self, flex_shrink: f32) {
726 if self.style_manager_mut().set_flex_shrink(flex_shrink) {
727 self.mark_dirty_propagate();
728 }
729 }
730 unsafe fn set_flex_grow(&self, flex_grow: f32) {
731 if self.style_manager_mut().set_flex_grow(flex_grow) {
732 self.mark_dirty_propagate();
733 }
734 }
735 unsafe fn set_flex_wrap(&self, flex_wrap: FlexWrap) {
736 if self.style_manager_mut().set_flex_wrap(flex_wrap) {
737 self.mark_dirty_propagate();
738 }
739 }
740 unsafe fn set_flex_basis(&self, flex_basis: Length) {
741 if self.style_manager_mut().set_flex_basis(flex_basis) {
742 self.mark_dirty_propagate();
743 }
744 }
745 unsafe fn set_justify_content(&self, justify_content: JustifyContent) {
746 if self
747 .style_manager_mut()
748 .set_justify_content(justify_content)
749 {
750 self.mark_dirty_propagate();
751 }
752 }
753 unsafe fn set_position(&self, position: Position) {
754 if self.style_manager_mut().set_position(position) {
755 self.mark_dirty_propagate();
756 }
757 }
758 unsafe fn set_overflow_x(&self, overflow_x: Overflow) {
759 if self.style_manager_mut().set_overflow_x(overflow_x) {
760 self.mark_dirty_propagate();
761 }
762 }
763 unsafe fn set_overflow_y(&self, overflow_y: Overflow) {
764 if self.style_manager_mut().set_overflow_y(overflow_y) {
765 self.mark_dirty_propagate();
766 }
767 }
768 unsafe fn set_writing_mode(&self, writing_mode: WritingMode) {
769 if self.style_manager_mut().set_writing_mode(writing_mode) {
770 self.mark_dirty_propagate();
771 }
772 }
773 unsafe fn set_margin(&self, margin: Length) {
774 let top_changed = self.style_manager_mut().set_margin_top(margin);
775 let right_changed = self.style_manager_mut().set_margin_right(margin);
776 let bottom_changed = self.style_manager_mut().set_margin_bottom(margin);
777 let left_changed = self.style_manager_mut().set_margin_left(margin);
778 if top_changed || bottom_changed || right_changed || left_changed {
779 self.mark_dirty_propagate();
780 }
781 }
782 unsafe fn set_margin_bottom(&self, margin_bottom: Length) {
783 if self.style_manager_mut().set_margin_bottom(margin_bottom) {
784 self.mark_dirty_propagate();
785 }
786 }
787 unsafe fn set_margin_left(&self, margin_left: Length) {
788 if self.style_manager_mut().set_margin_left(margin_left) {
789 self.mark_dirty_propagate();
790 }
791 }
792 unsafe fn set_margin_right(&self, margin_right: Length) {
793 if self.style_manager_mut().set_margin_right(margin_right) {
794 self.mark_dirty_propagate();
795 }
796 }
797 unsafe fn set_margin_top(&self, margin_top: Length) {
798 if self.style_manager_mut().set_margin_top(margin_top) {
799 self.mark_dirty_propagate();
800 }
801 }
802 unsafe fn set_max_height(&self, max_height: Length) {
803 if self.style_manager_mut().set_max_height(max_height) {
804 self.mark_dirty_propagate();
805 }
806 }
807 unsafe fn set_max_width(&self, max_width: Length) {
808 if self.style_manager_mut().set_max_width(max_width) {
809 self.mark_dirty_propagate();
810 }
811 }
812 unsafe fn set_min_height(&self, min_height: Length) {
813 if self.style_manager_mut().set_min_height(min_height) {
814 self.mark_dirty_propagate();
815 }
816 }
817
818 unsafe fn set_min_width(&self, min_width: Length) {
819 if self.style_manager_mut().set_min_width(min_width) {
820 self.mark_dirty_propagate();
821 }
822 }
823 unsafe fn set_padding(&self, padding: Length) {
824 let top_changed = self.style_manager_mut().set_padding_top(padding);
825 let right_changed = self.style_manager_mut().set_padding_right(padding);
826 let bottom_changed = self.style_manager_mut().set_padding_bottom(padding);
827 let left_changed = self.style_manager_mut().set_padding_left(padding);
828 if top_changed || bottom_changed || left_changed || right_changed {
829 self.mark_dirty_propagate();
830 }
831 }
832 unsafe fn set_padding_left(&self, padding_left: Length) {
833 if self.style_manager_mut().set_padding_left(padding_left) {
834 self.mark_dirty_propagate();
835 }
836 }
837 unsafe fn set_padding_right(&self, padding_right: Length) {
838 if self.style_manager_mut().set_padding_right(padding_right) {
839 self.mark_dirty_propagate();
840 }
841 }
842 unsafe fn set_padding_top(&self, padding_top: Length) {
843 if self.style_manager_mut().set_padding_top(padding_top) {
844 self.mark_dirty_propagate();
845 }
846 }
847 unsafe fn set_padding_bottom(&self, padding_bottom: Length) {
848 if self.style_manager_mut().set_padding_bottom(padding_bottom) {
849 self.mark_dirty_propagate();
850 }
851 }
852 unsafe fn set_order(&self, order: i32) {
853 if self.style_manager_mut().set_order(order) {
854 self.mark_dirty_propagate();
855 }
856 }
857 unsafe fn set_text_align(&self, text_align: TextAlign) {
858 if self.style_manager_mut().set_text_align(text_align) {
859 self.mark_dirty_propagate();
860 }
861 }
862 unsafe fn set_row_gap(&self, value: Length) {
863 if self.style_manager_mut().set_row_gap(value) {
864 self.mark_dirty_propagate();
865 }
866 }
867 unsafe fn set_column_gap(&self, value: Length) {
868 if self.style_manager_mut().set_column_gap(value) {
869 self.mark_dirty_propagate();
870 }
871 }
872}
873
874#[cfg(test)]
875mod test {
876 use crate::node::NodePtr;
877
878 use super::*;
879 fn new_node<'a>() -> (&'a Node, NodePtr) {
880 let node_ptr = Node::new_ptr();
881 (unsafe { get_ref_from_node_ptr(node_ptr) }, node_ptr)
882 }
883 #[test]
884 fn append_child() {
885 let (node_a, node_a_ptr) = new_node();
886 let (node_b, node_b_ptr) = new_node();
887 unsafe {
888 node_a.append_child(node_b_ptr);
889 assert!(std::ptr::eq(node_a, node_b.parent().unwrap()));
890 assert!(std::ptr::eq(node_a.get_child_at(0).unwrap(), node_b));
891 drop(Box::from_raw(node_a_ptr));
892 drop(Box::from_raw(node_b_ptr));
893 }
894 }
895 #[test]
896 fn insert_child_at() {
897 let (node_a, node_a_ptr) = new_node();
898 let (node_b, node_b_ptr) = new_node();
899 let (node_c, node_c_ptr) = new_node();
900 unsafe {
901 node_a.insert_child_at(node_b_ptr, 0);
902 node_a.insert_child_at(node_c_ptr, 0);
903 assert!(std::ptr::eq(node_a, node_b.parent().unwrap()));
904 assert!(std::ptr::eq(node_a, node_c.parent().unwrap()));
905 assert!(std::ptr::eq(node_a.get_child_at(0).unwrap(), node_c));
906 assert!(std::ptr::eq(node_a.get_child_at(1).unwrap(), node_b));
907 drop(Box::from_raw(node_a_ptr));
908 drop(Box::from_raw(node_b_ptr));
909 drop(Box::from_raw(node_c_ptr));
910 }
911 }
912
913 #[test]
914 fn remove_child() {
915 let (node_a, node_a_ptr) = new_node();
916 let (node_b, node_b_ptr) = new_node();
917 unsafe {
918 node_a.insert_child_at(node_b_ptr, 0);
919 assert!(std::ptr::eq(node_a, node_b.parent().unwrap()));
920 assert!(std::ptr::eq(node_a.get_child_at(0).unwrap(), node_b));
921 node_a.remove_child(node_b_ptr);
922 assert!(node_b.parent().is_none());
923 assert_eq!(node_a.children_len(), 0usize);
924 drop(Box::from_raw(node_a_ptr));
925 drop(Box::from_raw(node_b_ptr));
926 }
927 }
928
929 #[test]
930 fn remove_child_at() {
931 let (node_a, node_a_ptr) = new_node();
932 let (node_b, node_b_ptr) = new_node();
933 unsafe {
934 node_a.insert_child_at(node_b_ptr, 0);
935 assert!(std::ptr::eq(node_a, node_b.parent().unwrap()));
936 assert!(std::ptr::eq(node_a.get_child_at(0).unwrap(), node_b));
937 node_a.remove_child_at(0);
938 assert_eq!(node_a.children_len(), 0usize);
939 assert!(node_b.parent().is_none());
940 drop(Box::from_raw(node_a_ptr));
941 drop(Box::from_raw(node_b_ptr));
942 }
943 }
944}