// +spec:box-model:b3a79e - box assigned same styles as generating element; getters read from styled DOM per node
#[must_use] pub fn get_root_font_size(styled_dom: &StyledDom, _node_state: &StyledNodeState) -> f32 {
// +spec:overflow:3be57c - overflow:hidden disables user scrolling but programmatic scrolling still works
($fn_name:ident, $cache_method:ident, $ua_property:expr, compact_i16 = $compact_method:ident) => {
($fn_name:ident, $cache_method:ident, $return_type:ty, $ua_property:expr, compact = $compact_method:ident) => {
($fn_name:ident, $cache_method:ident, $return_type:ty, $ua_property:expr, compact_u32_dim = $compact_raw_method:ident, $px_variant:path, $auto_variant:path, $min_content_variant:path, $max_content_variant:path) => {
($fn_name:ident, $cache_method:ident, $return_type:ty, $ua_property:expr, compact_u32_struct = $compact_raw_method:ident) => {
azul_css::compact_cache::U32_AUTO | azul_css::compact_cache::U32_NONE => return MultiValue::Auto,
// +spec:overflow:17654b - overflow-block and overflow-inline logical properties resolve to physical overflow based on writing mode
// +spec:overflow:17654b - overflow-block and overflow-inline logical properties resolve to physical overflow based on writing mode
// +spec:writing-modes:3af12f - unicode-bidi does not affect direction for layout; we use direction property directly
// +spec:display-property:346799 - inline-level elements with unicode-bidi:normal have no effect on text ordering
// +spec:writing-modes:3e2632 - unicode-bidi property resolves embedding level for bidi algorithm (LRE/RLE/PDF)
// +spec:writing-modes:d2c94f - direction+unicode-bidi properties map to UAX#9 bidirectional algorithm
// +spec:display-property:db5125 - text-box-trim on inline boxes trims content box to text-box-edge metric
// +spec:display-property:dceb24 - text-box-trim on inline boxes: content edges coincide with text baselines
// +spec:overflow:5d15e2 - block-start/block-end scrollbar gutter follows same rules as inline gutters when auto
#[allow(clippy::match_same_arms)] // enum/value mapping/dispatch table: one arm per input variant (or cross-type bindings that can't merge)
// +spec:writing-modes:257296 - text-orientation getter for vertical typesetting (upright/sideways)
/// * `element_size` - The element's own size (width × height) for % resolution. According to CSS
// +spec:stacking-contexts:ae50ae - z-index specifies stack level; auto resolves to 0 (inherited from parent stacking context)
// +spec:positioning:c041c4 - positioned elements with z-index != auto establish stacking contexts
/// Returns true if z-index is `auto` (the initial value), false if it's an explicit `<integer>`.
#[must_use] pub fn is_z_index_auto(styled_dom: &StyledDom, node_id: Option<NodeId>) -> bool {
/// `background-image` on the root element is `none` AND its `background-color` is `transparent`,
#[allow(clippy::match_same_arms)] // enum/value mapping/dispatch table: one arm per input variant (or cross-type bindings that can't merge)
let get_node_bg = |nid: NodeId, ndata: &azul_core::dom::NodeData, state: &StyledNodeState| {
azul_css::props::style::StyleBackgroundContent::Image(_) => None, // Has image, not transparent
let first_child_state = &styled_dom.styled_nodes.as_container()[first_child].styled_node_state;
/// For HTML documents, if the root `<html>` element has no background (transparent with no image),
let first_child_state = &styled_dom.styled_nodes.as_container()[first_child].styled_node_state;
#[allow(clippy::too_many_lines)] // large but cohesive: single-purpose layout/render/parse routine (one branch per case)
#[allow(clippy::too_many_lines)] // large but cohesive: single-purpose layout/render/parse routine (one branch per case)
let p_top = resolve_padding(get_css_padding_top(styled_dom, node_id, node_state), viewport);
let p_right = resolve_padding(get_css_padding_right(styled_dom, node_id, node_state), viewport);
let p_bottom = resolve_padding(get_css_padding_bottom(styled_dom, node_id, node_state), viewport);
let p_left = resolve_padding(get_css_padding_left(styled_dom, node_id, node_state), viewport);
// Try to get selection background from CSS, otherwise use system color, otherwise hard-coded default
let default_text = system_style.and_then(|ss| ss.colors.selection_text.as_option().copied());
#[must_use] pub fn get_caret_style(styled_dom: &StyledDom, node_id: Option<NodeId>) -> CaretStyle {
.map_or(DEFAULT_CARET_WIDTH_PX, |w| w.inner.to_pixels_internal(0.0, DEFAULT_EM_SIZE, DEFAULT_EM_SIZE));
#[must_use] pub fn get_scrollbar_info_from_layout(node: &LayoutNode) -> ScrollbarRequirements {
#[allow(clippy::match_same_arms)] // enum/value mapping/dispatch table: one arm per input variant (or cross-type bindings that can't merge)
#[must_use] pub const fn blockify_display(raw_display: LayoutDisplay) -> LayoutDisplay {
// +spec:positioning:c31c24 - blockification is a computed-value change for absolute/float/root elements
// +spec:display-property:641ac5 - computed display value applies blockification/inlinification (not "as specified")
// +spec:positioning:ce02a1 - out-of-flow boxes (floated or absolutely positioned) get blockified display
// +spec:font-metrics:f7affa - vertical-align shorthand: maps CSS vertical-align values to inline layout alignment
// +spec:line-height:b41ee3 - percentage vertical-align: raise/lower by % of line-height, 0% = baseline
let shared = if let Some(existing) = bucket.iter().find(|existing| ***existing == built) {
#[allow(clippy::cast_possible_truncation)] // bounded graphics/coord/font/fixed-point/debug-marker cast
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)] // large but cohesive: single-purpose layout/render/parse routine (one branch per case)
/// Panics only on an internal indexing invariant (an in-range `get().unwrap()` over the font-family list).
let font_ref = (0..font_families.len()).find_map(|i| match font_families.get(i).unwrap() {
#[must_use] pub fn get_list_style_type(styled_dom: &StyledDom, dom_id: Option<NodeId>) -> StyleListStyleType {
#[must_use] pub fn get_break_before(styled_dom: &StyledDom, dom_id: Option<NodeId>) -> PageBreak {
#[must_use] pub fn get_break_after(styled_dom: &StyledDom, dom_id: Option<NodeId>) -> PageBreak {
#[must_use] pub fn get_break_inside(styled_dom: &StyledDom, dom_id: Option<NodeId>) -> BreakInside {
use crate::text3::cache::{FontChainKey, FontChainKeyOrRef, FontSelector, FontStack, FontStyle};
fn fontconfig_generic_aliases() -> &'static std::collections::BTreeMap<String, Vec<String>> {
/// Contains all unique font stacks and the mapping from `StyleFontFamiliesHash` to `FontChainKey`
#[must_use] pub fn get_by_chain_key(&self, key: &FontChainKey) -> Option<&FontFallbackChain> {
#[must_use] pub fn get_for_font_stack(&self, font_stack: &[FontSelector]) -> Option<&FontFallbackChain> {
#[must_use] pub fn into_fontconfig_chains(self) -> HashMap<FontChainKey, FontFallbackChain> {
#[allow(clippy::cast_possible_truncation)] // bounded graphics/coord/font/fixed-point/debug-marker cast
#[allow(clippy::too_many_lines)] // large but cohesive: single-purpose layout/render/parse routine (one branch per case)
let mut font_refs: HashMap<usize, azul_css::props::basic::font::FontRef> = HashMap::new();
if disc != unsafe { core::ptr::read_volatile((&raw const node_data.internal[0].node_type).cast::<u8>()) } {
#[must_use] pub fn collect_used_codepoints(styled_dom: &StyledDom) -> std::collections::BTreeSet<u32> {
#[must_use] pub fn collect_used_codepoints_all(styled_dom: &StyledDom) -> std::collections::BTreeSet<char> {
#[must_use] pub fn scripts_present_in_styled_dom(styled_dom: &StyledDom) -> Vec<UnicodeRange> {
faces.and_then(|f| pick_memory_face(f, weight, italic, oblique, MemoryFontTier::Primary))
let mut unresolved: std::collections::BTreeSet<String> = std::collections::BTreeSet::new();
#[must_use] pub fn collect_font_ids_from_chains(chains: &ResolvedFontChains) -> HashSet<FontId> {
#[allow(clippy::implicit_hasher)] // internal helper; only ever called with the default-hasher HashMap/HashSet
#[allow(clippy::implicit_hasher)] // internal helper; only ever called with the default-hasher HashMap/HashSet
#[allow(clippy::implicit_hasher)] // internal helper; only ever called with the default-hasher HashMap/HashSet
#[allow(clippy::too_many_lines)] // large but cohesive: single-purpose layout/render/parse routine (one branch per case)
#[must_use] pub fn is_node_contenteditable(styled_dom: &StyledDom, node_id: NodeId) -> bool {
#[must_use] pub fn get_opacity(styled_dom: &StyledDom, node_id: NodeId, node_state: &StyledNodeState) -> f32 {
#[must_use] pub fn is_node_contenteditable_inherited(styled_dom: &StyledDom, node_id: NodeId) -> bool {
current_node_id = hierarchy.get(nid).and_then(azul_core::styled_dom::NodeHierarchyItem::parent_id);
#[must_use] pub fn find_contenteditable_ancestor(styled_dom: &StyledDom, node_id: NodeId) -> Option<NodeId> {
current_node_id = hierarchy.get(nid).and_then(azul_core::styled_dom::NodeHierarchyItem::parent_id);
let mut dom = Dom::create_body().with_children(vec![Dom::create_text_do_not_use_without_block_level_wrapper(text)].into());
fn get_scrollbar_info_from_layout_returns_whatever_layout_stored_including_degenerate_floats() {
assert!(collect_font_ids_from_chains(&ResolvedFontChains { chains, ..Default::default() }).is_empty());
let half = get_opacity(&body_with_divs(1, "div { opacity: 0.5; }"), NodeId::new(1), &normal());
let nan_vp = get_inline_border_info(&sd, id, &st, &info, PhysicalSize::new(f32::NAN, f32::NAN))