diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000000..aafc8d0e84 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,51 @@ +name: CI + +on: + push: + branches: ["main"] + pull_request: + workflow_dispatch: + merge_group: + types: [checks_requested] + + +jobs: + linux-debug: + name: Linux (Debug) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + - name: Run Tests + run: cargo build --features servo + env: + RUST_BACKTRACE: 1 + + linux-release: + name: Linux (Release) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + - name: Run Tests + run: cargo build --release --features servo + env: + RUST_BACKTRACE: 1 + + build-result: + name: Result + runs-on: ubuntu-latest + if: ${{ always() }} + needs: + - linux-debug + - linux-release + steps: + - name: Success + if: ${{ !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }} + run: exit 0 + - name: Failure + if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} + run: exit 1 + diff --git a/.github/workflows/mirror-to-release-branch.yml b/.github/workflows/mirror-to-release-branch.yml new file mode 100644 index 0000000000..c8593195da --- /dev/null +++ b/.github/workflows/mirror-to-release-branch.yml @@ -0,0 +1,26 @@ +name: 🪞 Mirror `main` +on: + push: + branches: + - main + +jobs: + mirror: + name: Mirror + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Get branch name + id: branch-name + run: | + first_commit=$(git log --pretty=\%H --grep='Servo initial downstream commit') + upstream_base="$first_commit~" + echo BRANCH_NAME=$(git log -n1 --pretty='%as' $upstream_base) >> $GITHUB_OUTPUT + - uses: google/mirror-branch-action@v1.0 + name: Mirror to ${{ steps.branch-name.outputs.BRANCH_NAME }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + source: main + dest: ${{ steps.branch-name.outputs.BRANCH_NAME }} diff --git a/.github/workflows/sync-upstream.yml b/.github/workflows/sync-upstream.yml new file mode 100644 index 0000000000..992fe6d2ce --- /dev/null +++ b/.github/workflows/sync-upstream.yml @@ -0,0 +1,23 @@ +name: Sync upstream with mozilla-central + +on: + schedule: + - cron: '0 13 * * *' + workflow_dispatch: + +jobs: + sync: + name: Sync + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 1 + - uses: actions/cache@v3 + with: + path: _cache/upstream + key: upstream + - run: | + ./sync.sh _filtered + git fetch -f --progress ./_filtered master:upstream + git push -fu --progress origin upstream diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..fc3c2f9b3c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/_cache/ +/_filtered/ +/target/ +/style/properties/__pycache__/ +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000..d2547c0d06 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,18 @@ +[workspace] +resolver = "2" +members = [ + "stylo_atoms", + "stylo_dom", + "malloc_size_of", + "rustfmt.toml", + "selectors", + "servo_arc", + "style", + "style_derive", + "stylo_config", + "stylo_static_prefs", + "style_traits", + "to_shmem", + "to_shmem_derive", +] +default-members = ["style"] diff --git a/README.md b/README.md new file mode 100644 index 0000000000..83b951db55 --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +Stylo +===== + +This repo contains Servo’s downstream fork of [Stylo](https://searchfox.org/mozilla-central/source/servo). + +The branches are as follows: + +- [`upstream`](https://github.com/servo/style/tree/upstream) has upstream mozilla-central filtered to the paths we care about ([style.paths](style.paths)), but is otherwise unmodified +- [`main`](https://github.com/servo/style/tree/ci) has our downstream patches, plus the scripts and workflows for syncing with mozilla-central, to be rebased onto `upstream` + +## Building Servo against your local Stylo + +Assuming your local `servo` and `stylo` directories are siblings, you can build `servo` against `stylo` by adding the following to `servo/Cargo.toml`: + +```toml +[patch."https://github.com/servo/stylo"] +selectors = { path = "../stylo/selectors" } +servo_arc = { path = "../stylo/servo_arc" } +stylo_atoms = { path = "../stylo/stylo_atoms" } +stylo = { path = "../stylo/style" } +stylo_config = { path = "../stylo/stylo_config" } +stylo_dom = { path = "../stylo/stylo_dom" } +stylo_malloc_size_of = { path = "../stylo/malloc_size_of" } +stylo_traits = { path = "../stylo/style_traits" } +``` + +## Syncing `upstream` with mozilla-central + +Start by generating a filtered copy of mozilla-central. This will cache the raw mozilla-central in `_cache/upstream`, storing the result in `_filtered`: + +```sh +$ ./sync.sh _filtered +``` + +If `_filtered` already exists, you will need to delete it and try again: + +```sh +$ rm -Rf _filtered +``` + +Now overwrite our `upstream` with those commits and push: + +```sh +$ git fetch -f --progress ./_filtered master:upstream +$ git push -fu --progress origin upstream +``` + +## Rebasing `main` onto `upstream` + +Start by fetching `upstream` into your local repo: + +```sh +$ git fetch -f origin upstream:upstream +``` + +In general, the filtering process is deterministic, yielding the same commit hashes each time, so we can rebase normally: + +```sh +$ git rebase upstream +``` + +But if the filtering config changes or Mozilla moves to GitHub, the commit hashes on `upstream` may change. In this case, we need to tell git where the old upstream ends and our own commits start (notice the `~`): + +```sh +$ git log --pretty=\%H --grep='Servo initial downstream commit' +e62d7f0090941496e392e1dc91df103a38e3f488 + +$ git rebase --onto upstream e62d7f0090941496e392e1dc91df103a38e3f488~ +Successfully rebased and updated refs/heads/main. +``` + +`start-rebase.sh` takes care of this automatically, but you should still use `git rebase` for subsequent steps like `--continue` and `--abort`: + +```sh +$ ./start-rebase.sh upstream +$ ./start-rebase.sh upstream -i # interactive +$ git rebase --continue # not ./start-rebase.sh --continue +$ git rebase --abort # not ./start-rebase.sh --abort +``` + +Or if we aren’t ready to rebase onto the tip of upstream: + +```sh +$ ./start-rebase.sh upstream~10 -i +``` diff --git a/commit-from-merge.sh b/commit-from-merge.sh new file mode 100755 index 0000000000..94aa606f02 --- /dev/null +++ b/commit-from-merge.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Usage: commit-from-merge.sh [extra git-commit(1) arguments ...] +# Given a merge commit made by bors, runs git-commit(1) with your local changes +# while borrowing the author name/email from the right-hand parent of the merge, +# and the author date from the committer date of the merge. +set -eu + +lookup_repo=$1; shift +merge_commit=$1; shift +author_name_email=$(git -C "$lookup_repo" log -n1 --pretty='%aN <%aE>' "$merge_commit"\^2) +committer_date=$(git -C "$lookup_repo" log -n1 --pretty='%cd' "$merge_commit") + +set -- git commit --author="$author_name_email" --date="$committer_date" "$@" +echo "$@" +"$@" diff --git a/commit-from-squashed.sh b/commit-from-squashed.sh new file mode 100755 index 0000000000..004e0f7840 --- /dev/null +++ b/commit-from-squashed.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# Usage: commit-from-squashed.sh [extra git-commit(1) arguments ...] +# Given a squashed commit made by the GitHub merge queue, runs git-commit(1) with your local changes +# while borrowing our author name/email from that commit, our author date from its committer date, +# and our commit message from that commit. +set -eu + +squashed_commit=$1; shift +committer_date=$(git log -n1 --pretty='%cd' "$squashed_commit") + +# -c is equivalent to --author=$(...'%aN <%aE>') -m $(...'%B'), but allows editing +set -- git commit -c "$squashed_commit" --date="$committer_date" "$@" +echo "$@" +"$@" diff --git a/malloc_size_of/Cargo.toml b/malloc_size_of/Cargo.toml index eefd6cd89a..f8a512cc01 100644 --- a/malloc_size_of/Cargo.toml +++ b/malloc_size_of/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "malloc_size_of" +name = "stylo_malloc_size_of" version = "0.0.1" authors = ["The Servo Project Developers"] license = "MIT OR Apache-2.0" @@ -15,12 +15,12 @@ servo = ["string_cache"] [dependencies] app_units = "0.7" -cssparser = "0.34" +cssparser = "0.35" euclid = "0.22" selectors = { path = "../selectors" } servo_arc = { path = "../servo_arc" } smallbitvec = "2.3.0" -smallvec = "1.0" +smallvec = "1.13" string_cache = { version = "0.8", optional = true } -thin-vec = { version = "0.2.1" } +thin-vec = { version = "0.2.13" } void = "1.0.2" diff --git a/selectors/Cargo.toml b/selectors/Cargo.toml index 4e495a6c6b..86da918e36 100644 --- a/selectors/Cargo.toml +++ b/selectors/Cargo.toml @@ -21,12 +21,12 @@ to_shmem = ["dep:to_shmem", "dep:to_shmem_derive"] [dependencies] bitflags = "2" -cssparser = "0.34" +cssparser = "0.35" derive_more = { version = "0.99", default-features = false, features = ["add", "add_assign"] } -fxhash = "0.2" log = "0.4" phf = "0.11" precomputed-hash = "0.1" +rustc-hash = "2.1.1" servo_arc = { version = "0.4", path = "../servo_arc" } smallvec = "1.0" to_shmem = { version = "0.1", path = "../to_shmem", features = ["servo_arc"], optional = true } diff --git a/selectors/bloom.rs b/selectors/bloom.rs index 98461d1ba2..ab7c2cf581 100644 --- a/selectors/bloom.rs +++ b/selectors/bloom.rs @@ -283,10 +283,11 @@ fn hash2(hash: u32) -> u32 { #[test] fn create_and_insert_some_stuff() { - use fxhash::FxHasher; use std::hash::{Hash, Hasher}; use std::mem::transmute; + use rustc_hash::FxHasher; + fn hash_as_str(i: usize) -> u32 { let mut hasher = FxHasher::default(); let s = i.to_string(); diff --git a/selectors/nth_index_cache.rs b/selectors/nth_index_cache.rs index b4b41578d0..bd593ac50b 100644 --- a/selectors/nth_index_cache.rs +++ b/selectors/nth_index_cache.rs @@ -5,7 +5,7 @@ use std::hash::Hash; use crate::{parser::Selector, tree::OpaqueElement, SelectorImpl}; -use fxhash::FxHashMap; +use rustc_hash::FxHashMap; /// A cache to speed up matching of nth-index-like selectors. /// diff --git a/selectors/relative_selector/cache.rs b/selectors/relative_selector/cache.rs index d7681aa3a4..207ce888e4 100644 --- a/selectors/relative_selector/cache.rs +++ b/selectors/relative_selector/cache.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use fxhash::FxHashMap; +use rustc_hash::FxHashMap; /// Relative selector cache. This is useful for following cases. /// First case is non-subject relative selector: Imagine `.anchor:has(<..>) ~ .foo`, with DOM /// `.anchor + .foo + .. + .foo`. Each match on `.foo` triggers `:has()` traversal that diff --git a/selectors/relative_selector/filter.rs b/selectors/relative_selector/filter.rs index 3c3eb7d2fa..f29b750e85 100644 --- a/selectors/relative_selector/filter.rs +++ b/selectors/relative_selector/filter.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /// Bloom filter for relative selectors. -use fxhash::FxHashMap; +use rustc_hash::FxHashMap; use crate::bloom::BloomFilter; use crate::context::QuirksMode; diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000000..2c96e200aa --- /dev/null +++ b/shell.nix @@ -0,0 +1,6 @@ +with import (builtins.fetchTarball { + url = "https://github.com/NixOS/nixpkgs/archive/46ae0210ce163b3cba6c7da08840c1d63de9c701.tar.gz"; +}) {}; +stdenv.mkDerivation rec { + name = "style-sync-shell"; +} diff --git a/start-rebase.sh b/start-rebase.sh new file mode 100755 index 0000000000..fe417f7f08 --- /dev/null +++ b/start-rebase.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# Usage: start-rebase.sh [extra git-rebase(1) arguments ...] +# Equivalent to git rebase --onto . +set -eu + +new_base=$1; shift +first_commit=$(git log --pretty=\%H --grep='Servo initial downstream commit') +old_base=$first_commit~ + +git rebase --onto "$new_base" "$old_base" "$@" diff --git a/style.paths b/style.paths new file mode 100644 index 0000000000..d1d2d02638 --- /dev/null +++ b/style.paths @@ -0,0 +1,8 @@ +# Filters and renames use git-filter-repo(1) --paths-from-file: +# https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html#_filtering_based_on_many_paths + +servo/components/ +servo/rustfmt.toml + +regex:servo/components/(.+)==>\1 +servo/rustfmt.toml==>rustfmt.toml diff --git a/style/Cargo.toml b/style/Cargo.toml index b098f413ae..0d58da0d24 100644 --- a/style/Cargo.toml +++ b/style/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "style" +name = "stylo" version = "0.0.1" authors = ["The Servo Project Developers"] license = "MPL-2.0" @@ -18,6 +18,7 @@ path = "lib.rs" doctest = false [features] +default = ["servo"] gecko = [ "bindgen", "malloc_size_of/gecko", @@ -31,15 +32,15 @@ gecko = [ "to_shmem/gecko", ] servo = [ - "arrayvec/use_union", "cssparser/serde", "encoding_rs", "malloc_size_of/servo", "markup5ever", + "mime", "serde", "servo_arc/servo", "stylo_atoms", - "servo_config", + "style_config", "string_cache", "style_traits/servo", "url", @@ -48,31 +49,31 @@ servo = [ ] gecko_debug = [] gecko_refcount_logging = [] +nsstring = [] [dependencies] -app_units = "0.7" +app_units = "0.7.8" arrayvec = "0.7" atomic_refcell = "0.1" bitflags = "2" byteorder = "1.0" -cssparser = "0.34" +cssparser = "0.35" derive_more = { version = "0.99", default-features = false, features = ["add", "add_assign", "deref", "deref_mut", "from"] } -dom = { path = "../../../dom/base/rust" } +dom = { path = "../stylo_dom", version = "0.1", package = "stylo_dom" } new_debug_unreachable = "1.0" encoding_rs = {version = "0.8", optional = true} euclid = "0.22" -fxhash = "0.2" icu_segmenter = { version = "1.5", default-features = false, features = ["auto", "compiled_data"] } indexmap = {version = "2", features = ["std"]} itertools = "0.10" itoa = "1.0" lazy_static = "1" log = "0.4" -malloc_size_of = { path = "../malloc_size_of" } -malloc_size_of_derive = { path = "../../../xpcom/rust/malloc_size_of_derive" } -markup5ever = { version = "0.12", optional = true } +malloc_size_of = { path = "../malloc_size_of", package = "stylo_malloc_size_of" } +malloc_size_of_derive = "0.1" +markup5ever = { version = "0.15", optional = true } matches = "0.1" -nsstring = {path = "../../../xpcom/rust/nsstring/", optional = true} +mime = { version = "0.3.13", optional = true } num_cpus = {version = "1.1.0"} num-integer = "0.1" num-traits = "0.2" @@ -81,25 +82,25 @@ parking_lot = "0.12" precomputed-hash = "0.1.1" rayon = "1" rayon-core = "1" +rustc-hash = "2.1.1" selectors = { path = "../selectors" } serde = {version = "1.0", optional = true, features = ["derive"]} servo_arc = { path = "../servo_arc" } -stylo_atoms = {path = "../atoms", optional = true} -servo_config = {path = "../config", optional = true} +stylo_atoms = {path = "../stylo_atoms", optional = true} smallbitvec = "2.3.0" smallvec = "1.0" static_assertions = "1.1" -static_prefs = { path = "../../../modules/libpref/init/static_prefs" } +static_prefs = { version = "0.1", path = "../stylo_static_prefs", package = "stylo_static_prefs" } string_cache = { version = "0.8", optional = true } -style_derive = {path = "../style_derive"} -style_traits = {path = "../style_traits"} +style_config = { version = "0.1", path = "../stylo_config", package = "stylo_config", optional = true } +style_derive = { path = "../style_derive", package = "stylo_derive" } +style_traits = { path = "../style_traits", package = "stylo_traits" } to_shmem = {path = "../to_shmem"} to_shmem_derive = {path = "../to_shmem_derive"} -thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } +thin-vec = "0.2.1" uluru = "3.0" unicode-bidi = { version = "0.3", default-features = false } void = "1.0.2" -gecko-profiler = { path = "../../../tools/profiler/rust-api" } url = { version = "2.5", optional = true, features = ["serde"] } [build-dependencies] diff --git a/style/animation.rs b/style/animation.rs index c90e2327c5..c4ac973ddd 100644 --- a/style/animation.rs +++ b/style/animation.rs @@ -29,8 +29,8 @@ use crate::values::computed::{Time, TimingFunction}; use crate::values::generics::easing::BeforeFlag; use crate::values::specified::TransitionBehavior; use crate::Atom; -use fxhash::FxHashMap; use parking_lot::RwLock; +use rustc_hash::FxHashMap; use servo_arc::Arc; use std::fmt; diff --git a/style/build.rs b/style/build.rs index 4b27edbe2c..eacb9b3fc9 100644 --- a/style/build.rs +++ b/style/build.rs @@ -21,7 +21,7 @@ mod build_gecko { lazy_static! { pub static ref PYTHON: String = env::var("PYTHON3").ok().unwrap_or_else(|| { let candidates = if cfg!(windows) { - ["python3.exe"] + ["python.exe"] } else { ["python3"] }; diff --git a/style/context.rs b/style/context.rs index e151967ca4..6cf2de3d77 100644 --- a/style/context.rs +++ b/style/context.rs @@ -29,7 +29,7 @@ use app_units::Au; use euclid::default::Size2D; use euclid::Scale; #[cfg(feature = "servo")] -use fxhash::FxHashMap; +use rustc_hash::FxHashMap; use selectors::context::SelectorCaches; #[cfg(feature = "gecko")] use servo_arc::Arc; @@ -450,7 +450,7 @@ impl SequentialTask { /// Executes this task. pub fn execute(self) { use self::SequentialTask::*; - debug_assert_eq!(thread_state::get(), ThreadState::LAYOUT); + debug_assert!(thread_state::get().contains(ThreadState::LAYOUT)); match self { Unused(_) => unreachable!(), #[cfg(feature = "gecko")] @@ -511,7 +511,7 @@ where E: TElement, { fn drop(&mut self) { - debug_assert_eq!(thread_state::get(), ThreadState::LAYOUT); + debug_assert!(thread_state::get().contains(ThreadState::LAYOUT)); for task in self.0.drain(..) { task.execute() } diff --git a/style/gecko/wrapper.rs b/style/gecko/wrapper.rs index a836384ce1..1de513ce22 100644 --- a/style/gecko/wrapper.rs +++ b/style/gecko/wrapper.rs @@ -71,7 +71,7 @@ use app_units::Au; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use dom::{DocumentState, ElementState}; use euclid::default::Size2D; -use fxhash::FxHashMap; +use rustc_hash::FxHashMap; use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint}; use selectors::bloom::{BloomFilter, BLOOM_HASH_MASK}; use selectors::matching::VisitedHandlingMode; diff --git a/style/invalidation/element/relative_selector.rs b/style/invalidation/element/relative_selector.rs index f0873e06b6..7ce1bd2f41 100644 --- a/style/invalidation/element/relative_selector.rs +++ b/style/invalidation/element/relative_selector.rs @@ -26,7 +26,7 @@ use crate::invalidation::element::state_and_attributes::{ use crate::selector_parser::SnapshotMap as ServoElementSnapshotTable; use crate::stylist::{CascadeData, Stylist}; use dom::ElementState; -use fxhash::FxHashMap; +use rustc_hash::FxHashMap; use selectors::matching::{ matches_selector, ElementSelectorFlags, IncludeStartingStyle, MatchingContext, MatchingForInvalidation, MatchingMode, NeedsSelectorFlags, QuirksMode, SelectorCaches, diff --git a/style/invalidation/media_queries.rs b/style/invalidation/media_queries.rs index 6928b29d3d..b66fc0defb 100644 --- a/style/invalidation/media_queries.rs +++ b/style/invalidation/media_queries.rs @@ -9,7 +9,7 @@ use crate::media_queries::Device; use crate::shared_lock::SharedRwLockReadGuard; use crate::stylesheets::{DocumentRule, ImportRule, MediaRule}; use crate::stylesheets::{NestedRuleIterationCondition, StylesheetContents, SupportsRule}; -use fxhash::FxHashSet; +use rustc_hash::FxHashSet; /// A key for a given media query result. /// diff --git a/style/properties/Mako-1.1.2-py2.py3-none-any.whl b/style/properties/Mako-1.1.2-py2.py3-none-any.whl new file mode 100644 index 0000000000..9593025a47 Binary files /dev/null and b/style/properties/Mako-1.1.2-py2.py3-none-any.whl differ diff --git a/style/properties/build.py b/style/properties/build.py index 7e9224a1ae..1a92544bfd 100644 --- a/style/properties/build.py +++ b/style/properties/build.py @@ -8,6 +8,7 @@ import sys BASE = os.path.dirname(__file__.replace("\\", "/")) +sys.path.insert(0, os.path.join(BASE, "Mako-1.1.2-py2.py3-none-any.whl")) sys.path.insert(0, BASE) # For importing `data.py` from mako import exceptions diff --git a/style/properties/cascade.rs b/style/properties/cascade.rs index 6e3457d163..dff3581ef6 100644 --- a/style/properties/cascade.rs +++ b/style/properties/cascade.rs @@ -30,7 +30,7 @@ use crate::stylist::Stylist; #[cfg(feature = "gecko")] use crate::values::specified::length::FontBaseSize; use crate::values::{computed, specified}; -use fxhash::FxHashMap; +use rustc_hash::FxHashMap; use servo_arc::Arc; use smallvec::SmallVec; use std::borrow::Cow; @@ -1055,6 +1055,7 @@ impl<'b> Cascade<'b> { builder.add_flags(ComputedValueFlags::HAS_AUTHOR_SPECIFIED_WORD_SPACING); } + #[cfg(feature = "gecko")] if self .author_specified .contains(LonghandId::FontSynthesisWeight) @@ -1062,6 +1063,7 @@ impl<'b> Cascade<'b> { builder.add_flags(ComputedValueFlags::HAS_AUTHOR_SPECIFIED_FONT_SYNTHESIS_WEIGHT); } + #[cfg(feature = "gecko")] if self .author_specified .contains(LonghandId::FontSynthesisStyle) @@ -1197,7 +1199,6 @@ impl<'b> Cascade<'b> { } /// Some keyword sizes depend on the font family and language. - #[cfg(feature = "gecko")] fn recompute_keyword_font_size_if_needed(&self, context: &mut computed::Context) { use crate::values::computed::ToComputedValue; @@ -1216,6 +1217,7 @@ impl<'b> Cascade<'b> { }, }; + #[cfg(feature = "gecko")] if font.mScriptUnconstrainedSize == new_size.computed_size { return; } diff --git a/style/properties/helpers/animated_properties.mako.rs b/style/properties/helpers/animated_properties.mako.rs index 513a198a6a..9c1d9c925d 100644 --- a/style/properties/helpers/animated_properties.mako.rs +++ b/style/properties/helpers/animated_properties.mako.rs @@ -23,7 +23,7 @@ use crate::properties::{ }; use std::ptr; use std::mem; -use fxhash::FxHashMap; +use rustc_hash::FxHashMap; use super::ComputedValues; use crate::properties::OwnedPropertyDeclarationId; use crate::values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; diff --git a/style/properties/longhands/counters.mako.rs b/style/properties/longhands/counters.mako.rs index 4ced7e0faa..85e479939e 100644 --- a/style/properties/longhands/counters.mako.rs +++ b/style/properties/longhands/counters.mako.rs @@ -20,7 +20,7 @@ ${helpers.predefined_type( "counter-increment", "CounterIncrement", engines="gecko servo", - servo_pref="layout.layout.unimplemented", + servo_pref="layout.unimplemented", initial_value="Default::default()", animation_type="discrete", spec="https://drafts.csswg.org/css-lists/#propdef-counter-increment", @@ -32,7 +32,7 @@ ${helpers.predefined_type( "counter-reset", "CounterReset", engines="gecko servo", - servo_pref="layout.layout.unimplemented", + servo_pref="layout.unimplemented", initial_value="Default::default()", animation_type="discrete", spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset", diff --git a/style/properties/longhands/text.mako.rs b/style/properties/longhands/text.mako.rs index 56290ac735..a0054b77c4 100644 --- a/style/properties/longhands/text.mako.rs +++ b/style/properties/longhands/text.mako.rs @@ -9,7 +9,7 @@ ${helpers.predefined_type( "TextOverflow", "computed::TextOverflow::get_initial_value()", engines="gecko servo", - servo_pref="layout.layout.unimplemented", + servo_pref="layout.unimplemented", animation_type="discrete", boxed=True, spec="https://drafts.csswg.org/css-ui/#propdef-text-overflow", diff --git a/style/properties/mod.rs b/style/properties/mod.rs index 2cc7f89ba7..2fe6665faf 100644 --- a/style/properties/mod.rs +++ b/style/properties/mod.rs @@ -31,7 +31,7 @@ use crate::stylist::Stylist; use crate::values::{computed, serialize_atom_name}; use arrayvec::{ArrayVec, Drain as ArrayVecDrain}; use cssparser::{Parser, ParserInput}; -use fxhash::FxHashMap; +use rustc_hash::FxHashMap; use servo_arc::Arc; use std::{ borrow::Cow, diff --git a/style/properties/properties.mako.rs b/style/properties/properties.mako.rs index c1fbd2c832..028384b994 100644 --- a/style/properties/properties.mako.rs +++ b/style/properties/properties.mako.rs @@ -454,7 +454,7 @@ pub mod property_counts { /// The number of non-custom properties. pub const NON_CUSTOM: usize = LONGHANDS_AND_SHORTHANDS + ALIASES; /// The number of prioritary properties that we have. - pub const PRIORITARY: usize = ${len(PRIORITARY_PROPERTIES)}; + pub const PRIORITARY: usize = ${len(PRIORITARY_PROPERTIES.intersection(set(list(map(lambda p: p.name, data.longhands)))))}; /// The max number of longhands that a shorthand other than "all" expands to. pub const MAX_SHORTHAND_EXPANDED: usize = ${max(len(s.sub_properties) for s in data.shorthands_except_all())}; @@ -1383,7 +1383,7 @@ pub use super::gecko::style_structs; /// The module where all the style structs are defined. #[cfg(feature = "servo")] pub mod style_structs { - use fxhash::FxHasher; + use rustc_hash::FxHasher; use super::longhands; use std::hash::{Hash, Hasher}; use crate::values::specified::color::ColorSchemeFlags; diff --git a/style/rule_cache.rs b/style/rule_cache.rs index 20c2dd208e..ef772477a7 100644 --- a/style/rule_cache.rs +++ b/style/rule_cache.rs @@ -12,7 +12,7 @@ use crate::selector_parser::PseudoElement; use crate::shared_lock::StylesheetGuards; use crate::values::computed::{NonNegativeLength, Zoom}; use crate::values::specified::color::ColorSchemeFlags; -use fxhash::FxHashMap; +use rustc_hash::FxHashMap; use servo_arc::Arc; use smallvec::SmallVec; diff --git a/style/rule_tree/core.rs b/style/rule_tree/core.rs index 85584a0e22..4d58767e0f 100644 --- a/style/rule_tree/core.rs +++ b/style/rule_tree/core.rs @@ -128,7 +128,7 @@ impl RuleTree { return; } - let mut children_count = fxhash::FxHashMap::default(); + let mut children_count = rustc_hash::FxHashMap::default(); let mut stack = SmallVec::<[_; 32]>::new(); stack.push(self.root.clone()); diff --git a/style/rule_tree/map.rs b/style/rule_tree/map.rs index 33c470e9c1..7aeb3bd3bf 100644 --- a/style/rule_tree/map.rs +++ b/style/rule_tree/map.rs @@ -4,8 +4,8 @@ #![forbid(unsafe_code)] -use fxhash::FxHashMap; use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps}; +use rustc_hash::FxHashMap; use std::collections::hash_map; use std::hash::Hash; use std::mem; diff --git a/style/servo/selector_parser.rs b/style/servo/selector_parser.rs index ef3f34259c..d199c6021a 100644 --- a/style/servo/selector_parser.rs +++ b/style/servo/selector_parser.rs @@ -19,7 +19,7 @@ use crate::values::{AtomIdent, AtomString}; use crate::{Atom, CaseSensitivityExt, LocalName, Namespace, Prefix}; use cssparser::{serialize_identifier, CowRcStr, Parser as CssParser, SourceLocation, ToCss}; use dom::{DocumentState, ElementState}; -use fxhash::FxHashMap; +use rustc_hash::FxHashMap; use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint}; use selectors::parser::SelectorParseErrorKind; use selectors::visitor::SelectorVisitor; diff --git a/style/stylesheets/stylesheet.rs b/style/stylesheets/stylesheet.rs index 64d78fae46..b389a05d49 100644 --- a/style/stylesheets/stylesheet.rs +++ b/style/stylesheets/stylesheet.rs @@ -16,10 +16,10 @@ use crate::stylesheets::{CssRule, CssRules, Origin, UrlExtraData}; use crate::use_counters::UseCounters; use crate::{Namespace, Prefix}; use cssparser::{Parser, ParserInput, StyleSheetParser}; -use fxhash::FxHashMap; #[cfg(feature = "gecko")] use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf}; use parking_lot::RwLock; +use rustc_hash::FxHashMap; use servo_arc::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use style_traits::ParsingMode; @@ -122,13 +122,12 @@ impl StylesheetContents { /// An empty namespace map should be fine, as it is only used for parsing, /// not serialization of existing selectors. Since UA sheets are read only, /// we should never need the namespace map. - pub fn from_shared_data( + pub fn from_data( rules: Arc>, origin: Origin, url_data: UrlExtraData, quirks_mode: QuirksMode, ) -> Arc { - debug_assert!(rules.is_static()); Arc::new(Self { rules, origin, @@ -141,6 +140,17 @@ impl StylesheetContents { }) } + /// Same as above, but ensuring that the rules are static. + pub fn from_shared_data( + rules: Arc>, + origin: Origin, + url_data: UrlExtraData, + quirks_mode: QuirksMode, + ) -> Arc { + debug_assert!(rules.is_static()); + Self::from_data(rules, origin, url_data, quirks_mode) + } + /// Returns a reference to the list of rules. #[inline] pub fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] { diff --git a/style/stylist.rs b/style/stylist.rs index fa04a0a67d..8b852638f7 100644 --- a/style/stylist.rs +++ b/style/stylist.rs @@ -57,10 +57,10 @@ use crate::values::{computed, AtomIdent}; use crate::AllocErr; use crate::{Atom, LocalName, Namespace, ShrinkIfNeeded, WeakAtom}; use dom::{DocumentState, ElementState}; -use fxhash::FxHashMap; use malloc_size_of::{MallocSizeOf, MallocShallowSizeOf, MallocSizeOfOps}; #[cfg(feature = "gecko")] use malloc_size_of::MallocUnconditionalShallowSizeOf; +use rustc_hash::FxHashMap; use selectors::attr::{CaseSensitivity, NamespaceConstraint}; use selectors::bloom::BloomFilter; use selectors::matching::{ diff --git a/style/values/computed/length_percentage.rs b/style/values/computed/length_percentage.rs index 3d6fafc3f6..41fe48b744 100644 --- a/style/values/computed/length_percentage.rs +++ b/style/values/computed/length_percentage.rs @@ -515,7 +515,11 @@ impl LengthPercentage { /// Returns the used value. #[inline] pub fn to_used_value(&self, containing_length: Au) -> Au { - Au::from(self.to_pixel_length(containing_length)) + let length = self.to_pixel_length(containing_length); + if let Unpacked::Percentage(_) = self.unpack() { + return Au::from_f32_px_trunc(length.px()); + } + Au::from(length) } /// Returns the used value as CSSPixelLength. @@ -528,7 +532,11 @@ impl LengthPercentage { #[inline] pub fn maybe_to_used_value(&self, container_len: Option) -> Option { self.maybe_percentage_relative_to(container_len.map(Length::from)) - .map(Au::from) + .map(if let Unpacked::Percentage(_) = self.unpack() { + |length: Length| Au::from_f32_px_trunc(length.px()) + } else { + Au::from + }) } /// If there are special rules for computing percentages in a value (e.g. diff --git a/style/values/specified/effects.rs b/style/values/specified/effects.rs index 64e7ed290c..8ed38b739c 100644 --- a/style/values/specified/effects.rs +++ b/style/values/specified/effects.rs @@ -53,7 +53,7 @@ pub type SpecifiedFilter = GenericFilter< NonNegativeFactor, ZeroToOneFactor, NonNegativeLength, - Impossible, + SimpleShadow, Impossible, >; diff --git a/style/values/specified/text.rs b/style/values/specified/text.rs index ee8b20312b..f1fd9e80a7 100644 --- a/style/values/specified/text.rs +++ b/style/values/specified/text.rs @@ -398,10 +398,15 @@ bitflags! { /// Capitalize each word. const CAPITALIZE = 1 << 2; /// Automatic italicization of math variables. + #[cfg(feature = "gecko")] const MATH_AUTO = 1 << 3; /// All the case transforms, which are exclusive with each other. + #[cfg(feature = "gecko")] const CASE_TRANSFORMS = Self::UPPERCASE.0 | Self::LOWERCASE.0 | Self::CAPITALIZE.0 | Self::MATH_AUTO.0; + /// All the case transforms, which are exclusive with each other. + #[cfg(feature = "servo")] + const CASE_TRANSFORMS = Self::UPPERCASE.0 | Self::LOWERCASE.0 | Self::CAPITALIZE.0; /// full-width const FULL_WIDTH = 1 << 4; @@ -428,6 +433,19 @@ impl TextTransform { // Case bits are exclusive with each other. case.is_empty() || case.bits().is_power_of_two() } + + /// Returns the corresponding TextTransformCase. + pub fn case(&self) -> TextTransformCase { + match *self & Self::CASE_TRANSFORMS { + Self::NONE => TextTransformCase::None, + Self::UPPERCASE => TextTransformCase::Uppercase, + Self::LOWERCASE => TextTransformCase::Lowercase, + Self::CAPITALIZE => TextTransformCase::Capitalize, + #[cfg(feature = "gecko")] + Self::MATH_AUTO => TextTransformCase::MathAuto, + _ => unreachable!("Case bits are exclusive with each other"), + } + } } /// Specified and computed value of text-align-last. diff --git a/style_derive/Cargo.toml b/style_derive/Cargo.toml index 06f638b297..70ebd2f2a7 100644 --- a/style_derive/Cargo.toml +++ b/style_derive/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "style_derive" +name = "stylo_derive" version = "0.0.1" authors = ["The Servo Project Developers"] license = "MPL-2.0" diff --git a/style_traits/Cargo.toml b/style_traits/Cargo.toml index eea00a10a2..0975ea5344 100644 --- a/style_traits/Cargo.toml +++ b/style_traits/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "style_traits" +name = "stylo_traits" version = "0.0.1" authors = ["The Servo Project Developers"] license = "MPL-2.0" @@ -13,20 +13,19 @@ path = "lib.rs" [features] servo = ["stylo_atoms", "cssparser/serde", "url", "euclid/serde"] -gecko = ["nsstring"] +gecko = [] [dependencies] app_units = "0.7" bitflags = "2" -cssparser = "0.34" +cssparser = "0.35" euclid = "0.22" -malloc_size_of = { path = "../malloc_size_of" } -malloc_size_of_derive = { path = "../../../xpcom/rust/malloc_size_of_derive" } -nsstring = {path = "../../../xpcom/rust/nsstring/", optional = true} +malloc_size_of = { path = "../malloc_size_of", package = "stylo_malloc_size_of" } +malloc_size_of_derive = "0.1" selectors = { path = "../selectors" } serde = "1.0" servo_arc = { path = "../servo_arc" } -stylo_atoms = { path = "../atoms", optional = true } +stylo_atoms = { path = "../stylo_atoms", optional = true } thin-vec = "0.2" to_shmem = { path = "../to_shmem" } to_shmem_derive = { path = "../to_shmem_derive" } diff --git a/stylo_atoms/Cargo.toml b/stylo_atoms/Cargo.toml new file mode 100644 index 0000000000..e873a0adc3 --- /dev/null +++ b/stylo_atoms/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "stylo_atoms" +version = "0.1.0" +authors = ["The Servo Project Developers"] +documentation = "https://docs.rs/stylo_atoms/" +description = "Interned string type for the Servo and Stylo projects" +repository = "https://github.com/servo/stylo" +license = "MPL-2.0" +edition = "2018" +build = "build.rs" + +[lib] +path = "lib.rs" + +[dependencies] +string_cache = "0.8" + +[build-dependencies] +string_cache_codegen = "0.5" diff --git a/stylo_atoms/build.rs b/stylo_atoms/build.rs new file mode 100644 index 0000000000..b5f6775724 --- /dev/null +++ b/stylo_atoms/build.rs @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use std::env; +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::path::Path; + +fn main() { + let static_atoms = + Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("static_atoms.txt"); + let static_atoms = BufReader::new(File::open(&static_atoms).unwrap()); + let mut atom_type = string_cache_codegen::AtomType::new("Atom", "atom!"); + + macro_rules! predefined { + ($($name: expr,)+) => { + { + $( + atom_type.atom($name); + )+ + } + } + } + include!("./predefined_counter_styles.rs"); + + atom_type + .atoms(static_atoms.lines().map(Result::unwrap)) + .write_to_file(&Path::new(&env::var_os("OUT_DIR").unwrap()).join("atom.rs")) + .unwrap(); +} diff --git a/stylo_atoms/lib.rs b/stylo_atoms/lib.rs new file mode 100644 index 0000000000..03560a40c0 --- /dev/null +++ b/stylo_atoms/lib.rs @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +include!(concat!(env!("OUT_DIR"), "/atom.rs")); diff --git a/stylo_atoms/predefined_counter_styles.rs b/stylo_atoms/predefined_counter_styles.rs new file mode 100644 index 0000000000..f376981e32 --- /dev/null +++ b/stylo_atoms/predefined_counter_styles.rs @@ -0,0 +1,66 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + + // THIS FILE IS DUPLICATED FROM style/counter_style/predefined.rs. + // TO UPDATE IT: + // - Run `python style/counter_style/updated_predefined.py` + // - Re-copy style/counter_style/predefined.rs to this location + +predefined! { + "decimal", + "decimal-leading-zero", + "arabic-indic", + "armenian", + "upper-armenian", + "lower-armenian", + "bengali", + "cambodian", + "khmer", + "cjk-decimal", + "devanagari", + "georgian", + "gujarati", + "gurmukhi", + "hebrew", + "kannada", + "lao", + "malayalam", + "mongolian", + "myanmar", + "oriya", + "persian", + "lower-roman", + "upper-roman", + "tamil", + "telugu", + "thai", + "tibetan", + "lower-alpha", + "lower-latin", + "upper-alpha", + "upper-latin", + "cjk-earthly-branch", + "cjk-heavenly-stem", + "lower-greek", + "hiragana", + "hiragana-iroha", + "katakana", + "katakana-iroha", + "disc", + "circle", + "square", + "disclosure-open", + "disclosure-closed", + "japanese-informal", + "japanese-formal", + "korean-hangul-formal", + "korean-hanja-informal", + "korean-hanja-formal", + "simp-chinese-informal", + "simp-chinese-formal", + "trad-chinese-informal", + "trad-chinese-formal", + "cjk-ideographic", + "ethiopic-numeric", +} diff --git a/stylo_atoms/static_atoms.txt b/stylo_atoms/static_atoms.txt new file mode 100644 index 0000000000..2222317e81 --- /dev/null +++ b/stylo_atoms/static_atoms.txt @@ -0,0 +1,182 @@ +-moz-content-preferred-color-scheme +-moz-device-pixel-ratio +-moz-fixed-pos-containing-block +-moz-gtk-csd-close-button-position +-moz-gtk-csd-maximize-button-position +-moz-gtk-csd-menu-radius +-moz-gtk-csd-minimize-button-position +-moz-gtk-csd-titlebar-button-spacing +-moz-gtk-csd-titlebar-radius +-moz-gtk-menu-radius +-moz-mac-titlebar-height +-moz-overlay-scrollbar-fade-duration +DOMContentLoaded +abort +activate +addtrack +animationcancel +animationend +animationiteration +animationstart +aspect-ratio +beforeunload +block-size +button +canplay +canplaythrough +center +change +characteristicvaluechanged +checkbox +cancel +click +close +closing +color +complete +compositionend +compositionstart +compositionupdate +controllerchange +cursive +dark +datachannel +date +datetime-local +dir +device-pixel-ratio +durationchange +email +emptied +end +ended +error +fantasy +fetch +file +fill +fill-opacity +formdata +fullscreenchange +fullscreenerror +gattserverdisconnected +hashchange +height +hidden +icecandidate +iceconnectionstatechange +icegatheringstatechange +image +inline-size +input +inputsourceschange +invalid +keydown +keypress +kind +left +light +ltr +load +loadeddata +loadedmetadata +loadend +loadstart +message +message +messageerror +monospace +month +mousedown +mousemove +mouseover +mouseup +negotiationneeded +none +normal +number +onchange +open +orientation +pagehide +pageshow +password +pause +play +playing +popstate +postershown +prefers-color-scheme +print +progress +radio +range +ratechange +readystatechange +referrer +reftest-wait +rejectionhandled +removetrack +reset +resize +resolution +resourcetimingbufferfull +right +rtl +sans-serif +safe-area-inset-top +safe-area-inset-bottom +safe-area-inset-left +safe-area-inset-right +scan +screen +scroll-position +scrollbar-inline-size +search +seeked +seeking +select +selectend +selectionchange +selectstart +serif +sessionavailable +show +signalingstatechange +slotchange +squeeze +squeezeend +squeezestart +srclang +statechange +stroke +stroke-opacity +storage +submit +suspend +system-ui +tel +text +time +timeupdate +toggle +track +transitioncancel +transitionend +transitionrun +transitionstart +uncapturederror +unhandledrejection +unload +url +visibilitychange +volumechange +waiting +webglcontextcreationerror +webkitAnimationEnd +webkitAnimationIteration +webkitAnimationStart +webkitTransitionEnd +webkitTransitionRun +week +width diff --git a/stylo_config/Cargo.toml b/stylo_config/Cargo.toml new file mode 100644 index 0000000000..6c9e8a4db4 --- /dev/null +++ b/stylo_config/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "stylo_config" +version = "0.1.0" +authors = ["The Servo Project Developers"] +documentation = "https://docs.rs/stylo_config/" +description = "Runtime configuration for Stylo" +repository = "https://github.com/servo/stylo" +keywords = ["css", "style"] +license = "MPL-2.0" +edition = "2021" + +[lib] +name = "stylo_config" +path = "lib.rs" diff --git a/stylo_config/lib.rs b/stylo_config/lib.rs new file mode 100644 index 0000000000..ba504f625d --- /dev/null +++ b/stylo_config/lib.rs @@ -0,0 +1,91 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use std::collections::HashMap; +use std::sync::{LazyLock, RwLock}; + +static PREFS: LazyLock = LazyLock::new(Preferences::default); + +#[derive(Debug, Default)] +pub struct Preferences { + bool_prefs: RwLock>, + i32_prefs: RwLock>, +} + +impl Preferences { + pub fn get_bool(&self, key: &str) -> bool { + let prefs = self.bool_prefs.read().expect("RwLock is poisoned"); + *prefs.get(key).unwrap_or(&false) + } + + pub fn get_i32(&self, key: &str) -> i32 { + let prefs = self.i32_prefs.read().expect("RwLock is poisoned"); + *prefs.get(key).unwrap_or(&0) + } + + pub fn set_bool(&self, key: &str, value: bool) { + let mut prefs = self.bool_prefs.write().expect("RwLock is poisoned"); + + // Avoid cloning the key if it exists. + if let Some(pref) = prefs.get_mut(key) { + *pref = value; + } else { + prefs.insert(key.to_owned(), value); + } + } + + pub fn set_i32(&self, key: &str, value: i32) { + let mut prefs = self.i32_prefs.write().expect("RwLock is poisoned"); + + // Avoid cloning the key if it exists. + if let Some(pref) = prefs.get_mut(key) { + *pref = value; + } else { + prefs.insert(key.to_owned(), value); + } + } +} + +pub fn get_bool(key: &str) -> bool { + PREFS.get_bool(key) +} + +pub fn get_i32(key: &str) -> i32 { + PREFS.get_i32(key) +} + +pub fn set_bool(key: &str, value: bool) { + PREFS.set_bool(key, value) +} + +pub fn set_i32(key: &str, value: i32) { + PREFS.set_i32(key, value) +} + +#[test] +fn test() { + let prefs = Preferences::default(); + + // Prefs have default values when unset. + assert_eq!(prefs.get_bool("foo"), false); + assert_eq!(prefs.get_i32("bar"), 0); + + // Prefs can be set and retrieved. + prefs.set_bool("foo", true); + prefs.set_i32("bar", 1); + assert_eq!(prefs.get_bool("foo"), true); + assert_eq!(prefs.get_i32("bar"), 1); + prefs.set_bool("foo", false); + prefs.set_i32("bar", 2); + assert_eq!(prefs.get_bool("foo"), false); + assert_eq!(prefs.get_i32("bar"), 2); + + // Each value type currently has an independent namespace. + prefs.set_i32("foo", 3); + prefs.set_bool("bar", true); + assert_eq!(prefs.get_i32("foo"), 3); + assert_eq!(prefs.get_bool("foo"), false); + assert_eq!(prefs.get_bool("bar"), true); + assert_eq!(prefs.get_i32("bar"), 2); +} diff --git a/stylo_dom/Cargo.toml b/stylo_dom/Cargo.toml new file mode 100644 index 0000000000..e6f8a2831b --- /dev/null +++ b/stylo_dom/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "stylo_dom" +version = "0.1.0" +authors = ["The Servo Project Developers"] +documentation = "https://docs.rs/stylo_dom/" +description = "DOM state types for Stylo" +repository = "https://github.com/servo/stylo" +keywords = ["css", "style"] +license = "MPL-2.0" +edition = "2021" + +[lib] +path = "lib.rs" + +[dependencies] +bitflags = "2" +malloc_size_of = { path = "../malloc_size_of", package = "stylo_malloc_size_of" } diff --git a/stylo_dom/lib.rs b/stylo_dom/lib.rs new file mode 100644 index 0000000000..9137763491 --- /dev/null +++ b/stylo_dom/lib.rs @@ -0,0 +1,164 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use bitflags::bitflags; +use malloc_size_of::malloc_size_of_is_0; + +// DOM types to be shared between Rust and C++. +bitflags! { + /// Event-based element states. + #[repr(C)] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct ElementState: u64 { + /// The mouse is down on this element. + /// + /// FIXME(#7333): set/unset this when appropriate + const ACTIVE = 1 << 0; + /// This element has focus. + /// + const FOCUS = 1 << 1; + /// The mouse is hovering over this element. + /// + const HOVER = 1 << 2; + /// Content is enabled (and can be disabled). + /// + const ENABLED = 1 << 3; + /// Content is disabled. + /// + const DISABLED = 1 << 4; + /// Content is checked. + /// + const CHECKED = 1 << 5; + /// + const INDETERMINATE = 1 << 6; + /// + const PLACEHOLDER_SHOWN = 1 << 7; + /// + const URLTARGET = 1 << 8; + /// + const FULLSCREEN = 1 << 9; + /// + const VALID = 1 << 10; + /// + const INVALID = 1 << 11; + /// + const USER_VALID = 1 << 12; + /// + const USER_INVALID = 1 << 13; + /// All the validity bits at once. + const VALIDITY_STATES = Self::VALID.bits() | Self::INVALID.bits() | Self::USER_VALID.bits() | Self::USER_INVALID.bits(); + /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-broken + const BROKEN = 1 << 14; + /// + const REQUIRED = 1 << 15; + /// + /// We use an underscore to workaround a silly windows.h define. + const OPTIONAL_ = 1 << 16; + /// + const DEFINED = 1 << 17; + /// + const VISITED = 1 << 18; + /// + const UNVISITED = 1 << 19; + /// + const VISITED_OR_UNVISITED = Self::VISITED.bits() | Self::UNVISITED.bits(); + /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-drag-over + const DRAGOVER = 1 << 20; + /// + const INRANGE = 1 << 21; + /// + const OUTOFRANGE = 1 << 22; + /// + const READONLY = 1 << 23; + /// + const READWRITE = 1 << 24; + /// + const DEFAULT = 1 << 25; + /// Non-standard & undocumented. + const OPTIMUM = 1 << 26; + /// Non-standard & undocumented. + const SUB_OPTIMUM = 1 << 27; + /// Non-standard & undocumented. + const SUB_SUB_OPTIMUM = 1 << 28; + /// All the above bits in one place. + const METER_OPTIMUM_STATES = Self::OPTIMUM.bits() | Self::SUB_OPTIMUM.bits() | Self::SUB_SUB_OPTIMUM.bits(); + /// Non-standard & undocumented. + const INCREMENT_SCRIPT_LEVEL = 1 << 29; + /// + const FOCUSRING = 1 << 30; + /// + const FOCUS_WITHIN = 1u64 << 31; + /// :dir matching; the states are used for dynamic change detection. + /// State that elements that match :dir(ltr) are in. + const LTR = 1u64 << 32; + /// State that elements that match :dir(rtl) are in. + const RTL = 1u64 << 33; + /// State that HTML elements that have a "dir" attr are in. + const HAS_DIR_ATTR = 1u64 << 34; + /// State that HTML elements with dir="ltr" (or something + /// case-insensitively equal to "ltr") are in. + const HAS_DIR_ATTR_LTR = 1u64 << 35; + /// State that HTML elements with dir="rtl" (or something + /// case-insensitively equal to "rtl") are in. + const HAS_DIR_ATTR_RTL = 1u64 << 36; + /// State that HTML elements without a valid-valued "dir" attr or + /// any HTML elements (including ) with dir="auto" (or something + /// case-insensitively equal to "auto") are in. + const HAS_DIR_ATTR_LIKE_AUTO = 1u64 << 37; + /// Non-standard & undocumented. + const AUTOFILL = 1u64 << 38; + /// Non-standard & undocumented. + const AUTOFILL_PREVIEW = 1u64 << 39; + /// State for modal elements: + /// + const MODAL = 1u64 << 40; + /// + const INERT = 1u64 << 41; + /// State for the topmost modal element in top layer + const TOPMOST_MODAL = 1u64 << 42; + /// Initially used for the devtools highlighter, but now somehow only + /// used for the devtools accessibility inspector. + const DEVTOOLS_HIGHLIGHTED = 1u64 << 43; + /// Used for the devtools style editor. Probably should go away. + const STYLEEDITOR_TRANSITIONING = 1u64 << 44; + /// For :-moz-value-empty (to show widgets like the reveal password + /// button or the clear button). + const VALUE_EMPTY = 1u64 << 45; + /// For :-moz-revealed. + const REVEALED = 1u64 << 46; + /// https://html.spec.whatwg.org/#selector-popover-open + /// Match element's popover visibility state of showing + const POPOVER_OPEN = 1u64 << 47; + + /// Some convenience unions. + const DIR_STATES = Self::LTR.bits() | Self::RTL.bits(); + + const DIR_ATTR_STATES = Self::HAS_DIR_ATTR.bits() | + Self::HAS_DIR_ATTR_LTR.bits() | + Self::HAS_DIR_ATTR_RTL.bits() | + Self::HAS_DIR_ATTR_LIKE_AUTO.bits(); + + const DISABLED_STATES = Self::DISABLED.bits() | Self::ENABLED.bits(); + + const REQUIRED_STATES = Self::REQUIRED.bits() | Self::OPTIONAL_.bits(); + } +} + +bitflags! { + /// Event-based document states. + #[repr(C)] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct DocumentState: u64 { + /// Window activation status + const WINDOW_INACTIVE = 1 << 0; + /// RTL locale: specific to the XUL localedir attribute + const RTL_LOCALE = 1 << 1; + /// LTR locale: specific to the XUL localedir attribute + const LTR_LOCALE = 1 << 2; + + const ALL_LOCALEDIR_BITS = Self::LTR_LOCALE.bits() | Self::RTL_LOCALE.bits(); + } +} + +malloc_size_of_is_0!(ElementState, DocumentState); diff --git a/stylo_static_prefs/Cargo.toml b/stylo_static_prefs/Cargo.toml new file mode 100644 index 0000000000..48d738cddc --- /dev/null +++ b/stylo_static_prefs/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "stylo_static_prefs" +version = "0.1.0" +authors = ["The Servo Project Developers"] +documentation = "https://docs.rs/stylo_static_prefs/" +description = "Static configuration for Stylo" +repository = "https://github.com/servo/stylo" +keywords = ["css", "style"] +license = "MPL-2.0" +edition = "2021" diff --git a/stylo_static_prefs/src/lib.rs b/stylo_static_prefs/src/lib.rs new file mode 100644 index 0000000000..97c27c3ac9 --- /dev/null +++ b/stylo_static_prefs/src/lib.rs @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +//! A list of static preferences exposed to the style crate. These should +//! be kept sync with the preferences used by the style. +#[macro_export] +macro_rules! pref { + ("layout.css.stylo-local-work-queue.in-main-thread") => { + 32 + }; + ("layout.css.stylo-work-unit-size") => { + 16 + }; + ("layout.css.stylo-local-work-queue.in-worker") => { + 0 + }; + ("layout.css.system-ui.enabled") => { + true + }; + ("layout.css.basic-shape-rect.enabled") => { + true + }; + ("layout.css.basic-shape-xywh.enabled") => { + true + }; + ("layout.css.relative-color-syntax.enabled") => { + true + }; + ("layout.css.stretch-size-keyword.enabled") => { + true + }; + ("layout.css.transition-behavior.enabled") => { + true + }; + ($string:literal) => { + false + }; +} diff --git a/sync.sh b/sync.sh new file mode 100755 index 0000000000..e92182c746 --- /dev/null +++ b/sync.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# Usage: sync.sh +set -eu + +root=$(pwd) +mkdir -p "$1" +cd -- "$1" +filtered=$(pwd) +mkdir -p "$root/_cache" +cd "$root/_cache" +export PATH="$PWD:$PATH" + +step() { + if [ "${TERM-}" != '' ]; then + tput setaf 12 + fi + >&2 printf '* %s\n' "$*" + if [ "${TERM-}" != '' ]; then + tput sgr0 + fi +} + +step Downloading git-filter-repo if needed +if ! git filter-repo --version 2> /dev/null; then + curl -O https://raw.githubusercontent.com/newren/git-filter-repo/v2.38.0/git-filter-repo + chmod +x git-filter-repo + + git filter-repo --version +fi + +step Cloning upstream if needed +if ! [ -e upstream ]; then + git clone --bare --single-branch --progress https://github.com/mozilla/gecko-dev.git upstream +fi + +step Updating upstream +branch=$(git -C upstream rev-parse --abbrev-ref HEAD) +git -C upstream fetch origin $branch:$branch + +step Filtering upstream +# Cloning and filtering is much faster than git filter-repo --source --target. +git clone --bare upstream -- "$filtered" +git -C "$filtered" filter-repo --force --paths-from-file "$root/style.paths" diff --git a/to_shmem/Cargo.toml b/to_shmem/Cargo.toml index fadd1e6e3a..cfb9db60f0 100644 --- a/to_shmem/Cargo.toml +++ b/to_shmem/Cargo.toml @@ -23,7 +23,7 @@ string_cache = ["dep:string_cache"] thin-vec = ["dep:thin-vec"] [dependencies] -cssparser = { version = "0.34", optional = true } +cssparser = { version = "0.35", optional = true } servo_arc = { version = "0.4.0", path = "../servo_arc", optional = true } smallbitvec = { version = "2.3.0", optional = true } smallvec = { version = "1.13", optional = true }