1use crate::dom::{NodeData, NodeId};
8use crate::prop_cache::CssPropertyCache;
9use crate::styled_dom::StyledNodeState;
10use azul_css::compact_cache::*;
11use azul_css::css::CssPropertyValue;
12use azul_css::props::basic::length::SizeMetric;
13use azul_css::props::layout::dimensions::{LayoutHeight, LayoutWidth};
14use azul_css::props::layout::flex::LayoutFlexBasis;
15use azul_css::props::layout::position::LayoutZIndex;
16use core::hash::{Hash, Hasher};
17use std::collections::hash_map::DefaultHasher;
18
19impl CssPropertyCache {
20 pub fn build_compact_cache(&self, node_data: &[NodeData]) -> CompactLayoutCache {
29 let node_count = self.node_count;
30 let default_state = StyledNodeState::default();
31 let mut result = CompactLayoutCache::with_capacity(node_count);
32
33 for i in 0..node_count {
34 let node_id = NodeId::new(i);
35 let nd = &node_data[i];
36
37 let display = self
42 .get_display(nd, &node_id, &default_state)
43 .and_then(|v| v.get_property().copied())
44 .unwrap_or_default();
45 let position = self
46 .get_position(nd, &node_id, &default_state)
47 .and_then(|v| v.get_property().copied())
48 .unwrap_or_default();
49 let float = self
50 .get_float(nd, &node_id, &default_state)
51 .and_then(|v| v.get_property().copied())
52 .unwrap_or_default();
53 let overflow_x = self
54 .get_overflow_x(nd, &node_id, &default_state)
55 .and_then(|v| v.get_property().copied())
56 .unwrap_or_default();
57 let overflow_y = self
58 .get_overflow_y(nd, &node_id, &default_state)
59 .and_then(|v| v.get_property().copied())
60 .unwrap_or_default();
61 let box_sizing = self
62 .get_box_sizing(nd, &node_id, &default_state)
63 .and_then(|v| v.get_property().copied())
64 .unwrap_or_default();
65 let flex_direction = self
66 .get_flex_direction(nd, &node_id, &default_state)
67 .and_then(|v| v.get_property().copied())
68 .unwrap_or_default();
69 let flex_wrap = self
70 .get_flex_wrap(nd, &node_id, &default_state)
71 .and_then(|v| v.get_property().copied())
72 .unwrap_or_default();
73 let justify_content = self
74 .get_justify_content(nd, &node_id, &default_state)
75 .and_then(|v| v.get_property().copied())
76 .unwrap_or_default();
77 let align_items = self
78 .get_align_items(nd, &node_id, &default_state)
79 .and_then(|v| v.get_property().copied())
80 .unwrap_or_default();
81 let align_content = self
82 .get_align_content(nd, &node_id, &default_state)
83 .and_then(|v| v.get_property().copied())
84 .unwrap_or_default();
85 let writing_mode = self
86 .get_writing_mode(nd, &node_id, &default_state)
87 .and_then(|v| v.get_property().copied())
88 .unwrap_or_default();
89 let clear = self
90 .get_clear(nd, &node_id, &default_state)
91 .and_then(|v| v.get_property().copied())
92 .unwrap_or_default();
93 let font_weight = self
94 .get_font_weight(nd, &node_id, &default_state)
95 .and_then(|v| v.get_property().copied())
96 .unwrap_or_default();
97 let font_style = self
98 .get_font_style(nd, &node_id, &default_state)
99 .and_then(|v| v.get_property().copied())
100 .unwrap_or_default();
101 let text_align = self
102 .get_text_align(nd, &node_id, &default_state)
103 .and_then(|v| v.get_property().copied())
104 .unwrap_or_default();
105 let visibility = self
106 .get_visibility(nd, &node_id, &default_state)
107 .and_then(|v| v.get_property().copied())
108 .unwrap_or_default();
109 let white_space = self
110 .get_white_space(nd, &node_id, &default_state)
111 .and_then(|v| v.get_property().copied())
112 .unwrap_or_default();
113 let direction = self
114 .get_direction(nd, &node_id, &default_state)
115 .and_then(|v| v.get_property().copied())
116 .unwrap_or_default();
117 let vertical_align = self
118 .get_vertical_align(nd, &node_id, &default_state)
119 .and_then(|v| v.get_property().copied())
120 .unwrap_or_default();
121
122 let border_collapse = self
123 .get_border_collapse(nd, &node_id, &default_state)
124 .and_then(|v| v.get_property().copied())
125 .unwrap_or_default();
126
127 result.tier1_enums[i] = encode_tier1(
128 display,
129 position,
130 float,
131 overflow_x,
132 overflow_y,
133 box_sizing,
134 flex_direction,
135 flex_wrap,
136 justify_content,
137 align_items,
138 align_content,
139 writing_mode,
140 clear,
141 font_weight,
142 font_style,
143 text_align,
144 visibility,
145 white_space,
146 direction,
147 vertical_align,
148 border_collapse,
149 );
150
151 if let Some(val) = self.get_width(nd, &node_id, &default_state) {
157 result.tier2_dims[i].width = encode_layout_width(val);
158 }
159 if let Some(val) = self.get_height(nd, &node_id, &default_state) {
160 result.tier2_dims[i].height = encode_layout_height(val);
161 }
162
163 if let Some(val) = self.get_min_width(nd, &node_id, &default_state) {
165 result.tier2_dims[i].min_width = encode_pixel_prop(val);
166 }
167 if let Some(val) = self.get_max_width(nd, &node_id, &default_state) {
168 result.tier2_dims[i].max_width = encode_pixel_prop(val);
169 }
170 if let Some(val) = self.get_min_height(nd, &node_id, &default_state) {
171 result.tier2_dims[i].min_height = encode_pixel_prop(val);
172 }
173 if let Some(val) = self.get_max_height(nd, &node_id, &default_state) {
174 result.tier2_dims[i].max_height = encode_pixel_prop(val);
175 }
176
177 if let Some(val) = self.get_flex_basis(nd, &node_id, &default_state) {
179 result.tier2_dims[i].flex_basis = encode_flex_basis(val);
180 }
181
182 if let Some(val) = self.get_font_size(nd, &node_id, &default_state) {
184 result.tier2_dims[i].font_size = encode_pixel_prop(val);
185 }
186
187 if let Some(val) = self.get_padding_top(nd, &node_id, &default_state) {
189 result.tier2_dims[i].padding_top = encode_css_pixel_as_i16(val);
190 }
191 if let Some(val) = self.get_padding_right(nd, &node_id, &default_state) {
192 result.tier2_dims[i].padding_right = encode_css_pixel_as_i16(val);
193 }
194 if let Some(val) = self.get_padding_bottom(nd, &node_id, &default_state) {
195 result.tier2_dims[i].padding_bottom = encode_css_pixel_as_i16(val);
196 }
197 if let Some(val) = self.get_padding_left(nd, &node_id, &default_state) {
198 result.tier2_dims[i].padding_left = encode_css_pixel_as_i16(val);
199 }
200
201 if let Some(val) = self.get_margin_top(nd, &node_id, &default_state) {
203 result.tier2_dims[i].margin_top = encode_margin_i16(val);
204 }
205 if let Some(val) = self.get_margin_right(nd, &node_id, &default_state) {
206 result.tier2_dims[i].margin_right = encode_margin_i16(val);
207 }
208 if let Some(val) = self.get_margin_bottom(nd, &node_id, &default_state) {
209 result.tier2_dims[i].margin_bottom = encode_margin_i16(val);
210 }
211 if let Some(val) = self.get_margin_left(nd, &node_id, &default_state) {
212 result.tier2_dims[i].margin_left = encode_margin_i16(val);
213 }
214
215 if let Some(val) = self.get_border_top_width(nd, &node_id, &default_state) {
217 result.tier2_dims[i].border_top_width = encode_css_pixel_as_i16(val);
218 }
219 if let Some(val) = self.get_border_right_width(nd, &node_id, &default_state) {
220 result.tier2_dims[i].border_right_width = encode_css_pixel_as_i16(val);
221 }
222 if let Some(val) = self.get_border_bottom_width(nd, &node_id, &default_state) {
223 result.tier2_dims[i].border_bottom_width = encode_css_pixel_as_i16(val);
224 }
225 if let Some(val) = self.get_border_left_width(nd, &node_id, &default_state) {
226 result.tier2_dims[i].border_left_width = encode_css_pixel_as_i16(val);
227 }
228
229 if let Some(val) = self.get_top(nd, &node_id, &default_state) {
231 result.tier2_dims[i].top = encode_css_pixel_as_i16(val);
232 }
233 if let Some(val) = self.get_right(nd, &node_id, &default_state) {
234 result.tier2_dims[i].right = encode_css_pixel_as_i16(val);
235 }
236 if let Some(val) = self.get_bottom(nd, &node_id, &default_state) {
237 result.tier2_dims[i].bottom = encode_css_pixel_as_i16(val);
238 }
239 if let Some(val) = self.get_left(nd, &node_id, &default_state) {
240 result.tier2_dims[i].left = encode_css_pixel_as_i16(val);
241 }
242
243 if let Some(val) = self.get_flex_grow(nd, &node_id, &default_state) {
245 if let Some(exact) = val.get_property() {
246 result.tier2_dims[i].flex_grow = encode_flex_u16(exact.inner.get());
247 }
248 }
249 if let Some(val) = self.get_flex_shrink(nd, &node_id, &default_state) {
250 if let Some(exact) = val.get_property() {
251 result.tier2_dims[i].flex_shrink = encode_flex_u16(exact.inner.get());
252 }
253 }
254
255 if let Some(val) = self.get_z_index(nd, &node_id, &default_state) {
257 if let Some(exact) = val.get_property() {
258 match exact {
259 LayoutZIndex::Auto => result.tier2_dims[i].z_index = I16_AUTO,
260 LayoutZIndex::Integer(z) => {
261 if *z >= I16_SENTINEL_THRESHOLD as i32 {
262 result.tier2_dims[i].z_index = I16_SENTINEL;
263 } else {
264 result.tier2_dims[i].z_index = *z as i16;
265 }
266 }
267 }
268 }
269 }
270
271 {
273 let bts = self.get_border_top_style(nd, &node_id, &default_state)
274 .and_then(|v| v.get_property().copied())
275 .map(|v| v.inner)
276 .unwrap_or_default();
277 let brs = self.get_border_right_style(nd, &node_id, &default_state)
278 .and_then(|v| v.get_property().copied())
279 .map(|v| v.inner)
280 .unwrap_or_default();
281 let bbs = self.get_border_bottom_style(nd, &node_id, &default_state)
282 .and_then(|v| v.get_property().copied())
283 .map(|v| v.inner)
284 .unwrap_or_default();
285 let bls = self.get_border_left_style(nd, &node_id, &default_state)
286 .and_then(|v| v.get_property().copied())
287 .map(|v| v.inner)
288 .unwrap_or_default();
289 result.tier2_dims[i].border_styles_packed =
290 encode_border_styles_packed(bts, brs, bbs, bls);
291 }
292
293 if let Some(val) = self.get_border_top_color(nd, &node_id, &default_state) {
295 if let Some(color) = val.get_property() {
296 result.tier2_dims[i].border_top_color = encode_color_u32(&color.inner);
297 }
298 }
299 if let Some(val) = self.get_border_right_color(nd, &node_id, &default_state) {
300 if let Some(color) = val.get_property() {
301 result.tier2_dims[i].border_right_color = encode_color_u32(&color.inner);
302 }
303 }
304 if let Some(val) = self.get_border_bottom_color(nd, &node_id, &default_state) {
305 if let Some(color) = val.get_property() {
306 result.tier2_dims[i].border_bottom_color = encode_color_u32(&color.inner);
307 }
308 }
309 if let Some(val) = self.get_border_left_color(nd, &node_id, &default_state) {
310 if let Some(color) = val.get_property() {
311 result.tier2_dims[i].border_left_color = encode_color_u32(&color.inner);
312 }
313 }
314
315 if let Some(val) = self.get_border_spacing(nd, &node_id, &default_state) {
317 if let Some(spacing) = val.get_property() {
318 if spacing.horizontal.metric == SizeMetric::Px {
319 result.tier2_dims[i].border_spacing_h = encode_resolved_px_i16(spacing.horizontal.number.get());
320 }
321 if spacing.vertical.metric == SizeMetric::Px {
322 result.tier2_dims[i].border_spacing_v = encode_resolved_px_i16(spacing.vertical.number.get());
323 }
324 }
325 }
326
327 if let Some(val) = self.get_tab_size(nd, &node_id, &default_state) {
329 result.tier2_dims[i].tab_size = encode_css_pixel_as_i16(val);
330 }
331
332 if let Some(val) = self.get_text_color(nd, &node_id, &default_state) {
338 if let Some(color) = val.get_property() {
339 let c = &color.inner;
340 result.tier2b_text[i].text_color =
341 ((c.r as u32) << 24) | ((c.g as u32) << 16) | ((c.b as u32) << 8) | (c.a as u32);
342 }
343 }
344
345 if let Some(val) = self.get_font_family(nd, &node_id, &default_state) {
347 if let Some(families) = val.get_property() {
348 let mut hasher = DefaultHasher::new();
349 families.hash(&mut hasher);
350 let h = hasher.finish();
351 result.tier2b_text[i].font_family_hash = if h == 0 { 1 } else { h };
353 }
354 }
355
356 if let Some(val) = self.get_line_height(nd, &node_id, &default_state) {
358 if let Some(lh) = val.get_property() {
359 let pct_x10 = (lh.inner.normalized() * 1000.0).round() as i32;
363 if pct_x10 >= -32768 && pct_x10 < I16_SENTINEL_THRESHOLD as i32 {
364 result.tier2b_text[i].line_height = pct_x10 as i16;
365 } else {
366 result.tier2b_text[i].line_height = I16_SENTINEL;
367 }
368 }
369 }
370
371 if let Some(val) = self.get_letter_spacing(nd, &node_id, &default_state) {
373 result.tier2b_text[i].letter_spacing = encode_css_pixel_as_i16(val);
374 }
375
376 if let Some(val) = self.get_word_spacing(nd, &node_id, &default_state) {
378 result.tier2b_text[i].word_spacing = encode_css_pixel_as_i16(val);
379 }
380
381 if let Some(val) = self.get_text_indent(nd, &node_id, &default_state) {
383 result.tier2b_text[i].text_indent = encode_css_pixel_as_i16(val);
384 }
385 }
386
387 result
388 }
389}
390
391fn encode_layout_width<T: LayoutWidthLike>(val: &CssPropertyValue<T>) -> u32 {
397 match val {
398 CssPropertyValue::Exact(w) => w.encode_compact_u32(),
399 CssPropertyValue::Auto => U32_AUTO,
400 CssPropertyValue::Initial => U32_INITIAL,
401 CssPropertyValue::Inherit => U32_INHERIT,
402 CssPropertyValue::None => U32_NONE,
403 _ => U32_SENTINEL,
404 }
405}
406
407fn encode_layout_height<T: LayoutWidthLike>(val: &CssPropertyValue<T>) -> u32 {
409 encode_layout_width(val)
410}
411
412trait LayoutWidthLike {
415 fn encode_compact_u32(&self) -> u32;
416}
417
418impl LayoutWidthLike for LayoutWidth {
419 fn encode_compact_u32(&self) -> u32 {
420 match self {
421 LayoutWidth::Auto => U32_AUTO,
422 LayoutWidth::Px(pv) => encode_pixel_value_u32(pv),
423 LayoutWidth::MinContent => U32_MIN_CONTENT,
424 LayoutWidth::MaxContent => U32_MAX_CONTENT,
425 LayoutWidth::Calc(_) => U32_SENTINEL, }
427 }
428}
429
430impl LayoutWidthLike for LayoutHeight {
431 fn encode_compact_u32(&self) -> u32 {
432 match self {
433 LayoutHeight::Auto => U32_AUTO,
434 LayoutHeight::Px(pv) => encode_pixel_value_u32(pv),
435 LayoutHeight::MinContent => U32_MIN_CONTENT,
436 LayoutHeight::MaxContent => U32_MAX_CONTENT,
437 LayoutHeight::Calc(_) => U32_SENTINEL,
438 }
439 }
440}
441
442fn encode_pixel_prop<T: HasInnerPixelValue>(val: &CssPropertyValue<T>) -> u32 {
444 match val {
445 CssPropertyValue::Exact(inner) => encode_pixel_value_u32(&inner.get_inner_pixel()),
446 CssPropertyValue::Auto => U32_AUTO,
447 CssPropertyValue::Initial => U32_INITIAL,
448 CssPropertyValue::Inherit => U32_INHERIT,
449 CssPropertyValue::None => U32_NONE,
450 _ => U32_SENTINEL,
451 }
452}
453
454trait HasInnerPixelValue {
456 fn get_inner_pixel(&self) -> azul_css::props::basic::pixel::PixelValue;
457}
458
459macro_rules! impl_has_inner_pixel {
460 ($($ty:ty),*) => {
461 $(
462 impl HasInnerPixelValue for $ty {
463 fn get_inner_pixel(&self) -> azul_css::props::basic::pixel::PixelValue {
464 self.inner
465 }
466 }
467 )*
468 };
469}
470
471impl_has_inner_pixel!(
472 azul_css::props::layout::dimensions::LayoutMinWidth,
473 azul_css::props::layout::dimensions::LayoutMaxWidth,
474 azul_css::props::layout::dimensions::LayoutMinHeight,
475 azul_css::props::layout::dimensions::LayoutMaxHeight,
476 azul_css::props::basic::font::StyleFontSize,
477 azul_css::props::layout::spacing::LayoutPaddingTop,
478 azul_css::props::layout::spacing::LayoutPaddingRight,
479 azul_css::props::layout::spacing::LayoutPaddingBottom,
480 azul_css::props::layout::spacing::LayoutPaddingLeft,
481 azul_css::props::layout::spacing::LayoutMarginTop,
482 azul_css::props::layout::spacing::LayoutMarginRight,
483 azul_css::props::layout::spacing::LayoutMarginBottom,
484 azul_css::props::layout::spacing::LayoutMarginLeft,
485 azul_css::props::style::border::LayoutBorderTopWidth,
486 azul_css::props::style::border::LayoutBorderRightWidth,
487 azul_css::props::style::border::LayoutBorderBottomWidth,
488 azul_css::props::style::border::LayoutBorderLeftWidth,
489 azul_css::props::layout::position::LayoutTop,
490 azul_css::props::layout::position::LayoutRight,
491 azul_css::props::layout::position::LayoutInsetBottom,
492 azul_css::props::layout::position::LayoutLeft,
493 azul_css::props::style::text::StyleLetterSpacing,
494 azul_css::props::style::text::StyleWordSpacing,
495 azul_css::props::style::text::StyleTextIndent,
496 azul_css::props::style::text::StyleTabSize
497);
498
499fn encode_css_pixel_as_i16<T: HasInnerPixelValue>(val: &CssPropertyValue<T>) -> i16 {
502 match val {
503 CssPropertyValue::Exact(inner) => {
504 let pv = inner.get_inner_pixel();
505 if pv.metric == SizeMetric::Px {
506 encode_resolved_px_i16(pv.number.get())
507 } else {
508 I16_SENTINEL }
510 }
511 CssPropertyValue::Auto => I16_AUTO,
512 CssPropertyValue::Initial => I16_INITIAL,
513 CssPropertyValue::Inherit => I16_INHERIT,
514 _ => I16_SENTINEL,
515 }
516}
517
518fn encode_margin_i16<T: HasInnerPixelValue>(val: &CssPropertyValue<T>) -> i16 {
520 encode_css_pixel_as_i16(val)
521}
522
523fn encode_flex_basis(val: &CssPropertyValue<LayoutFlexBasis>) -> u32 {
525 match val {
526 CssPropertyValue::Exact(fb) => match fb {
527 LayoutFlexBasis::Auto => U32_AUTO,
528 LayoutFlexBasis::Exact(pv) => encode_pixel_value_u32(pv),
529 },
530 CssPropertyValue::Auto => U32_AUTO,
531 CssPropertyValue::Initial => U32_INITIAL,
532 CssPropertyValue::Inherit => U32_INHERIT,
533 CssPropertyValue::None => U32_NONE,
534 _ => U32_SENTINEL,
535 }
536}