diff --git a/Cargo.lock b/Cargo.lock index 075bd87299efb..6b6cbb7bc8316 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -800,14 +800,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "libweb_css_rust" -version = "0.1.0" -dependencies = [ - "cbindgen", - "serde_json", -] - [[package]] name = "libweb_html_tokenizer" version = "0.1.0" @@ -815,13 +807,6 @@ dependencies = [ "cbindgen", ] -[[package]] -name = "libweb_layout_rust" -version = "0.1.0" -dependencies = [ - "cbindgen", -] - [[package]] name = "libweb_rust" version = "0.1.0" @@ -829,6 +814,7 @@ dependencies = [ "cbindgen", "chardetng", "libweb_html_tokenizer", + "serde_json", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0146a4bed6220..07e6209a4c4f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,10 +8,8 @@ members = [ "Libraries/LibURL/Rust", "Libraries/LibWasm/Rust", "Libraries/LibWeb/ContentBlocker/Rust", - "Libraries/LibWeb/CSS/Rust", "Libraries/LibWeb/Rust", "Libraries/LibWeb/HTML/Parser/Rust", - "Libraries/LibWeb/Layout/Rust", ] exclude = [ "Libraries/LibJS/Flap", diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index b230bb31be7ce..7a9f704718d90 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -1343,29 +1343,13 @@ endforeach() import_rust_crate( MANIFEST_PATH Rust/Cargo.toml CRATE_NAME libweb_rust - FFI_HEADERS HTML/Parser/RustFFI.h -) - -set(layout_rust_features "") -if (NOT BUILD_SHARED_LIBS) - set(layout_rust_features FEATURES allocator) -endif() -import_rust_crate( - MANIFEST_PATH Layout/Rust/Cargo.toml - CRATE_NAME libweb_layout_rust - ${layout_rust_features} - FFI_HEADERS Layout/TreeBuilderRustFFI.h -) - -set(css_rust_features "") -if (NOT BUILD_SHARED_LIBS) - set(css_rust_features FEATURES allocator) -endif() -import_rust_crate( - MANIFEST_PATH CSS/Rust/Cargo.toml - CRATE_NAME libweb_css_rust - ${css_rust_features} - FFI_HEADERS RustFFI.h SelectorRustFFI.h StyleValueRustFFI.h ComputedValuesRustFFI.h + FFI_HEADERS + HTML/Parser/RustFFI.h + RustFFI.h + SelectorRustFFI.h + StyleValueRustFFI.h + ComputedValuesRustFFI.h + Layout/TreeBuilderRustFFI.h ) set(content_blocker_rust_features "") @@ -1373,10 +1357,8 @@ if (NOT BUILD_SHARED_LIBS) set(content_blocker_rust_features FEATURES allocator) endif() import_rust_crate(MANIFEST_PATH ContentBlocker/Rust/Cargo.toml CRATE_NAME libweb_content_blocker_rust ${content_blocker_rust_features} FFI_HEADER ContentBlockerRustFFI.h) -target_link_libraries(LibWeb PRIVATE libweb_rust libweb_layout_rust libweb_css_rust libweb_content_blocker_rust) +target_link_libraries(LibWeb PRIVATE libweb_rust libweb_content_blocker_rust) get_target_property(_libweb_rust_lib libweb_rust IMPORTED_LOCATION) -get_target_property(_libweb_layout_rust_lib libweb_layout_rust IMPORTED_LOCATION) -get_target_property(_libweb_css_rust_lib libweb_css_rust IMPORTED_LOCATION) get_target_property(_libweb_content_blocker_rust_lib libweb_content_blocker_rust IMPORTED_LOCATION) set_property(SOURCE HTML/Parser/HTMLTokenizer.cpp APPEND PROPERTY OBJECT_DEPENDS ${_libweb_rust_lib}) set_property(SOURCE HTML/Parser/HTMLParser.cpp APPEND PROPERTY OBJECT_DEPENDS ${_libweb_rust_lib}) @@ -1388,8 +1370,6 @@ endif() if(NOT BUILD_SHARED_LIBS) add_custom_command(TARGET LibWeb POST_BUILD COMMAND ${CMAKE_AR} -x $ - COMMAND ${CMAKE_AR} -x $ - COMMAND ${CMAKE_AR} -x $ COMMAND ${CMAKE_AR} -x $ COMMAND ${CMAKE_AR} -qS $ *.o COMMAND ${CMAKE_RANLIB} $ @@ -1404,9 +1384,9 @@ if(NOT BUILD_SHARED_LIBS) # stale Rust objects. Force the C++ FFI bridge files to depend on the # Rust archives: when they change, LibWeb re-archives, and POST_BUILD # re-merges the fresh Rust objects. - set_property(SOURCE CSS/Parser/RustTokenizer.cpp APPEND PROPERTY OBJECT_DEPENDS ${_libweb_css_rust_lib}) + set_property(SOURCE CSS/Parser/RustTokenizer.cpp APPEND PROPERTY OBJECT_DEPENDS ${_libweb_rust_lib}) set_property(SOURCE HTML/Parser/HTMLEncodingDetection.cpp APPEND PROPERTY OBJECT_DEPENDS ${_libweb_rust_lib}) - set_property(SOURCE Layout/TreeBuilder.cpp APPEND PROPERTY OBJECT_DEPENDS ${_libweb_layout_rust_lib}) + set_property(SOURCE Layout/TreeBuilder.cpp APPEND PROPERTY OBJECT_DEPENDS ${_libweb_rust_lib}) set_property(SOURCE Loader/ContentBlocker.cpp APPEND PROPERTY OBJECT_DEPENDS ${_libweb_content_blocker_rust_lib}) endif() diff --git a/Libraries/LibWeb/CSS/Rust/Cargo.toml b/Libraries/LibWeb/CSS/Rust/Cargo.toml deleted file mode 100644 index 9ee063c3285c4..0000000000000 --- a/Libraries/LibWeb/CSS/Rust/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "libweb_css_rust" -version = "0.1.0" -edition = "2024" - -[lib] -crate-type = ["staticlib"] - -# After changing dependencies, regenerate the Flatpak sources: -# python3 Meta/CMake/flatpak/generate-cargo-sources.py -[build-dependencies] -cbindgen = "0.29" -serde_json = { version = "1", features = ["float_roundtrip", "preserve_order"] } - -[features] -default = [] -allocator = [] - -[lints] -workspace = true diff --git a/Libraries/LibWeb/CSS/Rust/build.rs b/Libraries/LibWeb/CSS/Rust/build.rs deleted file mode 100644 index 77933e25ec3e4..0000000000000 --- a/Libraries/LibWeb/CSS/Rust/build.rs +++ /dev/null @@ -1,936 +0,0 @@ -/* - * Copyright (c) 2026-present, the Ladybird developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -use std::env; -use std::error::Error; -use std::fmt::Write; -use std::path::{Path, PathBuf}; - -// Mirrors title_casify() in Meta/Utils/utils.py. -fn title_casify(dashy_name: &str) -> String { - dashy_name - .split('-') - .filter(|part| !part.is_empty()) - .map(|part| { - let mut chars = part.chars(); - let first = chars.next().unwrap().to_ascii_uppercase(); - format!("{first}{}", chars.as_str()) - }) - .collect() -} - -fn ordered_pseudo_element_names( - pseudo_elements: &serde_json::Map, -) -> Result, Box> { - let mut synthetic = Vec::new(); - let mut element_reference = Vec::new(); - let mut functional = Vec::new(); - for (name, value) in pseudo_elements { - let object = value.as_object().unwrap(); - if object.contains_key("alias-for") { - continue; - } - if object.get("type").and_then(|value| value.as_str()) == Some("function") { - functional.push(name.clone()); - continue; - } - match object.get("implementation").and_then(|value| value.as_str()) { - Some("synthetic") => synthetic.push(name.clone()), - Some("element-reference") => element_reference.push(name.clone()), - other => return Err(format!("invalid or missing implementation type for ::{name}: {other:?}").into()), - } - } - synthetic.extend(element_reference); - synthetic.extend(functional); - Ok(synthetic) -} - -fn load_property_groups(path: &Path) -> Result>, Box> { - let mut groups = std::collections::HashMap::new(); - let mut current_group = None; - for raw_line in std::fs::read_to_string(path)?.lines() { - let line = raw_line.trim(); - if line.is_empty() || line.starts_with('#') { - continue; - } - if let Some(group) = line.strip_prefix('[').and_then(|line| line.strip_suffix(']')) { - groups.insert(format!("#{group}"), Vec::new()); - current_group = Some(format!("#{group}")); - continue; - } - let Some(group) = current_group.as_ref() else { - return Err(format!("property outside a pseudo-element property group: {line}").into()); - }; - groups.get_mut(group).unwrap().push(line.to_string()); - } - Ok(groups) -} - -fn write_enum_and_from_ffi(output: &mut String, enum_name: &str, variants: &[String]) { - writeln!(output, "#[derive(Clone, Copy, Debug, PartialEq, Eq)]").unwrap(); - writeln!(output, "#[repr(u8)]").unwrap(); - writeln!(output, "pub enum {enum_name} {{").unwrap(); - for variant in variants { - writeln!(output, " {variant},").unwrap(); - } - writeln!(output, "}}").unwrap(); - writeln!(output).unwrap(); - let fn_name = if enum_name == "PseudoClassType" { - "pseudo_class_from_ffi" - } else { - "pseudo_element_from_ffi" - }; - writeln!(output, "fn {fn_name}(value: u8) -> {enum_name} {{").unwrap(); - writeln!(output, " match value {{").unwrap(); - for (index, variant) in variants.iter().enumerate() { - writeln!(output, " {index} => {enum_name}::{variant},").unwrap(); - } - writeln!(output, " _ => panic!(\"invalid {enum_name} {{value}}\"),").unwrap(); - writeln!(output, " }}").unwrap(); - writeln!(output, "}}").unwrap(); - writeln!(output).unwrap(); -} - -// Generates the Rust twins of the C++ PseudoClass and PseudoElement enums from the same JSON -// sources as Meta/Generators/generate_libweb_css_pseudo_{class,element}.py, so the numeric -// values that cross the selector FFI cannot drift out of sync with the C++ side. -fn generate_selector_pseudo_types(manifest_dir: &Path, out_dir: &Path) -> Result<(), Box> { - let css_dir = manifest_dir.parent().unwrap(); - let pseudo_classes_path = css_dir.join("PseudoClasses.json"); - let pseudo_elements_path = css_dir.join("PseudoElements.json"); - println!("cargo:rerun-if-changed={}", pseudo_classes_path.display()); - println!("cargo:rerun-if-changed={}", pseudo_elements_path.display()); - - let parse_object = |path: &Path| -> Result, Box> { - let value: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(path)?)?; - match value { - serde_json::Value::Object(object) => Ok(object), - _ => Err(format!("{} does not contain a JSON object", path.display()).into()), - } - }; - - let pseudo_class_names = parse_object(&pseudo_classes_path)? - .iter() - .filter(|(_, value)| !value.as_object().unwrap().contains_key("legacy-alias-for")) - .map(|(name, _)| title_casify(name)) - .collect::>(); - - let pseudo_elements = parse_object(&pseudo_elements_path)?; - let mut pseudo_element_names = ordered_pseudo_element_names(&pseudo_elements)? - .iter() - .map(|name| title_casify(name)) - .collect::>(); - // NB: The C++ generator emits UnknownWebKit after KnownPseudoElementCount, so its FFI value is - // the number of known pseudo-elements. - pseudo_element_names.push("UnknownWebKit".to_string()); - - let mut output = String::new(); - writeln!( - output, - "// Generated by build.rs from CSS/PseudoClasses.json and CSS/PseudoElements.json." - ) - .unwrap(); - writeln!(output).unwrap(); - write_enum_and_from_ffi(&mut output, "PseudoClassType", &pseudo_class_names); - write_enum_and_from_ffi(&mut output, "PseudoElementType", &pseudo_element_names); - - std::fs::write(out_dir.join("selector_pseudo_generated.rs"), output)?; - Ok(()) -} - -// Generates the property metadata tables for the Rust style computation core from -// Properties.json, replicating the C++ generator's identifier assignment exactly: -// Custom is 0, then shorthands, inherited longhands and non-inherited longhands in -// JSON order, skipping legacy aliases. A C++ unit test compares the tables against -// the C++-generated equivalents so the two generators cannot drift. -fn generate_property_metadata(manifest_dir: &Path, out_dir: &Path) -> Result<(), Box> { - let properties_path = manifest_dir.parent().unwrap().join("Properties.json"); - println!("cargo:rerun-if-changed={}", properties_path.display()); - - let value: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&properties_path)?)?; - let serde_json::Value::Object(properties) = value else { - return Err("Properties.json does not contain a JSON object".into()); - }; - - // Logical alias properties take their metadata from the first physical property of - // their logical group, with local overrides, mirroring the C++ generator. - let groups_path = manifest_dir.parent().unwrap().join("LogicalPropertyGroups.json"); - println!("cargo:rerun-if-changed={}", groups_path.display()); - let groups_value: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&groups_path)?)?; - let serde_json::Value::Object(groups) = groups_value else { - return Err("LogicalPropertyGroups.json does not contain a JSON object".into()); - }; - let first_physical_in_group = - |group_name: &str| -> Option<&str> { groups[group_name]["physical"].as_object()?.values().next()?.as_str() }; - let property_field = |name: &str, field: &str| -> Option { - let object = properties[name].as_object().unwrap(); - if let Some(value) = object.get(field) { - return Some(value.clone()); - } - let group = object.get("logical-alias-for")?.as_object()?.get("group")?.as_str()?; - let physical = first_physical_in_group(group)?; - properties[physical].as_object().unwrap().get(field).cloned() - }; - - let mut shorthands = Vec::new(); - let mut inherited_longhands = Vec::new(); - let mut noninherited_longhands = Vec::new(); - for (name, value) in &properties { - let object = value.as_object().unwrap(); - if object.contains_key("legacy-alias-for") { - continue; - } - // NB: The C++ generator populates the "all" shorthand's longhand list - // programmatically, so it has no explicit "longhands" key. - if object.contains_key("longhands") || name == "all" { - shorthands.push(name.clone()); - } else if property_field(name, "inherited").unwrap().as_bool().unwrap() { - inherited_longhands.push(name.clone()); - } else { - noninherited_longhands.push(name.clone()); - } - } - - // Identifier assignment: Custom = 0, then the three runs in order. - let mut ids = std::collections::HashMap::new(); - for (index, name) in shorthands - .iter() - .chain(&inherited_longhands) - .chain(&noninherited_longhands) - .enumerate() - { - ids.insert(name.clone(), (index + 1) as u16); - } - let first_longhand = ids[&inherited_longhands[0]]; - let last_longhand = ids[noninherited_longhands.last().unwrap()]; - let first_inherited = ids[&inherited_longhands[0]]; - let last_inherited = ids[inherited_longhands.last().unwrap()]; - - let pseudo_elements_path = manifest_dir.parent().unwrap().join("PseudoElements.json"); - let property_groups_path = manifest_dir.parent().unwrap().join("PseudoElementPropertyGroups.txt"); - println!("cargo:rerun-if-changed={}", pseudo_elements_path.display()); - println!("cargo:rerun-if-changed={}", property_groups_path.display()); - let pseudo_elements_value: serde_json::Value = - serde_json::from_str(&std::fs::read_to_string(&pseudo_elements_path)?)?; - let serde_json::Value::Object(pseudo_elements) = pseudo_elements_value else { - return Err("PseudoElements.json does not contain a JSON object".into()); - }; - let property_groups = load_property_groups(&property_groups_path)?; - let property_id = |name: &str| -> Result> { - if name == "custom" { - return Ok(0); - } - ids.get(name) - .copied() - .ok_or_else(|| format!("unknown pseudo-element property '{name}'").into()) - }; - let property_ids = |entries: &[String]| -> Result, Box> { - let mut result = std::collections::BTreeSet::new(); - for entry in entries { - if entry.starts_with("FIXME:") { - continue; - } - if let Some(properties) = property_groups.get(entry) { - for property in properties { - result.insert(property_id(property)?); - } - } else if entry.starts_with('#') { - return Err(format!("unknown pseudo-element property group '{entry}'").into()); - } else { - result.insert(property_id(entry)?); - } - } - Ok(result.into_iter().collect()) - }; - let always_allowed_pseudo_properties = property_ids( - property_groups - .get("#always-allowed-properties") - .ok_or("missing always-allowed pseudo-element property group")?, - )?; - let mut pseudo_property_whitelist_rows = Vec::new(); - for name in ordered_pseudo_element_names(&pseudo_elements)? { - let object = pseudo_elements[&name].as_object().unwrap(); - let Some(whitelist) = object.get("property-whitelist") else { - pseudo_property_whitelist_rows.push(" None,".to_string()); - continue; - }; - let entries = whitelist - .as_array() - .unwrap() - .iter() - .map(|entry| entry.as_str().unwrap().to_string()) - .collect::>(); - let whitelist = property_ids(&entries)?; - pseudo_property_whitelist_rows.push(format!(" Some(&{whitelist:?}),")); - } - // UnknownWebKit follows the known pseudo-elements and accepts all properties. - pseudo_property_whitelist_rows.push(" None,".to_string()); - - // NB: Must match manually_specified_computation_order in - // Meta/Generators/generate_libweb_css_property_id.py; the parity test enforces it. - let manual_order = [ - "math-depth", - "font-family", - "font-feature-settings", - "font-kerning", - "font-optical-sizing", - "font-size", - "font-style", - "font-variant-alternates", - "font-variant-caps", - "font-variant-east-asian", - "font-variant-emoji", - "font-variant-ligatures", - "font-variant-numeric", - "font-variant-position", - "font-variation-settings", - "font-weight", - "font-width", - "text-rendering", - "line-height", - "color-scheme", - "background-image", - "direction", - "writing-mode", - ]; - let mut order = Vec::new(); - for name in manual_order { - order.push(ids[name]); - } - // NB: The remainder follows Properties.json iteration order across all longhands, - // matching the C++ generator, not grouped by inheritance. - for (name, value) in &properties { - let object = value.as_object().unwrap(); - if object.contains_key("legacy-alias-for") || object.contains_key("longhands") || name == "all" { - continue; - } - if !manual_order.contains(&name.as_str()) { - order.push(ids[name]); - } - } - - let mut levels = vec![0u8; (last_longhand - first_longhand + 1) as usize]; - let mut animation_types = vec![0u8; levels.len()]; - let mut numeric_range_rows = vec![String::new(); levels.len()]; - let value_types = [ - "anchor", - "anchor-size", - "angle", - "angle-percentage", - "background-position", - "basic-shape", - "color", - "corner-shape", - "counter", - "counter-style", - "custom-ident", - "dashed-ident", - "easing-function", - "filter-value-list", - "fit-content", - "flex", - "font-style", - "font-variant-alternates", - "font-variant-east-asian", - "font-variant-ligatures", - "font-variant-numeric", - "frequency", - "frequency-percentage", - "image", - "integer", - "length", - "length-percentage", - "number", - "opacity-value", - "opentype-tag", - "paint", - "percentage", - "position", - "ratio", - "rect", - "resolution", - "scroll-function", - "string", - "time", - "time-percentage", - "transform-function", - "transform-list", - "url", - "view-function", - "view-timeline-inset", - ]; - for name in inherited_longhands.iter().chain(&noninherited_longhands) { - let index = (ids[name] - first_longhand) as usize; - let requires_computation = property_field(name, "requires-computation").unwrap(); - let level = match requires_computation.as_str().unwrap() { - "never" => 0u8, - "cascaded-value" => 1, - "non-inherited-value" => 2, - "always" => 3, - other => return Err(format!("unknown requires-computation '{other}' for {name}").into()), - }; - levels[index] = level; - - animation_types[index] = match property_field(name, "animation-type").unwrap().as_str().unwrap() { - "discrete" => 0, - "by-computed-value" => 1, - "repeatable-list" => 2, - "custom" => 3, - "none" => 4, - other => return Err(format!("unknown animation-type '{other}' for {name}").into()), - }; - - let mut ranges = Vec::new(); - if let Some(valid_types) = property_field(name, "valid-types").and_then(|value| value.as_array().cloned()) { - for valid_type in valid_types { - let valid_type = valid_type.as_str().unwrap(); - let Some((type_name, range)) = valid_type.split_once(' ') else { - continue; - }; - if !range.starts_with('[') || !range.ends_with(']') || !range.contains(',') { - continue; - } - if type_name == "custom-ident" { - continue; - } - let value_type = value_types - .iter() - .position(|candidate| *candidate == type_name) - .ok_or_else(|| format!("unknown ranged value type '{type_name}' for {name}"))?; - let (min, max) = range[1..range.len() - 1] - .split_once(',') - .ok_or_else(|| format!("bad numeric range '{range}' for {name}"))?; - let format_bound = |bound: &str| match (type_name, bound) { - ("integer", "-∞") => "i32::MIN as f64".to_string(), - ("integer", "∞") => "i32::MAX as f64".to_string(), - (_, "-∞") => "f32::MIN as f64".to_string(), - (_, "∞") => "f32::MAX as f64".to_string(), - _ if bound.contains('.') => bound.to_string(), - _ => format!("{bound}.0"), - }; - ranges.push(format!( - "FfiPropertyNumericRange {{ value_type: {value_type}, min: {}, max: {} }}", - format_bound(min), - format_bound(max) - )); - } - } - numeric_range_rows[index] = ranges.join(", "); - } - - let mut output = String::new(); - output.push_str("// Generated by build.rs from CSS metadata. Do not edit.\n\n"); - // Shorthand expansion tables for the cascade. The "all" shorthand expands to every - // longhand except direction and unicode-bidi, mirroring the C++ generator. - let mut shorthand_rows = Vec::new(); - for name in &shorthands { - let longhand_names: Vec = if name == "all" { - properties - .iter() - .filter(|(name, value)| { - let object = value.as_object().unwrap(); - !object.contains_key("longhands") - && !object.contains_key("legacy-alias-for") - && name.as_str() != "all" - && name.as_str() != "direction" - && name.as_str() != "unicode-bidi" - }) - .map(|(name, _)| name.clone()) - .collect() - } else { - properties[name]["longhands"] - .as_array() - .unwrap() - .iter() - .map(|longhand| longhand.as_str().unwrap().to_string()) - .collect() - }; - let ids_row: Vec = longhand_names.iter().map(|longhand| ids[longhand]).collect(); - shorthand_rows.push(format!(" &{ids_row:?},")); - } - output.push_str(&format!( - "pub(crate) static SHORTHAND_EXPANSIONS: [&[u16]; {}] = [\n{}\n];\n\n", - shorthand_rows.len(), - shorthand_rows.join("\n") - )); - let property_names: Vec<&str> = shorthands - .iter() - .chain(&inherited_longhands) - .chain(&noninherited_longhands) - .map(String::as_str) - .collect(); - fn expanded_longhands( - name: &str, - properties: &serde_json::Map, - all_longhands: &[String], - result: &mut Vec, - ) { - if name == "all" { - result.extend_from_slice(all_longhands); - return; - } - let Some(longhands) = properties[name].get("longhands").and_then(|value| value.as_array()) else { - result.push(name.to_string()); - return; - }; - for longhand in longhands { - expanded_longhands(longhand.as_str().unwrap(), properties, all_longhands, result); - } - } - let all_longhands: Vec = inherited_longhands - .iter() - .chain(&noninherited_longhands) - .filter(|name| name.as_str() != "direction" && name.as_str() != "unicode-bidi") - .cloned() - .collect(); - let expanded_shorthand_longhands: Vec> = shorthands - .iter() - .map(|name| { - let mut result = Vec::new(); - expanded_longhands(name, &properties, &all_longhands, &mut result); - result - }) - .collect(); - let camel_case_property_name = |name: &str| { - let mut parts = name.split('-').filter(|part| !part.is_empty()); - let mut result = parts.next().unwrap_or_default().to_string(); - for part in parts { - let mut characters = part.chars(); - if let Some(first) = characters.next() { - result.extend(first.to_uppercase()); - result.extend(characters); - } - } - result - }; - let idl_names: Vec = property_names - .iter() - .map(|name| camel_case_property_name(name)) - .collect(); - let logical_aliases: Vec = property_names - .iter() - .enumerate() - .map(|(index, name)| { - let name: &str = if index < shorthands.len() { - expanded_shorthand_longhands[index][0].as_str() - } else { - name - }; - properties[name].as_object().unwrap().contains_key("logical-alias-for") - }) - .collect(); - let expanded_longhand_counts: Vec = expanded_shorthand_longhands.iter().map(Vec::len).collect(); - output.push_str(&format!( - "pub(crate) static PROPERTY_IDL_NAMES: [&str; {}] = {:?};\n", - idl_names.len(), - idl_names - )); - output.push_str(&format!( - "pub(crate) static PROPERTY_IS_LOGICAL_ALIAS: [bool; {}] = {:?};\n\n", - logical_aliases.len(), - logical_aliases - )); - output.push_str(&format!( - "pub(crate) static SHORTHAND_EXPANDED_LONGHAND_COUNTS: [usize; {}] = {:?};\n\n", - expanded_longhand_counts.len(), - expanded_longhand_counts - )); - output.push_str(&format!( - "pub const FIRST_SHORTHAND_PROPERTY_ID: u16 = {};\n", - ids[&shorthands[0]] - )); - output.push_str(&format!( - "pub const LAST_SHORTHAND_PROPERTY_ID: u16 = {};\n\n", - ids[shorthands.last().unwrap()] - )); - output.push_str("#[allow(dead_code)]\npub mod property_id {\n"); - output.push_str(" pub const CUSTOM: u16 = 0;\n"); - for name in shorthands - .iter() - .chain(&inherited_longhands) - .chain(&noninherited_longhands) - { - let constant = name.replace('-', "_").to_uppercase(); - output.push_str(&format!(" pub const {constant}: u16 = {};\n", ids[name])); - } - output.push_str("}\n\n"); - output.push_str(&format!( - "pub const FIRST_LONGHAND_PROPERTY_ID: u16 = {first_longhand};\n" - )); - output.push_str(&format!( - "pub const LAST_LONGHAND_PROPERTY_ID: u16 = {last_longhand};\n" - )); - output.push_str(&format!( - "pub const FIRST_INHERITED_PROPERTY_ID: u16 = {first_inherited};\n" - )); - output.push_str(&format!( - "pub const LAST_INHERITED_PROPERTY_ID: u16 = {last_inherited};\n\n" - )); - output.push_str(&format!( - "pub(crate) static PROPERTY_COMPUTATION_ORDER: [u16; {}] = {:?};\n\n", - order.len(), - order - )); - output.push_str(&format!( - "pub(crate) static REQUIRES_COMPUTATION_LEVELS: [u8; {}] = {:?};\n", - levels.len(), - levels - )); - output.push_str(&format!( - "pub(crate) static PROPERTY_ANIMATION_TYPES: [u8; {}] = {:?};\n", - animation_types.len(), - animation_types - )); - output.push_str(&format!( - "pub(crate) static PROPERTY_NUMERIC_RANGES: [&[FfiPropertyNumericRange]; {}] = [\n{}\n];\n", - numeric_range_rows.len(), - numeric_range_rows - .iter() - .map(|ranges| format!(" &[{ranges}],")) - .collect::>() - .join("\n") - )); - output.push_str(&format!( - "\npub(crate) static PSEUDO_ELEMENT_ALWAYS_ALLOWED_PROPERTIES: &[u16] = &{always_allowed_pseudo_properties:?};\n" - )); - output.push_str(&format!( - "pub(crate) static PSEUDO_ELEMENT_PROPERTY_WHITELISTS: [Option<&[u16]>; {}] = [\n{}\n];\n", - pseudo_property_whitelist_rows.len(), - pseudo_property_whitelist_rows.join("\n") - )); - std::fs::write(out_dir.join("property_metadata_generated.rs"), output)?; - Ok(()) -} - -// Generates the length unit table for the Rust style computation core from Units.json. -// Unit codes are the alphabetical index within the "length" object, matching the C++ -// LengthUnit enum; absolute units carry their canonical px ratio. -fn generate_length_units(manifest_dir: &Path, out_dir: &Path) -> Result<(), Box> { - let units_path = manifest_dir.parent().unwrap().join("Units.json"); - println!("cargo:rerun-if-changed={}", units_path.display()); - let value: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&units_path)?)?; - let lengths = value["length"].as_object().ok_or("Units.json has no length object")?; - - let mut names = Vec::new(); - let mut ratios = Vec::new(); - for (name, unit) in lengths { - names.push(name.clone()); - let object = unit.as_object().unwrap(); - if object - .get("is-canonical-unit") - .is_some_and(|canonical| canonical.as_bool() == Some(true)) - { - ratios.push("1.0".to_string()); - } else if let Some(ratio) = object.get("number-of-canonical-unit") { - ratios.push(format!("{:?}", ratio.as_f64().unwrap())); - } else { - ratios.push("f64::NAN".to_string()); - } - } - - let mut output = String::new(); - output.push_str("// Generated by build.rs from Units.json. Do not edit.\n\n"); - output.push_str(&format!( - "pub(crate) static LENGTH_UNIT_NAMES: [&str; {}] = {:?};\n\n", - names.len(), - names - )); - output.push_str(&format!( - "pub(crate) static LENGTH_UNIT_CANONICAL_PX_RATIOS: [f64; {}] = [{}];\n", - ratios.len(), - ratios.join(", ") - )); - std::fs::write(out_dir.join("length_units_generated.rs"), output)?; - - // Canonical-unit ratios for the other dimensions, indexed by unit code in - // JSON order like the C++ unit enums. Relative units (none exist outside - // lengths) would be NaN. - let mut output = String::from("// Generated by build.rs from Units.json. Do not edit.\n"); - for dimension in ["angle", "flex", "frequency", "resolution", "time"] { - let units = value[dimension] - .as_object() - .ok_or_else(|| format!("Units.json has no {dimension} object"))?; - let mut ratios = Vec::new(); - for (_, unit) in units { - let object = unit.as_object().unwrap(); - if object - .get("is-canonical-unit") - .is_some_and(|canonical| canonical.as_bool() == Some(true)) - { - ratios.push("1.0".to_string()); - } else if let Some(ratio) = object.get("number-of-canonical-unit") { - ratios.push(format!("{:?}", ratio.as_f64().unwrap())); - } else { - ratios.push("f64::NAN".to_string()); - } - } - output.push_str(&format!( - "\npub(crate) static {}_UNIT_CANONICAL_RATIOS: [f64; {}] = [{}];\n", - dimension.to_uppercase(), - ratios.len(), - ratios.join(", ") - )); - let names: Vec<&str> = units.keys().map(String::as_str).collect(); - output.push_str(&format!( - "\n#[allow(dead_code)]\npub(crate) static {}_UNIT_NAMES: [&str; {}] = {:?};\n", - dimension.to_uppercase(), - names.len(), - names - )); - } - std::fs::write(out_dir.join("dimension_units_generated.rs"), output)?; - Ok(()) -} - -// Generates keyword codes for the Rust style computation core from Keywords.json. -// Invalid is 0 and the codes follow the array order, matching the C++ Keyword enum. -fn generate_keywords(manifest_dir: &Path, out_dir: &Path) -> Result<(), Box> { - let keywords_path = manifest_dir.parent().unwrap().join("Keywords.json"); - println!("cargo:rerun-if-changed={}", keywords_path.display()); - let value: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&keywords_path)?)?; - let keywords = value.as_array().ok_or("Keywords.json is not an array")?; - - let mut output = String::new(); - output.push_str("// Generated by build.rs from Keywords.json. Do not edit.\n\n"); - output.push_str("#[allow(dead_code)]\npub mod keyword {\n"); - output.push_str(" pub const INVALID: u16 = 0;\n"); - for (index, keyword) in keywords.iter().enumerate() { - let name = keyword.as_str().unwrap(); - let constant = name.replace('-', "_").to_uppercase(); - output.push_str(&format!(" pub const {constant}: u16 = {};\n", index + 1)); - } - output.push_str("}\n"); - std::fs::write(out_dir.join("keywords_generated.rs"), output)?; - Ok(()) -} - -// Generates enum value codes for the Rust style computation core from Enums.json. -// Values follow the array order skipping aliases, matching the C++ enum generator. -fn generate_css_enums(manifest_dir: &Path, out_dir: &Path) -> Result<(), Box> { - let enums_path = manifest_dir.parent().unwrap().join("Enums.json"); - println!("cargo:rerun-if-changed={}", enums_path.display()); - let value: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&enums_path)?)?; - let enums = value.as_object().ok_or("Enums.json is not an object")?; - - let mut output = String::new(); - output.push_str("// Generated by build.rs from Enums.json. Do not edit.\n\n"); - for (name, values) in enums { - let values = values.as_array().ok_or("enum values are not an array")?; - let module = name.replace('-', "_"); - output.push_str(&format!("#[allow(dead_code)]\npub mod {module} {{\n")); - let mut code: u8 = 0; - for value in values { - let value = value.as_str().ok_or("enum value is not a string")?; - // Aliases are not included in the enum. - if value.contains('=') { - continue; - } - let constant = value.replace('-', "_").to_uppercase(); - output.push_str(&format!(" pub const {constant}: u8 = {code};\n")); - code = code.checked_add(1).ok_or("enum has too many values for u8")?; - } - output.push_str("}\n\n"); - - // The keyword-to-enum-value mapping, mirroring the C++ keyword_to_ generator, - // including its alias handling ("keyword=member" maps the keyword to member's value). - let mut member_codes = std::collections::HashMap::new(); - let mut member_code: u8 = 0; - for value in values { - let value = value.as_str().ok_or("enum value is not a string")?; - if value.contains('=') { - continue; - } - member_codes.insert(value.to_string(), member_code); - member_code = member_code.checked_add(1).ok_or("enum has too many values for u8")?; - } - output.push_str(&format!( - "#[allow(dead_code)]\npub fn keyword_to_{module}(keyword: u16) -> Option {{\n match keyword {{\n" - )); - for value in values { - let value = value.as_str().ok_or("enum value is not a string")?; - let (keyword_name, member_name) = match value.split_once('=') { - Some((keyword, member)) => (keyword, member), - None => (value, value), - }; - let keyword_constant = keyword_name.replace('-', "_").to_uppercase(); - let code = member_codes - .get(member_name) - .ok_or("enum alias targets an unknown member")?; - output.push_str(&format!(" keyword::{keyword_constant} => Some({code}),\n")); - } - output.push_str(" _ => None,\n }\n}\n\n"); - } - std::fs::write(out_dir.join("css_enums_generated.rs"), output)?; - Ok(()) -} - -fn generate_ffi_header( - config: cbindgen::Config, - sources: &[PathBuf], - out_dir: &Path, - ffi_out_dir: &Path, - header: &Path, -) { - let builder = sources - .iter() - .fold(cbindgen::Builder::new().with_config(config), |builder, source| { - builder.with_src(source) - }); - builder.generate().map_or_else( - |error| match error { - cbindgen::Error::ParseSyntaxError { .. } => {} - other => panic!("{other:?}"), - }, - |bindings| { - let output_header = out_dir.join(header); - std::fs::create_dir_all(output_header.parent().unwrap()).unwrap(); - bindings.write_to_file(output_header); - if ffi_out_dir != out_dir { - let ffi_header = ffi_out_dir.join(header); - std::fs::create_dir_all(ffi_header.parent().unwrap()).unwrap(); - bindings.write_to_file(ffi_header); - } - }, - ); -} - -fn main() -> Result<(), Box> { - let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); - let out_dir = PathBuf::from(env::var("OUT_DIR")?); - - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-changed=cbindgen.toml"); - println!("cargo:rerun-if-env-changed=FFI_OUTPUT_DIR"); - println!("cargo:rerun-if-changed=src"); - - generate_selector_pseudo_types(&manifest_dir, &out_dir)?; - generate_property_metadata(&manifest_dir, &out_dir)?; - generate_length_units(&manifest_dir, &out_dir)?; - generate_keywords(&manifest_dir, &out_dir)?; - generate_css_enums(&manifest_dir, &out_dir)?; - - let ffi_out_dir = env::var("FFI_OUTPUT_DIR") - .map(PathBuf::from) - .unwrap_or_else(|_| out_dir.clone()); - - let base_config = cbindgen::Config::from_file(manifest_dir.join("cbindgen.toml"))?; - - // CSS tokenizer header — namespace Web::CSS::Parser::FFI, CSS types only. - let mut css_config = base_config.clone(); - css_config.namespaces = Some(vec![ - "Web".to_string(), - "CSS".to_string(), - "Parser".to_string(), - "FFI".to_string(), - ]); - css_config.export.include = vec![ - "CssHashType".to_string(), - "CssNumberType".to_string(), - "CssToken".to_string(), - "CssTokenType".to_string(), - ]; - - generate_ffi_header( - css_config, - &[manifest_dir.join("src/css_tokenizer.rs")], - &out_dir, - &ffi_out_dir, - Path::new("RustFFI.h"), - ); - - // Selector matching header - namespace Web::CSS::SelectorFFI. Generate both sides of this - // ABI from the Rust declarations so changes to layouts or signatures cannot drift silently. - let mut selector_config = base_config.clone(); - selector_config.namespaces = Some(vec!["Web".to_string(), "CSS".to_string(), "SelectorFFI".to_string()]); - for (rust_name, cxx_name) in [ - ("FfiSimpleSelectorType", "SimpleSelectorType"), - ("FfiDirection", "Direction"), - ("FfiPseudoElementValueType", "PseudoElementValueType"), - ("FfiStringView", "StringView"), - ("FfiSimpleSelector", "SimpleSelector"), - ("FfiCompoundSelector", "CompoundSelector"), - ("FfiSelector", "Selector"), - ("FfiElement", "Element"), - ("FfiElementQualifiedName", "ElementQualifiedName"), - ("FfiInternedStringList", "InternedStringList"), - ("FfiDomStringView", "DomStringView"), - ("FfiDomAttribute", "DomAttribute"), - ("FfiResolvedNamespaceType", "ResolvedNamespaceType"), - ("FfiResolvedNamespace", "ResolvedNamespace"), - ("FfiElementAndShadowHost", "ElementAndShadowHost"), - ] { - selector_config - .export - .rename - .insert(rust_name.to_string(), cxx_name.to_string()); - } - - generate_ffi_header( - selector_config, - &[ - manifest_dir.join("src/selector_engine.rs"), - manifest_dir.join("src/ffi_support.rs"), - ], - &out_dir, - &ffi_out_dir, - Path::new("SelectorRustFFI.h"), - ); - - // Style value header - namespace Web::CSS::StyleValueFFI. The StyleValueData layout is - // exposed so converted C++ StyleValue subclasses can read variant payloads inline without - // an FFI call. - let mut style_value_config = base_config.clone(); - style_value_config.namespaces = Some(vec!["Web".to_string(), "CSS".to_string(), "StyleValueFFI".to_string()]); - style_value_config.export.include = vec!["StyleValueData".to_string()]; - - generate_ffi_header( - style_value_config, - &[ - manifest_dir.join("src/style_value.rs"), - manifest_dir.join("src/color_interpolation.rs"), - manifest_dir.join("src/animation.rs"), - manifest_dir.join("src/transition.rs"), - manifest_dir.join("src/calc.rs"), - manifest_dir.join("src/ffi_stats.rs"), - ], - &out_dir, - &ffi_out_dir, - Path::new("StyleValueRustFFI.h"), - ); - - // Computed values header - namespace Web::CSS::ComputedValuesFFI. Exposes the style group - // vtable and lifecycle functions; the reference count header layout is documented in - // computed_values.rs and mirrored by StyleStructRef. - let mut computed_values_config = base_config; - computed_values_config.namespaces = Some(vec![ - "Web".to_string(), - "CSS".to_string(), - "ComputedValuesFFI".to_string(), - ]); - computed_values_config.export.include = vec![ - "StyleGroupVTable".to_string(), - "STYLE_GROUP_STATIC_REFCOUNT".to_string(), - "CascadeOrigin".to_string(), - ]; - - generate_ffi_header( - computed_values_config, - &[ - manifest_dir.join("src/computed_values.rs"), - manifest_dir.join("src/property_metadata.rs"), - manifest_dir.join("src/style_compute.rs"), - manifest_dir.join("src/display.rs"), - manifest_dir.join("src/css_pixels.rs"), - manifest_dir.join("src/cascaded_properties.rs"), - manifest_dir.join("src/custom_properties.rs"), - ], - &out_dir, - &ffi_out_dir, - Path::new("ComputedValuesRustFFI.h"), - ); - - Ok(()) -} diff --git a/Libraries/LibWeb/CSS/Rust/cbindgen.toml b/Libraries/LibWeb/CSS/Rust/cbindgen.toml deleted file mode 100644 index b355945eabffd..0000000000000 --- a/Libraries/LibWeb/CSS/Rust/cbindgen.toml +++ /dev/null @@ -1,22 +0,0 @@ -language = "C++" -header = """/* - * Copyright (c) 2026-present, the Ladybird developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */""" -pragma_once = true -include_version = true -line_length = 120 -tab_width = 4 -no_includes = true -sys_includes = ["stdint.h", "stddef.h"] -usize_is_size_t = true - -[parse] -parse_deps = false - -[parse.expand] -all_features = false - -[export.mangle] -rename_types = "PascalCase" diff --git a/Libraries/LibWeb/CSS/Rust/src/lib.rs b/Libraries/LibWeb/CSS/Rust/src/lib.rs deleted file mode 100644 index d3ac08ea5af93..0000000000000 --- a/Libraries/LibWeb/CSS/Rust/src/lib.rs +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2026-present, the Ladybird developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#[cfg(feature = "allocator")] -#[path = "../../../../RustAllocator.rs"] -mod rust_allocator; - -pub mod animation; -pub mod calc; -pub mod cascaded_properties; -mod color_conversion; -pub mod color_interpolation; -pub mod computed_values; -pub mod css_enums; -pub mod css_pixels; -mod css_tokenizer; -pub mod custom_properties; -pub mod display; -pub mod ffi_stats; -pub mod ffi_support; -pub mod property_metadata; -mod selector_engine; -pub mod style_compute; -mod style_value; -pub mod transition; - -use std::panic::AssertUnwindSafe; -use std::panic::catch_unwind; - -pub use css_tokenizer::CssHashType; -pub use css_tokenizer::CssNumberType; -pub use css_tokenizer::CssToken; -pub use css_tokenizer::CssTokenType; - -fn abort_on_panic R, R>(f: F) -> R { - match catch_unwind(AssertUnwindSafe(f)) { - Ok(result) => result, - Err(payload) => { - let message = if let Some(message) = payload.downcast_ref::<&str>() { - (*message).to_string() - } else if let Some(message) = payload.downcast_ref::() { - message.clone() - } else { - "unknown panic".to_string() - }; - eprintln!("Rust panic at FFI boundary: {message}"); - std::process::abort(); - } - } -} - -unsafe fn bytes_from_raw<'a>(bytes: *const u8, len: usize) -> Option<&'a [u8]> { - unsafe { - if len == 0 { - return Some(&[]); - } - if bytes.is_null() { - eprintln!("bytes_from_raw: null pointer with non-zero length {len}"); - return None; - } - Some(std::slice::from_raw_parts(bytes, len)) - } -} diff --git a/Libraries/LibWeb/Layout/Rust/Cargo.toml b/Libraries/LibWeb/Layout/Rust/Cargo.toml deleted file mode 100644 index e96b3be9c956f..0000000000000 --- a/Libraries/LibWeb/Layout/Rust/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "libweb_layout_rust" -version = "0.1.0" -edition = "2024" - -[lib] -crate-type = ["staticlib"] - -[features] -default = [] -allocator = [] - -[build-dependencies] -cbindgen = "0.29" - -[lints] -workspace = true diff --git a/Libraries/LibWeb/Layout/Rust/build.rs b/Libraries/LibWeb/Layout/Rust/build.rs deleted file mode 100644 index 04aeb36194b40..0000000000000 --- a/Libraries/LibWeb/Layout/Rust/build.rs +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2026-present, the Ladybird developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -use std::env; -use std::error::Error; -use std::path::{Path, PathBuf}; - -fn main() -> Result<(), Box> { - let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); - let out_dir = PathBuf::from(env::var("OUT_DIR")?); - - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-changed=cbindgen.toml"); - println!("cargo:rerun-if-env-changed=FFI_OUTPUT_DIR"); - println!("cargo:rerun-if-changed=src"); - - let ffi_out_dir = env::var("FFI_OUTPUT_DIR") - .map(PathBuf::from) - .unwrap_or_else(|_| out_dir.clone()); - let config = cbindgen::Config::from_file(manifest_dir.join("cbindgen.toml"))?; - let header = Path::new("Layout/TreeBuilderRustFFI.h"); - let builder = cbindgen::Builder::new().with_config(config).with_crate(&manifest_dir); - - builder.generate().map_or_else( - |error| match error { - cbindgen::Error::ParseSyntaxError { .. } => {} - other => panic!("{other:?}"), - }, - |bindings| { - let output_header = out_dir.join(header); - std::fs::create_dir_all(output_header.parent().unwrap()).unwrap(); - bindings.write_to_file(output_header); - if ffi_out_dir != out_dir { - let ffi_header = ffi_out_dir.join(header); - std::fs::create_dir_all(ffi_header.parent().unwrap()).unwrap(); - bindings.write_to_file(ffi_header); - } - }, - ); - - Ok(()) -} diff --git a/Libraries/LibWeb/Layout/Rust/cbindgen.toml b/Libraries/LibWeb/Layout/Rust/cbindgen.toml deleted file mode 100644 index 69ff24f7bf24b..0000000000000 --- a/Libraries/LibWeb/Layout/Rust/cbindgen.toml +++ /dev/null @@ -1,26 +0,0 @@ -language = "C++" -header = """/* - * Copyright (c) 2026-present, the Ladybird developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */""" -pragma_once = true -include_version = true -namespaces = ["Web", "Layout", "RustFFI"] -line_length = 120 -tab_width = 4 -no_includes = true -sys_includes = ["stdint.h", "stddef.h"] -usize_is_size_t = true - -[parse] -parse_deps = false - -[parse.expand] -all_features = false - -[export] -include = ["FfiNodeKindFacts", "FfiTableDisplay", "NodeAllocation", "NodeData", "NodeDisplayFlag", "NodeFlag", "NodeKind", "NodeSlotId"] - -[export.mangle] -rename_types = "PascalCase" diff --git a/Libraries/LibWeb/Layout/Rust/src/lib.rs b/Libraries/LibWeb/Layout/Rust/src/lib.rs deleted file mode 100644 index 339e4422fb46c..0000000000000 --- a/Libraries/LibWeb/Layout/Rust/src/lib.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2026-present, the Ladybird developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#[cfg(feature = "allocator")] -#[path = "../../../../RustAllocator.rs"] -mod rust_allocator; - -mod layout_node_arena; -pub mod node_data; -mod tree_builder; - -use std::panic::AssertUnwindSafe; -use std::panic::catch_unwind; - -fn abort_on_panic R, R>(f: F) -> R { - match catch_unwind(AssertUnwindSafe(f)) { - Ok(result) => result, - Err(payload) => { - let message = if let Some(message) = payload.downcast_ref::<&str>() { - (*message).to_string() - } else if let Some(message) = payload.downcast_ref::() { - message.clone() - } else { - "unknown panic".to_string() - }; - eprintln!("Rust panic at FFI boundary: {message}"); - std::process::abort(); - } - } -} diff --git a/Libraries/LibWeb/Rust/Cargo.toml b/Libraries/LibWeb/Rust/Cargo.toml index 50c59e00fa781..491f945286075 100644 --- a/Libraries/LibWeb/Rust/Cargo.toml +++ b/Libraries/LibWeb/Rust/Cargo.toml @@ -9,11 +9,12 @@ crate-type = ["staticlib"] # After changing dependencies, regenerate the Flatpak sources: # python3 Meta/CMake/flatpak/generate-cargo-sources.py [dependencies] -libweb_html_tokenizer = { path = "../HTML/Parser/Rust" } chardetng = "1.0.0" +libweb_html_tokenizer = { path = "../HTML/Parser/Rust" } [build-dependencies] cbindgen = "0.29" +serde_json = { version = "1", features = ["float_roundtrip", "preserve_order"] } [lints] workspace = true diff --git a/Libraries/LibWeb/Rust/build.rs b/Libraries/LibWeb/Rust/build.rs index e3226fd551a32..64876bdaad8a2 100644 --- a/Libraries/LibWeb/Rust/build.rs +++ b/Libraries/LibWeb/Rust/build.rs @@ -6,32 +6,782 @@ use std::env; use std::error::Error; +use std::fmt::Write; use std::path::{Path, PathBuf}; -fn main() -> Result<(), Box> { - let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); - let out_dir = PathBuf::from(env::var("OUT_DIR")?); +// Mirrors title_casify() in Meta/Utils/utils.py. +fn title_casify(dashy_name: &str) -> String { + dashy_name + .split('-') + .filter(|part| !part.is_empty()) + .map(|part| { + let mut chars = part.chars(); + let first = chars.next().unwrap().to_ascii_uppercase(); + format!("{first}{}", chars.as_str()) + }) + .collect() +} - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-changed=cbindgen.toml"); - println!("cargo:rerun-if-env-changed=FFI_OUTPUT_DIR"); - println!("cargo:rerun-if-changed=src"); +fn ordered_pseudo_element_names( + pseudo_elements: &serde_json::Map, +) -> Result, Box> { + let mut synthetic = Vec::new(); + let mut element_reference = Vec::new(); + let mut functional = Vec::new(); + for (name, value) in pseudo_elements { + let object = value.as_object().unwrap(); + if object.contains_key("alias-for") { + continue; + } + if object.get("type").and_then(|value| value.as_str()) == Some("function") { + functional.push(name.clone()); + continue; + } + match object.get("implementation").and_then(|value| value.as_str()) { + Some("synthetic") => synthetic.push(name.clone()), + Some("element-reference") => element_reference.push(name.clone()), + other => return Err(format!("invalid or missing implementation type for ::{name}: {other:?}").into()), + } + } + synthetic.extend(element_reference); + synthetic.extend(functional); + Ok(synthetic) +} - let ffi_out_dir = env::var("FFI_OUTPUT_DIR") - .map(PathBuf::from) - .unwrap_or_else(|_| out_dir.clone()); +fn load_property_groups(path: &Path) -> Result>, Box> { + let mut groups = std::collections::HashMap::new(); + let mut current_group = None; + for raw_line in std::fs::read_to_string(path)?.lines() { + let line = raw_line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + if let Some(group) = line.strip_prefix('[').and_then(|line| line.strip_suffix(']')) { + groups.insert(format!("#{group}"), Vec::new()); + current_group = Some(format!("#{group}")); + continue; + } + let Some(group) = current_group.as_ref() else { + return Err(format!("property outside a pseudo-element property group: {line}").into()); + }; + groups.get_mut(group).unwrap().push(line.to_string()); + } + Ok(groups) +} + +fn write_enum_and_from_ffi(output: &mut String, enum_name: &str, variants: &[String]) { + writeln!(output, "#[derive(Clone, Copy, Debug, PartialEq, Eq)]").unwrap(); + writeln!(output, "#[repr(u8)]").unwrap(); + writeln!(output, "pub enum {enum_name} {{").unwrap(); + for variant in variants { + writeln!(output, " {variant},").unwrap(); + } + writeln!(output, "}}").unwrap(); + writeln!(output).unwrap(); + let fn_name = if enum_name == "PseudoClassType" { + "pseudo_class_from_ffi" + } else { + "pseudo_element_from_ffi" + }; + writeln!(output, "fn {fn_name}(value: u8) -> {enum_name} {{").unwrap(); + writeln!(output, " match value {{").unwrap(); + for (index, variant) in variants.iter().enumerate() { + writeln!(output, " {index} => {enum_name}::{variant},").unwrap(); + } + writeln!(output, " _ => panic!(\"invalid {enum_name} {{value}}\"),").unwrap(); + writeln!(output, " }}").unwrap(); + writeln!(output, "}}").unwrap(); + writeln!(output).unwrap(); +} - let config = cbindgen::Config::from_file(manifest_dir.join("cbindgen.toml"))?; +// Generates the Rust twins of the C++ PseudoClass and PseudoElement enums from the same JSON +// sources as Meta/Generators/generate_libweb_css_pseudo_{class,element}.py, so the numeric +// values that cross the selector FFI cannot drift out of sync with the C++ side. +fn generate_selector_pseudo_types(manifest_dir: &Path, out_dir: &Path) -> Result<(), Box> { + let css_dir = manifest_dir.parent().unwrap().join("CSS"); + let pseudo_classes_path = css_dir.join("PseudoClasses.json"); + let pseudo_elements_path = css_dir.join("PseudoElements.json"); + println!("cargo:rerun-if-changed={}", pseudo_classes_path.display()); + println!("cargo:rerun-if-changed={}", pseudo_elements_path.display()); - // Encoding-detection header - namespace Web::HTML::Parser, rust_detect_encoding only. - let mut html_config = config; - html_config.namespaces = Some(vec!["Web".to_string(), "HTML".to_string(), "Parser".to_string()]); - html_config.export.include = vec!["rust_detect_encoding".to_string()]; + let parse_object = |path: &Path| -> Result, Box> { + let value: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(path)?)?; + match value { + serde_json::Value::Object(object) => Ok(object), + _ => Err(format!("{} does not contain a JSON object", path.display()).into()), + } + }; + + let pseudo_class_names = parse_object(&pseudo_classes_path)? + .iter() + .filter(|(_, value)| !value.as_object().unwrap().contains_key("legacy-alias-for")) + .map(|(name, _)| title_casify(name)) + .collect::>(); + + let pseudo_elements = parse_object(&pseudo_elements_path)?; + let mut pseudo_element_names = ordered_pseudo_element_names(&pseudo_elements)? + .iter() + .map(|name| title_casify(name)) + .collect::>(); + // NB: The C++ generator emits UnknownWebKit after KnownPseudoElementCount, so its FFI value is + // the number of known pseudo-elements. + pseudo_element_names.push("UnknownWebKit".to_string()); + + let mut output = String::new(); + writeln!( + output, + "// Generated by build.rs from CSS/PseudoClasses.json and CSS/PseudoElements.json." + ) + .unwrap(); + writeln!(output).unwrap(); + write_enum_and_from_ffi(&mut output, "PseudoClassType", &pseudo_class_names); + write_enum_and_from_ffi(&mut output, "PseudoElementType", &pseudo_element_names); + + std::fs::write(out_dir.join("selector_pseudo_generated.rs"), output)?; + Ok(()) +} + +// Generates the property metadata tables for the Rust style computation core from +// Properties.json, replicating the C++ generator's identifier assignment exactly: +// Custom is 0, then shorthands, inherited longhands and non-inherited longhands in +// JSON order, skipping legacy aliases. A C++ unit test compares the tables against +// the C++-generated equivalents so the two generators cannot drift. +fn generate_property_metadata(manifest_dir: &Path, out_dir: &Path) -> Result<(), Box> { + let properties_path = manifest_dir.parent().unwrap().join("CSS/Properties.json"); + println!("cargo:rerun-if-changed={}", properties_path.display()); + + let value: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&properties_path)?)?; + let serde_json::Value::Object(properties) = value else { + return Err("Properties.json does not contain a JSON object".into()); + }; + + // Logical alias properties take their metadata from the first physical property of + // their logical group, with local overrides, mirroring the C++ generator. + let groups_path = manifest_dir.parent().unwrap().join("CSS/LogicalPropertyGroups.json"); + println!("cargo:rerun-if-changed={}", groups_path.display()); + let groups_value: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&groups_path)?)?; + let serde_json::Value::Object(groups) = groups_value else { + return Err("LogicalPropertyGroups.json does not contain a JSON object".into()); + }; + let first_physical_in_group = + |group_name: &str| -> Option<&str> { groups[group_name]["physical"].as_object()?.values().next()?.as_str() }; + let property_field = |name: &str, field: &str| -> Option { + let object = properties[name].as_object().unwrap(); + if let Some(value) = object.get(field) { + return Some(value.clone()); + } + let group = object.get("logical-alias-for")?.as_object()?.get("group")?.as_str()?; + let physical = first_physical_in_group(group)?; + properties[physical].as_object().unwrap().get(field).cloned() + }; + + let mut shorthands = Vec::new(); + let mut inherited_longhands = Vec::new(); + let mut noninherited_longhands = Vec::new(); + for (name, value) in &properties { + let object = value.as_object().unwrap(); + if object.contains_key("legacy-alias-for") { + continue; + } + // NB: The C++ generator populates the "all" shorthand's longhand list + // programmatically, so it has no explicit "longhands" key. + if object.contains_key("longhands") || name == "all" { + shorthands.push(name.clone()); + } else if property_field(name, "inherited").unwrap().as_bool().unwrap() { + inherited_longhands.push(name.clone()); + } else { + noninherited_longhands.push(name.clone()); + } + } + + // Identifier assignment: Custom = 0, then the three runs in order. + let mut ids = std::collections::HashMap::new(); + for (index, name) in shorthands + .iter() + .chain(&inherited_longhands) + .chain(&noninherited_longhands) + .enumerate() + { + ids.insert(name.clone(), (index + 1) as u16); + } + let first_longhand = ids[&inherited_longhands[0]]; + let last_longhand = ids[noninherited_longhands.last().unwrap()]; + let first_inherited = ids[&inherited_longhands[0]]; + let last_inherited = ids[inherited_longhands.last().unwrap()]; + + let pseudo_elements_path = manifest_dir.parent().unwrap().join("CSS/PseudoElements.json"); + let property_groups_path = manifest_dir + .parent() + .unwrap() + .join("CSS/PseudoElementPropertyGroups.txt"); + println!("cargo:rerun-if-changed={}", pseudo_elements_path.display()); + println!("cargo:rerun-if-changed={}", property_groups_path.display()); + let pseudo_elements_value: serde_json::Value = + serde_json::from_str(&std::fs::read_to_string(&pseudo_elements_path)?)?; + let serde_json::Value::Object(pseudo_elements) = pseudo_elements_value else { + return Err("PseudoElements.json does not contain a JSON object".into()); + }; + let property_groups = load_property_groups(&property_groups_path)?; + let property_id = |name: &str| -> Result> { + if name == "custom" { + return Ok(0); + } + ids.get(name) + .copied() + .ok_or_else(|| format!("unknown pseudo-element property '{name}'").into()) + }; + let property_ids = |entries: &[String]| -> Result, Box> { + let mut result = std::collections::BTreeSet::new(); + for entry in entries { + if entry.starts_with("FIXME:") { + continue; + } + if let Some(properties) = property_groups.get(entry) { + for property in properties { + result.insert(property_id(property)?); + } + } else if entry.starts_with('#') { + return Err(format!("unknown pseudo-element property group '{entry}'").into()); + } else { + result.insert(property_id(entry)?); + } + } + Ok(result.into_iter().collect()) + }; + let always_allowed_pseudo_properties = property_ids( + property_groups + .get("#always-allowed-properties") + .ok_or("missing always-allowed pseudo-element property group")?, + )?; + let mut pseudo_property_whitelist_rows = Vec::new(); + for name in ordered_pseudo_element_names(&pseudo_elements)? { + let object = pseudo_elements[&name].as_object().unwrap(); + let Some(whitelist) = object.get("property-whitelist") else { + pseudo_property_whitelist_rows.push(" None,".to_string()); + continue; + }; + let entries = whitelist + .as_array() + .unwrap() + .iter() + .map(|entry| entry.as_str().unwrap().to_string()) + .collect::>(); + let whitelist = property_ids(&entries)?; + pseudo_property_whitelist_rows.push(format!(" Some(&{whitelist:?}),")); + } + // UnknownWebKit follows the known pseudo-elements and accepts all properties. + pseudo_property_whitelist_rows.push(" None,".to_string()); + + // NB: Must match manually_specified_computation_order in + // Meta/Generators/generate_libweb_css_property_id.py; the parity test enforces it. + let manual_order = [ + "math-depth", + "font-family", + "font-feature-settings", + "font-kerning", + "font-optical-sizing", + "font-size", + "font-style", + "font-variant-alternates", + "font-variant-caps", + "font-variant-east-asian", + "font-variant-emoji", + "font-variant-ligatures", + "font-variant-numeric", + "font-variant-position", + "font-variation-settings", + "font-weight", + "font-width", + "text-rendering", + "line-height", + "color-scheme", + "background-image", + "direction", + "writing-mode", + ]; + let mut order = Vec::new(); + for name in manual_order { + order.push(ids[name]); + } + // NB: The remainder follows Properties.json iteration order across all longhands, + // matching the C++ generator, not grouped by inheritance. + for (name, value) in &properties { + let object = value.as_object().unwrap(); + if object.contains_key("legacy-alias-for") || object.contains_key("longhands") || name == "all" { + continue; + } + if !manual_order.contains(&name.as_str()) { + order.push(ids[name]); + } + } + + let mut levels = vec![0u8; (last_longhand - first_longhand + 1) as usize]; + let mut animation_types = vec![0u8; levels.len()]; + let mut numeric_range_rows = vec![String::new(); levels.len()]; + let value_types = [ + "anchor", + "anchor-size", + "angle", + "angle-percentage", + "background-position", + "basic-shape", + "color", + "corner-shape", + "counter", + "counter-style", + "custom-ident", + "dashed-ident", + "easing-function", + "filter-value-list", + "fit-content", + "flex", + "font-style", + "font-variant-alternates", + "font-variant-east-asian", + "font-variant-ligatures", + "font-variant-numeric", + "frequency", + "frequency-percentage", + "image", + "integer", + "length", + "length-percentage", + "number", + "opacity-value", + "opentype-tag", + "paint", + "percentage", + "position", + "ratio", + "rect", + "resolution", + "scroll-function", + "string", + "time", + "time-percentage", + "transform-function", + "transform-list", + "url", + "view-function", + "view-timeline-inset", + ]; + for name in inherited_longhands.iter().chain(&noninherited_longhands) { + let index = (ids[name] - first_longhand) as usize; + let requires_computation = property_field(name, "requires-computation").unwrap(); + let level = match requires_computation.as_str().unwrap() { + "never" => 0u8, + "cascaded-value" => 1, + "non-inherited-value" => 2, + "always" => 3, + other => return Err(format!("unknown requires-computation '{other}' for {name}").into()), + }; + levels[index] = level; + + animation_types[index] = match property_field(name, "animation-type").unwrap().as_str().unwrap() { + "discrete" => 0, + "by-computed-value" => 1, + "repeatable-list" => 2, + "custom" => 3, + "none" => 4, + other => return Err(format!("unknown animation-type '{other}' for {name}").into()), + }; + + let mut ranges = Vec::new(); + if let Some(valid_types) = property_field(name, "valid-types").and_then(|value| value.as_array().cloned()) { + for valid_type in valid_types { + let valid_type = valid_type.as_str().unwrap(); + let Some((type_name, range)) = valid_type.split_once(' ') else { + continue; + }; + if !range.starts_with('[') || !range.ends_with(']') || !range.contains(',') { + continue; + } + if type_name == "custom-ident" { + continue; + } + let value_type = value_types + .iter() + .position(|candidate| *candidate == type_name) + .ok_or_else(|| format!("unknown ranged value type '{type_name}' for {name}"))?; + let (min, max) = range[1..range.len() - 1] + .split_once(',') + .ok_or_else(|| format!("bad numeric range '{range}' for {name}"))?; + let format_bound = |bound: &str| match (type_name, bound) { + ("integer", "-∞") => "i32::MIN as f64".to_string(), + ("integer", "∞") => "i32::MAX as f64".to_string(), + (_, "-∞") => "f32::MIN as f64".to_string(), + (_, "∞") => "f32::MAX as f64".to_string(), + _ if bound.contains('.') => bound.to_string(), + _ => format!("{bound}.0"), + }; + ranges.push(format!( + "FfiPropertyNumericRange {{ value_type: {value_type}, min: {}, max: {} }}", + format_bound(min), + format_bound(max) + )); + } + } + numeric_range_rows[index] = ranges.join(", "); + } + + let mut output = String::new(); + output.push_str("// Generated by build.rs from CSS metadata. Do not edit.\n\n"); + // Shorthand expansion tables for the cascade. The "all" shorthand expands to every + // longhand except direction and unicode-bidi, mirroring the C++ generator. + let mut shorthand_rows = Vec::new(); + for name in &shorthands { + let longhand_names: Vec = if name == "all" { + properties + .iter() + .filter(|(name, value)| { + let object = value.as_object().unwrap(); + !object.contains_key("longhands") + && !object.contains_key("legacy-alias-for") + && name.as_str() != "all" + && name.as_str() != "direction" + && name.as_str() != "unicode-bidi" + }) + .map(|(name, _)| name.clone()) + .collect() + } else { + properties[name]["longhands"] + .as_array() + .unwrap() + .iter() + .map(|longhand| longhand.as_str().unwrap().to_string()) + .collect() + }; + let ids_row: Vec = longhand_names.iter().map(|longhand| ids[longhand]).collect(); + shorthand_rows.push(format!(" &{ids_row:?},")); + } + output.push_str(&format!( + "pub(crate) static SHORTHAND_EXPANSIONS: [&[u16]; {}] = [\n{}\n];\n\n", + shorthand_rows.len(), + shorthand_rows.join("\n") + )); + let property_names: Vec<&str> = shorthands + .iter() + .chain(&inherited_longhands) + .chain(&noninherited_longhands) + .map(String::as_str) + .collect(); + fn expanded_longhands( + name: &str, + properties: &serde_json::Map, + all_longhands: &[String], + result: &mut Vec, + ) { + if name == "all" { + result.extend_from_slice(all_longhands); + return; + } + let Some(longhands) = properties[name].get("longhands").and_then(|value| value.as_array()) else { + result.push(name.to_string()); + return; + }; + for longhand in longhands { + expanded_longhands(longhand.as_str().unwrap(), properties, all_longhands, result); + } + } + let all_longhands: Vec = inherited_longhands + .iter() + .chain(&noninherited_longhands) + .filter(|name| name.as_str() != "direction" && name.as_str() != "unicode-bidi") + .cloned() + .collect(); + let expanded_shorthand_longhands: Vec> = shorthands + .iter() + .map(|name| { + let mut result = Vec::new(); + expanded_longhands(name, &properties, &all_longhands, &mut result); + result + }) + .collect(); + let camel_case_property_name = |name: &str| { + let mut parts = name.split('-').filter(|part| !part.is_empty()); + let mut result = parts.next().unwrap_or_default().to_string(); + for part in parts { + let mut characters = part.chars(); + if let Some(first) = characters.next() { + result.extend(first.to_uppercase()); + result.extend(characters); + } + } + result + }; + let idl_names: Vec = property_names + .iter() + .map(|name| camel_case_property_name(name)) + .collect(); + let logical_aliases: Vec = property_names + .iter() + .enumerate() + .map(|(index, name)| { + let name: &str = if index < shorthands.len() { + expanded_shorthand_longhands[index][0].as_str() + } else { + name + }; + properties[name].as_object().unwrap().contains_key("logical-alias-for") + }) + .collect(); + let expanded_longhand_counts: Vec = expanded_shorthand_longhands.iter().map(Vec::len).collect(); + output.push_str(&format!( + "pub(crate) static PROPERTY_IDL_NAMES: [&str; {}] = {:?};\n", + idl_names.len(), + idl_names + )); + output.push_str(&format!( + "pub(crate) static PROPERTY_IS_LOGICAL_ALIAS: [bool; {}] = {:?};\n\n", + logical_aliases.len(), + logical_aliases + )); + output.push_str(&format!( + "pub(crate) static SHORTHAND_EXPANDED_LONGHAND_COUNTS: [usize; {}] = {:?};\n\n", + expanded_longhand_counts.len(), + expanded_longhand_counts + )); + output.push_str(&format!( + "pub const FIRST_SHORTHAND_PROPERTY_ID: u16 = {};\n", + ids[&shorthands[0]] + )); + output.push_str(&format!( + "pub const LAST_SHORTHAND_PROPERTY_ID: u16 = {};\n\n", + ids[shorthands.last().unwrap()] + )); + output.push_str("#[allow(dead_code)]\npub mod property_id {\n"); + output.push_str(" pub const CUSTOM: u16 = 0;\n"); + for name in shorthands + .iter() + .chain(&inherited_longhands) + .chain(&noninherited_longhands) + { + let constant = name.replace('-', "_").to_uppercase(); + output.push_str(&format!(" pub const {constant}: u16 = {};\n", ids[name])); + } + output.push_str("}\n\n"); + output.push_str(&format!( + "pub const FIRST_LONGHAND_PROPERTY_ID: u16 = {first_longhand};\n" + )); + output.push_str(&format!( + "pub const LAST_LONGHAND_PROPERTY_ID: u16 = {last_longhand};\n" + )); + output.push_str(&format!( + "pub const FIRST_INHERITED_PROPERTY_ID: u16 = {first_inherited};\n" + )); + output.push_str(&format!( + "pub const LAST_INHERITED_PROPERTY_ID: u16 = {last_inherited};\n\n" + )); + output.push_str(&format!( + "pub(crate) static PROPERTY_COMPUTATION_ORDER: [u16; {}] = {:?};\n\n", + order.len(), + order + )); + output.push_str(&format!( + "pub(crate) static REQUIRES_COMPUTATION_LEVELS: [u8; {}] = {:?};\n", + levels.len(), + levels + )); + output.push_str(&format!( + "pub(crate) static PROPERTY_ANIMATION_TYPES: [u8; {}] = {:?};\n", + animation_types.len(), + animation_types + )); + output.push_str(&format!( + "pub(crate) static PROPERTY_NUMERIC_RANGES: [&[FfiPropertyNumericRange]; {}] = [\n{}\n];\n", + numeric_range_rows.len(), + numeric_range_rows + .iter() + .map(|ranges| format!(" &[{ranges}],")) + .collect::>() + .join("\n") + )); + output.push_str(&format!( + "\npub(crate) static PSEUDO_ELEMENT_ALWAYS_ALLOWED_PROPERTIES: &[u16] = &{always_allowed_pseudo_properties:?};\n" + )); + output.push_str(&format!( + "pub(crate) static PSEUDO_ELEMENT_PROPERTY_WHITELISTS: [Option<&[u16]>; {}] = [\n{}\n];\n", + pseudo_property_whitelist_rows.len(), + pseudo_property_whitelist_rows.join("\n") + )); + std::fs::write(out_dir.join("property_metadata_generated.rs"), output)?; + Ok(()) +} + +// Generates the length unit table for the Rust style computation core from Units.json. +// Unit codes are the alphabetical index within the "length" object, matching the C++ +// LengthUnit enum; absolute units carry their canonical px ratio. +fn generate_length_units(manifest_dir: &Path, out_dir: &Path) -> Result<(), Box> { + let units_path = manifest_dir.parent().unwrap().join("CSS/Units.json"); + println!("cargo:rerun-if-changed={}", units_path.display()); + let value: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&units_path)?)?; + let lengths = value["length"].as_object().ok_or("Units.json has no length object")?; + + let mut names = Vec::new(); + let mut ratios = Vec::new(); + for (name, unit) in lengths { + names.push(name.clone()); + let object = unit.as_object().unwrap(); + if object + .get("is-canonical-unit") + .is_some_and(|canonical| canonical.as_bool() == Some(true)) + { + ratios.push("1.0".to_string()); + } else if let Some(ratio) = object.get("number-of-canonical-unit") { + ratios.push(format!("{:?}", ratio.as_f64().unwrap())); + } else { + ratios.push("f64::NAN".to_string()); + } + } + + let mut output = String::new(); + output.push_str("// Generated by build.rs from Units.json. Do not edit.\n\n"); + output.push_str(&format!( + "pub(crate) static LENGTH_UNIT_NAMES: [&str; {}] = {:?};\n\n", + names.len(), + names + )); + output.push_str(&format!( + "pub(crate) static LENGTH_UNIT_CANONICAL_PX_RATIOS: [f64; {}] = [{}];\n", + ratios.len(), + ratios.join(", ") + )); + std::fs::write(out_dir.join("length_units_generated.rs"), output)?; + + // Canonical-unit ratios for the other dimensions, indexed by unit code in + // JSON order like the C++ unit enums. Relative units (none exist outside + // lengths) would be NaN. + let mut output = String::from("// Generated by build.rs from Units.json. Do not edit.\n"); + for dimension in ["angle", "flex", "frequency", "resolution", "time"] { + let units = value[dimension] + .as_object() + .ok_or_else(|| format!("Units.json has no {dimension} object"))?; + let mut ratios = Vec::new(); + for (_, unit) in units { + let object = unit.as_object().unwrap(); + if object + .get("is-canonical-unit") + .is_some_and(|canonical| canonical.as_bool() == Some(true)) + { + ratios.push("1.0".to_string()); + } else if let Some(ratio) = object.get("number-of-canonical-unit") { + ratios.push(format!("{:?}", ratio.as_f64().unwrap())); + } else { + ratios.push("f64::NAN".to_string()); + } + } + output.push_str(&format!( + "\npub(crate) static {}_UNIT_CANONICAL_RATIOS: [f64; {}] = [{}];\n", + dimension.to_uppercase(), + ratios.len(), + ratios.join(", ") + )); + let names: Vec<&str> = units.keys().map(String::as_str).collect(); + output.push_str(&format!( + "\n#[allow(dead_code)]\npub(crate) static {}_UNIT_NAMES: [&str; {}] = {:?};\n", + dimension.to_uppercase(), + names.len(), + names + )); + } + std::fs::write(out_dir.join("dimension_units_generated.rs"), output)?; + Ok(()) +} + +// Generates keyword codes for the Rust style computation core from Keywords.json. +// Invalid is 0 and the codes follow the array order, matching the C++ Keyword enum. +fn generate_keywords(manifest_dir: &Path, out_dir: &Path) -> Result<(), Box> { + let keywords_path = manifest_dir.parent().unwrap().join("CSS/Keywords.json"); + println!("cargo:rerun-if-changed={}", keywords_path.display()); + let value: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&keywords_path)?)?; + let keywords = value.as_array().ok_or("Keywords.json is not an array")?; + + let mut output = String::new(); + output.push_str("// Generated by build.rs from Keywords.json. Do not edit.\n\n"); + output.push_str("#[allow(dead_code)]\npub mod keyword {\n"); + output.push_str(" pub const INVALID: u16 = 0;\n"); + for (index, keyword) in keywords.iter().enumerate() { + let name = keyword.as_str().unwrap(); + let constant = name.replace('-', "_").to_uppercase(); + output.push_str(&format!(" pub const {constant}: u16 = {};\n", index + 1)); + } + output.push_str("}\n"); + std::fs::write(out_dir.join("keywords_generated.rs"), output)?; + Ok(()) +} + +// Generates enum value codes for the Rust style computation core from Enums.json. +// Values follow the array order skipping aliases, matching the C++ enum generator. +fn generate_css_enums(manifest_dir: &Path, out_dir: &Path) -> Result<(), Box> { + let enums_path = manifest_dir.parent().unwrap().join("CSS/Enums.json"); + println!("cargo:rerun-if-changed={}", enums_path.display()); + let value: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&enums_path)?)?; + let enums = value.as_object().ok_or("Enums.json is not an object")?; + + let mut output = String::new(); + output.push_str("// Generated by build.rs from Enums.json. Do not edit.\n\n"); + for (name, values) in enums { + let values = values.as_array().ok_or("enum values are not an array")?; + let module = name.replace('-', "_"); + output.push_str(&format!("#[allow(dead_code)]\npub mod {module} {{\n")); + let mut code: u8 = 0; + for value in values { + let value = value.as_str().ok_or("enum value is not a string")?; + // Aliases are not included in the enum. + if value.contains('=') { + continue; + } + let constant = value.replace('-', "_").to_uppercase(); + output.push_str(&format!(" pub const {constant}: u8 = {code};\n")); + code = code.checked_add(1).ok_or("enum has too many values for u8")?; + } + output.push_str("}\n\n"); - let header = Path::new("HTML/Parser/RustFFI.h"); - let builder = cbindgen::Builder::new() - .with_config(html_config) - .with_src(manifest_dir.join("src/encoding_detection.rs")); + // The keyword-to-enum-value mapping, mirroring the C++ keyword_to_ generator, + // including its alias handling ("keyword=member" maps the keyword to member's value). + let mut member_codes = std::collections::HashMap::new(); + let mut member_code: u8 = 0; + for value in values { + let value = value.as_str().ok_or("enum value is not a string")?; + if value.contains('=') { + continue; + } + member_codes.insert(value.to_string(), member_code); + member_code = member_code.checked_add(1).ok_or("enum has too many values for u8")?; + } + output.push_str(&format!( + "#[allow(dead_code)]\npub fn keyword_to_{module}(keyword: u16) -> Option {{\n match keyword {{\n" + )); + for value in values { + let value = value.as_str().ok_or("enum value is not a string")?; + let (keyword_name, member_name) = match value.split_once('=') { + Some((keyword, member)) => (keyword, member), + None => (value, value), + }; + let keyword_constant = keyword_name.replace('-', "_").to_uppercase(); + let code = member_codes + .get(member_name) + .ok_or("enum alias targets an unknown member")?; + output.push_str(&format!(" keyword::{keyword_constant} => Some({code}),\n")); + } + output.push_str(" _ => None,\n }\n}\n\n"); + } + std::fs::write(out_dir.join("css_enums_generated.rs"), output)?; + Ok(()) +} + +fn generate_ffi_header( + config: cbindgen::Config, + sources: &[PathBuf], + out_dir: &Path, + ffi_out_dir: &Path, + header: &Path, +) { + let builder = sources + .iter() + .fold(cbindgen::Builder::new().with_config(config), |builder, source| { + builder.with_src(source) + }); builder.generate().map_or_else( |error| match error { cbindgen::Error::ParseSyntaxError { .. } => {} @@ -48,6 +798,217 @@ fn main() -> Result<(), Box> { } }, ); +} + +/// Strict variant for the layout headers: dormant layout sources are parsed +/// by cbindgen before they join the module tree, so a syntax error anywhere +/// must fail the build instead of silently producing a stale header. +fn generate_ffi_header_strict( + config: cbindgen::Config, + sources: &[PathBuf], + out_dir: &Path, + ffi_out_dir: &Path, + header: &Path, +) { + let builder = sources + .iter() + .fold(cbindgen::Builder::new().with_config(config), |builder, source| { + builder.with_src(source) + }); + builder.generate().map_or_else( + |error| panic!("{error}"), + |bindings| { + let output_header = out_dir.join(header); + std::fs::create_dir_all(output_header.parent().unwrap()).unwrap(); + bindings.write_to_file(output_header); + if ffi_out_dir != out_dir { + let ffi_header = ffi_out_dir.join(header); + std::fs::create_dir_all(ffi_header.parent().unwrap()).unwrap(); + bindings.write_to_file(ffi_header); + } + }, + ); +} + +fn main() -> Result<(), Box> { + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); + let out_dir = PathBuf::from(env::var("OUT_DIR")?); + + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=cbindgen.toml"); + println!("cargo:rerun-if-env-changed=FFI_OUTPUT_DIR"); + println!("cargo:rerun-if-changed=src"); + + generate_selector_pseudo_types(&manifest_dir, &out_dir)?; + generate_property_metadata(&manifest_dir, &out_dir)?; + generate_length_units(&manifest_dir, &out_dir)?; + generate_keywords(&manifest_dir, &out_dir)?; + generate_css_enums(&manifest_dir, &out_dir)?; + + let ffi_out_dir = env::var("FFI_OUTPUT_DIR") + .map(PathBuf::from) + .unwrap_or_else(|_| out_dir.clone()); + + let base_config = cbindgen::Config::from_file(manifest_dir.join("cbindgen.toml"))?; + + // CSS tokenizer header — namespace Web::CSS::Parser::FFI, CSS types only. + let mut css_config = base_config.clone(); + css_config.namespaces = Some(vec![ + "Web".to_string(), + "CSS".to_string(), + "Parser".to_string(), + "FFI".to_string(), + ]); + css_config.export.include = vec![ + "CssHashType".to_string(), + "CssNumberType".to_string(), + "CssToken".to_string(), + "CssTokenType".to_string(), + ]; + + generate_ffi_header( + css_config, + &[manifest_dir.join("src/css/css_tokenizer.rs")], + &out_dir, + &ffi_out_dir, + Path::new("RustFFI.h"), + ); + + // Selector matching header - namespace Web::CSS::SelectorFFI. Generate both sides of this + // ABI from the Rust declarations so changes to layouts or signatures cannot drift silently. + let mut selector_config = base_config.clone(); + selector_config.namespaces = Some(vec!["Web".to_string(), "CSS".to_string(), "SelectorFFI".to_string()]); + for (rust_name, cxx_name) in [ + ("FfiSimpleSelectorType", "SimpleSelectorType"), + ("FfiDirection", "Direction"), + ("FfiPseudoElementValueType", "PseudoElementValueType"), + ("FfiStringView", "StringView"), + ("FfiSimpleSelector", "SimpleSelector"), + ("FfiCompoundSelector", "CompoundSelector"), + ("FfiSelector", "Selector"), + ("FfiElement", "Element"), + ("FfiElementQualifiedName", "ElementQualifiedName"), + ("FfiInternedStringList", "InternedStringList"), + ("FfiDomStringView", "DomStringView"), + ("FfiDomAttribute", "DomAttribute"), + ("FfiResolvedNamespaceType", "ResolvedNamespaceType"), + ("FfiResolvedNamespace", "ResolvedNamespace"), + ("FfiElementAndShadowHost", "ElementAndShadowHost"), + ] { + selector_config + .export + .rename + .insert(rust_name.to_string(), cxx_name.to_string()); + } + + generate_ffi_header( + selector_config, + &[ + manifest_dir.join("src/css/selector_engine.rs"), + manifest_dir.join("src/css/ffi_support.rs"), + ], + &out_dir, + &ffi_out_dir, + Path::new("SelectorRustFFI.h"), + ); + + // Style value header - namespace Web::CSS::StyleValueFFI. The StyleValueData layout is + // exposed so converted C++ StyleValue subclasses can read variant payloads inline without + // an FFI call. + let mut style_value_config = base_config.clone(); + style_value_config.namespaces = Some(vec!["Web".to_string(), "CSS".to_string(), "StyleValueFFI".to_string()]); + style_value_config.export.include = vec!["StyleValueData".to_string()]; + + generate_ffi_header( + style_value_config, + &[ + manifest_dir.join("src/css/style_value.rs"), + manifest_dir.join("src/css/color_interpolation.rs"), + manifest_dir.join("src/css/animation.rs"), + manifest_dir.join("src/css/transition.rs"), + manifest_dir.join("src/css/calc.rs"), + manifest_dir.join("src/css/ffi_stats.rs"), + ], + &out_dir, + &ffi_out_dir, + Path::new("StyleValueRustFFI.h"), + ); + + // Computed values header - namespace Web::CSS::ComputedValuesFFI. Exposes the style group + // vtable and lifecycle functions; the reference count header layout is documented in + // computed_values.rs and mirrored by StyleStructRef. + let mut computed_values_config = base_config.clone(); + computed_values_config.namespaces = Some(vec![ + "Web".to_string(), + "CSS".to_string(), + "ComputedValuesFFI".to_string(), + ]); + computed_values_config.export.include = vec![ + "StyleGroupVTable".to_string(), + "STYLE_GROUP_STATIC_REFCOUNT".to_string(), + "CascadeOrigin".to_string(), + ]; + + generate_ffi_header( + computed_values_config, + &[ + manifest_dir.join("src/css/computed_values.rs"), + manifest_dir.join("src/css/property_metadata.rs"), + manifest_dir.join("src/css/style_compute.rs"), + manifest_dir.join("src/css/display.rs"), + manifest_dir.join("src/css/computed_value_types.rs"), + manifest_dir.join("src/css/css_pixels.rs"), + manifest_dir.join("src/css/cascaded_properties.rs"), + manifest_dir.join("src/css/custom_properties.rs"), + ], + &out_dir, + &ffi_out_dir, + Path::new("ComputedValuesRustFFI.h"), + ); + + // Encoding-detection header - namespace Web::HTML::Parser, rust_detect_encoding only. + let mut html_config = base_config.clone(); + html_config.namespaces = Some(vec!["Web".to_string(), "HTML".to_string(), "Parser".to_string()]); + html_config.export.include = vec!["rust_detect_encoding".to_string()]; + + generate_ffi_header( + html_config, + &[manifest_dir.join("src/encoding_detection.rs")], + &out_dir, + &ffi_out_dir, + Path::new("HTML/Parser/RustFFI.h"), + ); + + // Layout tree-builder header - namespace Web::Layout::RustFFI. The node arena and its + // node records are read directly by the C++ layout tree wrappers. + let mut tree_builder_config = base_config; + tree_builder_config.namespaces = Some(vec!["Web".to_string(), "Layout".to_string(), "RustFFI".to_string()]); + tree_builder_config.export.include = vec![ + "FfiNodeKindFacts".to_string(), + "FfiTableDisplay".to_string(), + "NodeAllocation".to_string(), + "NodeData".to_string(), + "NodeDisplayFlag".to_string(), + "NodeFlag".to_string(), + "NodeKind".to_string(), + "NodeSlotId".to_string(), + ]; + tree_builder_config.export.exclude = vec![ + "rust_calc_node_create_numeric_dimension".to_string(), + "rust_calc_resolve".to_string(), + ]; + generate_ffi_header_strict( + tree_builder_config, + &[ + manifest_dir.join("src/layout/layout_node_arena.rs"), + manifest_dir.join("src/layout/node_data.rs"), + manifest_dir.join("src/layout/tree_builder.rs"), + manifest_dir.join("../../RustAllocator.rs"), + ], + &out_dir, + &ffi_out_dir, + Path::new("Layout/TreeBuilderRustFFI.h"), + ); Ok(()) } diff --git a/Libraries/LibWeb/CSS/Rust/src/animation.rs b/Libraries/LibWeb/Rust/src/css/animation.rs similarity index 95% rename from Libraries/LibWeb/CSS/Rust/src/animation.rs rename to Libraries/LibWeb/Rust/src/css/animation.rs index f869d9e330bec..a12f15449df04 100644 --- a/Libraries/LibWeb/CSS/Rust/src/animation.rs +++ b/Libraries/LibWeb/Rust/src/css/animation.rs @@ -11,8 +11,8 @@ use std::sync::Arc; -use crate::property_metadata::{property_animation_type, property_numeric_ranges}; -use crate::style_value::{ +use crate::css::property_metadata::{property_animation_type, property_numeric_ranges}; +use crate::css::style_value::{ ColorBase, GridTrackEntryKind, RetainedGridTrackEntry, RetainedGridTrackEntryList, RetainedNumericRangeList, RetainedShapePoint, RetainedShapePointList, RetainedStyleValueData, RetainedStyleValueDataList, RetainedUtf16FlyString, RetainedUtf16FlyStringList, StyleValueData, @@ -496,7 +496,7 @@ struct AnimationPropertyConflictCandidate { fn property_is_important(property_id: u16, bitmap: &[u8]) -> bool { let Some(index) = property_id - .checked_sub(crate::property_metadata::FIRST_LONGHAND_PROPERTY_ID) + .checked_sub(crate::css::property_metadata::FIRST_LONGHAND_PROPERTY_ID) .map(usize::from) else { return false; @@ -525,15 +525,15 @@ fn animation_specified_value_source(value: &StyleValueData, property_id: u16) -> // https://www.w3.org/TR/css-cascade-4/#inherit // If the cascaded value of a property is the inherit keyword, the property's specified and // computed values are the inherited value. - if *keyword == crate::style_compute::keyword::INHERIT { + if *keyword == crate::css::style_compute::keyword::INHERIT { return FfiAnimationSpecifiedValueSource::Inherited; } // https://www.w3.org/TR/css-cascade-4/#inherit-initial // If the cascaded value of a property is the unset keyword, then if it is an inherited // property, this is treated as inherit, and if it is not, this is treated as initial. - if *keyword == crate::style_compute::keyword::UNSET { - return if crate::property_metadata::property_is_inherited(property_id) { + if *keyword == crate::css::style_compute::keyword::UNSET { + return if crate::css::property_metadata::property_is_inherited(property_id) { FfiAnimationSpecifiedValueSource::Inherited } else { FfiAnimationSpecifiedValueSource::Initial @@ -543,12 +543,12 @@ fn animation_specified_value_source(value: &StyleValueData, property_id: u16) -> // https://www.w3.org/TR/css-cascade-4/#initial // If the cascaded value of a property is the initial keyword, the property's specified value // is its initial value. - if *keyword == crate::style_compute::keyword::INITIAL { + if *keyword == crate::css::style_compute::keyword::INITIAL { return FfiAnimationSpecifiedValueSource::Initial; } if matches!( *keyword, - crate::style_compute::keyword::REVERT | crate::style_compute::keyword::REVERT_LAYER + crate::css::style_compute::keyword::REVERT | crate::css::style_compute::keyword::REVERT_LAYER ) { return FfiAnimationSpecifiedValueSource::Underlying; } @@ -579,7 +579,7 @@ fn resolve_animation_property_conflicts( continue; } if !winner.use_initial - && !crate::property_metadata::animation_property_is_preferred( + && !crate::css::property_metadata::animation_property_is_preferred( candidate.source_property_id, winner.source_property_id, ) @@ -613,20 +613,20 @@ fn resolve_animation_declarations( !declaration.value.is_null(), "animation declaration value must not be null" ); - crate::style_compute::expand_shorthands_with( + crate::css::style_compute::expand_shorthands_with( declaration.property_id, declaration.value.cast(), false, &mut |longhand_id, data, _| { let physical_property_id = - crate::style_compute::map_logical_alias_to_physical(longhand_id, writing_mode, direction); + crate::css::style_compute::map_logical_alias_to_physical(longhand_id, writing_mode, direction); candidates.push(AnimationPropertyConflictCandidate { keyframe_index: declaration.keyframe_index, physical_property_id, source_property_id: declaration.property_id, source_longhand_id: longhand_id, value: unsafe { - RetainedStyleValueData::from_retained_pointer(crate::style_value::rust_style_value_retain( + RetainedStyleValueData::from_retained_pointer(crate::css::style_value::rust_style_value_retain( data.cast(), )) }, @@ -827,7 +827,7 @@ fn handled_without_value() -> FfiAnimationValueResult { } fn handled_retained_value(value: RetainedStyleValueData) -> FfiAnimationValueResult { - let pointer = unsafe { crate::style_value::rust_style_value_retain(value.data()) }; + let pointer = unsafe { crate::css::style_value::rust_style_value_retain(value.data()) }; FfiAnimationValueResult { value: pointer, handled: true, @@ -845,7 +845,7 @@ fn discrete_value( } let value = if delta < 0.5 { from } else { to }; FfiAnimationValueResult { - value: unsafe { crate::style_value::rust_style_value_retain(value) }, + value: unsafe { crate::css::style_value::rust_style_value_retain(value) }, handled: true, } } @@ -864,7 +864,7 @@ fn interpolate_visibility( if from_keyword == to_keyword { return FfiAnimationValueResult { - value: unsafe { crate::style_value::rust_style_value_retain(from) }, + value: unsafe { crate::css::style_value::rust_style_value_retain(from) }, handled: true, }; } @@ -872,7 +872,7 @@ fn interpolate_visibility( // https://drafts.csswg.org/web-animations-1/#animating-visibility // For the visibility property, visible is interpolated as a discrete step where values of p between 0 and 1 map to visible and other values of p map to the closer endpoint. // If neither value is visible, then discrete animation is used. - let visible = crate::style_compute::keyword::VISIBLE; + let visible = crate::css::style_compute::keyword::VISIBLE; if *from_keyword == visible || *to_keyword == visible { let value = if delta <= 0.0 { from @@ -884,7 +884,7 @@ fn interpolate_visibility( to }; return FfiAnimationValueResult { - value: unsafe { crate::style_value::rust_style_value_retain(value) }, + value: unsafe { crate::css::style_value::rust_style_value_retain(value) }, handled: true, }; } @@ -906,7 +906,7 @@ fn interpolate_content_visibility( if from_keyword == to_keyword { return FfiAnimationValueResult { - value: unsafe { crate::style_value::rust_style_value_retain(from) }, + value: unsafe { crate::css::style_value::rust_style_value_retain(from) }, handled: true, }; } @@ -915,7 +915,7 @@ fn interpolate_content_visibility( // In general, the content-visibility property’s animation type is discrete. // However, similar to interpolation of visibility, during interpolation between hidden and any other content-visibility value, // p values between 0 and 1 map to the non-hidden value. - let hidden = crate::style_compute::keyword::HIDDEN; + let hidden = crate::css::style_compute::keyword::HIDDEN; if *from_keyword == hidden || *to_keyword == hidden { if !context.is_some_and(|context| context.allow_discrete) { return handled_without_value(); @@ -928,7 +928,7 @@ fn interpolate_content_visibility( from }; return FfiAnimationValueResult { - value: unsafe { crate::style_value::rust_style_value_retain(value) }, + value: unsafe { crate::css::style_value::rust_style_value_retain(value) }, handled: true, }; } @@ -948,7 +948,7 @@ fn interpolate_display( if from_raw == to_raw { return FfiAnimationValueResult { - value: unsafe { crate::style_value::rust_style_value_retain(from) }, + value: unsafe { crate::css::style_value::rust_style_value_retain(from) }, handled: true, }; } @@ -960,8 +960,8 @@ fn interpolate_display( // inert as long as its display value would compute to none when ignoring the Transitions and Animations // cascade origins. // FIXME: Implement the inertness portion of this. - let from_is_none = crate::style_compute::display_is_none(*from_raw); - let to_is_none = crate::style_compute::display_is_none(*to_raw); + let from_is_none = crate::css::style_compute::display_is_none(*from_raw); + let to_is_none = crate::css::style_compute::display_is_none(*to_raw); if from_is_none || to_is_none { if !context.is_some_and(|context| context.allow_discrete) { return handled_without_value(); @@ -974,7 +974,7 @@ fn interpolate_display( from }; return FfiAnimationValueResult { - value: unsafe { crate::style_value::rust_style_value_retain(value) }, + value: unsafe { crate::css::style_value::rust_style_value_retain(value) }, handled: true, }; } @@ -983,12 +983,12 @@ fn interpolate_display( } fn interpolate_scale(from: &StyleValueData, to: &StyleValueData, delta: f32) -> FfiAnimationValueResult { - let none = crate::style_compute::none_keyword(); + let none = crate::css::style_compute::none_keyword(); if matches!(from, StyleValueData::Keyword { keyword } if *keyword == none) && matches!(to, StyleValueData::Keyword { keyword } if *keyword == none) { return FfiAnimationValueResult { - value: unsafe { crate::style_value::rust_style_value_retain(from) }, + value: unsafe { crate::css::style_value::rust_style_value_retain(from) }, handled: true, }; } @@ -1019,8 +1019,8 @@ fn interpolate_scale(from: &StyleValueData, to: &StyleValueData, delta: f32) -> StyleValueData::Number { value } => Some(*value), StyleValueData::Percentage { value } => Some(*value / 100.0), calculated @ StyleValueData::Calculated { .. } => { - crate::calc::resolve_calculated_number_without_context(calculated).or_else(|| { - crate::calc::resolve_calculated_percentage_without_context(calculated) + crate::css::calc::resolve_calculated_number_without_context(calculated).or_else(|| { + crate::css::calc::resolve_calculated_percentage_without_context(calculated) .map(|value| value / 100.0) }) } @@ -1042,7 +1042,7 @@ fn interpolate_scale(from: &StyleValueData, to: &StyleValueData, delta: f32) -> .map(|(from, to)| retained_number(interpolate_f64(from, to, delta, None))) .collect(); owned(StyleValueData::Transformation { - property: crate::property_metadata::property_id::SCALE, + property: crate::css::property_metadata::property_id::SCALE, transform_function: if is_3d { TRANSFORM_FUNCTION_SCALE_3D } else { @@ -1052,61 +1052,61 @@ fn interpolate_scale(from: &StyleValueData, to: &StyleValueData, delta: f32) -> }) } -fn length_percentage_calculation_node(value: &StyleValueData) -> Option> { +fn length_percentage_calculation_node(value: &StyleValueData) -> Option> { match value { - StyleValueData::Length { value, unit } => Some(Arc::new(crate::calc::CalcNode::Numeric( - crate::calc::CalcNumericValue::Length { + StyleValueData::Length { value, unit } => Some(Arc::new(crate::css::calc::CalcNode::Numeric( + crate::css::calc::CalcNumericValue::Length { value: *value, unit: *unit, }, ))), - StyleValueData::Percentage { value } => Some(Arc::new(crate::calc::CalcNode::Numeric( - crate::calc::CalcNumericValue::Percentage(*value), + StyleValueData::Percentage { value } => Some(Arc::new(crate::css::calc::CalcNode::Numeric( + crate::css::calc::CalcNumericValue::Percentage(*value), ))), StyleValueData::Calculated { rust_calculation, .. } => Some(rust_calculation.node_arc()), _ => None, } } -fn numeric_calculation_node(value: &StyleValueData) -> Option> { +fn numeric_calculation_node(value: &StyleValueData) -> Option> { let numeric = match value { - StyleValueData::Number { value } => crate::calc::CalcNumericValue::Number { + StyleValueData::Number { value } => crate::css::calc::CalcNumericValue::Number { value: *value, number_type: 0, }, - StyleValueData::Integer { value } => crate::calc::CalcNumericValue::Number { + StyleValueData::Integer { value } => crate::css::calc::CalcNumericValue::Number { value: *value as f64, number_type: 2, }, - StyleValueData::Angle { value, unit } => crate::calc::CalcNumericValue::Angle { + StyleValueData::Angle { value, unit } => crate::css::calc::CalcNumericValue::Angle { value: *value, unit: *unit, }, - StyleValueData::Flex { value, unit } => crate::calc::CalcNumericValue::Flex { + StyleValueData::Flex { value, unit } => crate::css::calc::CalcNumericValue::Flex { value: *value, unit: *unit, }, - StyleValueData::Frequency { value, unit } => crate::calc::CalcNumericValue::Frequency { + StyleValueData::Frequency { value, unit } => crate::css::calc::CalcNumericValue::Frequency { value: *value, unit: *unit, }, - StyleValueData::Length { value, unit } => crate::calc::CalcNumericValue::Length { + StyleValueData::Length { value, unit } => crate::css::calc::CalcNumericValue::Length { value: *value, unit: *unit, }, - StyleValueData::Percentage { value } => crate::calc::CalcNumericValue::Percentage(*value), - StyleValueData::Resolution { value, unit } => crate::calc::CalcNumericValue::Resolution { + StyleValueData::Percentage { value } => crate::css::calc::CalcNumericValue::Percentage(*value), + StyleValueData::Resolution { value, unit } => crate::css::calc::CalcNumericValue::Resolution { value: *value, unit: *unit, }, - StyleValueData::Time { value, unit } => crate::calc::CalcNumericValue::Time { + StyleValueData::Time { value, unit } => crate::css::calc::CalcNumericValue::Time { value: *value, unit: *unit, }, StyleValueData::Calculated { rust_calculation, .. } => return Some(rust_calculation.node_arc()), _ => return None, }; - Some(Arc::new(crate::calc::CalcNode::Numeric(numeric))) + Some(Arc::new(crate::css::calc::CalcNode::Numeric(numeric))) } struct AnimationCalculationContext<'a> { @@ -1142,12 +1142,12 @@ fn animation_calculation_context(value: &StyleValueData) -> Option, - resolved_type: crate::calc::FfiNumericType, + calculation: Arc, + resolved_type: crate::css::calc::FfiNumericType, context: &AnimationCalculationContext<'_>, ) -> RetainedStyleValueData { let value = Arc::into_raw(Arc::new(StyleValueData::Calculated { - rust_calculation: crate::calc::CalcNodeHandle::from_arc(calculation), + rust_calculation: crate::css::calc::CalcNodeHandle::from_arc(calculation), resolve_as_is_number: context.resolve_as_is_number, resolve_as_base: context.resolve_as_base, resolved_type, @@ -1160,21 +1160,21 @@ fn retained_calculation( } fn retained_length_percentage_calculation( - calculation: Arc, - resolved_type: crate::calc::FfiNumericType, + calculation: Arc, + resolved_type: crate::css::calc::FfiNumericType, ) -> RetainedStyleValueData { let value = match &*calculation { - crate::calc::CalcNode::Numeric(crate::calc::CalcNumericValue::Length { value, unit }) => { + crate::css::calc::CalcNode::Numeric(crate::css::calc::CalcNumericValue::Length { value, unit }) => { StyleValueData::Length { value: *value, unit: *unit, } } - crate::calc::CalcNode::Numeric(crate::calc::CalcNumericValue::Percentage(value)) => { + crate::css::calc::CalcNode::Numeric(crate::css::calc::CalcNumericValue::Percentage(value)) => { StyleValueData::Percentage { value: *value } } _ => StyleValueData::Calculated { - rust_calculation: crate::calc::CalcNodeHandle::from_arc(calculation), + rust_calculation: crate::css::calc::CalcNodeHandle::from_arc(calculation), resolve_as_is_number: false, resolve_as_base: 0, resolved_type, @@ -1221,17 +1221,17 @@ fn interpolate_translate_component( let from = length_percentage_calculation_node(from)?; let to = length_percentage_calculation_node(to)?; - let (calculation, resolved_type) = crate::calc::interpolate_length_percentage_calculations(from, to, delta)?; + let (calculation, resolved_type) = crate::css::calc::interpolate_length_percentage_calculations(from, to, delta)?; Some(retained_length_percentage_calculation(calculation, resolved_type)) } fn interpolate_translate(from: &StyleValueData, to: &StyleValueData, delta: f32) -> FfiAnimationValueResult { - let none = crate::style_compute::none_keyword(); + let none = crate::css::style_compute::none_keyword(); if matches!(from, StyleValueData::Keyword { keyword } if *keyword == none) && matches!(to, StyleValueData::Keyword { keyword } if *keyword == none) { return FfiAnimationValueResult { - value: unsafe { crate::style_value::rust_style_value_retain(from) }, + value: unsafe { crate::css::style_value::rust_style_value_retain(from) }, handled: true, }; } @@ -1248,7 +1248,7 @@ fn interpolate_translate(from: &StyleValueData, to: &StyleValueData, delta: f32) let zero = || { let zero = Arc::into_raw(Arc::new(StyleValueData::Length { value: 0.0, - unit: crate::calc::canonical_pixel_unit(), + unit: crate::css::calc::canonical_pixel_unit(), })); unsafe { RetainedStyleValueData::from_retained_pointer(zero) } }; @@ -1276,7 +1276,7 @@ fn interpolate_translate(from: &StyleValueData, to: &StyleValueData, delta: f32) let zero = || { let zero = Arc::into_raw(Arc::new(StyleValueData::Length { value: 0.0, - unit: crate::calc::canonical_pixel_unit(), + unit: crate::css::calc::canonical_pixel_unit(), })); unsafe { RetainedStyleValueData::from_retained_pointer(zero) } }; @@ -1289,7 +1289,7 @@ fn interpolate_translate(from: &StyleValueData, to: &StyleValueData, delta: f32) .zip(to.iter()) .map(|(from, to)| { interpolate_translate_component( - crate::property_metadata::property_id::TRANSLATE, + crate::css::property_metadata::property_id::TRANSLATE, from.data(), to.data(), delta, @@ -1300,7 +1300,7 @@ fn interpolate_translate(from: &StyleValueData, to: &StyleValueData, delta: f32) return not_handled(); }; owned(StyleValueData::Transformation { - property: crate::property_metadata::property_id::TRANSLATE, + property: crate::css::property_metadata::property_id::TRANSLATE, transform_function: if is_3d { TRANSFORM_FUNCTION_TRANSLATE_3D } else { @@ -1311,12 +1311,12 @@ fn interpolate_translate(from: &StyleValueData, to: &StyleValueData, delta: f32) } fn interpolate_individual_rotate(from: &StyleValueData, to: &StyleValueData, delta: f32) -> FfiAnimationValueResult { - let none = crate::style_compute::none_keyword(); + let none = crate::css::style_compute::none_keyword(); if matches!(from, StyleValueData::Keyword { keyword } if *keyword == none) && matches!(to, StyleValueData::Keyword { keyword } if *keyword == none) { return FfiAnimationValueResult { - value: unsafe { crate::style_value::rust_style_value_retain(from) }, + value: unsafe { crate::css::style_value::rust_style_value_retain(from) }, handled: true, }; } @@ -1356,7 +1356,7 @@ fn interpolate_individual_rotate(from: &StyleValueData, to: &StyleValueData, del unit: 0, })); return owned(StyleValueData::Transformation { - property: crate::property_metadata::property_id::ROTATE, + property: crate::css::property_metadata::property_id::ROTATE, transform_function: TRANSFORM_FUNCTION_ROTATE, values: RetainedStyleValueDataList::from_retained_values(vec![unsafe { RetainedStyleValueData::from_retained_pointer(angle) @@ -1405,7 +1405,7 @@ fn interpolate_individual_rotate(from: &StyleValueData, to: &StyleValueData, del return not_handled(); }; interpolate_rotate_3d( - crate::property_metadata::property_id::ROTATE, + crate::css::property_metadata::property_id::ROTATE, TRANSFORM_FUNCTION_ROTATE_3D, &from, &to, @@ -1704,7 +1704,7 @@ fn composite_grid_component( length_percentage_calculation_node(underlying.data()), length_percentage_calculation_node(animated.data()), ) && let Some((calculation, resolved_type)) = - crate::calc::add_length_percentage_calculations(underlying, animated) + crate::css::calc::add_length_percentage_calculations(underlying, animated) { // https://drafts.csswg.org/css-values-4/#combine-mixed // Addition of is defined the same as interpolation except by adding each component rather than interpolating it. @@ -1869,7 +1869,9 @@ fn resolve_color_component(value: &StyleValueData, reference_value: f32) -> Opti match value { StyleValueData::Number { value } => Some((*value as f32, false)), StyleValueData::Percentage { value } => Some((*value as f32 / 100.0 * reference_value, false)), - StyleValueData::Keyword { keyword } if *keyword == crate::style_compute::none_keyword() => Some((0.0, true)), + StyleValueData::Keyword { keyword } if *keyword == crate::css::style_compute::none_keyword() => { + Some((0.0, true)) + } _ => None, } } @@ -1894,7 +1896,9 @@ fn native_color_components(value: &StyleValueData) -> Option { let resolve_hue = |value: &StyleValueData| match value { StyleValueData::Number { value } => Some((*value as f32, false)), StyleValueData::Angle { value, unit } => angle_to_degrees(*value, *unit).map(|value| (value as f32, false)), - StyleValueData::Keyword { keyword } if *keyword == crate::style_compute::none_keyword() => Some((0.0, true)), + StyleValueData::Keyword { keyword } if *keyword == crate::css::style_compute::none_keyword() => { + Some((0.0, true)) + } _ => None, }; let resolve = |value: &RetainedStyleValueData, reference: f32| resolve_color_component(value.data(), reference); @@ -2062,7 +2066,7 @@ fn substitute_missing_components( fn legacy_srgb_components(value: &StyleValueData) -> Option<([f32; 4], [bool; 4])> { let color = native_color_components(value)?; - let components = crate::color_conversion::legacy_color_to_srgb(color.color_type, color.components)?; + let components = crate::css::color_conversion::legacy_color_to_srgb(color.color_type, color.components)?; let missing = carry_forward_missing_components( color.missing, color_component_categories(color.color_type), @@ -2086,8 +2090,8 @@ fn interpolate_modern_color(from: &StyleValueData, to: &StyleValueData, delta: f // 3. converting them both to a given color space which will be referred to as the interpolation color space // below. - let mut from_components = crate::color_conversion::to_oklab(from.color_type, from.components)?; - let mut to_components = crate::color_conversion::to_oklab(to.color_type, to.components)?; + let mut from_components = crate::css::color_conversion::to_oklab(from.color_type, from.components)?; + let mut to_components = crate::css::color_conversion::to_oklab(to.color_type, to.components)?; let target_categories = color_component_categories(COLOR_TYPE_OKLAB); let from_missing = carry_forward_missing_components( from.missing, @@ -2643,7 +2647,7 @@ fn composite_scalar_value( if let Some(context) = animation_calculation_context(underlying).or_else(|| animation_calculation_context(animated)) && let (Some(underlying), Some(animated)) = (numeric_calculation_node(underlying), numeric_calculation_node(animated)) - && let Some((calculation, resolved_type)) = crate::calc::add_calculations( + && let Some((calculation, resolved_type)) = crate::css::calc::add_calculations( underlying, animated, context.has_percentages_resolve_as, @@ -2664,7 +2668,7 @@ fn composite_scalar_value( length_percentage_calculation_node(animated), ) && let Some((calculation, resolved_type)) = - crate::calc::add_length_percentage_calculations(underlying, animated) + crate::css::calc::add_length_percentage_calculations(underlying, animated) { // https://drafts.csswg.org/css-values-4/#combine-mixed // Addition of is defined the same as interpolation except by adding each component rather than interpolating it. @@ -3268,7 +3272,7 @@ fn interpolate_scalar_value( ) -> FfiAnimationValueResult { if let Some(context) = animation_calculation_context(from).or_else(|| animation_calculation_context(to)) && let (Some(from), Some(to)) = (numeric_calculation_node(from), numeric_calculation_node(to)) - && let Some((calculation, resolved_type)) = crate::calc::interpolate_calculations( + && let Some((calculation, resolved_type)) = crate::css::calc::interpolate_calculations( from, to, delta, @@ -3309,7 +3313,7 @@ fn interpolate_scalar_value( length_percentage_calculation_node(to), ) && let Some((calculation, resolved_type)) = - crate::calc::interpolate_length_percentage_calculations(from, to, delta) + crate::css::calc::interpolate_length_percentage_calculations(from, to, delta) { return handled_retained_value(retained_length_percentage_calculation(calculation, resolved_type)); } @@ -3363,7 +3367,7 @@ fn interpolate_scalar_value( if from == to => { FfiAnimationValueResult { - value: unsafe { crate::style_value::rust_style_value_retain(from_value) }, + value: unsafe { crate::css::style_value::rust_style_value_retain(from_value) }, handled: true, } } @@ -4167,7 +4171,7 @@ fn retained_number(value: f64) -> RetainedStyleValueData { fn retained_zero_px() -> RetainedStyleValueData { let value = Arc::into_raw(Arc::new(StyleValueData::Length { value: 0.0, - unit: crate::style_compute::px_length_unit(), + unit: crate::css::style_compute::px_length_unit(), })); unsafe { RetainedStyleValueData::from_retained_pointer(value) } } @@ -4179,7 +4183,7 @@ fn retained_length(value: f64, unit: u8) -> RetainedStyleValueData { fn retained_none_keyword() -> RetainedStyleValueData { let value = Arc::into_raw(Arc::new(StyleValueData::Keyword { - keyword: crate::style_compute::none_keyword(), + keyword: crate::css::style_compute::none_keyword(), })); unsafe { RetainedStyleValueData::from_retained_pointer(value) } } @@ -4759,7 +4763,7 @@ fn transformation_to_matrix( _ => None, }; let length = |argument: &RetainedStyleValueData, reference_length: Option| match argument.data() { - StyleValueData::Length { value, unit } => crate::style_compute::absolute_length_to_px(*value, *unit), + StyleValueData::Length { value, unit } => crate::css::style_compute::absolute_length_to_px(*value, *unit), StyleValueData::Percentage { value } => { reference_length.map(|reference_length| value / 100.0 * reference_length) } @@ -4838,7 +4842,7 @@ fn transformation_to_matrix( })) } (TRANSFORM_FUNCTION_PERSPECTIVE, [argument]) => match argument.data() { - StyleValueData::Keyword { keyword } if *keyword == crate::style_compute::none_keyword() => { + StyleValueData::Keyword { keyword } if *keyword == crate::css::style_compute::none_keyword() => { Some(identity_matrix()) } _ => { @@ -4961,14 +4965,14 @@ fn interpolate_transform_list( to: &StyleValueData, delta: f32, ) -> Option> { - if matches!(from, StyleValueData::Keyword { keyword } if *keyword == crate::style_compute::none_keyword()) - && matches!(to, StyleValueData::Keyword { keyword } if *keyword == crate::style_compute::none_keyword()) + if matches!(from, StyleValueData::Keyword { keyword } if *keyword == crate::css::style_compute::none_keyword()) + && matches!(to, StyleValueData::Keyword { keyword } if *keyword == crate::css::style_compute::none_keyword()) { // https://drafts.csswg.org/css-transforms-1/#interpolation-of-transforms // * If both Va and Vb are none: // * Vresult is none. return Some(Some(StyleValueData::Keyword { - keyword: crate::style_compute::none_keyword(), + keyword: crate::css::style_compute::none_keyword(), })); } @@ -4986,7 +4990,7 @@ fn interpolate_transform_list( *separator, *collapsible, )), - StyleValueData::Keyword { keyword } if *keyword == crate::style_compute::none_keyword() => { + StyleValueData::Keyword { keyword } if *keyword == crate::css::style_compute::none_keyword() => { Some((Vec::new(), 0, false)) } _ => None, @@ -5060,7 +5064,7 @@ fn interpolate_transform_list( }; let reciprocal_depth = |argument: &RetainedStyleValueData| match argument.data() { StyleValueData::Length { value, unit } => Some((1.0 / value.max(1.0), Some(*unit))), - StyleValueData::Keyword { keyword } if *keyword == crate::style_compute::none_keyword() => { + StyleValueData::Keyword { keyword } if *keyword == crate::css::style_compute::none_keyword() => { Some((0.0, None)) } _ => None, @@ -5088,7 +5092,7 @@ fn interpolate_transform_list( value: 1.0 / reciprocal_depth, unit: from_unit .or(to_unit) - .unwrap_or_else(crate::style_compute::px_length_unit), + .unwrap_or_else(crate::css::style_compute::px_length_unit), })); unsafe { RetainedStyleValueData::from_retained_pointer(value) } }; @@ -5220,18 +5224,18 @@ fn retained_transparent_legacy_color() -> RetainedStyleValueData { fn animation_length_resolution_context( context: Option<&FfiAnimationContext>, -) -> Option { +) -> Option { let animation_context = &context .filter(|context| context.has_length_resolution_context)? .length_resolution_context; - let font_metrics = |metrics: &FfiAnimationFontMetrics| crate::style_compute::FfiFontMetrics { + let font_metrics = |metrics: &FfiAnimationFontMetrics| crate::css::style_compute::FfiFontMetrics { font_size: metrics.font_size, x_height: metrics.x_height, cap_height: metrics.cap_height, zero_advance: metrics.zero_advance, line_height: metrics.line_height, }; - Some(crate::style_compute::FfiLengthResolutionContext { + Some(crate::css::style_compute::FfiLengthResolutionContext { viewport_width: animation_context.viewport_width, viewport_height: animation_context.viewport_height, font_metrics: font_metrics(&animation_context.font_metrics), @@ -5244,10 +5248,11 @@ fn animation_length_resolution_context( fn resolve_animation_length(context: Option<&FfiAnimationContext>, value: &StyleValueData) -> Option { match value { - StyleValueData::Length { value, unit } => crate::style_compute::absolute_length_to_px(*value, *unit), - StyleValueData::Calculated { .. } => { - crate::calc::resolve_calculated_length_with_context(value, &animation_length_resolution_context(context)?) - } + StyleValueData::Length { value, unit } => crate::css::style_compute::absolute_length_to_px(*value, *unit), + StyleValueData::Calculated { .. } => crate::css::calc::resolve_calculated_length_with_context( + value, + &animation_length_resolution_context(context)?, + ), _ => None, } } @@ -5266,7 +5271,7 @@ fn interpolate_animation_length( delta, range, ), - crate::style_compute::px_length_unit(), + crate::css::style_compute::px_length_unit(), )) } @@ -5274,8 +5279,8 @@ fn resolve_animation_angle(context: Option<&FfiAnimationContext>, value: &StyleV match value { StyleValueData::Angle { value, unit } => angle_to_degrees(*value, *unit), StyleValueData::Calculated { .. } => animation_length_resolution_context(context) - .and_then(|context| crate::calc::resolve_calculated_angle_with_context(value, &context)) - .or_else(|| crate::calc::resolve_calculated_angle_without_context(value)), + .and_then(|context| crate::css::calc::resolve_calculated_angle_with_context(value, &context)) + .or_else(|| crate::css::calc::resolve_calculated_angle_without_context(value)), _ => None, } } @@ -5284,8 +5289,8 @@ fn resolve_animation_number(context: Option<&FfiAnimationContext>, value: &Style match value { StyleValueData::Number { value } => Some(*value), StyleValueData::Calculated { .. } => animation_length_resolution_context(context) - .and_then(|context| crate::calc::resolve_calculated_number_with_context(value, &context)) - .or_else(|| crate::calc::resolve_calculated_number_without_context(value)), + .and_then(|context| crate::css::calc::resolve_calculated_number_with_context(value, &context)) + .or_else(|| crate::css::calc::resolve_calculated_number_without_context(value)), _ => None, } } @@ -5296,7 +5301,7 @@ fn resolve_animation_color( ) -> Option { let use_current_color = match color.optional_data() { None => true, - Some(StyleValueData::Keyword { keyword }) => *keyword == crate::style_compute::current_color_keyword(), + Some(StyleValueData::Keyword { keyword }) => *keyword == crate::css::style_compute::current_color_keyword(), Some(_) => false, }; if !use_current_color { @@ -5306,7 +5311,7 @@ fn resolve_animation_color( if current_color.is_null() { return None; } - let retained = unsafe { crate::style_value::rust_style_value_retain(current_color) }; + let retained = unsafe { crate::css::style_value::rust_style_value_retain(current_color) }; Some(unsafe { RetainedStyleValueData::from_retained_pointer(retained) }) } @@ -5330,7 +5335,7 @@ fn resolve_root_animation_color<'a>( ) -> Option> { match color { StyleValueData::ColorFunction { .. } => Some(RootAnimationColor::Borrowed(color)), - StyleValueData::Keyword { keyword } if *keyword == crate::style_compute::current_color_keyword() => { + StyleValueData::Keyword { keyword } if *keyword == crate::css::style_compute::current_color_keyword() => { let current_color = context?.current_color; if current_color.is_null() { return None; @@ -5495,7 +5500,7 @@ fn interpolate_shadow_list( // the shorter list is otherwise compatible with the longer one let list = |value: &StyleValueData| -> Option<(Vec, u8, bool)> { match value { - StyleValueData::Keyword { keyword } if *keyword == crate::style_compute::none_keyword() => { + StyleValueData::Keyword { keyword } if *keyword == crate::css::style_compute::none_keyword() => { Some((Vec::new(), 0, false)) } StyleValueData::ValueList { @@ -5756,7 +5761,7 @@ fn accumulate_filter_function( FILTER_KIND_BLUR => retained_length( resolve_animation_length(Some(context), underlying_value.data())? + resolve_animation_length(Some(context), animated_value.data())?, - crate::style_compute::px_length_unit(), + crate::css::style_compute::px_length_unit(), ), FILTER_KIND_HUE_ROTATE => { let angle = Arc::into_raw(Arc::new(StyleValueData::Angle { @@ -5801,7 +5806,7 @@ fn accumulate_filter_function( Some(retained_length( resolve_animation_length(Some(context), underlying.data())? + resolve_animation_length(Some(context), animated.data())?, - crate::style_compute::px_length_unit(), + crate::css::style_compute::px_length_unit(), )) }; let offset_x = add_lengths(underlying_offset_x, animated_offset_x)?; @@ -5816,7 +5821,7 @@ fn accumulate_filter_function( Some(value) => resolve_animation_length(Some(context), value)?, None => 0.0, }; - retained_length(underlying + animated, crate::style_compute::px_length_unit()) + retained_length(underlying + animated, crate::css::style_compute::px_length_unit()) } else { empty_retained_style_value() }; @@ -5868,7 +5873,7 @@ fn composite_filter_list( } let list = |value: &StyleValueData| -> Option<(Vec, u8, bool)> { match value { - StyleValueData::Keyword { keyword } if *keyword == crate::style_compute::none_keyword() => { + StyleValueData::Keyword { keyword } if *keyword == crate::css::style_compute::none_keyword() => { Some((Vec::new(), 0, false)) } StyleValueData::ValueList { @@ -5979,7 +5984,7 @@ fn interpolate_filter_list( ) -> FfiAnimationValueResult { let list = |value: &StyleValueData| -> Option<(Vec, u8, bool)> { match value { - StyleValueData::Keyword { keyword } if *keyword == crate::style_compute::none_keyword() => { + StyleValueData::Keyword { keyword } if *keyword == crate::css::style_compute::none_keyword() => { Some((Vec::new(), 0, false)) } StyleValueData::ValueList { @@ -6076,7 +6081,7 @@ pub(crate) fn interpolate_value( // NB: Such values are normally filtered before evaluation. Preserve the C++ scalar API's // existing endpoint behavior if one reaches this lower-level operation. return FfiAnimationValueResult { - value: unsafe { crate::style_value::rust_style_value_retain(to) }, + value: unsafe { crate::css::style_value::rust_style_value_retain(to) }, handled: true, }; } @@ -6099,7 +6104,8 @@ pub(crate) fn interpolate_value( if animation_type == ANIMATION_TYPE_CUSTOM && matches!( property_id, - crate::property_metadata::property_id::FILTER | crate::property_metadata::property_id::BACKDROP_FILTER + crate::css::property_metadata::property_id::FILTER + | crate::css::property_metadata::property_id::BACKDROP_FILTER ) { let result = interpolate_filter_list(context, property_id, from, to, delta); @@ -6110,7 +6116,8 @@ pub(crate) fn interpolate_value( if animation_type == ANIMATION_TYPE_CUSTOM && matches!( property_id, - crate::property_metadata::property_id::BOX_SHADOW | crate::property_metadata::property_id::TEXT_SHADOW + crate::css::property_metadata::property_id::BOX_SHADOW + | crate::css::property_metadata::property_id::TEXT_SHADOW ) { let result = interpolate_shadow_list(context, property_id, from, to, delta); @@ -6119,7 +6126,7 @@ pub(crate) fn interpolate_value( } } let is_stroke_dasharray = animation_type == ANIMATION_TYPE_CUSTOM - && property_id == crate::property_metadata::property_id::STROKE_DASHARRAY; + && property_id == crate::css::property_metadata::property_id::STROKE_DASHARRAY; if is_stroke_dasharray && (!matches!(from, StyleValueData::ValueList { .. }) || !matches!(to, StyleValueData::ValueList { .. })) { @@ -6202,7 +6209,7 @@ pub(crate) fn interpolate_value( }); } if animation_type == ANIMATION_TYPE_CUSTOM - && property_id == crate::property_metadata::property_id::FONT_STYLE + && property_id == crate::css::property_metadata::property_id::FONT_STYLE && let ( StyleValueData::FontStyle { font_style: from_font_style, @@ -6262,46 +6269,47 @@ pub(crate) fn interpolate_value( angle_value, }); } - if animation_type == ANIMATION_TYPE_CUSTOM && property_id == crate::property_metadata::property_id::VISIBILITY { + if animation_type == ANIMATION_TYPE_CUSTOM && property_id == crate::css::property_metadata::property_id::VISIBILITY + { let result = interpolate_visibility(context, from, to, delta); if result.handled { return result; } } if animation_type == ANIMATION_TYPE_CUSTOM - && property_id == crate::property_metadata::property_id::CONTENT_VISIBILITY + && property_id == crate::css::property_metadata::property_id::CONTENT_VISIBILITY { let result = interpolate_content_visibility(context, from, to, delta); if result.handled { return result; } } - if animation_type == ANIMATION_TYPE_CUSTOM && property_id == crate::property_metadata::property_id::DISPLAY { + if animation_type == ANIMATION_TYPE_CUSTOM && property_id == crate::css::property_metadata::property_id::DISPLAY { let result = interpolate_display(context, from, to, delta); if result.handled { return result; } } - if animation_type == ANIMATION_TYPE_CUSTOM && property_id == crate::property_metadata::property_id::SCALE { + if animation_type == ANIMATION_TYPE_CUSTOM && property_id == crate::css::property_metadata::property_id::SCALE { let result = interpolate_scale(from, to, delta); if result.handled { return result; } } - if animation_type == ANIMATION_TYPE_CUSTOM && property_id == crate::property_metadata::property_id::TRANSLATE { + if animation_type == ANIMATION_TYPE_CUSTOM && property_id == crate::css::property_metadata::property_id::TRANSLATE { let result = interpolate_translate(from, to, delta); if result.handled { return result; } } - if animation_type == ANIMATION_TYPE_CUSTOM && property_id == crate::property_metadata::property_id::ROTATE { + if animation_type == ANIMATION_TYPE_CUSTOM && property_id == crate::css::property_metadata::property_id::ROTATE { let result = interpolate_individual_rotate(from, to, delta); if result.handled { return result; } } if animation_type == ANIMATION_TYPE_CUSTOM - && property_id == crate::property_metadata::property_id::FONT_VARIATION_SETTINGS + && property_id == crate::css::property_metadata::property_id::FONT_VARIATION_SETTINGS { let result = interpolate_font_variation_settings(context, property_id, from, to, delta); if result.handled { @@ -6309,7 +6317,7 @@ pub(crate) fn interpolate_value( } } if animation_type == ANIMATION_TYPE_CUSTOM - && property_id == crate::property_metadata::property_id::TRANSFORM + && property_id == crate::css::property_metadata::property_id::TRANSFORM && let Some(value) = interpolate_transform_list(context, property_id, from, to, delta) { return value.map_or_else( @@ -6326,8 +6334,8 @@ pub(crate) fn interpolate_value( if animation_type == ANIMATION_TYPE_CUSTOM && matches!( property_id, - crate::property_metadata::property_id::GRID_TEMPLATE_COLUMNS - | crate::property_metadata::property_id::GRID_TEMPLATE_ROWS + crate::css::property_metadata::property_id::GRID_TEMPLATE_COLUMNS + | crate::css::property_metadata::property_id::GRID_TEMPLATE_ROWS ) && let ( StyleValueData::GridTrackSizeList { @@ -6395,7 +6403,8 @@ fn composite_batch_value<'a>( ) -> BatchAnimationValue<'a> { let result = if matches!( property_id, - crate::property_metadata::property_id::FILTER | crate::property_metadata::property_id::BACKDROP_FILTER + crate::css::property_metadata::property_id::FILTER + | crate::css::property_metadata::property_id::BACKDROP_FILTER ) { composite_filter_list(context, underlying, animated, operation) } else { @@ -6453,7 +6462,7 @@ fn evaluate_animation_value( } return FfiAnimatedProperty { property_id: input.property_id, - value: unsafe { crate::style_value::rust_style_value_retain(start_keyframe.value) }, + value: unsafe { crate::css::style_value::rust_style_value_retain(start_keyframe.value) }, progress, start_index, end_index, @@ -6501,7 +6510,7 @@ pub unsafe extern "C" fn rust_evaluate_animations( callbacks: *const FfiAnimationCallbacks, ) -> usize { crate::abort_on_panic(|| { - crate::ffi_stats::rust_style_ffi_note_animation_evaluation(); + crate::css::ffi_stats::rust_style_ffi_note_animation_evaluation(); let batch = unsafe { &*batch }; let callbacks = unsafe { &*callbacks }; let declarations = unsafe { std::slice::from_raw_parts(batch.declarations, batch.declaration_count) }; @@ -6517,7 +6526,7 @@ pub unsafe extern "C" fn rust_evaluate_animations( if resolved.properties.is_empty() { return 0; } - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::AnimationComputeBatchCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::AnimationComputeBatchCallback); let computed = unsafe { (callbacks.compute_values)( callbacks.context, @@ -6596,7 +6605,7 @@ mod tests { #[test] fn resolves_keyframe_property_conflicts_as_one_batch() { - use crate::property_metadata::property_id; + use crate::css::property_metadata::property_id; let value = || { let pointer = Arc::into_raw(Arc::new(StyleValueData::Number { value: 1.0 })); unsafe { RetainedStyleValueData::from_retained_pointer(pointer) } @@ -6656,8 +6665,8 @@ mod tests { #[test] fn resolves_animation_css_wide_keywords() { - use crate::property_metadata::property_id; - use crate::style_compute::keyword; + use crate::css::property_metadata::property_id; + use crate::css::style_compute::keyword; let keyword_value = |keyword| StyleValueData::Keyword { keyword }; assert_eq!( @@ -6694,7 +6703,7 @@ mod tests { }); let declaration = FfiAnimationDeclaration { keyframe_index: 0, - property_id: crate::property_metadata::property_id::BORDER, + property_id: crate::css::property_metadata::property_id::BORDER, value: &raw const *pending, use_initial: false, is_transition: false, @@ -6720,7 +6729,7 @@ mod tests { #[test] fn reads_important_property_snapshot() { - use crate::property_metadata::{FIRST_LONGHAND_PROPERTY_ID, property_id}; + use crate::css::property_metadata::{FIRST_LONGHAND_PROPERTY_ID, property_id}; let important_index = usize::from(property_id::COLOR - FIRST_LONGHAND_PROPERTY_ID); let mut bitmap = vec![0; important_index / 8 + 1]; bitmap[important_index / 8] |= 1 << (important_index % 8); @@ -6759,12 +6768,17 @@ mod tests { fn calculated_number(value: f64) -> StyleValueData { StyleValueData::Calculated { - rust_calculation: crate::calc::CalcNodeHandle::from_arc(Arc::new(crate::calc::CalcNode::Numeric( - crate::calc::CalcNumericValue::Number { value, number_type: 0 }, - ))), + rust_calculation: crate::css::calc::CalcNodeHandle::from_arc(Arc::new( + crate::css::calc::CalcNode::Numeric(crate::css::calc::CalcNumericValue::Number { + value, + number_type: 0, + }), + )), resolve_as_is_number: false, resolve_as_base: 0, - resolved_type: crate::calc::FfiNumericType::from_calc(Some(crate::calc::CalcNumericType::default())), + resolved_type: crate::css::calc::FfiNumericType::from_calc(Some( + crate::css::calc::CalcNumericType::default(), + )), has_percentages_resolve_as: false, percentages_resolve_as: 0, resolve_numbers_as_integers: false, @@ -6844,7 +6858,7 @@ mod tests { }, ]; let input = FfiAnimationValueInput { - property_id: crate::property_metadata::property_id::FLEX_GROW, + property_id: crate::css::property_metadata::property_id::FLEX_GROW, underlying: &raw const underlying, initial: &raw const underlying, current_key: 75.0, @@ -6894,7 +6908,7 @@ mod tests { }, ]; let input = FfiAnimationValueInput { - property_id: crate::property_metadata::property_id::FLEX_GROW, + property_id: crate::css::property_metadata::property_id::FLEX_GROW, underlying: Arc::as_ptr(&underlying), initial: Arc::as_ptr(&initial), current_key: 50.0, @@ -6926,7 +6940,7 @@ mod tests { fn evaluates_discrete_animation_values() { let from = Arc::new(StyleValueData::Keyword { keyword: 1 }); let to = Arc::new(StyleValueData::Keyword { keyword: 2 }); - let property_id = crate::property_metadata::property_id::ALIGN_CONTENT; + let property_id = crate::css::property_metadata::property_id::ALIGN_CONTENT; let result = interpolate_value(Some(&animation_context(true)), property_id, &from, &to, 0.25); assert!(result.handled); @@ -6945,19 +6959,19 @@ mod tests { #[test] fn evaluates_incompatible_by_computed_values_as_discrete() { - let property_id = crate::property_metadata::property_id::FLEX_GROW; + let property_id = crate::css::property_metadata::property_id::FLEX_GROW; let from = Arc::new(StyleValueData::Keyword { keyword: 1 }); let to = Arc::new(StyleValueData::Keyword { keyword: 2 }); let result = interpolate_value(Some(&animation_context(true)), property_id, &from, &to, 0.25); assert!(result.handled); assert_eq!(result.value, Arc::as_ptr(&from)); - unsafe { crate::style_value::rust_style_value_release(result.value) }; + unsafe { crate::css::style_value::rust_style_value_release(result.value) }; let result = interpolate_value(Some(&animation_context(true)), property_id, &from, &to, 0.75); assert!(result.handled); assert_eq!(result.value, Arc::as_ptr(&to)); - unsafe { crate::style_value::rust_style_value_release(result.value) }; + unsafe { crate::css::style_value::rust_style_value_release(result.value) }; let result = interpolate_value(Some(&animation_context(false)), property_id, &from, &to, 0.75); assert!(result.handled); @@ -6970,7 +6984,7 @@ mod tests { let to = Arc::new(StyleValueData::Keyword { keyword: 2 }); let result = interpolate_value( Some(&animation_context(true)), - crate::property_metadata::property_id::ANIMATION_DURATION, + crate::css::property_metadata::property_id::ANIMATION_DURATION, &from, &to, 0.25, @@ -6984,7 +6998,7 @@ mod tests { fn evaluates_declined_custom_animation_values_as_discrete() { let from = Arc::new(StyleValueData::Keyword { keyword: 1 }); let to = Arc::new(StyleValueData::Keyword { keyword: 2 }); - let property_id = crate::property_metadata::property_id::SCALE; + let property_id = crate::css::property_metadata::property_id::SCALE; let result = interpolate_value(Some(&animation_context(true)), property_id, &from, &to, 0.75); assert!(result.handled); @@ -6998,7 +7012,7 @@ mod tests { #[test] fn normalizes_repeatable_scalar_and_list_values() { - let property_id = crate::property_metadata::property_id::OBJECT_POSITION; + let property_id = crate::css::property_metadata::property_id::OBJECT_POSITION; let from = Arc::new(StyleValueData::Number { value: 10.0 }); let to = Arc::new(StyleValueData::ValueList { values: RetainedStyleValueDataList::from_retained_values(vec![ @@ -7025,7 +7039,7 @@ mod tests { let to = Arc::new(StyleValueData::Number { value: 20.0 }); let result = interpolate_value( Some(&animation_context(true)), - crate::property_metadata::property_id::OBJECT_POSITION, + crate::css::property_metadata::property_id::OBJECT_POSITION, &from, &to, 0.5, @@ -7041,7 +7055,7 @@ mod tests { let to = Arc::new(StyleValueData::Percentage { value: 50.0 }); let result = interpolate_value( Some(&animation_context(true)), - crate::property_metadata::property_id::WIDTH, + crate::css::property_metadata::property_id::WIDTH, &from, &to, 0.5, @@ -7057,7 +7071,7 @@ mod tests { let to = Arc::new(StyleValueData::Length { value: 20.0, unit: 1 }); let result = interpolate_value( Some(&animation_context(true)), - crate::property_metadata::property_id::WIDTH, + crate::css::property_metadata::property_id::WIDTH, &from, &to, 0.75, @@ -7085,8 +7099,14 @@ mod tests { retained_number(0.0), retained_angle(180.0), ]); - let result = interpolate_rotate_3d(crate::property_metadata::property_id::TRANSFORM, 0, &from, &to, 0.5) - .expect("rotate3d values should interpolate"); + let result = interpolate_rotate_3d( + crate::css::property_metadata::property_id::TRANSFORM, + 0, + &from, + &to, + 0.5, + ) + .expect("rotate3d values should interpolate"); let StyleValueData::Transformation { values, .. } = result else { panic!("expected a transform function"); }; @@ -7109,7 +7129,7 @@ mod tests { #[test] fn owns_unsupported_composition_decisions() { let underlying = Arc::new(StyleValueData::Keyword { - keyword: crate::style_compute::none_keyword(), + keyword: crate::css::style_compute::none_keyword(), }); let animated = Arc::new(StyleValueData::Number { value: 4.0 }); let result = composite_scalar_value(&underlying, &animated, FfiCompositeOperation::Add); @@ -7123,7 +7143,7 @@ mod tests { let to = Arc::new(StyleValueData::Number { value: 4.0 }); let result = interpolate_value( Some(&animation_context(true)), - crate::property_metadata::property_id::FLEX_GROW, + crate::css::property_metadata::property_id::FLEX_GROW, &from, &to, 0.5, diff --git a/Libraries/LibWeb/CSS/Rust/src/calc.rs b/Libraries/LibWeb/Rust/src/css/calc.rs similarity index 96% rename from Libraries/LibWeb/CSS/Rust/src/calc.rs rename to Libraries/LibWeb/Rust/src/css/calc.rs index 9e83abb9648b2..6513a99098e13 100644 --- a/Libraries/LibWeb/CSS/Rust/src/calc.rs +++ b/Libraries/LibWeb/Rust/src/css/calc.rs @@ -15,7 +15,7 @@ use std::sync::Arc; -use crate::style_value::RetainedStyleValueData; +use crate::css::style_value::RetainedStyleValueData; include!(concat!(env!("OUT_DIR"), "/dimension_units_generated.rs")); @@ -319,7 +319,7 @@ pub(crate) type LengthFallbackResolver<'a> = dyn Fn(f64, u8) -> Option + 'a /// context plus an optional per-element fallback for units it cannot handle. #[derive(Clone, Copy, Default)] pub(crate) struct LengthResolution<'a> { - pub context: Option<&'a crate::style_compute::FfiLengthResolutionContext>, + pub context: Option<&'a crate::css::style_compute::FfiLengthResolutionContext>, pub fallback: Option<&'a LengthFallbackResolver<'a>>, } @@ -339,14 +339,14 @@ impl CalcNumericValue { CalcNumericValue::Time { value, unit } => value * TIME_UNIT_CANONICAL_RATIOS[unit as usize], CalcNumericValue::Length { value, unit } => { // Absolute lengths resolve without a context. - let ratio = crate::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS[unit as usize]; + let ratio = crate::css::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS[unit as usize]; if ratio.is_finite() { return value * ratio; } let Some(context) = length_resolution.context else { return f64::NAN; }; - let result = crate::style_compute::absolutize_length_for_calc(value, unit as usize, context); + let result = crate::css::style_compute::absolutize_length_for_calc(value, unit as usize, context); if result.handled { return result.px; } @@ -421,7 +421,7 @@ pub unsafe extern "C" fn rust_numeric_type_operate( first: *const FfiNumericType, second: *const FfiNumericType, ) -> FfiNumericType { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcOperationEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcOperationEntry); crate::abort_on_panic(|| { let first = unsafe { &*first }.to_calc(); let second = unsafe { &*second }.to_calc(); @@ -917,7 +917,7 @@ unsafe fn children_from_raw(children: *const *const CalcNode, count: usize) -> V /// order number, angle, flex, frequency, length, percentage, resolution, time. #[unsafe(no_mangle)] pub extern "C" fn rust_calc_node_create_numeric_dimension(kind: u8, value: f64, unit: u8) -> *const CalcNode { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeBuildEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeBuildEntry); crate::abort_on_panic(|| { let numeric = match kind { 0 => CalcNumericValue::Number { @@ -939,7 +939,7 @@ pub extern "C" fn rust_calc_node_create_numeric_dimension(kind: u8, value: f64, #[unsafe(no_mangle)] pub extern "C" fn rust_calc_node_create_channel_keyword(channel: u8) -> *const CalcNode { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeBuildEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeBuildEntry); crate::abort_on_panic(|| handle(CalcNode::ChannelKeyword(channel))) } @@ -954,7 +954,7 @@ pub unsafe extern "C" fn rust_calc_node_create_variadic( children: *const *const CalcNode, count: usize, ) -> *const CalcNode { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeBuildEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeBuildEntry); crate::abort_on_panic(|| { let children = unsafe { children_from_raw(children, count) }; let node = match kind { @@ -977,7 +977,7 @@ pub unsafe extern "C" fn rust_calc_node_create_variadic( /// `child` must be a valid transferred handle. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_calc_node_create_unary(kind: u8, child: *const CalcNode) -> *const CalcNode { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeBuildEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeBuildEntry); crate::abort_on_panic(|| { let child = unsafe { Arc::from_raw(child) }; let node = match kind { @@ -1010,7 +1010,7 @@ pub unsafe extern "C" fn rust_calc_node_create_binary( first: *const CalcNode, second: *const CalcNode, ) -> *const CalcNode { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeBuildEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeBuildEntry); crate::abort_on_panic(|| { let first = unsafe { Arc::from_raw(first) }; let second = unsafe { Arc::from_raw(second) }; @@ -1046,7 +1046,7 @@ pub unsafe extern "C" fn rust_calc_node_create_clamp( center: *const CalcNode, max: *const CalcNode, ) -> *const CalcNode { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeBuildEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeBuildEntry); crate::abort_on_panic(|| { handle(CalcNode::Clamp { min: unsafe { Arc::from_raw(min) }, @@ -1065,7 +1065,7 @@ pub unsafe extern "C" fn rust_calc_node_create_progress( from: *const CalcNode, to: *const CalcNode, ) -> *const CalcNode { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeBuildEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeBuildEntry); crate::abort_on_panic(|| { handle(CalcNode::Progress { no_clamp, @@ -1084,7 +1084,7 @@ pub unsafe extern "C" fn rust_calc_node_create_round( value: *const CalcNode, interval: *const CalcNode, ) -> *const CalcNode { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeBuildEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeBuildEntry); crate::abort_on_panic(|| { handle(CalcNode::Round { strategy, @@ -1104,7 +1104,7 @@ pub unsafe extern "C" fn rust_calc_node_create_random( step: *const CalcNode, sharing: *const std::ffi::c_void, ) -> *const CalcNode { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeBuildEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeBuildEntry); crate::abort_on_panic(|| { handle(CalcNode::Random { min: unsafe { Arc::from_raw(min) }, @@ -1126,7 +1126,7 @@ pub unsafe extern "C" fn rust_calc_node_create_non_math_function( value: *const std::ffi::c_void, numeric_type: *const FfiNumericType, ) -> *const CalcNode { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeBuildEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeBuildEntry); crate::abort_on_panic(|| { handle(CalcNode::NonMathFunction { value: unsafe { RetainedStyleValueData::from_retained_pointer(value.cast()) }, @@ -1139,7 +1139,7 @@ pub unsafe extern "C" fn rust_calc_node_create_non_math_function( /// `node` must be a valid transferred handle; this releases it. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_calc_node_release(node: *const CalcNode) { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeRetainReleaseEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeRetainReleaseEntry); crate::abort_on_panic(|| drop(unsafe { Arc::from_raw(node) })); } @@ -1150,7 +1150,7 @@ pub unsafe extern "C" fn rust_calc_node_release(node: *const CalcNode) { /// `node` must be a valid calculation node pointer. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_calc_node_retain(node: *const CalcNode) { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeRetainReleaseEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeRetainReleaseEntry); crate::abort_on_panic(|| unsafe { Arc::increment_strong_count(node) }); } @@ -1168,7 +1168,7 @@ pub unsafe extern "C" fn rust_calc_node_determine_type( resolve_as_is_number: bool, resolve_as_base: u8, ) -> FfiNumericType { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeQueryEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeQueryEntry); crate::abort_on_panic(|| { let resolve_as = resolve_as_from_fields(has_percentages_resolve_as, resolve_as_is_number, resolve_as_base); let percentage_leaf_type = percentage_leaf_type_for(resolve_as); @@ -1182,7 +1182,7 @@ pub unsafe extern "C" fn rust_calc_node_determine_type( /// `node` must be a valid calculation node pointer. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_calc_node_contains_percentage(node: *const CalcNode) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeQueryEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeQueryEntry); crate::abort_on_panic(|| unsafe { &*node }.contains_percentage()) } @@ -1228,7 +1228,7 @@ fn is_canonical_unit(value: CalcNumericValue) -> bool { match value { CalcNumericValue::Number { .. } | CalcNumericValue::Percentage(..) => true, CalcNumericValue::Length { unit, .. } => { - unit == canonical_unit_code(&crate::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS) + unit == canonical_unit_code(&crate::css::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS) } CalcNumericValue::Angle { unit, .. } => unit == canonical_unit_code(&ANGLE_UNIT_CANONICAL_RATIOS), CalcNumericValue::Flex { unit, .. } => unit == canonical_unit_code(&FLEX_UNIT_CANONICAL_RATIOS), @@ -1239,7 +1239,7 @@ fn is_canonical_unit(value: CalcNumericValue) -> bool { } pub(crate) fn canonical_pixel_unit() -> u8 { - canonical_unit_code(&crate::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS) + canonical_unit_code(&crate::css::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS) } impl CalcNode { @@ -1838,7 +1838,7 @@ fn make_calc_result_node(result: &CalcResult, resolve_as: Option) -> } else if numeric_type.matches_dimension(0, resolve_as) { CalcNumericValue::Length { value, - unit: canonical_unit_code(&crate::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS), + unit: canonical_unit_code(&crate::css::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS), } } else if numeric_type.matches_dimension(4, resolve_as) { CalcNumericValue::Resolution { @@ -1930,8 +1930,8 @@ impl CalcNumericValue { unit: canonical_unit_code(&TIME_UNIT_CANONICAL_RATIOS), }), CalcNumericValue::Length { value, unit } => { - let px = canonical_unit_code(&crate::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS); - let ratio = crate::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS[unit as usize]; + let px = canonical_unit_code(&crate::css::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS); + let ratio = crate::css::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS[unit as usize]; if ratio.is_finite() { return Some(CalcNumericValue::Length { value: value * ratio, @@ -1939,7 +1939,7 @@ impl CalcNumericValue { }); } let context = length_resolution.context?; - let result = crate::style_compute::absolutize_length_for_calc(value, unit as usize, context); + let result = crate::css::style_compute::absolutize_length_for_calc(value, unit as usize, context); if result.handled { return Some(CalcNumericValue::Length { value: result.px, @@ -2499,7 +2499,7 @@ fn collect_external_resolutions(node: &CalcNode, resolutions: &mut Vec + if crate::css::style_compute::LENGTH_UNIT_NAMES[*unit as usize].starts_with("cq") => { append(FfiCalcExternalResolutionKind::Length, std::ptr::null(), *value, *unit); } @@ -2520,14 +2520,14 @@ pub unsafe extern "C" fn rust_calc_external_resolutions( basis_value: f64, basis_unit: u8, ) -> FfiCalcExternalResolutions { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcOperationEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcOperationEntry); crate::abort_on_panic(|| { let mut resolutions = Vec::new(); let root = unsafe { &*root }; collect_external_resolutions(root, &mut resolutions); if basis_kind == 3 && root.contains_percentage() - && crate::style_compute::LENGTH_UNIT_NAMES[basis_unit as usize].starts_with("cq") + && crate::css::style_compute::LENGTH_UNIT_NAMES[basis_unit as usize].starts_with("cq") { resolutions.push(FfiCalcExternalResolution { kind: FfiCalcExternalResolutionKind::Length, @@ -2567,7 +2567,7 @@ pub unsafe extern "C" fn rust_calc_external_resolutions_release(storage: *mut st drop(unsafe { Arc::from_raw(resolution.resolved_node) }); } if !resolution.resolved_style_value.is_null() { - unsafe { crate::style_value::rust_style_value_release(resolution.resolved_style_value.cast()) }; + unsafe { crate::css::style_value::rust_style_value_release(resolution.resolved_style_value.cast()) }; } } } @@ -2661,7 +2661,8 @@ fn with_ffi_evaluation( None } else { Some(unsafe { - &*(context.length_resolution_context as *const crate::style_compute::FfiLengthResolutionContext) + &*(context.length_resolution_context + as *const crate::css::style_compute::FfiLengthResolutionContext) }) }, fallback: Some(&resolve_length_fallback), @@ -2677,7 +2678,7 @@ fn with_ffi_evaluation( }) .filter(|resolution| !resolution.resolved_style_value.is_null()) .map(|resolution| unsafe { - RetainedStyleValueData::from_retained_pointer(crate::style_value::rust_style_value_retain( + RetainedStyleValueData::from_retained_pointer(crate::css::style_value::rust_style_value_retain( resolution.resolved_style_value.cast(), )) }) @@ -2729,7 +2730,7 @@ fn resolve_simplified_calculation( evaluation_context: &CalcEvaluationContext, resolve_as: Option, resolve_numbers_as_integers: bool, - accepted_ranges: &[crate::style_value::RetainedNumericRangeByType], + accepted_ranges: &[crate::css::style_value::RetainedNumericRangeByType], apply_censoring_and_clamping: bool, ) -> Option<(f64, Option)> { if !matches!(&**simplified, CalcNode::Numeric(..)) || (simplified.contains_percentage() && resolve_as.is_some()) { @@ -2789,11 +2790,11 @@ fn resolve_simplified_calculation( /// callbacks for non-math functions, relative-color channels, and random() /// remain unavailable. fn resolve_calculated_with_length_resolution( - calculated: &crate::style_value::StyleValueData, + calculated: &crate::css::style_value::StyleValueData, percentage_basis: Option, length_resolution: LengthResolution, ) -> Option<(f64, CalcNumericType, Option)> { - use crate::style_value::StyleValueData; + use crate::css::style_value::StyleValueData; let StyleValueData::Calculated { rust_calculation, has_percentages_resolve_as, @@ -2834,7 +2835,7 @@ fn resolve_calculated_with_length_resolution( } fn resolve_calculated_without_context( - calculated: &crate::style_value::StyleValueData, + calculated: &crate::css::style_value::StyleValueData, percentage_basis: Option, ) -> Option<(f64, CalcNumericType, Option)> { resolve_calculated_with_length_resolution(calculated, percentage_basis, LengthResolution::default()) @@ -2843,7 +2844,7 @@ fn resolve_calculated_without_context( /// Resolves a calculated value that must produce a number, with no external /// context; the equivalent of the C++ resolve_number with an empty context. pub(crate) fn resolve_calculated_number_without_context( - calculated: &crate::style_value::StyleValueData, + calculated: &crate::css::style_value::StyleValueData, ) -> Option { let (value, numeric_type, resolve_as) = resolve_calculated_without_context(calculated, None)?; numeric_type.matches_number(resolve_as).then_some(value) @@ -2852,8 +2853,8 @@ pub(crate) fn resolve_calculated_number_without_context( /// Resolves a calculated value that must produce a number using the immutable /// per-element length metrics supplied to animation evaluation. pub(crate) fn resolve_calculated_number_with_context( - calculated: &crate::style_value::StyleValueData, - context: &crate::style_compute::FfiLengthResolutionContext, + calculated: &crate::css::style_value::StyleValueData, + context: &crate::css::style_compute::FfiLengthResolutionContext, ) -> Option { let (value, numeric_type, resolve_as) = resolve_calculated_with_length_resolution( calculated, @@ -2870,7 +2871,7 @@ pub(crate) fn resolve_calculated_number_with_context( /// external context; the equivalent of the C++ resolve_percentage with an /// empty context. pub(crate) fn resolve_calculated_percentage_without_context( - calculated: &crate::style_value::StyleValueData, + calculated: &crate::css::style_value::StyleValueData, ) -> Option { let (value, numeric_type, ..) = resolve_calculated_without_context(calculated, None)?; numeric_type.matches_percentage().then_some(value) @@ -2878,7 +2879,9 @@ pub(crate) fn resolve_calculated_percentage_without_context( /// Resolves a calculated value that must produce an angle, with no external /// context; the equivalent of the C++ resolve_angle with an empty context. -pub(crate) fn resolve_calculated_angle_without_context(calculated: &crate::style_value::StyleValueData) -> Option { +pub(crate) fn resolve_calculated_angle_without_context( + calculated: &crate::css::style_value::StyleValueData, +) -> Option { let (value, numeric_type, resolve_as) = resolve_calculated_without_context(calculated, None)?; numeric_type.matches_dimension(1, resolve_as).then_some(value) } @@ -2886,8 +2889,8 @@ pub(crate) fn resolve_calculated_angle_without_context(calculated: &crate::style /// Resolves a calculated value that must produce an angle using the immutable /// per-element length metrics supplied to animation evaluation. pub(crate) fn resolve_calculated_angle_with_context( - calculated: &crate::style_value::StyleValueData, - context: &crate::style_compute::FfiLengthResolutionContext, + calculated: &crate::css::style_value::StyleValueData, + context: &crate::css::style_compute::FfiLengthResolutionContext, ) -> Option { let (value, numeric_type, resolve_as) = resolve_calculated_with_length_resolution( calculated, @@ -2904,7 +2907,7 @@ pub(crate) fn resolve_calculated_angle_with_context( /// nearest integer (toward +inf on a .5 fraction), with no external context; /// the equivalent of the C++ resolve_integer with an empty context. pub(crate) fn resolve_calculated_integer_without_context( - calculated: &crate::style_value::StyleValueData, + calculated: &crate::css::style_value::StyleValueData, ) -> Option { let (value, numeric_type, resolve_as) = resolve_calculated_without_context(calculated, None)?; if !numeric_type.matches_number(resolve_as) { @@ -2925,12 +2928,12 @@ pub(crate) fn resolve_calculated_integer_without_context( /// basis length; the equivalent of the C++ resolve_length with a percentage /// basis and an otherwise empty context. Returns pixels. pub(crate) fn resolve_calculated_length_without_context( - calculated: &crate::style_value::StyleValueData, + calculated: &crate::css::style_value::StyleValueData, percentage_basis_px: f64, ) -> Option { let basis = CalcNumericValue::Length { value: percentage_basis_px, - unit: canonical_unit_code(&crate::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS), + unit: canonical_unit_code(&crate::css::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS), }; let (value, numeric_type, resolve_as) = resolve_calculated_without_context(calculated, Some(basis))?; (numeric_type.matches_dimension(0, resolve_as) || numeric_type.matches_percentage()).then_some(value) @@ -2939,8 +2942,8 @@ pub(crate) fn resolve_calculated_length_without_context( /// Resolves a calculated value that must produce a length using the immutable /// per-element length metrics supplied to animation evaluation. pub(crate) fn resolve_calculated_length_with_context( - calculated: &crate::style_value::StyleValueData, - context: &crate::style_compute::FfiLengthResolutionContext, + calculated: &crate::css::style_value::StyleValueData, + context: &crate::css::style_compute::FfiLengthResolutionContext, ) -> Option { let (value, numeric_type, resolve_as) = resolve_calculated_with_length_resolution( calculated, @@ -2964,12 +2967,12 @@ pub(crate) enum ResolvedLineHeightCalc { /// and percentages resolve to pixels, numbers stay multipliers, as in the C++ /// compute_line_height calc handling. pub(crate) fn resolve_calculated_line_height_without_context( - calculated: &crate::style_value::StyleValueData, + calculated: &crate::css::style_value::StyleValueData, computed_font_size_px: f64, ) -> Option { let basis = CalcNumericValue::Length { value: computed_font_size_px, - unit: canonical_unit_code(&crate::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS), + unit: canonical_unit_code(&crate::css::style_compute::LENGTH_UNIT_CANONICAL_PX_RATIOS), }; let (value, numeric_type, resolve_as) = resolve_calculated_without_context(calculated, Some(basis))?; if numeric_type.matches_dimension(0, resolve_as) || numeric_type.matches_percentage() { @@ -2993,8 +2996,8 @@ pub unsafe extern "C" fn rust_calc_resolve( context: *const FfiCalcResolutionContext, apply_censoring_and_clamping: bool, ) -> FfiResolvedCalc { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcOperationEntry); - use crate::style_value::StyleValueData; + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcOperationEntry); + use crate::css::style_value::StyleValueData; crate::abort_on_panic(|| { let StyleValueData::Calculated { rust_calculation, @@ -3084,7 +3087,7 @@ impl CalcNumericValue { CalcNumericValue::Angle { unit, .. } => ANGLE_UNIT_NAMES[unit as usize], CalcNumericValue::Flex { unit, .. } => FLEX_UNIT_NAMES[unit as usize], CalcNumericValue::Frequency { unit, .. } => FREQUENCY_UNIT_NAMES[unit as usize], - CalcNumericValue::Length { unit, .. } => crate::style_compute::LENGTH_UNIT_NAMES[unit as usize], + CalcNumericValue::Length { unit, .. } => crate::css::style_compute::LENGTH_UNIT_NAMES[unit as usize], CalcNumericValue::Resolution { unit, .. } => RESOLUTION_UNIT_NAMES[unit as usize], CalcNumericValue::Time { unit, .. } => TIME_UNIT_NAMES[unit as usize], } @@ -3095,7 +3098,7 @@ struct CalcSerializer<'a> { pieces: Vec, resolved_mode: bool, resolve_numbers_as_integers: bool, - accepted_ranges: &'a [crate::style_value::RetainedNumericRangeByType], + accepted_ranges: &'a [crate::css::style_value::RetainedNumericRangeByType], } impl CalcSerializer<'_> { @@ -3533,8 +3536,8 @@ pub unsafe extern "C" fn rust_calc_serialize( calculated: *const std::ffi::c_void, resolved_mode: bool, ) -> FfiCalcSerialization { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcOperationEntry); - use crate::style_value::StyleValueData; + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcOperationEntry); + use crate::css::style_value::StyleValueData; crate::abort_on_panic(|| { let StyleValueData::Calculated { rust_calculation, @@ -3729,7 +3732,7 @@ impl CalcNode { fn contains_anchor_function(&self) -> bool { if let CalcNode::NonMathFunction { value, .. } = self - && matches!(value.data(), crate::style_value::StyleValueData::Anchor { .. }) + && matches!(value.data(), crate::css::style_value::StyleValueData::Anchor { .. }) { return true; } @@ -3746,8 +3749,8 @@ impl CalcNode { /// Both pointers must reference Calculated style value data. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_calc_equals(first: *const std::ffi::c_void, second: *const std::ffi::c_void) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcOperationEntry); - use crate::style_value::StyleValueData; + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcOperationEntry); + use crate::css::style_value::StyleValueData; crate::abort_on_panic(|| { let tree_of = |data: *const std::ffi::c_void| { let StyleValueData::Calculated { rust_calculation, .. } = (unsafe { &*(data as *const StyleValueData) }) @@ -3768,10 +3771,10 @@ pub unsafe extern "C" fn rust_calc_equals(first: *const std::ffi::c_void, second /// `calculated` must point at Calculated style value data. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_calc_contains_anchor(calculated: *const std::ffi::c_void) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcOperationEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcOperationEntry); crate::abort_on_panic(|| { - let crate::style_value::StyleValueData::Calculated { rust_calculation, .. } = - (unsafe { &*(calculated as *const crate::style_value::StyleValueData) }) + let crate::css::style_value::StyleValueData::Calculated { rust_calculation, .. } = + (unsafe { &*(calculated as *const crate::css::style_value::StyleValueData) }) else { unreachable!("rust_calc_contains_anchor requires calculated value data"); }; @@ -3899,15 +3902,15 @@ fn append_reification_node( /// `calculated` must point at Calculated style value data. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_calc_describe_for_typed_om(calculated: *const std::ffi::c_void) -> FfiCalcReification { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcOperationEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcOperationEntry); crate::abort_on_panic(|| { - let crate::style_value::StyleValueData::Calculated { + let crate::css::style_value::StyleValueData::Calculated { rust_calculation, has_percentages_resolve_as, resolve_as_is_number, resolve_as_base, .. - } = (unsafe { &*(calculated as *const crate::style_value::StyleValueData) }) + } = (unsafe { &*(calculated as *const crate::css::style_value::StyleValueData) }) else { unreachable!("rust_calc_describe_for_typed_om requires calculated value data"); }; @@ -3970,7 +3973,7 @@ pub unsafe extern "C" fn rust_calc_reification_release(storage: *mut std::ffi::c /// `node` must be a valid calculation node pointer. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_calc_node_style_value(node: *const CalcNode) -> *const std::ffi::c_void { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcNodeQueryEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcNodeQueryEntry); crate::abort_on_panic(|| match unsafe { &*node } { CalcNode::Random { sharing, .. } => sharing.data() as *const _ as *const _, CalcNode::NonMathFunction { value, .. } => value.data() as *const _ as *const _, @@ -3996,7 +3999,7 @@ pub unsafe extern "C" fn rust_calc_simplify_tree( resolve_as_is_number: bool, resolve_as_base: u8, ) -> *const CalcNode { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcOperationEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcOperationEntry); crate::abort_on_panic(|| { let context = unsafe { &*context }; unsafe { Arc::increment_strong_count(root) }; @@ -4030,8 +4033,8 @@ pub unsafe extern "C" fn rust_calc_absolutize( calculated: *const std::ffi::c_void, context: *const FfiCalcResolutionContext, ) -> FfiAbsolutizedCalc { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CalcOperationEntry); - use crate::style_value::StyleValueData; + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CalcOperationEntry); + use crate::css::style_value::StyleValueData; crate::abort_on_panic(|| { let StyleValueData::Calculated { rust_calculation, diff --git a/Libraries/LibWeb/CSS/Rust/src/cascaded_properties.rs b/Libraries/LibWeb/Rust/src/css/cascaded_properties.rs similarity index 94% rename from Libraries/LibWeb/CSS/Rust/src/cascaded_properties.rs rename to Libraries/LibWeb/Rust/src/css/cascaded_properties.rs index e999652bdca2f..ca7511035d2c2 100644 --- a/Libraries/LibWeb/CSS/Rust/src/cascaded_properties.rs +++ b/Libraries/LibWeb/Rust/src/css/cascaded_properties.rs @@ -19,11 +19,11 @@ use std::hash::BuildHasherDefault; use std::hash::Hasher; use crate::abort_on_panic; -use crate::property_metadata::LAST_LONGHAND_PROPERTY_ID; -use crate::style_compute::expand_shorthands_with; -use crate::style_value::RetainedStyleValueData; -use crate::style_value::RetainedUtf16FlyString; -use crate::style_value::StyleValueData; +use crate::css::property_metadata::LAST_LONGHAND_PROPERTY_ID; +use crate::css::style_compute::expand_shorthands_with; +use crate::css::style_value::RetainedStyleValueData; +use crate::css::style_value::RetainedUtf16FlyString; +use crate::css::style_value::StyleValueData; /// Mirrors the C++ `enum class CascadeOrigin : u8`; the C++ side static_asserts /// that every discriminant matches. @@ -298,7 +298,7 @@ pub unsafe extern "C" fn rust_cascaded_properties_property( store: *const CascadedPropertyStore, property_id: u16, ) -> *const c_void { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CascadedStoreQueryEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CascadedStoreQueryEntry); abort_on_panic(|| match unsafe { &*store }.last_entry(property_id) { Some(entry) => entry.value.pointer().cast(), None => std::ptr::null(), @@ -314,7 +314,7 @@ pub unsafe extern "C" fn rust_cascaded_properties_source_slot( store: *const CascadedPropertyStore, property_id: u16, ) -> i64 { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CascadedStoreQueryEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CascadedStoreQueryEntry); abort_on_panic(|| match unsafe { &*store }.last_entry(property_id) { Some(entry) => entry.source_slot as i64, None => -1, @@ -331,7 +331,7 @@ pub unsafe extern "C" fn rust_cascaded_properties_has_style_sheet_context( store: *const CascadedPropertyStore, property_id: u16, ) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CascadedStoreQueryEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CascadedStoreQueryEntry); abort_on_panic(|| { unsafe { &*store } .last_entry(property_id) @@ -403,20 +403,20 @@ fn apply_declaration_block( if declared_is_unresolved { let native_resolution = unsafe { - crate::custom_properties::resolve_vars(custom_property_store, custom_property_registry, data) + crate::css::custom_properties::resolve_vars(custom_property_store, custom_property_registry, data) }; match native_resolution { - crate::custom_properties::NativeVarResolution::Resolved(source) => { + crate::css::custom_properties::NativeVarResolution::Resolved(source) => { let resolved = parse_substituted(declaration.property_id, &source); data = resolved.data; has_style_sheet_context = resolved.has_style_sheet_context; } - crate::custom_properties::NativeVarResolution::Invalid => { + crate::css::custom_properties::NativeVarResolution::Invalid => { let resolved = parse_substituted(declaration.property_id, &[]); data = resolved.data; has_style_sheet_context = resolved.has_style_sheet_context; } - crate::custom_properties::NativeVarResolution::NotHandled => { + crate::css::custom_properties::NativeVarResolution::NotHandled => { let resolved = resolve_unresolved(declaration.property_id, data); data = resolved.data; has_style_sheet_context = resolved.has_style_sheet_context; @@ -472,9 +472,9 @@ fn apply_declaration_block( StyleValueData::Keyword { keyword } => Some(*keyword), _ => None, }; - if longhand_keyword == Some(crate::style_compute::keyword::REVERT) { + if longhand_keyword == Some(crate::css::style_compute::keyword::REVERT) { store.revert_property(longhand_id, important, origin); - } else if longhand_keyword == Some(crate::style_compute::keyword::REVERT_LAYER) { + } else if longhand_keyword == Some(crate::css::style_compute::keyword::REVERT_LAYER) { store.revert_layer_property( longhand_id, important, @@ -488,7 +488,7 @@ fn apply_declaration_block( // stylesheet can be adopted into multiple scopes at once, so the declaration object alone is // not specific enough. let retained_value = unsafe { - RetainedStyleValueData::from_retained_pointer(crate::style_value::rust_style_value_retain( + RetainedStyleValueData::from_retained_pointer(crate::css::style_value::rust_style_value_retain( longhand_data.cast(), )) }; @@ -620,7 +620,7 @@ pub unsafe extern "C" fn rust_cascade_matched_blocks( unset_data: *const c_void, callbacks: *const FfiBulkCascadeCallbacks, ) { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CascadeBulkEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CascadeBulkEntry); abort_on_panic(|| { let store = unsafe { &mut *store }; let callbacks = unsafe { &*callbacks }; @@ -711,9 +711,9 @@ pub unsafe extern "C" fn rust_cascade_matched_blocks( let has_pseudo_element = pseudo_element != NO_PSEUDO_ELEMENT; let cascade_custom_properties = !has_pseudo_element - || crate::property_metadata::pseudo_element_supports_property( + || crate::css::property_metadata::pseudo_element_supports_property( pseudo_element, - crate::property_metadata::property_id::CUSTOM, + crate::css::property_metadata::property_id::CUSTOM, ); let mut custom_property_store = std::ptr::null(); if cascade_custom_properties { @@ -748,7 +748,7 @@ pub unsafe extern "C" fn rust_cascade_matched_blocks( } } } - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CascadeCustomPropertyBatchCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CascadeCustomPropertyBatchCallback); unsafe { custom_property_store = (callbacks.set_custom_properties)(context, custom_properties.as_ptr(), custom_properties.len()); @@ -768,7 +768,7 @@ pub unsafe extern "C" fn rust_cascade_matched_blocks( if block.bypass_pseudo_element_property_whitelist || !has_pseudo_element { return false; } - !crate::property_metadata::pseudo_element_supports_property(pseudo_element, property_id) + !crate::css::property_metadata::pseudo_element_supports_property(pseudo_element, property_id) }; apply_declaration_block( store, @@ -781,11 +781,11 @@ pub unsafe extern "C" fn rust_cascade_matched_blocks( unset_data, &is_property_disallowed, &|property_id, data| { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CascadeResolveUnresolvedCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CascadeResolveUnresolvedCallback); unsafe { (callbacks.resolve_unresolved)(context, property_id, data) } }, &|property_id, source| { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CascadeParseSubstitutedCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CascadeParseSubstitutedCallback); unsafe { (callbacks.parse_substituted)(context, property_id, source.as_ptr(), source.len()) } }, custom_property_store, @@ -804,7 +804,7 @@ pub unsafe extern "C" fn rust_cascade_matched_blocks( } if !source_slot_assignments.is_empty() { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CascadeSourceSlotCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CascadeSourceSlotCallback); unsafe { (callbacks.assign_source_slots)( context, @@ -830,7 +830,7 @@ mod tests { let mut store = CascadedPropertyStore::new(); store.set_property( - crate::property_metadata::property_id::OPACITY, + crate::css::property_metadata::property_id::OPACITY, retained_value, false, false, @@ -840,7 +840,7 @@ mod tests { ); let (data, important, source_slot, has_style_sheet_context) = store - .winning_declaration(crate::property_metadata::property_id::OPACITY) + .winning_declaration(crate::css::property_metadata::property_id::OPACITY) .expect("the declaration must be retained"); assert!(!important); assert_eq!(source_slot, 0); diff --git a/Libraries/LibWeb/CSS/Rust/src/color_conversion.rs b/Libraries/LibWeb/Rust/src/css/color_conversion.rs similarity index 100% rename from Libraries/LibWeb/CSS/Rust/src/color_conversion.rs rename to Libraries/LibWeb/Rust/src/css/color_conversion.rs diff --git a/Libraries/LibWeb/CSS/Rust/src/color_interpolation.rs b/Libraries/LibWeb/Rust/src/css/color_interpolation.rs similarity index 98% rename from Libraries/LibWeb/CSS/Rust/src/color_interpolation.rs rename to Libraries/LibWeb/Rust/src/css/color_interpolation.rs index dbb4c355e70d8..106c2310f6bba 100644 --- a/Libraries/LibWeb/CSS/Rust/src/color_interpolation.rs +++ b/Libraries/LibWeb/Rust/src/css/color_interpolation.rs @@ -11,8 +11,8 @@ use std::sync::Arc; -use crate::color_conversion; -use crate::style_value::{ColorBase, RetainedStyleValueData, StyleValueData}; +use crate::css::color_conversion; +use crate::css::style_value::{ColorBase, RetainedStyleValueData, StyleValueData}; const COLOR_SYNTAX_MODERN: u8 = 1; @@ -226,7 +226,7 @@ fn retained_number(value: f32) -> RetainedStyleValueData { fn retained_none() -> RetainedStyleValueData { let value = Arc::into_raw(Arc::new(StyleValueData::Keyword { - keyword: crate::style_compute::none_keyword(), + keyword: crate::css::style_compute::none_keyword(), })); unsafe { RetainedStyleValueData::from_retained_pointer(value) } } @@ -259,7 +259,7 @@ fn make_result(color_type: u8, components: [f32; 4], missing: [bool; 4]) -> Styl channel_2: retained_component(components[2], missing[2]), alpha: retained_component(components[3], missing[3]), has_name: false, - name: unsafe { crate::style_value::RetainedUtf16FlyString::from_leaked_raw(0) }, + name: unsafe { crate::css::style_value::RetainedUtf16FlyString::from_leaked_raw(0) }, origin_color: unsafe { RetainedStyleValueData::from_retained_optional_pointer(std::ptr::null()) }, } } diff --git a/Libraries/LibWeb/Rust/src/css/computed_value_types.rs b/Libraries/LibWeb/Rust/src/css/computed_value_types.rs new file mode 100644 index 0000000000000..6c4edc3dd5baf --- /dev/null +++ b/Libraries/LibWeb/Rust/src/css/computed_value_types.rs @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2026-present, the Ladybird developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +/// The computed forms accepted by width and height sizing properties. +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ComputedSizeKind { + Auto, + Calculated, + Length, + Percentage, + MinContent, + MaxContent, + FitContent, + None, +} + +/// A computed sizing value. Scalar and calculated values retain their +/// immutable Rust style-value identity. Fit-content retains only its +/// argument, and keyword-only forms leave the handle empty. +#[repr(C)] +pub struct ComputedStyleValueHandle { + pub pointer: *const std::ffi::c_void, +} + +#[repr(C)] +pub struct ComputedSize { + pub kind: ComputedSizeKind, + pub value: ComputedStyleValueHandle, +} + +/// Layout of the six computed sizing properties. +#[repr(C)] +pub struct SizingValues { + pub width: ComputedSize, + pub min_width: ComputedSize, + pub max_width: ComputedSize, + pub height: ComputedSize, + pub min_height: ComputedSize, + pub max_height: ComputedSize, +} + +/// A computed flex-basis value. Content uses the flag; every other form +/// uses the same computed-size representation as width and height. +#[repr(C)] +pub struct ComputedFlexBasis { + pub is_content: bool, + pub size: ComputedSize, +} + +/// A computed row-gap or column-gap value. Normal uses the flag; every +/// other form retains its immutable length-percentage identity. +#[repr(C)] +pub struct ComputedGap { + pub is_normal: bool, + pub value: ComputedStyleValueHandle, +} + +/// Layout of the computed flexbox and box-alignment properties. +#[repr(C)] +pub struct AlignmentValues { + pub flex_direction: u8, + pub flex_wrap: u8, + pub flex_basis: ComputedFlexBasis, + pub flex_grow: f64, + pub flex_shrink: f64, + pub order: i32, + pub align_content: u8, + pub align_items: u8, + pub align_self: u8, + pub justify_content: u8, + pub justify_items: u8, + pub justify_self: u8, + pub column_gap: ComputedGap, + pub row_gap: ComputedGap, +} + +/// A computed length-percentage-or-auto value. +#[repr(C)] +pub struct ComputedLengthPercentageOrAuto { + pub is_auto: bool, + pub value: ComputedStyleValueHandle, +} + +/// Four physical computed length-percentage-or-auto sides. +#[repr(C)] +pub struct ComputedLengthBox { + pub top: ComputedLengthPercentageOrAuto, + pub right: ComputedLengthPercentageOrAuto, + pub bottom: ComputedLengthPercentageOrAuto, + pub left: ComputedLengthPercentageOrAuto, +} + +/// Layout of the computed inset, margin, and padding properties. +#[repr(C)] +pub struct SurroundValues { + pub inset: ComputedLengthBox, + pub top_anchor_inset: ComputedStyleValueHandle, + pub right_anchor_inset: ComputedStyleValueHandle, + pub bottom_anchor_inset: ComputedStyleValueHandle, + pub left_anchor_inset: ComputedStyleValueHandle, + pub margin: ComputedLengthBox, + pub padding: ComputedLengthBox, +} + +/// Layout of the non-inherited SVG geometry and painting properties. +#[repr(C)] +pub struct SVGResetValues { + pub cx: ComputedStyleValueHandle, + pub cy: ComputedStyleValueHandle, + pub r: ComputedStyleValueHandle, + pub rx: ComputedLengthPercentageOrAuto, + pub ry: ComputedLengthPercentageOrAuto, + pub x: ComputedStyleValueHandle, + pub y: ComputedStyleValueHandle, + pub stop_color: u32, + pub stop_opacity: f32, + pub flood_color: u32, + pub flood_opacity: f32, + pub vector_effect: u8, + pub shape_rendering: u8, +} diff --git a/Libraries/LibWeb/CSS/Rust/src/computed_values.rs b/Libraries/LibWeb/Rust/src/css/computed_values.rs similarity index 89% rename from Libraries/LibWeb/CSS/Rust/src/computed_values.rs rename to Libraries/LibWeb/Rust/src/css/computed_values.rs index 69d92d39de387..2ffdb798c7e0c 100644 --- a/Libraries/LibWeb/CSS/Rust/src/computed_values.rs +++ b/Libraries/LibWeb/Rust/src/css/computed_values.rs @@ -30,6 +30,10 @@ use std::sync::OnceLock; use std::sync::atomic::{AtomicUsize, Ordering}; use crate::abort_on_panic; +pub use crate::css::computed_value_types::{ + AlignmentValues, ComputedFlexBasis, ComputedGap, ComputedLengthBox, ComputedLengthPercentageOrAuto, ComputedSize, + ComputedSizeKind, ComputedStyleValueHandle, SVGResetValues, SizingValues, SurroundValues, +}; /// Reference count value marking an intentionally leaked payload. pub const STYLE_GROUP_STATIC_REFCOUNT: usize = usize::MAX; @@ -50,28 +54,6 @@ pub struct InheritedBoxValues { pub image_rendering: u8, } -/// The computed forms accepted by width and height sizing properties. -#[repr(u8)] -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum ComputedSizeKind { - Auto, - Calculated, - Length, - Percentage, - MinContent, - MaxContent, - FitContent, - None, -} - -/// A computed sizing value. Scalar and calculated values retain their -/// immutable Rust style-value identity. Fit-content retains only its argument, -/// and keyword-only forms leave the handle empty. -#[repr(C)] -pub struct ComputedStyleValueHandle { - pub pointer: *const c_void, -} - impl ComputedStyleValueHandle { fn empty() -> Self { Self { @@ -79,35 +61,38 @@ impl ComputedStyleValueHandle { } } - fn retained(data: *const crate::style_value::StyleValueData) -> Self { + fn retained(data: *const crate::css::style_value::StyleValueData) -> Self { Self { - pointer: unsafe { crate::style_value::rust_style_value_retain(data) }.cast(), + pointer: unsafe { crate::css::style_value::rust_style_value_retain(data) }.cast(), } } fn length(value: f64) -> Self { Self { - pointer: crate::style_value::rust_style_value_create_length(value, crate::style_compute::px_length_unit()) - .cast(), + pointer: crate::css::style_value::rust_style_value_create_length( + value, + crate::css::style_compute::px_length_unit(), + ) + .cast(), } } - fn data(&self) -> Option<&crate::style_value::StyleValueData> { - unsafe { self.pointer.cast::().as_ref() } + fn data(&self) -> Option<&crate::css::style_value::StyleValueData> { + unsafe { self.pointer.cast::().as_ref() } } } impl Clone for ComputedStyleValueHandle { fn clone(&self) -> Self { Self { - pointer: unsafe { crate::style_value::rust_style_value_retain(self.pointer.cast()) }.cast(), + pointer: unsafe { crate::css::style_value::rust_style_value_retain(self.pointer.cast()) }.cast(), } } } impl Drop for ComputedStyleValueHandle { fn drop(&mut self) { - unsafe { crate::style_value::rust_style_value_release(self.pointer.cast()) }; + unsafe { crate::css::style_value::rust_style_value_release(self.pointer.cast()) }; } } @@ -121,12 +106,6 @@ impl PartialEq for ComputedStyleValueHandle { } } -#[repr(C)] -pub struct ComputedSize { - pub kind: ComputedSizeKind, - pub value: ComputedStyleValueHandle, -} - impl Clone for ComputedSize { fn clone(&self) -> Self { Self { @@ -142,105 +121,81 @@ impl PartialEq for ComputedSize { } } -/// Layout of the six computed sizing properties. -#[repr(C)] -#[derive(Clone, PartialEq)] -pub struct SizingValues { - pub width: ComputedSize, - pub min_width: ComputedSize, - pub max_width: ComputedSize, - pub height: ComputedSize, - pub min_height: ComputedSize, - pub max_height: ComputedSize, -} - -/// A computed flex-basis value. Content uses the flag; every other form uses -/// the same computed-size representation as width and height. -#[repr(C)] -#[derive(Clone, PartialEq)] -pub struct ComputedFlexBasis { - pub is_content: bool, - pub size: ComputedSize, -} - -/// A computed row-gap or column-gap value. Normal uses the flag; every other -/// form retains its immutable length-percentage identity. -#[repr(C)] -#[derive(Clone, PartialEq)] -pub struct ComputedGap { - pub is_normal: bool, - pub value: ComputedStyleValueHandle, -} - -/// Layout of the computed flexbox and box-alignment properties. -#[repr(C)] -#[derive(Clone, PartialEq)] -pub struct AlignmentValues { - pub flex_direction: u8, - pub flex_wrap: u8, - pub flex_basis: ComputedFlexBasis, - pub flex_grow: f64, - pub flex_shrink: f64, - pub order: i32, - pub align_content: u8, - pub align_items: u8, - pub align_self: u8, - pub justify_content: u8, - pub justify_items: u8, - pub justify_self: u8, - pub column_gap: ComputedGap, - pub row_gap: ComputedGap, -} - -/// A computed length-percentage-or-auto value. -#[repr(C)] -#[derive(Clone, PartialEq)] -pub struct ComputedLengthPercentageOrAuto { - pub is_auto: bool, - pub value: ComputedStyleValueHandle, -} - -/// Four physical computed length-percentage-or-auto sides. -#[repr(C)] -#[derive(Clone, PartialEq)] -pub struct ComputedLengthBox { - pub top: ComputedLengthPercentageOrAuto, - pub right: ComputedLengthPercentageOrAuto, - pub bottom: ComputedLengthPercentageOrAuto, - pub left: ComputedLengthPercentageOrAuto, -} - -/// Layout of the computed inset, margin, and padding properties. -#[repr(C)] -#[derive(Clone, PartialEq)] -pub struct SurroundValues { - pub inset: ComputedLengthBox, - pub top_anchor_inset: ComputedStyleValueHandle, - pub right_anchor_inset: ComputedStyleValueHandle, - pub bottom_anchor_inset: ComputedStyleValueHandle, - pub left_anchor_inset: ComputedStyleValueHandle, - pub margin: ComputedLengthBox, - pub padding: ComputedLengthBox, -} +macro_rules! impl_computed_payload_clone_and_eq { + ($type:ty { $($field:ident),+ $(,)? }) => { + impl Clone for $type { + fn clone(&self) -> Self { + Self { + $($field: self.$field.clone(),)+ + } + } + } -/// Layout of the non-inherited SVG geometry and painting properties. -#[repr(C)] -#[derive(Clone, PartialEq)] -pub struct SVGResetValues { - pub cx: ComputedStyleValueHandle, - pub cy: ComputedStyleValueHandle, - pub r: ComputedStyleValueHandle, - pub rx: ComputedLengthPercentageOrAuto, - pub ry: ComputedLengthPercentageOrAuto, - pub x: ComputedStyleValueHandle, - pub y: ComputedStyleValueHandle, - pub stop_color: u32, - pub stop_opacity: f32, - pub flood_color: u32, - pub flood_opacity: f32, - pub vector_effect: u8, - pub shape_rendering: u8, -} + impl PartialEq for $type { + fn eq(&self, other: &Self) -> bool { + true $(&& self.$field == other.$field)+ + } + } + }; +} + +impl_computed_payload_clone_and_eq!(SizingValues { + width, + min_width, + max_width, + height, + min_height, + max_height, +}); +impl_computed_payload_clone_and_eq!(ComputedFlexBasis { is_content, size }); +impl_computed_payload_clone_and_eq!(ComputedGap { is_normal, value }); +impl_computed_payload_clone_and_eq!(AlignmentValues { + flex_direction, + flex_wrap, + flex_basis, + flex_grow, + flex_shrink, + order, + align_content, + align_items, + align_self, + justify_content, + justify_items, + justify_self, + column_gap, + row_gap, +}); +impl_computed_payload_clone_and_eq!(ComputedLengthPercentageOrAuto { is_auto, value }); +impl_computed_payload_clone_and_eq!(ComputedLengthBox { + top, + right, + bottom, + left, +}); +impl_computed_payload_clone_and_eq!(SurroundValues { + inset, + top_anchor_inset, + right_anchor_inset, + bottom_anchor_inset, + left_anchor_inset, + margin, + padding, +}); +impl_computed_payload_clone_and_eq!(SVGResetValues { + cx, + cy, + r, + rx, + ry, + x, + y, + stop_color, + stop_opacity, + flood_color, + flood_opacity, + vector_effect, + shape_rendering, +}); /// Selects the language that owns a style group's payload lifecycle. #[repr(u8)] @@ -493,7 +448,7 @@ pub unsafe extern "C" fn rust_style_group_registry_register( /// `source` must be a valid payload of the same group type. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_style_group_clone(group_index: usize, source: *const c_void) -> *mut c_void { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::StyleGroupCloneEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::StyleGroupCloneEntry); abort_on_panic(|| unsafe { let table = vtable(group_index); let payload = allocate_payload(table, 1); @@ -509,7 +464,7 @@ pub unsafe extern "C" fn rust_style_group_clone(group_index: usize, source: *con /// references, and must not be a static default payload. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_style_group_free(group_index: usize, payload: *mut c_void) { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::StyleGroupFreeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::StyleGroupFreeEntry); abort_on_panic(|| unsafe { let table = vtable(group_index); debug_assert!(refcount_of(payload, payload_align(table)).load(Ordering::Relaxed) == 0); @@ -641,7 +596,7 @@ pub unsafe extern "C" fn rust_build_style_group( count: usize, parent_payload: *const c_void, ) -> *const c_void { - use crate::style_value::StyleValueData; + use crate::css::style_value::StyleValueData; abort_on_panic(|| { let all = &FIELD_DESCRIPTORS.get()?.0; @@ -696,12 +651,12 @@ pub unsafe extern "C" fn rust_build_style_group( let StyleValueData::Length { value, unit } = data else { return None; }; - if *unit != crate::style_compute::px_length_unit() { + if *unit != crate::css::style_compute::px_length_unit() { return None; } pokes.push(Poke::I32( descriptor.offset, - crate::css_pixels::CssPixels::nearest_value_for(*value).raw_value(), + crate::css::css_pixels::CssPixels::nearest_value_for(*value).raw_value(), )); } GROUP_FIELD_U64 => { @@ -750,7 +705,7 @@ pub unsafe extern "C" fn rust_build_style_group( let StyleValueData::Length { value, unit } = data else { return None; }; - if *unit != crate::style_compute::px_length_unit() || *value != descriptor.required_px { + if *unit != crate::css::style_compute::px_length_unit() || *value != descriptor.required_px { return None; } } @@ -764,7 +719,7 @@ pub unsafe extern "C" fn rust_build_style_group( } }, GROUP_FIELD_REQUIRE_INITIAL_VALUE => { - if value.data != crate::style_compute::initial_value_data(descriptor.property_id).cast() { + if value.data != crate::css::style_compute::initial_value_data(descriptor.property_id).cast() { return None; } } @@ -772,12 +727,12 @@ pub unsafe extern "C" fn rust_build_style_group( let StyleValueData::Length { value, unit } = data else { return None; }; - if *unit != crate::style_compute::px_length_unit() { + if *unit != crate::css::style_compute::px_length_unit() { return None; } pokes.push(Poke::I32( descriptor.offset, - crate::css_pixels::CssPixels::nearest_value_for(value.max(0.0)).raw_value(), + crate::css::css_pixels::CssPixels::nearest_value_for(value.max(0.0)).raw_value(), )); } GROUP_FIELD_RESOLVED_F64 => { @@ -821,7 +776,7 @@ pub unsafe extern "C" fn rust_build_style_group( Poke::U32(offset, value) => *(base.add(offset as usize) as *mut u32) = value, Poke::Data(offset, data) => { // The slot's constructor default is null, so nothing is released. - let retained = crate::style_value::rust_style_value_retain(data); + let retained = crate::css::style_value::rust_style_value_retain(data); *(base.add(offset as usize) as *mut *const StyleValueData) = retained; } } @@ -872,7 +827,7 @@ pub unsafe extern "C" fn rust_build_inherited_box_group( image_rendering: *const c_void, parent_payload: *const c_void, ) -> *const c_void { - use crate::style_value::StyleValueData; + use crate::css::style_value::StyleValueData; abort_on_panic(|| { let keyword_code = |data: *const c_void, map: fn(u16) -> Option| -> Option { @@ -882,11 +837,14 @@ pub unsafe extern "C" fn rust_build_inherited_box_group( } }; let built = InheritedBoxValues { - visibility: keyword_code(visibility, crate::style_compute::keyword_to_visibility)?, - direction: keyword_code(direction, crate::style_compute::keyword_to_direction)?, - writing_mode: keyword_code(writing_mode, crate::style_compute::keyword_to_writing_mode)?, - content_visibility: keyword_code(content_visibility, crate::style_compute::keyword_to_content_visibility)?, - image_rendering: keyword_code(image_rendering, crate::style_compute::keyword_to_image_rendering)?, + visibility: keyword_code(visibility, crate::css::style_compute::keyword_to_visibility)?, + direction: keyword_code(direction, crate::css::style_compute::keyword_to_direction)?, + writing_mode: keyword_code(writing_mode, crate::css::style_compute::keyword_to_writing_mode)?, + content_visibility: keyword_code( + content_visibility, + crate::css::style_compute::keyword_to_content_visibility, + )?, + image_rendering: keyword_code(image_rendering, crate::css::style_compute::keyword_to_image_rendering)?, }; if !parent_payload.is_null() { @@ -919,7 +877,7 @@ impl ComputedSize { } } - fn retained(kind: ComputedSizeKind, data: *const crate::style_value::StyleValueData) -> Self { + fn retained(kind: ComputedSizeKind, data: *const crate::css::style_value::StyleValueData) -> Self { Self { kind, value: ComputedStyleValueHandle::retained(data), @@ -927,8 +885,8 @@ impl ComputedSize { } fn from_data(data: *const c_void) -> Self { - use crate::css_enums::keyword; - use crate::style_value::StyleValueData; + use crate::css::css_enums::keyword; + use crate::css::style_value::StyleValueData; let data = data.cast::(); match unsafe { data.as_ref() } { @@ -975,8 +933,8 @@ impl SizingValues { impl ComputedFlexBasis { fn from_data(data: *const c_void) -> Self { - use crate::css_enums::keyword; - use crate::style_value::StyleValueData; + use crate::css::css_enums::keyword; + use crate::css::style_value::StyleValueData; let is_content = matches!( unsafe { data.cast::().as_ref() }, @@ -995,8 +953,8 @@ impl ComputedFlexBasis { impl ComputedGap { fn from_data(data: *const c_void) -> Self { - use crate::css_enums::keyword; - use crate::style_value::StyleValueData; + use crate::css::css_enums::keyword; + use crate::css::style_value::StyleValueData; let data = data.cast::(); let is_normal = matches!( @@ -1016,7 +974,7 @@ impl ComputedGap { impl AlignmentValues { fn initial() -> Self { - use crate::css_enums::{ + use crate::css::css_enums::{ align_content, align_items, align_self, flex_direction, flex_wrap, justify_content, justify_items, justify_self, }; @@ -1065,8 +1023,8 @@ impl ComputedLengthPercentageOrAuto { } fn from_data(data: *const c_void) -> Self { - use crate::css_enums::keyword; - use crate::style_value::StyleValueData; + use crate::css::css_enums::keyword; + use crate::css::style_value::StyleValueData; let data = data.cast::(); let is_auto = matches!( @@ -1084,8 +1042,8 @@ impl ComputedLengthPercentageOrAuto { } fn from_length_box_data(data: *const c_void, default_is_auto: bool) -> Self { - use crate::css_enums::keyword; - use crate::style_value::StyleValueData; + use crate::css::css_enums::keyword; + use crate::css::style_value::StyleValueData; let data = data.cast::(); match unsafe { data.as_ref() } { @@ -1158,7 +1116,7 @@ impl SurroundValues { impl SVGResetValues { fn initial() -> Self { - use crate::css_enums::{shape_rendering, vector_effect}; + use crate::css::css_enums::{shape_rendering, vector_effect}; const OPAQUE_BLACK_BGRA: u32 = 0xff00_0000; @@ -1215,7 +1173,7 @@ pub unsafe extern "C" fn rust_build_alignment_group( row_gap: *const c_void, parent_payload: *const c_void, ) -> *const c_void { - use crate::style_value::StyleValueData; + use crate::css::style_value::StyleValueData; abort_on_panic(|| { let keyword_code = |data: *const c_void, map: fn(u16) -> Option| -> Option { @@ -1225,18 +1183,18 @@ pub unsafe extern "C" fn rust_build_alignment_group( } }; let built = AlignmentValues { - flex_direction: keyword_code(flex_direction, crate::css_enums::keyword_to_flex_direction)?, - flex_wrap: keyword_code(flex_wrap, crate::css_enums::keyword_to_flex_wrap)?, + flex_direction: keyword_code(flex_direction, crate::css::css_enums::keyword_to_flex_direction)?, + flex_wrap: keyword_code(flex_wrap, crate::css::css_enums::keyword_to_flex_wrap)?, flex_basis: ComputedFlexBasis::from_data(flex_basis), flex_grow, flex_shrink, order, - align_content: keyword_code(align_content, crate::css_enums::keyword_to_align_content)?, - align_items: keyword_code(align_items, crate::css_enums::keyword_to_align_items)?, - align_self: keyword_code(align_self, crate::css_enums::keyword_to_align_self)?, - justify_content: keyword_code(justify_content, crate::css_enums::keyword_to_justify_content)?, - justify_items: keyword_code(justify_items, crate::css_enums::keyword_to_justify_items)?, - justify_self: keyword_code(justify_self, crate::css_enums::keyword_to_justify_self)?, + align_content: keyword_code(align_content, crate::css::css_enums::keyword_to_align_content)?, + align_items: keyword_code(align_items, crate::css::css_enums::keyword_to_align_items)?, + align_self: keyword_code(align_self, crate::css::css_enums::keyword_to_align_self)?, + justify_content: keyword_code(justify_content, crate::css::css_enums::keyword_to_justify_content)?, + justify_items: keyword_code(justify_items, crate::css::css_enums::keyword_to_justify_items)?, + justify_self: keyword_code(justify_self, crate::css::css_enums::keyword_to_justify_self)?, column_gap: ComputedGap::from_data(column_gap), row_gap: ComputedGap::from_data(row_gap), }; @@ -1285,7 +1243,7 @@ pub unsafe extern "C" fn rust_build_svg_reset_group( shape_rendering: *const c_void, parent_payload: *const c_void, ) -> *const c_void { - use crate::style_value::StyleValueData; + use crate::css::style_value::StyleValueData; abort_on_panic(|| { let keyword_code = |data: *const c_void, map: fn(u16) -> Option| -> Option { @@ -1307,8 +1265,8 @@ pub unsafe extern "C" fn rust_build_svg_reset_group( stop_opacity, flood_color, flood_opacity, - vector_effect: keyword_code(vector_effect, crate::css_enums::keyword_to_vector_effect)?, - shape_rendering: keyword_code(shape_rendering, crate::css_enums::keyword_to_shape_rendering)?, + vector_effect: keyword_code(vector_effect, crate::css::css_enums::keyword_to_vector_effect)?, + shape_rendering: keyword_code(shape_rendering, crate::css::css_enums::keyword_to_shape_rendering)?, }; if !parent_payload.is_null() && built.eq(unsafe { &*parent_payload.cast::() }) { @@ -1352,7 +1310,7 @@ pub unsafe extern "C" fn rust_build_surround_group( padding_left: *const c_void, parent_payload: *const c_void, ) -> *const c_void { - use crate::style_value::StyleValueData; + use crate::css::style_value::StyleValueData; abort_on_panic(|| { let anchor = |data: *const c_void| { @@ -1451,7 +1409,7 @@ pub unsafe extern "C" fn rust_build_inherited_table_group( border_spacing: *const c_void, parent_payload: *const c_void, ) -> *const c_void { - use crate::style_value::StyleValueData; + use crate::css::style_value::StyleValueData; abort_on_panic(|| { let keyword_code = |data: *const c_void, map: fn(u16) -> Option| -> Option { @@ -1461,15 +1419,15 @@ pub unsafe extern "C" fn rust_build_inherited_table_group( } }; let spacing = match unsafe { (border_spacing as *const StyleValueData).as_ref() } { - Some(StyleValueData::Length { value, unit }) if *unit == crate::style_compute::px_length_unit() => { - crate::css_pixels::CssPixels::nearest_value_for(*value).raw_value() + Some(StyleValueData::Length { value, unit }) if *unit == crate::css::style_compute::px_length_unit() => { + crate::css::css_pixels::CssPixels::nearest_value_for(*value).raw_value() } _ => return None, }; let built = InheritedTableValues { - border_collapse: keyword_code(border_collapse, crate::style_compute::keyword_to_border_collapse)?, - caption_side: keyword_code(caption_side, crate::style_compute::keyword_to_caption_side)?, - empty_cells: keyword_code(empty_cells, crate::style_compute::keyword_to_empty_cells)?, + border_collapse: keyword_code(border_collapse, crate::css::style_compute::keyword_to_border_collapse)?, + caption_side: keyword_code(caption_side, crate::css::style_compute::keyword_to_caption_side)?, + empty_cells: keyword_code(empty_cells, crate::css::style_compute::keyword_to_empty_cells)?, border_spacing_horizontal: spacing, border_spacing_vertical: spacing, }; @@ -1512,7 +1470,7 @@ pub struct InheritedTableValues { impl InheritedTableValues { fn initial() -> Self { - use crate::css_enums::{border_collapse, caption_side, empty_cells}; + use crate::css::css_enums::{border_collapse, caption_side, empty_cells}; Self { border_collapse: border_collapse::SEPARATE, @@ -1526,7 +1484,7 @@ impl InheritedTableValues { impl InheritedBoxValues { fn initial() -> Self { - use crate::css_enums::{content_visibility, direction, image_rendering, visibility, writing_mode}; + use crate::css::css_enums::{content_visibility, direction, image_rendering, visibility, writing_mode}; Self { visibility: visibility::VISIBLE, diff --git a/Libraries/LibWeb/CSS/Rust/src/css_enums.rs b/Libraries/LibWeb/Rust/src/css/css_enums.rs similarity index 100% rename from Libraries/LibWeb/CSS/Rust/src/css_enums.rs rename to Libraries/LibWeb/Rust/src/css/css_enums.rs diff --git a/Libraries/LibWeb/CSS/Rust/src/css_pixels.rs b/Libraries/LibWeb/Rust/src/css/css_pixels.rs similarity index 62% rename from Libraries/LibWeb/CSS/Rust/src/css_pixels.rs rename to Libraries/LibWeb/Rust/src/css/css_pixels.rs index 5b30e1b832fca..92aceea21e7d1 100644 --- a/Libraries/LibWeb/CSS/Rust/src/css_pixels.rs +++ b/Libraries/LibWeb/Rust/src/css/css_pixels.rs @@ -4,17 +4,17 @@ * SPDX-License-Identifier: BSD-2-Clause */ -//! CSSPixels fixed-point arithmetic, bit-exact with the C++ implementation in -//! PixelUnits.h: an i32 with 6 fractional bits. The parity test on the C++ -//! side compares every operation against the original. -//! -//! Rounding notes, matching C++ exactly: -//! - Conversion from floating point rounds half to even (the C++ path goes -//! through the x87 fistp instruction in the default rounding mode) and -//! saturates at the i32 bounds. -//! - Multiplication rounds the cut-off fraction half away from zero when more -//! fraction bits follow, and half to even otherwise. -//! - Fraction-to-value conversion truncates (plain integer division). +// CSSPixels fixed-point arithmetic, bit-exact with the C++ implementation in +// PixelUnits.h: an i32 with 6 fractional bits. The parity test on the C++ +// side compares every operation against the original. +// +// Rounding notes, matching C++ exactly: +// - Conversion from floating point rounds half to even (the C++ path goes +// through the x87 fistp instruction in the default rounding mode) and +// saturates at the i32 bounds. +// - Multiplication rounds the cut-off fraction half away from zero when more +// fraction bits follow, and half to even otherwise. +// - Fraction-to-value conversion truncates (plain integer division). pub const FRACTIONAL_BITS: u32 = 6; pub const FIXED_POINT_DENOMINATOR: i32 = 1 << FRACTIONAL_BITS; @@ -22,7 +22,8 @@ pub const RADIX_MASK: i32 = FIXED_POINT_DENOMINATOR - 1; pub const MAX_INTEGER_VALUE: i32 = i32::MAX >> FRACTIONAL_BITS; pub const MIN_INTEGER_VALUE: i32 = i32::MIN >> FRACTIONAL_BITS; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[repr(transparent)] pub struct CssPixels(i32); impl std::ops::Mul for CssPixels { @@ -46,6 +47,16 @@ fn clamp_f64_to_i32(value: f64) -> i32 { value.round_ties_even() as i32 } +fn clamp_f32_to_i32(value: f32) -> i32 { + if value >= i32::MAX as f32 { + return i32::MAX; + } + if value <= i32::MIN as f32 { + return i32::MIN; + } + value.round_ties_even() as i32 +} + impl CssPixels { pub fn from_raw(raw: i32) -> Self { Self(raw) @@ -72,6 +83,29 @@ impl CssPixels { Self(clamp_f64_to_i32(value * FIXED_POINT_DENOMINATOR as f64)) } + /// Matches `CSSPixels::nearest_value_for(float)`: the scaling and + /// ties-to-even conversion both stay on the f32 path. + pub fn nearest_value_for_f32(value: f32) -> Self { + if value.is_nan() { + return Self(0); + } + Self(clamp_f32_to_i32(value * FIXED_POINT_DENOMINATOR as f32)) + } + + pub fn floor(self) -> Self { + Self(self.0 & !RADIX_MASK) + } + + pub fn ceil(self) -> Self { + let floor = self.0 & !RADIX_MASK; + let increment = if self.0 & RADIX_MASK != 0 { + FIXED_POINT_DENOMINATOR + } else { + 0 + }; + Self(floor.wrapping_add(increment)) + } + pub fn to_double(self) -> f64 { self.0 as f64 / FIXED_POINT_DENOMINATOR as f64 } @@ -126,6 +160,36 @@ mod tests { assert_eq!(CssPixels::nearest_value_for(f64::NAN).raw_value(), 0); } + #[test] + fn f32_nearest_value_keeps_the_float_instantiation() { + assert_eq!(CssPixels::nearest_value_for_f32(0.0078125).raw_value(), 0); + assert_eq!(CssPixels::nearest_value_for_f32(0.0234375).raw_value(), 2); + assert_eq!(CssPixels::nearest_value_for_f32(f32::NAN).raw_value(), 0); + assert_eq!(CssPixels::nearest_value_for_f32(f32::INFINITY).raw_value(), i32::MAX); + assert_eq!( + CssPixels::nearest_value_for_f32(f32::NEG_INFINITY).raw_value(), + i32::MIN + ); + } + + #[test] + fn fixed_point_floor_and_ceil_match_cpp_bit_operations() { + for (raw, floor, ceil) in [ + (0, 0, 0), + (1, 0, 64), + (63, 0, 64), + (64, 64, 64), + (65, 64, 128), + (-1, -64, 0), + (-63, -64, 0), + (-64, -64, -64), + (-65, -128, -64), + ] { + assert_eq!(CssPixels::from_raw(raw).floor().raw_value(), floor); + assert_eq!(CssPixels::from_raw(raw).ceil().raw_value(), ceil); + } + } + #[test] fn multiplication_rounding_modes() { // 0.5 * 0.5 = 0.25: exact, no rounding. @@ -153,22 +217,24 @@ mod tests { /// FFI hooks for the C++ parity test. #[unsafe(no_mangle)] pub extern "C" fn rust_css_pixels_multiply(left_raw: i32, right_raw: i32) -> i32 { - (CssPixels::from_raw(left_raw) * CssPixels::from_raw(right_raw)).raw_value() + crate::abort_on_panic(|| (CssPixels::from_raw(left_raw) * CssPixels::from_raw(right_raw)).raw_value()) } #[unsafe(no_mangle)] pub extern "C" fn rust_css_pixels_divide_as_fraction(numerator_raw: i32, denominator_raw: i32) -> i32 { - CssPixels::from_raw(numerator_raw) - .div_as_fraction(CssPixels::from_raw(denominator_raw)) - .raw_value() + crate::abort_on_panic(|| { + CssPixels::from_raw(numerator_raw) + .div_as_fraction(CssPixels::from_raw(denominator_raw)) + .raw_value() + }) } #[unsafe(no_mangle)] pub extern "C" fn rust_css_pixels_nearest_value_for(value: f64) -> i32 { - CssPixels::nearest_value_for(value).raw_value() + crate::abort_on_panic(|| CssPixels::nearest_value_for(value).raw_value()) } #[unsafe(no_mangle)] pub extern "C" fn rust_css_pixels_scaled(raw: i32, factor: f64) -> i32 { - CssPixels::from_raw(raw).scaled(factor).raw_value() + crate::abort_on_panic(|| CssPixels::from_raw(raw).scaled(factor).raw_value()) } diff --git a/Libraries/LibWeb/CSS/Rust/src/css_tokenizer.rs b/Libraries/LibWeb/Rust/src/css/css_tokenizer.rs similarity index 100% rename from Libraries/LibWeb/CSS/Rust/src/css_tokenizer.rs rename to Libraries/LibWeb/Rust/src/css/css_tokenizer.rs diff --git a/Libraries/LibWeb/CSS/Rust/src/custom_properties.rs b/Libraries/LibWeb/Rust/src/css/custom_properties.rs similarity index 97% rename from Libraries/LibWeb/CSS/Rust/src/custom_properties.rs rename to Libraries/LibWeb/Rust/src/css/custom_properties.rs index 0db30cc2bf920..b704a1a442249 100644 --- a/Libraries/LibWeb/CSS/Rust/src/custom_properties.rs +++ b/Libraries/LibWeb/Rust/src/css/custom_properties.rs @@ -13,12 +13,12 @@ use std::ffi::c_void; use std::rc::Rc; use crate::abort_on_panic; -use crate::css_tokenizer::OwnedToken; -use crate::css_tokenizer::OwnedTokenKind; -use crate::css_tokenizer::tokenize_owned; -use crate::style_value::RetainedStyleValueData; -use crate::style_value::RetainedUtf16FlyString; -use crate::style_value::StyleValueData; +use crate::css::css_tokenizer::OwnedToken; +use crate::css::css_tokenizer::OwnedTokenKind; +use crate::css::css_tokenizer::tokenize_owned; +use crate::css::style_value::RetainedStyleValueData; +use crate::css::style_value::RetainedUtf16FlyString; +use crate::css::style_value::StyleValueData; #[repr(C)] pub struct FfiCustomPropertyStoreEntry { @@ -560,7 +560,7 @@ pub unsafe extern "C" fn rust_custom_property_store_create( entry_count: usize, parent: *const c_void, ) -> *const c_void { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CustomPropertyStoreLifecycleEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CustomPropertyStoreLifecycleEntry); abort_on_panic(|| { let entries = if entry_count == 0 { &[] @@ -608,7 +608,7 @@ pub unsafe extern "C" fn rust_custom_property_store_create( /// not already been released. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_custom_property_store_destroy(store: *const c_void) { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CustomPropertyStoreLifecycleEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CustomPropertyStoreLifecycleEntry); abort_on_panic(|| drop(unsafe { Rc::from_raw(store.cast::()) })); } @@ -630,7 +630,7 @@ pub unsafe extern "C" fn rust_custom_property_store_get( store: *const c_void, name_raw: usize, ) -> FfiCustomPropertyStoreValue { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::CustomPropertyStoreQueryEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::CustomPropertyStoreQueryEntry); abort_on_panic(|| { let store = unsafe { &*store.cast::() }; let Some(entry) = store.get(name_raw) else { diff --git a/Libraries/LibWeb/CSS/Rust/src/display.rs b/Libraries/LibWeb/Rust/src/css/display.rs similarity index 69% rename from Libraries/LibWeb/CSS/Rust/src/display.rs rename to Libraries/LibWeb/Rust/src/css/display.rs index 42a6ee7972728..47b00775bc6ab 100644 --- a/Libraries/LibWeb/CSS/Rust/src/display.rs +++ b/Libraries/LibWeb/Rust/src/css/display.rs @@ -6,7 +6,28 @@ //! The CSS `display` value and its predicates, mirroring `Web::CSS::Display`. -use crate::css_enums::{display_box, display_inside, display_internal, display_outside}; +use crate::css::css_enums::{display_box, display_inside, display_internal, display_outside}; + +const DISPLAY_BOX_CONTENTS: u8 = display_box::CONTENTS; +const DISPLAY_BOX_NONE: u8 = display_box::NONE; +const DISPLAY_INSIDE_FLOW: u8 = display_inside::FLOW; +const DISPLAY_INSIDE_FLOW_ROOT: u8 = display_inside::FLOW_ROOT; +const DISPLAY_INSIDE_TABLE: u8 = display_inside::TABLE; +const DISPLAY_INSIDE_FLEX: u8 = display_inside::FLEX; +const DISPLAY_INSIDE_GRID: u8 = display_inside::GRID; +const DISPLAY_INSIDE_RUBY: u8 = display_inside::RUBY; +const DISPLAY_INSIDE_MATH: u8 = display_inside::MATH; +const DISPLAY_INSIDE_WEBKIT_BOX: u8 = display_inside::_WEBKIT_BOX; +const DISPLAY_INTERNAL_TABLE_ROW_GROUP: u8 = display_internal::TABLE_ROW_GROUP; +const DISPLAY_INTERNAL_TABLE_HEADER_GROUP: u8 = display_internal::TABLE_HEADER_GROUP; +const DISPLAY_INTERNAL_TABLE_FOOTER_GROUP: u8 = display_internal::TABLE_FOOTER_GROUP; +const DISPLAY_INTERNAL_TABLE_ROW: u8 = display_internal::TABLE_ROW; +const DISPLAY_INTERNAL_TABLE_CELL: u8 = display_internal::TABLE_CELL; +const DISPLAY_INTERNAL_TABLE_COLUMN_GROUP: u8 = display_internal::TABLE_COLUMN_GROUP; +const DISPLAY_INTERNAL_TABLE_COLUMN: u8 = display_internal::TABLE_COLUMN; +const DISPLAY_INTERNAL_TABLE_CAPTION: u8 = display_internal::TABLE_CAPTION; +const DISPLAY_OUTSIDE_BLOCK: u8 = display_outside::BLOCK; +const DISPLAY_OUTSIDE_INLINE: u8 = display_outside::INLINE; /// Mirror of the CSS Display value; the C++ tagged union crosses as explicit /// fields, with the unused fields zeroed so equality is field-wise. `tag` uses @@ -68,27 +89,27 @@ impl FfiDisplay { } pub fn block() -> Self { - Self::outside_and_inside(display_outside::BLOCK, display_inside::FLOW, false) + Self::outside_and_inside(DISPLAY_OUTSIDE_BLOCK, DISPLAY_INSIDE_FLOW, false) } pub fn inline() -> Self { - Self::outside_and_inside(display_outside::INLINE, display_inside::FLOW, false) + Self::outside_and_inside(DISPLAY_OUTSIDE_INLINE, DISPLAY_INSIDE_FLOW, false) } pub fn inline_block() -> Self { - Self::outside_and_inside(display_outside::INLINE, display_inside::FLOW_ROOT, false) + Self::outside_and_inside(DISPLAY_OUTSIDE_INLINE, DISPLAY_INSIDE_FLOW_ROOT, false) } pub fn flow_root() -> Self { - Self::outside_and_inside(display_outside::BLOCK, display_inside::FLOW_ROOT, false) + Self::outside_and_inside(DISPLAY_OUTSIDE_BLOCK, DISPLAY_INSIDE_FLOW_ROOT, false) } pub fn table() -> Self { - Self::outside_and_inside(display_outside::BLOCK, display_inside::TABLE, false) + Self::outside_and_inside(DISPLAY_OUTSIDE_BLOCK, DISPLAY_INSIDE_TABLE, false) } pub fn inline_table() -> Self { - Self::outside_and_inside(display_outside::INLINE, display_inside::TABLE, false) + Self::outside_and_inside(DISPLAY_OUTSIDE_INLINE, DISPLAY_INSIDE_TABLE, false) } pub fn encoded(&self) -> u32 { @@ -108,7 +129,7 @@ impl FfiDisplay { inside: 0, list_item: false, internal: 0, - box_value: display_box::NONE, + box_value: DISPLAY_BOX_NONE, } } @@ -119,7 +140,7 @@ impl FfiDisplay { inside: 0, list_item: false, internal: 0, - box_value: display_box::CONTENTS, + box_value: DISPLAY_BOX_CONTENTS, } } @@ -132,19 +153,19 @@ impl FfiDisplay { } pub fn is_none(&self) -> bool { - self.tag == DISPLAY_TAG_BOX && self.box_value == display_box::NONE + self.tag == DISPLAY_TAG_BOX && self.box_value == DISPLAY_BOX_NONE } pub fn is_contents(&self) -> bool { - self.tag == DISPLAY_TAG_BOX && self.box_value == display_box::CONTENTS + self.tag == DISPLAY_TAG_BOX && self.box_value == DISPLAY_BOX_CONTENTS } pub fn is_block_outside(&self) -> bool { - self.is_outside_and_inside() && self.outside == display_outside::BLOCK + self.is_outside_and_inside() && self.outside == DISPLAY_OUTSIDE_BLOCK } pub fn is_inline_outside(&self) -> bool { - self.is_outside_and_inside() && self.outside == display_outside::INLINE + self.is_outside_and_inside() && self.outside == DISPLAY_OUTSIDE_INLINE } pub fn is_inline_block(&self) -> bool { @@ -156,76 +177,75 @@ impl FfiDisplay { } pub fn is_flow_inside(&self) -> bool { - self.is_outside_and_inside() && self.inside == display_inside::FLOW + self.is_outside_and_inside() && self.inside == DISPLAY_INSIDE_FLOW } pub fn is_flow_root_inside(&self) -> bool { - self.is_outside_and_inside() && self.inside == display_inside::FLOW_ROOT + self.is_outside_and_inside() && self.inside == DISPLAY_INSIDE_FLOW_ROOT } pub fn is_table_inside(&self) -> bool { - self.is_outside_and_inside() && self.inside == display_inside::TABLE + self.is_outside_and_inside() && self.inside == DISPLAY_INSIDE_TABLE } pub fn is_flex_inside(&self) -> bool { - self.is_outside_and_inside() - && (self.inside == display_inside::FLEX || self.inside == display_inside::_WEBKIT_BOX) + self.is_outside_and_inside() && (self.inside == DISPLAY_INSIDE_FLEX || self.inside == DISPLAY_INSIDE_WEBKIT_BOX) } pub fn is_grid_inside(&self) -> bool { - self.is_outside_and_inside() && self.inside == display_inside::GRID + self.is_outside_and_inside() && self.inside == DISPLAY_INSIDE_GRID } pub fn is_ruby_inside(&self) -> bool { - self.is_outside_and_inside() && self.inside == display_inside::RUBY + self.is_outside_and_inside() && self.inside == DISPLAY_INSIDE_RUBY } pub fn is_math_inside(&self) -> bool { - self.is_outside_and_inside() && self.inside == display_inside::MATH + self.is_outside_and_inside() && self.inside == DISPLAY_INSIDE_MATH } pub fn is_table_row(&self) -> bool { - self.is_internal() && self.internal == display_internal::TABLE_ROW + self.is_internal() && self.internal == DISPLAY_INTERNAL_TABLE_ROW } pub fn is_table_cell(&self) -> bool { - self.is_internal() && self.internal == display_internal::TABLE_CELL + self.is_internal() && self.internal == DISPLAY_INTERNAL_TABLE_CELL } pub fn is_table_column(&self) -> bool { - self.is_internal() && self.internal == display_internal::TABLE_COLUMN + self.is_internal() && self.internal == DISPLAY_INTERNAL_TABLE_COLUMN } pub fn is_table_column_group(&self) -> bool { - self.is_internal() && self.internal == display_internal::TABLE_COLUMN_GROUP + self.is_internal() && self.internal == DISPLAY_INTERNAL_TABLE_COLUMN_GROUP } pub fn is_table_row_group(&self) -> bool { - self.is_internal() && self.internal == display_internal::TABLE_ROW_GROUP + self.is_internal() && self.internal == DISPLAY_INTERNAL_TABLE_ROW_GROUP } pub fn is_table_header_group(&self) -> bool { - self.is_internal() && self.internal == display_internal::TABLE_HEADER_GROUP + self.is_internal() && self.internal == DISPLAY_INTERNAL_TABLE_HEADER_GROUP } pub fn is_table_footer_group(&self) -> bool { - self.is_internal() && self.internal == display_internal::TABLE_FOOTER_GROUP + self.is_internal() && self.internal == DISPLAY_INTERNAL_TABLE_FOOTER_GROUP } pub fn is_table_caption(&self) -> bool { - self.is_internal() && self.internal == display_internal::TABLE_CAPTION + self.is_internal() && self.internal == DISPLAY_INTERNAL_TABLE_CAPTION } // https://drafts.csswg.org/css-display-3/#internal-table-element pub fn is_internal_table(&self) -> bool { self.is_internal() - && (self.internal == display_internal::TABLE_ROW_GROUP - || self.internal == display_internal::TABLE_HEADER_GROUP - || self.internal == display_internal::TABLE_FOOTER_GROUP - || self.internal == display_internal::TABLE_ROW - || self.internal == display_internal::TABLE_CELL - || self.internal == display_internal::TABLE_COLUMN_GROUP - || self.internal == display_internal::TABLE_COLUMN) + && (self.internal == DISPLAY_INTERNAL_TABLE_ROW_GROUP + || self.internal == DISPLAY_INTERNAL_TABLE_HEADER_GROUP + || self.internal == DISPLAY_INTERNAL_TABLE_FOOTER_GROUP + || self.internal == DISPLAY_INTERNAL_TABLE_ROW + || self.internal == DISPLAY_INTERNAL_TABLE_CELL + || self.internal == DISPLAY_INTERNAL_TABLE_COLUMN_GROUP + || self.internal == DISPLAY_INTERNAL_TABLE_COLUMN) } } diff --git a/Libraries/LibWeb/CSS/Rust/src/ffi_stats.rs b/Libraries/LibWeb/Rust/src/css/ffi_stats.rs similarity index 100% rename from Libraries/LibWeb/CSS/Rust/src/ffi_stats.rs rename to Libraries/LibWeb/Rust/src/css/ffi_stats.rs diff --git a/Libraries/LibWeb/CSS/Rust/src/ffi_support.rs b/Libraries/LibWeb/Rust/src/css/ffi_support.rs similarity index 100% rename from Libraries/LibWeb/CSS/Rust/src/ffi_support.rs rename to Libraries/LibWeb/Rust/src/css/ffi_support.rs diff --git a/Libraries/LibWeb/Rust/src/css/mod.rs b/Libraries/LibWeb/Rust/src/css/mod.rs new file mode 100644 index 0000000000000..04d99165ab1fc --- /dev/null +++ b/Libraries/LibWeb/Rust/src/css/mod.rs @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026-present, the Ladybird developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +pub mod animation; +pub mod calc; +pub mod cascaded_properties; +pub(crate) mod color_conversion; +pub mod color_interpolation; +pub mod computed_value_types; +pub mod computed_values; +pub mod css_enums; +pub mod css_pixels; +pub(crate) mod css_tokenizer; +pub mod custom_properties; +pub mod display; +pub mod ffi_stats; +pub mod ffi_support; +pub mod property_metadata; +pub(crate) mod selector_engine; +pub mod style_compute; +pub(crate) mod style_value; +pub mod transition; + +pub use css_tokenizer::CssHashType; +pub use css_tokenizer::CssNumberType; +pub use css_tokenizer::CssToken; +pub use css_tokenizer::CssTokenType; diff --git a/Libraries/LibWeb/CSS/Rust/src/property_metadata.rs b/Libraries/LibWeb/Rust/src/css/property_metadata.rs similarity index 100% rename from Libraries/LibWeb/CSS/Rust/src/property_metadata.rs rename to Libraries/LibWeb/Rust/src/css/property_metadata.rs diff --git a/Libraries/LibWeb/CSS/Rust/src/selector_engine.rs b/Libraries/LibWeb/Rust/src/css/selector_engine.rs similarity index 95% rename from Libraries/LibWeb/CSS/Rust/src/selector_engine.rs rename to Libraries/LibWeb/Rust/src/css/selector_engine.rs index 246ba5e1811b6..8f56883f98c17 100644 --- a/Libraries/LibWeb/CSS/Rust/src/selector_engine.rs +++ b/Libraries/LibWeb/Rust/src/css/selector_engine.rs @@ -12,7 +12,7 @@ use std::rc::Rc; use std::sync::atomic::{AtomicU64, Ordering}; use crate::abort_on_panic; -use crate::ffi_support::{ +use crate::css::ffi_support::{ DomStringView, FfiCallScope, FfiDomStringView, RetainedCxxPointer, ascii_lowercase, utf16_equals, utf16_equals_ignoring_ascii_case, }; @@ -1592,20 +1592,20 @@ pub struct FfiElement { impl FfiElement { fn qualified_name(self) -> FfiElementQualifiedName { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_qualified_name(self.pointer) } } fn id(self) -> Option { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element. A non-null result points at its // current pinned `Utf16FlyString` storage for this matching call. unsafe { selector_ffi_element_id(self.pointer).as_ref().copied() } } unsafe fn id_value<'a>(self) -> DomStringView<'a> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element. C++ returns its current ID with // backing storage owned by the element for this matching call. // SAFETY: C++ guarantees that the returned string view remains valid for matching. @@ -1613,43 +1613,43 @@ impl FfiElement { } fn id_and_class_names_are_case_insensitive(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_id_and_class_names_are_case_insensitive(self.pointer) } } fn namespace_is_null(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_namespace_is_null(self.pointer) } } fn is_html_element_in_html_document(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_html_element_in_html_document(self.pointer) } } fn is_document_root(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_document_root(self.pointer) } } fn is_link(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_link(self.pointer) } } fn is_fullscreen(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_fullscreen(self.pointer) } } fn heading_level(self) -> Option { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. match unsafe { selector_ffi_element_heading_level(self.pointer) } { 0 => None, @@ -1658,19 +1658,19 @@ impl FfiElement { } fn has_popover_attribute(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_has_popover_attribute(self.pointer) } } fn popover_is_showing(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_popover_is_showing(self.pointer) } } fn direction(self) -> Direction { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. match unsafe { selector_ffi_element_direction(self.pointer) } { FfiDirection::LeftToRight => Direction::LeftToRight, @@ -1680,14 +1680,14 @@ impl FfiElement { } fn has_custom_state(self, state: usize) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element and `state` is the copied identity of // an interned selector identifier. unsafe { selector_ffi_element_has_custom_state(self.pointer, state) } } unsafe fn language<'a>(self) -> Option> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element. C++ returns its current language with // backing storage owned by the element for this matching call. let view = unsafe { selector_ffi_element_language(self.pointer) }; @@ -1695,187 +1695,187 @@ impl FfiElement { } fn is_focused(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_focused(self.pointer) } } fn should_indicate_focus(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_should_indicate_focus(self.pointer) } } fn has_focus_within(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_has_focus_within(self.pointer) } } fn is_active(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_active(self.pointer) } } fn is_checked(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_checked(self.pointer) } } fn is_defined(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_defined(self.pointer) } } fn is_disabled(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_disabled(self.pointer) } } fn is_enabled(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_enabled(self.pointer) } } fn is_local_link(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_local_link(self.pointer) } } fn is_placeholder_shown(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_placeholder_shown(self.pointer) } } fn is_target(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_target(self.pointer) } } fn is_unchecked(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_unchecked(self.pointer) } } fn is_media_element(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_media_element(self.pointer) } } fn media_is_blocked(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_media_is_blocked(self.pointer) } } fn media_is_muted(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_media_is_muted(self.pointer) } } fn media_is_paused(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_media_is_paused(self.pointer) } } fn media_is_seeking(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_media_is_seeking(self.pointer) } } fn media_is_stalled(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_media_is_stalled(self.pointer) } } fn is_default(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_default(self.pointer) } } fn meter_value_state(self) -> FfiMeterValueState { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_meter_value_state(self.pointer) } } fn meter_value_is_high(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_meter_value_is_high(self.pointer) } } fn meter_value_is_low(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_meter_value_is_low(self.pointer) } } fn is_hovered(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_hovered(self.pointer) } } fn is_indeterminate(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_indeterminate(self.pointer) } } fn validity_state(self) -> FfiValidityState { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_validity_state(self.pointer) } } fn is_modal(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_modal(self.pointer) } } fn is_open(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_open(self.pointer) } } fn required_state(self) -> FfiRequiredState { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_required_state(self.pointer) } } fn is_read_write(self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_is_read_write(self.pointer) } } fn user_validity_state(self) -> FfiValidityState { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_user_validity_state(self.pointer) } } unsafe fn local_name<'a>(self) -> DomStringView<'a> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element. C++ returns a string view borrowed // from its current local name for this matching call. // SAFETY: C++ guarantees that the returned string view remains valid for matching. @@ -1883,7 +1883,7 @@ impl FfiElement { } unsafe fn class_name<'a>(self, index: usize) -> DomStringView<'a> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element and `index` identifies one of its // current classes. C++ returns a view borrowed for this matching call. // SAFETY: The caller guarantees that `index` is within the current class list. @@ -1891,13 +1891,13 @@ impl FfiElement { } fn attribute_count(self) -> usize { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element for the duration of matching. unsafe { selector_ffi_element_attribute_count(self.pointer) } } unsafe fn attribute<'a>(self, index: usize) -> DomAttribute<'a> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element and `index` identifies one of its // current attributes. C++ returns its facts and a value view borrowed for matching. DomAttribute { @@ -1908,7 +1908,7 @@ impl FfiElement { } unsafe fn classes<'a>(self) -> &'a [usize] { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The handle identifies a live DOM element. C++ returns its current class storage, // borrowed for this matching call. let classes = unsafe { selector_ffi_element_classes(self.pointer) }; @@ -2550,13 +2550,13 @@ impl<'a> FfiDom<'a> { } fn default_namespace(&self) -> FfiResolvedNamespace { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The matching context remains live for this matching call. unsafe { selector_ffi_default_namespace(self.context) } } fn resolve_namespace(&self, prefix: &[u16]) -> FfiResolvedNamespace { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: The matching context remains live, and the prefix view is borrowed for this // accessor call only. unsafe { selector_ffi_resolve_namespace(self.context, ffi_string_view(prefix)) } @@ -2805,7 +2805,7 @@ impl<'a> SelectorDom for FfiDom<'a> { } fn parent_element(&mut self, element: FfiNode<'a>, shadow_host: Option>) -> Option> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: `FfiDom` guarantees that the input handles remain valid. The callback returns // either null or another live element borrowed for the same lifetime. unsafe { @@ -2817,42 +2817,42 @@ impl<'a> SelectorDom for FfiDom<'a> { } fn parent_element_in_light_tree(&mut self, element: FfiNode<'a>) -> Option> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: `FfiDom` guarantees that the input remains valid. The callback returns either // null or another live element borrowed for the same lifetime. unsafe { self.element(selector_ffi_parent_element_in_light_tree(element.as_element_pointer())) } } fn previous_element_sibling(&mut self, element: FfiNode<'a>) -> Option> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: `FfiDom` guarantees that the input remains valid. The callback returns either // null or another live element borrowed for the same lifetime. unsafe { self.element(selector_ffi_previous_element_sibling(element.as_element_pointer())) } } fn next_element_sibling(&mut self, element: FfiNode<'a>) -> Option> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: `FfiDom` guarantees that the input remains valid. The callback returns either // null or another live element borrowed for the same lifetime. unsafe { self.element(selector_ffi_next_element_sibling(element.as_element_pointer())) } } fn first_element_child(&mut self, element: FfiNode<'a>) -> Option> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: `FfiDom` guarantees that the input remains valid. The callback returns either // null or another live element borrowed for the same lifetime. unsafe { self.element(selector_ffi_first_element_child(element.as_element_pointer())) } } fn first_element_descendant(&mut self, element: FfiNode<'a>) -> Option> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: `FfiDom` guarantees that the input remains valid. The callback returns either // null or another live element borrowed for the same lifetime. unsafe { self.element(selector_ffi_first_element_descendant(element.as_element_pointer())) } } fn next_element_descendant(&mut self, element: FfiNode<'a>, root: FfiNode<'a>) -> Option> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: `FfiDom` guarantees that both element handles remain valid for this call. The // callback returns either null or another live element borrowed for the same lifetime. unsafe { @@ -2864,12 +2864,12 @@ impl<'a> SelectorDom for FfiDom<'a> { } fn has_no_element_or_nonempty_text_children(&mut self, element: FfiNode<'a>) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: `FfiDom` guarantees that the element remains valid for matching. if unsafe { selector_ffi_element_has_element_child(element.as_element_pointer()) } { return false; } - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: `FfiDom` guarantees that the element remains valid for matching. !unsafe { selector_ffi_element_has_nonempty_text_child(element.as_element_pointer()) } } @@ -2885,13 +2885,13 @@ impl<'a> SelectorDom for FfiDom<'a> { } fn is_shadow_tree_slot(&mut self, element: FfiNode<'a>) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: `FfiDom` guarantees that the element remains valid for matching. unsafe { selector_ffi_is_shadow_tree_slot(element.as_element_pointer()) } } fn slotted_parent(&mut self, element: FfiNode<'a>) -> Option<(FfiNode<'a>, Option>)> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); // SAFETY: `FfiDom` guarantees that the context and element remain valid. The callback // returns null or live elements borrowed for the same lifetime. unsafe { self.element_and_shadow_host(selector_ffi_slotted_parent(self.context, element.as_element_pointer())) } @@ -2904,7 +2904,7 @@ impl<'a> SelectorDom for FfiDom<'a> { allow_same_shadow_root_scope: bool, shadow_host: Option>, ) -> Option<(FfiNode<'a>, Option>)> { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorDomReadCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorDomReadCallback); let identifiers = identifiers .iter() .map(|identifier| ffi_string_view(identifier)) @@ -2928,7 +2928,7 @@ impl<'a> SelectorDom for FfiDom<'a> { if !self.collects_selector_involvement_metadata { return; } - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorMetadataCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorMetadataCallback); // SAFETY: `FfiDom` guarantees that the context and element remain valid for matching. unsafe { selector_ffi_note_structural_pseudo_class(self.context, element.as_element_pointer(), pseudo_class as u8); @@ -2939,7 +2939,7 @@ impl<'a> SelectorDom for FfiDom<'a> { if !self.collects_selector_involvement_metadata { return; } - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorMetadataCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorMetadataCallback); // SAFETY: `FfiDom` guarantees that the context and element remain valid for matching. unsafe { selector_ffi_note_has_pseudo_class(self.context, element.as_element_pointer()) } } @@ -2953,7 +2953,7 @@ impl<'a> SelectorDom for FfiDom<'a> { if !self.collects_selector_involvement_metadata { return; } - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorMetadataCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorMetadataCallback); // SAFETY: `FfiDom` guarantees that the context and element remain valid for matching. unsafe { selector_ffi_note_sibling_combinator( @@ -2969,7 +2969,7 @@ impl<'a> SelectorDom for FfiDom<'a> { if !self.collects_selector_involvement_metadata { return; } - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorMetadataCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorMetadataCallback); // SAFETY: `FfiDom` guarantees that the context and anchor remain valid for matching. unsafe { selector_ffi_note_has_sibling_combinator_anchor(self.context, anchor.as_element_pointer()) } } @@ -2978,7 +2978,7 @@ impl<'a> SelectorDom for FfiDom<'a> { if !self.collects_selector_involvement_metadata { return; } - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorMetadataCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorMetadataCallback); // SAFETY: `FfiDom` guarantees that the context and element remain valid for matching. unsafe { selector_ffi_note_has_sibling_combinator_element(self.context, element.as_element_pointer()) } } @@ -2987,7 +2987,7 @@ impl<'a> SelectorDom for FfiDom<'a> { if !self.collects_selector_involvement_metadata || !self.inside_has_argument { return; } - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorMetadataCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorMetadataCallback); // SAFETY: `FfiDom` guarantees that the context and element remain valid for matching. unsafe { selector_ffi_note_has_scope_element(self.context, element.as_element_pointer()) } } @@ -2997,7 +2997,7 @@ impl<'a> SelectorDom for FfiDom<'a> { } fn enter_has_argument_matching(&mut self) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorMetadataCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorMetadataCallback); let previous_value = self.inside_has_argument; self.inside_has_argument = true; // SAFETY: `FfiDom` guarantees that the context remains valid for matching. @@ -3006,14 +3006,14 @@ impl<'a> SelectorDom for FfiDom<'a> { } fn leave_has_argument_matching(&mut self, previous_value: bool) { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorMetadataCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorMetadataCallback); self.inside_has_argument = previous_value; // SAFETY: `FfiDom` guarantees that the context remains valid for matching. unsafe { selector_ffi_set_inside_has_argument(self.context, previous_value) } } fn has_cache_get(&mut self, selector_id: u64, anchor: FfiNode<'a>) -> Option { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorMetadataCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorMetadataCallback); // SAFETY: `FfiDom` guarantees that the context and anchor remain valid for matching. match unsafe { selector_ffi_has_cache_get(self.context, selector_id, anchor.as_element_pointer()) } { HasCacheResult::NotCached => None, @@ -3023,13 +3023,13 @@ impl<'a> SelectorDom for FfiDom<'a> { } fn has_cache_set(&mut self, selector_id: u64, anchor: FfiNode<'a>, result: bool) { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorMetadataCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorMetadataCallback); // SAFETY: `FfiDom` guarantees that the context and anchor remain valid for matching. unsafe { selector_ffi_has_cache_set(self.context, selector_id, anchor.as_element_pointer(), result) } } fn should_reject_has_argument(&mut self, selector: &CompiledSelector, anchor: FfiNode<'a>) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorMetadataCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorMetadataCallback); // SAFETY: `FfiDom` guarantees that the context, retained selector, and anchor remain valid // for matching. unsafe { @@ -3325,7 +3325,7 @@ pub unsafe extern "C" fn rust_selector_matches( collects_selector_involvement_metadata: bool, inside_has_argument: bool, ) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorMatchEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorMatchEntry); abort_on_panic(|| { assert!(!selector.is_null()); assert!(!element.pointer.is_null()); @@ -3375,7 +3375,7 @@ pub unsafe extern "C" fn rust_selector_matches_originating_element( collects_selector_involvement_metadata: bool, inside_has_argument: bool, ) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::SelectorMatchEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::SelectorMatchEntry); abort_on_panic(|| { assert!(!selector.is_null()); assert!(!element.pointer.is_null()); diff --git a/Libraries/LibWeb/CSS/Rust/src/style_compute.rs b/Libraries/LibWeb/Rust/src/css/style_compute.rs similarity index 95% rename from Libraries/LibWeb/CSS/Rust/src/style_compute.rs rename to Libraries/LibWeb/Rust/src/css/style_compute.rs index 4ec552b432ebf..722cdbe131526 100644 --- a/Libraries/LibWeb/CSS/Rust/src/style_compute.rs +++ b/Libraries/LibWeb/Rust/src/css/style_compute.rs @@ -19,15 +19,15 @@ use std::ffi::c_void; use std::sync::{Arc, OnceLock}; use crate::abort_on_panic; -use crate::cascaded_properties::CascadedPropertyStore; -use crate::css_pixels::CssPixels; -use crate::display::FfiDisplay; -use crate::property_metadata::longhands_for_shorthand; -use crate::property_metadata::property_is_inherited; -use crate::property_metadata::property_is_shorthand; -use crate::style_value::{GridTrackEntryKind, RetainedStyleValueData, RetainedStyleValueDataList, StyleValueData}; +use crate::css::cascaded_properties::CascadedPropertyStore; +use crate::css::css_pixels::CssPixels; +use crate::css::display::FfiDisplay; +use crate::css::property_metadata::longhands_for_shorthand; +use crate::css::property_metadata::property_is_inherited; +use crate::css::property_metadata::property_is_shorthand; +use crate::css::style_value::{GridTrackEntryKind, RetainedStyleValueData, RetainedStyleValueDataList, StyleValueData}; -pub use crate::css_enums::*; +pub use crate::css::css_enums::*; include!(concat!(env!("OUT_DIR"), "/length_units_generated.rs")); @@ -303,7 +303,7 @@ pub unsafe extern "C" fn rust_absolutize_length( unit: u8, context: *const FfiLengthResolutionContext, ) -> FfiAbsolutizedLength { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| absolutize_length(value, unit as usize, unsafe { &*context })) } @@ -407,7 +407,7 @@ fn compute_font_weight(value: &StyleValueData, inherited_font_weight: f64) -> Ff }, // Calc values resolve in the calc core with no external context; anything the // core cannot resolve keeps the C++ caller's behavior. - StyleValueData::Calculated { .. } => match crate::calc::resolve_calculated_number_without_context(value) { + StyleValueData::Calculated { .. } => match crate::css::calc::resolve_calculated_number_without_context(value) { Some(resolved) => computed(resolved), None => NUMBER_UNHANDLED, }, @@ -453,10 +453,12 @@ fn compute_font_width(value: &StyleValueData) -> FfiComputedNumber { }, // Calc percentages resolve in the calc core with no external context; anything // the core cannot resolve keeps the C++ caller's behavior. - StyleValueData::Calculated { .. } => match crate::calc::resolve_calculated_percentage_without_context(value) { - Some(resolved) => computed(resolved), - None => NUMBER_UNHANDLED, - }, + StyleValueData::Calculated { .. } => { + match crate::css::calc::resolve_calculated_percentage_without_context(value) { + Some(resolved) => computed(resolved), + None => NUMBER_UNHANDLED, + } + } _ => NUMBER_UNHANDLED, } } @@ -467,7 +469,7 @@ fn compute_font_width(value: &StyleValueData) -> FfiComputedNumber { /// `absolutized_value` must point at a valid StyleValueData. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_compute_font_width(absolutized_value: *const c_void) -> FfiComputedNumber { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| { let value = unsafe { &*(absolutized_value as *const StyleValueData) }; compute_font_width(value) @@ -597,7 +599,7 @@ fn compute_font_size( // Calc lengths and percentages resolve in the calc core against the inherited // font size; anything the core cannot resolve keeps the C++ caller's behavior. StyleValueData::Calculated { .. } => { - match crate::calc::resolve_calculated_length_without_context(value, inherited_font_size.to_double()) { + match crate::css::calc::resolve_calculated_length_without_context(value, inherited_font_size.to_double()) { Some(px) => computed(px), None => NUMBER_UNHANDLED, } @@ -619,7 +621,7 @@ pub unsafe extern "C" fn rust_compute_font_size( inherited_math_depth: i32, default_font_size_raw: i32, ) -> FfiComputedNumber { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| { let value = unsafe { &*(absolutized_value as *const StyleValueData) }; compute_font_size( @@ -676,7 +678,7 @@ pub unsafe extern "C" fn rust_recascade_font_size_step( default_size_raw: i32, length_resolution_context: *const FfiLengthResolutionContext, ) -> FfiFontSizeRecascadeStep { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| { let value = unsafe { &*(value as *const StyleValueData) }; let current_size = CssPixels::from_raw(current_size_raw); @@ -750,11 +752,11 @@ pub unsafe extern "C" fn rust_recascade_font_size_step( /// styles must be computed even when no rules matched. #[unsafe(no_mangle)] pub extern "C" fn rust_pseudo_element_has_implicit_style(pseudo_element: u8) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); - use crate::selector_engine::PseudoElementType; + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); + use crate::css::selector_engine::PseudoElementType; abort_on_panic(|| { matches!( - crate::selector_engine::pseudo_element_type_from_code(pseudo_element), + crate::css::selector_engine::pseudo_element_type_from_code(pseudo_element), PseudoElementType::DetailsContent | PseudoElementType::FileSelectorButton | PseudoElementType::Marker @@ -773,8 +775,8 @@ pub extern "C" fn rust_pseudo_element_has_implicit_style(pseudo_element: u8) -> /// `content_value` must be null or point at a valid StyleValueData. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_pseudo_element_content_bails(content_value: *const c_void, pseudo_element: u8) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); - use crate::selector_engine::PseudoElementType; + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); + use crate::css::selector_engine::PseudoElementType; abort_on_panic(|| { let content_is_normal = if content_value.is_null() { // NOTE: `normal` is the initial value, so the absence of a value is treated as `normal`. @@ -792,7 +794,7 @@ pub unsafe extern "C" fn rust_pseudo_element_content_bails(content_value: *const }; content_is_normal && matches!( - crate::selector_engine::pseudo_element_type_from_code(pseudo_element), + crate::css::selector_engine::pseudo_element_type_from_code(pseudo_element), PseudoElementType::Before | PseudoElementType::After ) }) @@ -807,7 +809,7 @@ pub unsafe extern "C" fn rust_pseudo_element_content_bails(content_value: *const /// container is likewise undecided when any nested value is unsupported. fn value_is_computationally_independent(value: &StyleValueData) -> Option { fn grid_entries_are_computationally_independent( - entries: &[crate::style_value::RetainedGridTrackEntry], + entries: &[crate::css::style_value::RetainedGridTrackEntry], ) -> Option { for entry in entries { let independent = match entry.kind { @@ -836,7 +838,7 @@ fn value_is_computationally_independent(value: &StyleValueData) -> Option Some(true) } - let all_data_in_list = |list: &crate::style_value::RetainedStyleValueDataList| -> Option { + let all_data_in_list = |list: &crate::css::style_value::RetainedStyleValueDataList| -> Option { let mut independent = true; for retained in list.as_slice() { if let Some(data) = retained.optional_data() { @@ -845,7 +847,7 @@ fn value_is_computationally_independent(value: &StyleValueData) -> Option } Some(independent) }; - let all_data = |children: &[&crate::style_value::RetainedStyleValueData]| -> Option { + let all_data = |children: &[&crate::css::style_value::RetainedStyleValueData]| -> Option { let mut independent = true; for retained in children { independent = independent && value_is_computationally_independent(retained.data())?; @@ -1202,7 +1204,7 @@ fn value_is_computationally_independent(value: &StyleValueData) -> Option /// `data` must point at a valid StyleValueData. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_style_value_is_computationally_independent(data: *const c_void) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::StyleValueQueryEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::StyleValueQueryEntry); abort_on_panic(|| { value_is_computationally_independent(unsafe { &*(data as *const StyleValueData) }) .expect("computational independence requested for an unsupported value") @@ -1232,10 +1234,12 @@ fn compute_math_depth( StyleValueData::Integer { value } => computed(*value), // Calc values resolve to an integer in the calc core with no external context; // anything the core cannot resolve keeps the C++ caller's behavior. - StyleValueData::Calculated { .. } => match crate::calc::resolve_calculated_integer_without_context(value) { - Some(int) => computed(int), - None => NUMBER_UNHANDLED, - }, + StyleValueData::Calculated { .. } => { + match crate::css::calc::resolve_calculated_integer_without_context(value) { + Some(int) => computed(int), + None => NUMBER_UNHANDLED, + } + } // AD-HOC: the add() function form is resolved by the C++ caller. StyleValueData::Function { .. } => NUMBER_UNHANDLED, // - Otherwise, the computed value of math-depth of the element is the inherited one. @@ -1253,7 +1257,7 @@ pub unsafe extern "C" fn rust_compute_math_depth( inherited_math_depth: i32, inherited_math_style_is_compact: bool, ) -> FfiComputedNumber { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| { let value = unsafe { &*(absolutized_value as *const StyleValueData) }; compute_math_depth(value, inherited_math_depth, inherited_math_style_is_compact) @@ -1289,14 +1293,17 @@ fn compute_line_height(value: &StyleValueData, computed_font_size: CssPixels) -> // computed font size; anything the core cannot resolve keeps the C++ caller's // behavior. Any other value would be unreachable there. StyleValueData::Calculated { .. } => { - match crate::calc::resolve_calculated_line_height_without_context(value, computed_font_size.to_double()) { - Some(crate::calc::ResolvedLineHeightCalc::Px(px)) => FfiComputedLineHeight { + match crate::css::calc::resolve_calculated_line_height_without_context( + value, + computed_font_size.to_double(), + ) { + Some(crate::css::calc::ResolvedLineHeightCalc::Px(px)) => FfiComputedLineHeight { handled: true, unchanged: false, is_number: false, value: px, }, - Some(crate::calc::ResolvedLineHeightCalc::Number(number)) => FfiComputedLineHeight { + Some(crate::css::calc::ResolvedLineHeightCalc::Number(number)) => FfiComputedLineHeight { handled: true, unchanged: false, is_number: true, @@ -1319,7 +1326,7 @@ pub unsafe extern "C" fn rust_compute_line_height( absolutized_value: *const c_void, computed_font_size_raw: i32, ) -> FfiComputedLineHeight { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| { let value = unsafe { &*(absolutized_value as *const StyleValueData) }; compute_line_height(value, CssPixels::from_raw(computed_font_size_raw)) @@ -1389,7 +1396,7 @@ pub unsafe extern "C" fn rust_compute_border_or_outline_width( absolutized_value: *const c_void, device_pixels_per_css_pixel: f64, ) -> FfiComputedNumber { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| { let value = unsafe { &*(absolutized_value as *const StyleValueData) }; compute_border_or_outline_width(value, device_pixels_per_css_pixel) @@ -1438,7 +1445,7 @@ fn compute_corner_shape_parameter(value: &StyleValueData) -> FfiComputedNumber { /// `absolutized_value` must point at a valid StyleValueData. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_compute_corner_shape_parameter(absolutized_value: *const c_void) -> FfiComputedNumber { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| { let value = unsafe { &*(absolutized_value as *const StyleValueData) }; compute_corner_shape_parameter(value) @@ -1453,7 +1460,7 @@ pub unsafe extern "C" fn rust_compute_corner_shape_parameter(absolutized_value: /// `data` must point at a valid StyleValueData. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_font_family_is_monospace(data: *const c_void) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| { let StyleValueData::ValueList { values, .. } = (unsafe { &*(data as *const StyleValueData) }) else { return false; @@ -1479,7 +1486,7 @@ pub unsafe extern "C" fn rust_font_family_is_monospace(data: *const c_void) -> b #[unsafe(no_mangle)] #[allow(clippy::arc_with_non_send_sync)] pub unsafe extern "C" fn rust_compute_font_feature_settings(data: *const c_void) -> *const c_void { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| { let StyleValueData::ValueList { values, @@ -1505,7 +1512,7 @@ pub unsafe extern "C" fn rust_compute_font_feature_settings(data: *const c_void) .map(|index| values[index].clone_retained()) .collect(); Arc::into_raw(Arc::new(StyleValueData::ValueList { - values: crate::style_value::RetainedStyleValueDataList::from_retained_values(values), + values: crate::css::style_value::RetainedStyleValueDataList::from_retained_values(values), separator: *separator, collapsible: *collapsible, })) @@ -1536,7 +1543,7 @@ fn value_contains_percentage(value: &StyleValueData) -> bool { /// # Safety /// `value` must point at a valid StyleValueData. pub(crate) fn value_depends_on_inherited_info_for_property(value: &StyleValueData, property_id: u16) -> bool { - use crate::property_metadata::property_id as prop; + use crate::css::property_metadata::property_id as prop; match property_id { prop::FONT_WEIGHT => { matches!(value, StyleValueData::Keyword { keyword } if matches!(*keyword, keyword::BOLDER | keyword::LIGHTER)) @@ -1558,7 +1565,7 @@ pub unsafe extern "C" fn rust_value_depends_on_inherited_info_for_property( value: *const c_void, property_id: u16, ) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::StyleValueQueryEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::StyleValueQueryEntry); abort_on_panic(|| { value_depends_on_inherited_info_for_property(unsafe { &*(value as *const StyleValueData) }, property_id) }) @@ -1582,7 +1589,7 @@ pub struct FfiFontStyleComputation { /// `absolutized_value` must point at a valid StyleValueData. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_compute_font_style(absolutized_value: *const c_void) -> FfiFontStyleComputation { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| { if let StyleValueData::Keyword { keyword } = (unsafe { &*(absolutized_value as *const StyleValueData) }) && let Some(font_style_keyword) = keyword_to_font_style_keyword(*keyword) @@ -1606,7 +1613,7 @@ pub unsafe extern "C" fn rust_compute_font_style(absolutized_value: *const c_voi /// `absolutized_value` must point at a valid StyleValueData. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_compute_letter_or_word_spacing(absolutized_value: *const c_void) -> FfiComputedNumber { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| compute_letter_or_word_spacing_value(unsafe { &*(absolutized_value as *const StyleValueData) })) } @@ -1720,7 +1727,7 @@ fn compute_position_area(value: &StyleValueData) -> Option> } /// The per-longhand initial values as shared Rust value identities. -struct InitialValueTable(Vec); +struct InitialValueTable(Vec); // SAFETY: The entries reference immortal, immutable style values. unsafe impl Send for InitialValueTable {} @@ -1739,14 +1746,14 @@ pub unsafe extern "C" fn rust_style_metadata_set_initial_value_table(entries: *c let entries = unsafe { std::slice::from_raw_parts(entries, length) } .iter() .map(|entry| unsafe { - crate::style_value::RetainedStyleValueData::from_retained_pointer( - (*entry).cast::(), + crate::css::style_value::RetainedStyleValueData::from_retained_pointer( + (*entry).cast::(), ) }) .collect(); assert_eq!( length, - crate::property_metadata::NUMBER_OF_LONGHAND_PROPERTIES, + crate::css::property_metadata::NUMBER_OF_LONGHAND_PROPERTIES, "initial value table has one entry per longhand" ); assert!( @@ -1757,8 +1764,8 @@ pub unsafe extern "C" fn rust_style_metadata_set_initial_value_table(entries: *c } /// Returns the initial value data of a longhand property. -pub(crate) fn initial_value_data(property_id: u16) -> *const crate::style_value::StyleValueData { - use crate::property_metadata::FIRST_LONGHAND_PROPERTY_ID; +pub(crate) fn initial_value_data(property_id: u16) -> *const crate::css::style_value::StyleValueData { + use crate::css::property_metadata::FIRST_LONGHAND_PROPERTY_ID; let table = INITIAL_VALUE_TABLE.get().expect("initial value table not installed"); table.0[(property_id - FIRST_LONGHAND_PROPERTY_ID) as usize].pointer() } @@ -1835,7 +1842,7 @@ fn longhand_decision(value: Option<&StyleValueData>, property_id: u16) -> FfiLon // https://www.w3.org/TR/css-color-4/#resolving-other-colors // In the color property, the used value of currentcolor is the resolved inherited value. should_inherit |= - property_id == crate::property_metadata::property_id::COLOR && keyword == Some(keyword::CURRENTCOLOR); + property_id == crate::css::property_metadata::property_id::COLOR && keyword == Some(keyword::CURRENTCOLOR); FfiLonghandDecision { should_inherit, @@ -1873,7 +1880,7 @@ pub unsafe extern "C" fn rust_style_metadata_set_logical_alias_table(table: *con /// writing mode and direction, or returns the property itself when it is not /// a logical alias. pub fn map_logical_alias_to_physical(property_id: u16, writing_mode: u8, direction: u8) -> u16 { - use crate::property_metadata::FIRST_LONGHAND_PROPERTY_ID; + use crate::css::property_metadata::FIRST_LONGHAND_PROPERTY_ID; let Some(table) = LOGICAL_ALIAS_TABLE.get() else { return property_id; }; @@ -1912,7 +1919,7 @@ pub unsafe extern "C" fn rust_style_metadata_set_physical_to_logical_table(table /// Maps a physical longhand to its logical alias for the given writing mode /// and direction, or returns the property itself when it has no logical alias. pub fn map_physical_to_logical_alias(property_id: u16, writing_mode: u8, direction: u8) -> u16 { - use crate::property_metadata::FIRST_LONGHAND_PROPERTY_ID; + use crate::css::property_metadata::FIRST_LONGHAND_PROPERTY_ID; let Some(table) = PHYSICAL_TO_LOGICAL_TABLE.get() else { return property_id; }; @@ -2084,7 +2091,7 @@ enum ComputationContextKind { } fn computation_context_kind(property_id: u16) -> ComputationContextKind { - use crate::property_metadata::property_id as prop; + use crate::css::property_metadata::property_id as prop; match property_id { prop::COLOR_SCHEME | prop::FONT_FAMILY @@ -2135,7 +2142,7 @@ fn absolutization_is_identity(value: &StyleValueData) -> bool { /// plain absolutization. Mirrors the C++ switch until the dispatch moves /// into the core. fn property_has_dedicated_compute_rule(property_id: u16) -> bool { - use crate::property_metadata::property_id as prop; + use crate::css::property_metadata::property_id as prop; matches!( property_id, prop::ANIMATION_NAME @@ -2197,7 +2204,7 @@ pub struct FfiLonghandDriverResults { } fn table_row_maps(table: &std::sync::OnceLock>, property_id: u16) -> bool { - use crate::property_metadata::FIRST_LONGHAND_PROPERTY_ID; + use crate::css::property_metadata::FIRST_LONGHAND_PROPERTY_ID; let Some(table) = table.get() else { return false; }; @@ -2218,13 +2225,13 @@ fn value_is_initial_or_unset(value: *const c_void) -> bool { } fn set_longhand_bit(words: &mut [u64], property_id: u16) { - use crate::property_metadata::FIRST_LONGHAND_PROPERTY_ID; + use crate::css::property_metadata::FIRST_LONGHAND_PROPERTY_ID; let index = (property_id - FIRST_LONGHAND_PROPERTY_ID) as usize; words[index / 64] |= 1 << (index % 64); } fn clear_longhand_bit(words: &mut [u64], property_id: u16) { - use crate::property_metadata::FIRST_LONGHAND_PROPERTY_ID; + use crate::css::property_metadata::FIRST_LONGHAND_PROPERTY_ID; let index = (property_id - FIRST_LONGHAND_PROPERTY_ID) as usize; words[index / 64] &= !(1 << (index % 64)); } @@ -2258,9 +2265,9 @@ pub unsafe extern "C" fn rust_drive_property_computation( default_font_size_raw: i32, results: *mut FfiLonghandDriverResults, ) { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::LonghandDriverEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::LonghandDriverEntry); abort_on_panic(|| { - use crate::property_metadata::{ + use crate::css::property_metadata::{ FIRST_INHERITED_PROPERTY_ID, NUMBER_OF_LONGHAND_PROPERTIES, REQUIRES_COMPUTATION_ALWAYS, REQUIRES_COMPUTATION_CASCADED, REQUIRES_COMPUTATION_NON_INHERITED, property_id as prop, property_is_inherited, property_requires_computation_level, @@ -2298,7 +2305,7 @@ pub unsafe extern "C" fn rust_drive_property_computation( if pending_stores.is_empty() && *pending_effective_color_scheme < 0 { return; } - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::LonghandStoreBatchCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::LonghandStoreBatchCallback); // SAFETY: The entries and their values stay alive for the call; the callback // table outlives the drive. unsafe { @@ -2327,7 +2334,7 @@ pub unsafe extern "C" fn rust_drive_property_computation( if caches[kind].is_none() { // Building a context on the C++ side reads stored values, so request it // as part of the same ordered action batch that applies those values. - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::LonghandStoreBatchCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::LonghandStoreBatchCallback); let mut fetched = std::mem::MaybeUninit::::uninit(); // SAFETY: The callback applies the entries in order and then fills the // requested context before returning. @@ -2353,7 +2360,7 @@ pub unsafe extern "C" fn rust_drive_property_computation( /// The Rust-owned data of a parent snapshot entry. fn snapshot_entry_data(snapshot: &FfiParentSnapshot, property_id: u16) -> Option<&StyleValueData> { - use crate::property_metadata::FIRST_INHERITED_PROPERTY_ID; + use crate::css::property_metadata::FIRST_INHERITED_PROPERTY_ID; let index = (property_id - FIRST_INHERITED_PROPERTY_ID) as usize; assert!(index < snapshot.entry_count); // SAFETY: Snapshot entries are valid for the drive. @@ -2377,7 +2384,7 @@ pub unsafe extern "C" fn rust_drive_property_computation( let mut computed_float: Option = None; let mut computed_position: Option = None; - for &property_id in crate::property_metadata::property_computation_order() { + for &property_id in crate::css::property_metadata::property_computation_order() { let mut cascaded_property_id = property_id; let mut inherited_property_id = property_id; @@ -2426,10 +2433,10 @@ pub unsafe extern "C" fn rust_drive_property_computation( } // Keep the raw winning cascaded font-size for the monospace font-size // recascade (see recascade_font_size_if_needed on the C++ side). - if property_id == crate::property_metadata::property_id::FONT_SIZE { + if property_id == crate::css::property_metadata::property_id::FONT_SIZE { results.raw_cascaded_font_size_data = value_data; } - } else if property_id == crate::property_metadata::property_id::FONT_SIZE && has_new_font_size { + } else if property_id == crate::css::property_metadata::property_id::FONT_SIZE && has_new_font_size { // NOTE: The recascaded font-size has already been stored before the loop. continue; } @@ -2461,7 +2468,7 @@ pub unsafe extern "C" fn rust_drive_property_computation( assert!(index < snapshot.entry_count); unsafe { *snapshot.entries.add(index) } } else { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::LonghandParentValueFetchCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::LonghandParentValueFetchCallback); let mut parent_data = std::ptr::null(); let mut request = empty_longhand_batch_request(); request.property_id = inherited_property_id; @@ -2504,19 +2511,19 @@ pub unsafe extern "C" fn rust_drive_property_computation( // value must be kept for re-resolution when an ancestor changes. let value_data = unsafe { &*(value as *const StyleValueData) }; - if inherited_property_id == crate::property_metadata::property_id::BACKGROUND_IMAGE + if inherited_property_id == crate::css::property_metadata::property_id::BACKGROUND_IMAGE && let StyleValueData::ValueList { values, .. } = value_data { background_image_list_length = Some(values.as_slice().len()); } if let StyleValueData::Keyword { keyword } = value_data { - if property_id == crate::property_metadata::property_id::WRITING_MODE { + if property_id == crate::css::property_metadata::property_id::WRITING_MODE { computed_writing_mode = keyword_to_writing_mode(*keyword); - } else if property_id == crate::property_metadata::property_id::DIRECTION { + } else if property_id == crate::css::property_metadata::property_id::DIRECTION { computed_direction = keyword_to_direction(*keyword); } } - let inheritance_dependent = crate::style_value::value_depends_on_current_color(value_data) + let inheritance_dependent = crate::css::style_value::value_depends_on_current_color(value_data) || !value_is_computationally_independent(value_data) .expect("computational independence requested for an unsupported value") || value_depends_on_inherited_info_for_property(value_data, property_id); @@ -2574,7 +2581,7 @@ pub unsafe extern "C" fn rust_drive_property_computation( FontStyle(u8), StyleValue(Arc), } - use crate::property_metadata::property_id as prop; + use crate::css::property_metadata::property_id as prop; let synthesized_px_length = |absolutized: Option| { absolutized.map(|px| StyleValueData::Length { value: px, @@ -2853,7 +2860,7 @@ pub unsafe extern "C" fn rust_drive_property_computation( NativeValue::StyleValue(value) => (COMPUTED_KIND_STYLE_VALUE, 0.0, Arc::into_raw(value).cast()), NativeValue::Unchanged => (COMPUTED_KIND_UNCHANGED, 0.0, std::ptr::null()), NativeValue::Unsupported => { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::LonghandCppComputeFallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::LonghandCppComputeFallback); (COMPUTED_KIND_COMPUTE_IN_CPP, 0.0, std::ptr::null()) } }; @@ -3022,7 +3029,7 @@ pub unsafe extern "C" fn rust_drive_property_computation( clear_longhand_bit(important_words, prop::TEXT_ALIGN); clear_longhand_bit(inherited_words, prop::TEXT_ALIGN); } - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::LonghandStoreBatchCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::LonghandStoreBatchCallback); let mut input_line_height_metrics = std::mem::MaybeUninit::::uninit(); let mut request = empty_longhand_batch_request(); request.display_before = display_before; @@ -3098,7 +3105,7 @@ pub unsafe extern "C" fn rust_drive_property_computation( )); } if !adjustments.is_empty() { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::LonghandStoreBatchCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::LonghandStoreBatchCallback); unsafe { (callbacks.execute_computation_batch)( context, @@ -3118,8 +3125,8 @@ pub unsafe extern "C" fn rust_drive_property_computation( } fn property_affects_font_metrics(property_id: u16) -> bool { - property_id == crate::property_metadata::property_id::FONT_SIZE - || property_id == crate::property_metadata::property_id::LINE_HEIGHT + property_id == crate::css::property_metadata::property_id::FONT_SIZE + || property_id == crate::css::property_metadata::property_id::LINE_HEIGHT } /// Callback for each longhand produced by shorthand expansion. Values are @@ -3168,8 +3175,9 @@ pub(crate) fn expand_shorthands_with( // https://drafts.csswg.org/css-values-5/#pending-substitution-value // Ensure we keep the longhand around until it can be resolved. sink(property_id, data, has_style_sheet_context); - let retained_data = unsafe { crate::style_value::rust_style_value_retain(data.cast::()) }; - let pending_data = unsafe { crate::style_value::rust_style_value_create_pending_substitution(retained_data) }; + let retained_data = unsafe { crate::css::style_value::rust_style_value_retain(data.cast::()) }; + let pending_data = + unsafe { crate::css::style_value::rust_style_value_create_pending_substitution(retained_data) }; let pending = unsafe { RetainedStyleValueData::from_retained_pointer(pending_data) }; for &longhand in longhands_for_shorthand(property_id) { expand_shorthands_with(longhand, pending.pointer().cast(), has_style_sheet_context, sink); @@ -3206,7 +3214,7 @@ pub(crate) fn expand_shorthands_with( fn expand_shorthands(callbacks: &FfiShorthandExpansionCallbacks, property_id: u16, data: *const c_void) { let context = callbacks.context; expand_shorthands_with(property_id, data, false, &mut |longhand_id, longhand_data, _| { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::ShorthandSetLonghandCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::ShorthandSetLonghandCallback); unsafe { (callbacks.set_longhand_property)(context, longhand_id, longhand_data) }; }); } @@ -3223,7 +3231,7 @@ pub unsafe extern "C" fn rust_for_each_property_expanding_shorthands( property_id: u16, data: *const c_void, ) { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::ShorthandExpansionEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::ShorthandExpansionEntry); abort_on_panic(|| expand_shorthands(unsafe { &*callbacks }, property_id, data)); } @@ -3480,7 +3488,7 @@ fn transform_box_type(input: &FfiBoxTypeTransformationInput) -> FfiBoxTypeTransf pub unsafe extern "C" fn rust_transform_box_type( input: *const FfiBoxTypeTransformationInput, ) -> FfiBoxTypeTransformation { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| transform_box_type(unsafe { &*input })) } @@ -3528,7 +3536,7 @@ fn resolve_effective_overflow_keywords(overflow_x: u16, overflow_y: u16) -> FfiE #[unsafe(no_mangle)] pub extern "C" fn rust_resolve_effective_overflow_keywords(overflow_x: u16, overflow_y: u16) -> FfiEffectiveOverflow { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| resolve_effective_overflow_keywords(overflow_x, overflow_y)) } @@ -3668,7 +3676,7 @@ pub extern "C" fn rust_compute_text_align( parent_text_align: u16, parent_direction_is_ltr: bool, ) -> FfiTextAlignAdjustment { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| { compute_text_align_adjustment( text_align, @@ -3689,7 +3697,7 @@ pub unsafe extern "C" fn rust_compute_font_weight( absolutized_value: *const c_void, inherited_font_weight: f64, ) -> FfiComputedNumber { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::NestedPropertyComputeEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::NestedPropertyComputeEntry); abort_on_panic(|| { let value = unsafe { &*(absolutized_value as *const StyleValueData) }; compute_font_weight(value, inherited_font_weight) @@ -4096,7 +4104,7 @@ mod tests { #[test] fn longhand_decisions() { - use crate::property_metadata::{FIRST_INHERITED_PROPERTY_ID, LAST_LONGHAND_PROPERTY_ID}; + use crate::css::property_metadata::{FIRST_INHERITED_PROPERTY_ID, LAST_LONGHAND_PROPERTY_ID}; let inherited_id = FIRST_INHERITED_PROPERTY_ID; let reset_id = LAST_LONGHAND_PROPERTY_ID; @@ -4128,7 +4136,9 @@ mod tests { let currentcolor = StyleValueData::Keyword { keyword: keyword::CURRENTCOLOR, }; - assert!(longhand_decision(Some(¤tcolor), crate::property_metadata::property_id::COLOR).should_inherit); + assert!( + longhand_decision(Some(¤tcolor), crate::css::property_metadata::property_id::COLOR).should_inherit + ); assert!(!longhand_decision(Some(¤tcolor), reset_id).should_inherit); } diff --git a/Libraries/LibWeb/CSS/Rust/src/style_value.rs b/Libraries/LibWeb/Rust/src/css/style_value.rs similarity index 99% rename from Libraries/LibWeb/CSS/Rust/src/style_value.rs rename to Libraries/LibWeb/Rust/src/css/style_value.rs index 8e77e0981fc7e..a7c3b543454c2 100644 --- a/Libraries/LibWeb/CSS/Rust/src/style_value.rs +++ b/Libraries/LibWeb/Rust/src/css/style_value.rs @@ -166,7 +166,7 @@ impl RetainedUtf16FlyString { /// # Safety /// `raw` must be the raw representation of a live fly string. pub(crate) unsafe fn from_borrowed_raw(raw: usize) -> Self { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::StringRetainReleaseCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::StringRetainReleaseCallback); unsafe { ladybird_utf16_fly_string_ref(raw) }; Self { raw } } @@ -174,7 +174,7 @@ impl RetainedUtf16FlyString { impl Drop for RetainedUtf16FlyString { fn drop(&mut self) { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::StringRetainReleaseCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::StringRetainReleaseCallback); unsafe { ladybird_utf16_fly_string_unref(self.raw) }; } } @@ -278,7 +278,7 @@ impl PartialEq for RetainedString { impl Drop for RetainedString { fn drop(&mut self) { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::StringRetainReleaseCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::StringRetainReleaseCallback); unsafe { ladybird_string_unref(self.raw) }; if !self.bytes.is_null() { drop(unsafe { Box::from_raw(std::ptr::slice_from_raw_parts_mut(self.bytes, self.length)) }); @@ -331,7 +331,7 @@ impl PartialEq for RetainedReadableString { impl Drop for RetainedReadableString { fn drop(&mut self) { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::StringRetainReleaseCallback); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::StringRetainReleaseCallback); unsafe { ladybird_string_unref(self.raw) }; if !self.bytes.is_null() { drop(unsafe { Box::from_raw(std::ptr::slice_from_raw_parts_mut(self.bytes, self.length)) }); @@ -915,13 +915,13 @@ pub enum StyleValueData { /// A calc() or other math function: the retained calculation node tree root, its resolved /// numeric type, and the parse-time calculation context. Calculated { - rust_calculation: crate::calc::CalcNodeHandle, + rust_calculation: crate::css::calc::CalcNodeHandle, /// The resolve-against target, base-mapped at creation: whether one /// exists, whether it is the number type, and otherwise its base type /// index in the numeric type order. resolve_as_is_number: bool, resolve_as_base: u8, - resolved_type: crate::calc::FfiNumericType, + resolved_type: crate::css::calc::FfiNumericType, has_percentages_resolve_as: bool, percentages_resolve_as: u8, resolve_numbers_as_integers: bool, @@ -2505,8 +2505,8 @@ pub unsafe extern "C" fn rust_style_value_create_basic_shape( /// are copied. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_style_value_create_calculated( - rust_calculation: *const crate::calc::CalcNode, - resolved_type: crate::calc::FfiNumericType, + rust_calculation: *const crate::css::calc::CalcNode, + resolved_type: crate::css::calc::FfiNumericType, has_percentages_resolve_as: bool, resolve_as_is_number: bool, resolve_as_base: u8, @@ -2517,7 +2517,7 @@ pub unsafe extern "C" fn rust_style_value_create_calculated( ) -> *const StyleValueData { abort_on_panic(|| { Arc::into_raw(Arc::new(StyleValueData::Calculated { - rust_calculation: unsafe { crate::calc::CalcNodeHandle::from_raw(rust_calculation) }, + rust_calculation: unsafe { crate::css::calc::CalcNodeHandle::from_raw(rust_calculation) }, resolve_as_is_number, resolve_as_base, resolved_type, @@ -2550,7 +2550,7 @@ pub unsafe extern "C" fn rust_style_value_create_image( #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_style_value_release(value: *const StyleValueData) { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::StyleValueDestroyEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::StyleValueDestroyEntry); abort_on_panic(|| { if value.is_null() { return; @@ -2580,7 +2580,7 @@ pub(crate) fn value_depends_on_current_color(value: &StyleValueData) -> bool { let retained_data_depends = |retained: &RetainedStyleValueData| -> bool { value_depends_on_current_color(retained.data()) }; match value { - StyleValueData::Keyword { keyword } => *keyword == crate::style_compute::keyword::CURRENTCOLOR, + StyleValueData::Keyword { keyword } => *keyword == crate::css::style_compute::keyword::CURRENTCOLOR, StyleValueData::ColorFunction { origin_color, .. } => { origin_color.optional_data().is_some_and(value_depends_on_current_color) } @@ -2599,6 +2599,6 @@ pub(crate) fn value_depends_on_current_color(value: &StyleValueData) -> bool { /// `data` must point at a valid StyleValueData. #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_style_value_depends_on_current_color(data: *const c_void) -> bool { - crate::ffi_stats::bump(crate::ffi_stats::FfiOp::StyleValueQueryEntry); + crate::css::ffi_stats::bump(crate::css::ffi_stats::FfiOp::StyleValueQueryEntry); crate::abort_on_panic(|| value_depends_on_current_color(unsafe { &*(data as *const StyleValueData) })) } diff --git a/Libraries/LibWeb/CSS/Rust/src/transition.rs b/Libraries/LibWeb/Rust/src/css/transition.rs similarity index 83% rename from Libraries/LibWeb/CSS/Rust/src/transition.rs rename to Libraries/LibWeb/Rust/src/css/transition.rs index e64efdf2d8e89..5a3b7678bd55f 100644 --- a/Libraries/LibWeb/CSS/Rust/src/transition.rs +++ b/Libraries/LibWeb/Rust/src/css/transition.rs @@ -21,11 +21,11 @@ pub enum FfiTransitionActionKind { #[repr(C)] pub struct FfiTransitionPropertyInput { pub property_id: u16, - pub before_change_value: *const crate::style_value::StyleValueData, - pub after_change_value: *const crate::style_value::StyleValueData, - pub current_value: *const crate::style_value::StyleValueData, - pub existing_end_value: *const crate::style_value::StyleValueData, - pub reversing_adjusted_start_value: *const crate::style_value::StyleValueData, + pub before_change_value: *const crate::css::style_value::StyleValueData, + pub after_change_value: *const crate::css::style_value::StyleValueData, + pub current_value: *const crate::css::style_value::StyleValueData, + pub existing_end_value: *const crate::css::style_value::StyleValueData, + pub reversing_adjusted_start_value: *const crate::css::style_value::StyleValueData, pub has_matching_transition: bool, pub allow_discrete: bool, pub before_change_value_originates_from_current_color: bool, @@ -40,7 +40,7 @@ pub struct FfiTransitionPropertyInput { #[repr(C)] pub struct FfiTransitionInput { - pub context: crate::animation::FfiAnimationContext, + pub context: crate::css::animation::FfiAnimationContext, pub properties: *const FfiTransitionPropertyInput, pub property_count: usize, } @@ -55,18 +55,18 @@ pub struct FfiTransitionAction { } fn property_values_are_transitionable( - context: &crate::animation::FfiAnimationContext, + context: &crate::css::animation::FfiAnimationContext, property_id: u16, - old_value: *const crate::style_value::StyleValueData, - new_value: *const crate::style_value::StyleValueData, + old_value: *const crate::css::style_value::StyleValueData, + new_value: *const crate::css::style_value::StyleValueData, allow_discrete: bool, ) -> bool { - let animation_type = crate::property_metadata::property_animation_type(property_id); + let animation_type = crate::css::property_metadata::property_animation_type(property_id); // https://drafts.csswg.org/css-transitions/#transitionable // When comparing the before-change style and after-change style for a given property, the property values are transitionable if they have an animation type that is neither not animatable nor discrete. - if animation_type == crate::animation::ANIMATION_TYPE_NONE - || !allow_discrete && animation_type == crate::animation::ANIMATION_TYPE_DISCRETE + if animation_type == crate::css::animation::ANIMATION_TYPE_NONE + || !allow_discrete && animation_type == crate::css::animation::ANIMATION_TYPE_DISCRETE { return false; } @@ -74,7 +74,7 @@ fn property_values_are_transitionable( return true; } - let result = crate::animation::interpolate_value( + let result = crate::css::animation::interpolate_value( Some(context), property_id, unsafe { &*old_value }, @@ -83,18 +83,18 @@ fn property_values_are_transitionable( ); assert!(result.handled); if !result.value.is_null() { - unsafe { crate::style_value::rust_style_value_release(result.value) }; + unsafe { crate::css::style_value::rust_style_value_release(result.value) }; return true; } false } fn decide_transition( - context: &crate::animation::FfiAnimationContext, + context: &crate::css::animation::FfiAnimationContext, input: &FfiTransitionPropertyInput, ) -> FfiTransitionAction { - let values_equal = |first: *const crate::style_value::StyleValueData, - second: *const crate::style_value::StyleValueData| { + let values_equal = |first: *const crate::css::style_value::StyleValueData, + second: *const crate::css::style_value::StyleValueData| { assert!(!first.is_null()); assert!(!second.is_null()); let (first, second) = unsafe { (&*first, &*second) }; @@ -267,7 +267,7 @@ fn decide_transition( #[unsafe(no_mangle)] pub unsafe extern "C" fn rust_decide_transitions(input: *const FfiTransitionInput, actions: *mut FfiTransitionAction) { crate::abort_on_panic(|| { - crate::ffi_stats::rust_style_ffi_note_transition_decision(); + crate::css::ffi_stats::rust_style_ffi_note_transition_decision(); let input = unsafe { &*input }; let properties = if input.property_count == 0 { &[] @@ -284,19 +284,19 @@ pub unsafe extern "C" fn rust_decide_transitions(input: *const FfiTransitionInpu mod tests { use super::*; - fn animation_context() -> crate::animation::FfiAnimationContext { - let font_metrics = || crate::animation::FfiAnimationFontMetrics { + fn animation_context() -> crate::css::animation::FfiAnimationContext { + let font_metrics = || crate::css::animation::FfiAnimationFontMetrics { font_size: 0.0, x_height: 0.0, cap_height: 0.0, zero_advance: 0.0, line_height: 0.0, }; - crate::animation::FfiAnimationContext { + crate::css::animation::FfiAnimationContext { allow_discrete: false, current_color: std::ptr::null(), has_length_resolution_context: false, - length_resolution_context: crate::animation::FfiAnimationLengthResolutionContext { + length_resolution_context: crate::css::animation::FfiAnimationLengthResolutionContext { viewport_width: 0.0, viewport_height: 0.0, font_metrics: font_metrics(), @@ -311,18 +311,19 @@ mod tests { } fn by_computed_value_property() -> u16 { - (crate::property_metadata::FIRST_LONGHAND_PROPERTY_ID..=crate::property_metadata::LAST_LONGHAND_PROPERTY_ID) + (crate::css::property_metadata::FIRST_LONGHAND_PROPERTY_ID + ..=crate::css::property_metadata::LAST_LONGHAND_PROPERTY_ID) .find(|property_id| { - crate::property_metadata::property_animation_type(*property_id) - == crate::animation::ANIMATION_TYPE_BY_COMPUTED_VALUE + crate::css::property_metadata::property_animation_type(*property_id) + == crate::css::animation::ANIMATION_TYPE_BY_COMPUTED_VALUE }) .unwrap() } fn input( - before_change_value: &crate::style_value::StyleValueData, - after_change_value: &crate::style_value::StyleValueData, - current_value: &crate::style_value::StyleValueData, + before_change_value: &crate::css::style_value::StyleValueData, + after_change_value: &crate::css::style_value::StyleValueData, + current_value: &crate::css::style_value::StyleValueData, ) -> FfiTransitionPropertyInput { FfiTransitionPropertyInput { property_id: by_computed_value_property(), @@ -346,8 +347,8 @@ mod tests { #[test] fn starts_an_initial_transition() { - let before = crate::style_value::StyleValueData::Number { value: 0.0 }; - let after = crate::style_value::StyleValueData::Number { value: 1.0 }; + let before = crate::css::style_value::StyleValueData::Number { value: 0.0 }; + let after = crate::css::style_value::StyleValueData::Number { value: 1.0 }; assert_eq!( decide_transition(&animation_context(), &input(&before, &after, &before)).kind, FfiTransitionActionKind::Start @@ -367,11 +368,12 @@ mod tests { #[test] fn equal_nested_values_do_not_start_a_transition() { let nested_value = || { - let number = std::sync::Arc::into_raw(std::sync::Arc::new(crate::style_value::StyleValueData::Number { - value: 0.5, - })); - crate::style_value::StyleValueData::OpacityValue { - value: unsafe { crate::style_value::RetainedStyleValueData::from_retained_pointer(number) }, + let number = + std::sync::Arc::into_raw(std::sync::Arc::new(crate::css::style_value::StyleValueData::Number { + value: 0.5, + })); + crate::css::style_value::StyleValueData::OpacityValue { + value: unsafe { crate::css::style_value::RetainedStyleValueData::from_retained_pointer(number) }, } }; let before = nested_value(); @@ -384,8 +386,8 @@ mod tests { #[test] fn current_color_origins_are_equivalent() { - let before = crate::style_value::StyleValueData::Number { value: 0.0 }; - let after = crate::style_value::StyleValueData::Number { value: 1.0 }; + let before = crate::css::style_value::StyleValueData::Number { value: 0.0 }; + let after = crate::css::style_value::StyleValueData::Number { value: 1.0 }; let mut input = input(&before, &after, &before); input.before_change_value_originates_from_current_color = true; input.after_change_value_originates_from_current_color = true; @@ -397,8 +399,8 @@ mod tests { #[test] fn removes_a_completed_transition_before_replacement() { - let before = crate::style_value::StyleValueData::Number { value: 0.0 }; - let after = crate::style_value::StyleValueData::Number { value: 1.0 }; + let before = crate::css::style_value::StyleValueData::Number { value: 0.0 }; + let after = crate::css::style_value::StyleValueData::Number { value: 1.0 }; let mut input = input(&before, &after, &before); input.has_completed_transition = true; input.existing_end_value = &raw const before; @@ -410,9 +412,9 @@ mod tests { #[test] fn adjusts_a_reversing_transition() { - let before = crate::style_value::StyleValueData::Number { value: 0.0 }; - let after = crate::style_value::StyleValueData::Number { value: 1.0 }; - let current = crate::style_value::StyleValueData::Number { value: 0.5 }; + let before = crate::css::style_value::StyleValueData::Number { value: 0.0 }; + let after = crate::css::style_value::StyleValueData::Number { value: 1.0 }; + let current = crate::css::style_value::StyleValueData::Number { value: 0.5 }; let mut input = input(&before, &after, ¤t); input.has_running_transition = true; input.existing_end_value = &raw const before; diff --git a/Libraries/LibWeb/Layout/Rust/src/layout_node_arena.rs b/Libraries/LibWeb/Rust/src/layout/layout_node_arena.rs similarity index 99% rename from Libraries/LibWeb/Layout/Rust/src/layout_node_arena.rs rename to Libraries/LibWeb/Rust/src/layout/layout_node_arena.rs index 9348271af434a..857a866225553 100644 --- a/Libraries/LibWeb/Layout/Rust/src/layout_node_arena.rs +++ b/Libraries/LibWeb/Rust/src/layout/layout_node_arena.rs @@ -5,8 +5,8 @@ */ use crate::abort_on_panic; -use crate::node_data::NodeData; -use crate::node_data::NodeSlotId; +use crate::layout::node_data::NodeData; +use crate::layout::node_data::NodeSlotId; use std::ffi::c_void; use std::thread; diff --git a/Libraries/LibWeb/Rust/src/layout/mod.rs b/Libraries/LibWeb/Rust/src/layout/mod.rs new file mode 100644 index 0000000000000..0ec5b6a399857 --- /dev/null +++ b/Libraries/LibWeb/Rust/src/layout/mod.rs @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2026-present, the Ladybird developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +mod layout_node_arena; +pub mod node_data; +mod tree_builder; diff --git a/Libraries/LibWeb/Layout/Rust/src/node_data.rs b/Libraries/LibWeb/Rust/src/layout/node_data.rs similarity index 100% rename from Libraries/LibWeb/Layout/Rust/src/node_data.rs rename to Libraries/LibWeb/Rust/src/layout/node_data.rs diff --git a/Libraries/LibWeb/Layout/Rust/src/tree_builder.rs b/Libraries/LibWeb/Rust/src/layout/tree_builder.rs similarity index 99% rename from Libraries/LibWeb/Layout/Rust/src/tree_builder.rs rename to Libraries/LibWeb/Rust/src/layout/tree_builder.rs index 6601916b20dff..6f2931c622553 100644 --- a/Libraries/LibWeb/Layout/Rust/src/tree_builder.rs +++ b/Libraries/LibWeb/Rust/src/layout/tree_builder.rs @@ -5,8 +5,8 @@ */ use crate::abort_on_panic; -use crate::layout_node_arena::LayoutNodeArena; -use crate::node_data::{ +use crate::layout::layout_node_arena::LayoutNodeArena; +use crate::layout::node_data::{ FfiTableDisplay, GENERATED_FOR_MARKER, NodeData, NodeDisplayFlag, NodeFlag, NodeKind, NodeSlotId, }; use std::ffi::c_void; @@ -3146,7 +3146,7 @@ mod tests { principal_box_generation_decision, principal_box_placement_decision, principal_node_entry_decision, pseudo_element_decision, }; - use crate::node_data::NodeSlotId; + use crate::layout::node_data::NodeSlotId; use std::ffi::c_void; unsafe extern "C" fn text_length(context: *mut c_void) -> usize { diff --git a/Libraries/LibWeb/Rust/src/lib.rs b/Libraries/LibWeb/Rust/src/lib.rs index 47d52d6a3d5a4..d7ad031988377 100644 --- a/Libraries/LibWeb/Rust/src/lib.rs +++ b/Libraries/LibWeb/Rust/src/lib.rs @@ -4,11 +4,17 @@ * SPDX-License-Identifier: BSD-2-Clause */ +// Unconditional in every build flavor: the HTML tokenizer transfers allocation +// ownership across the FFI boundary, so the crate-global allocator must stay +// the Ladybird allocator for C++-side frees to stay balanced. #[path = "../../../RustAllocator.rs"] mod rust_allocator; mod encoding_detection; +pub mod css; +pub mod layout; + pub use libweb_html_tokenizer as html_tokenizer; use std::panic::AssertUnwindSafe;