From 7da7804ea4eb0d861f03c28367ff06479bd780fe Mon Sep 17 00:00:00 2001 From: Delan Azabani Date: Wed, 7 Feb 2024 17:52:11 +0800 Subject: [PATCH 01/11] Servo initial downstream commit Any ancestors of this commit are from upstream mozilla-central, with some filtering and renaming. Our patches and sync tooling start here. The sync tooling has all been squashed into this commit, based on: https://github.com/servo/stylo/commits/64731e10dc8ef87ef52aa2fb9f988c3b2530f3a7 --- .github/workflows/main.yml | 51 +++++++++++ .../workflows/mirror-to-release-branch.yml | 26 ++++++ .github/workflows/sync-upstream.yml | 23 +++++ .gitignore | 5 ++ README.md | 85 +++++++++++++++++++ commit-from-merge.sh | 15 ++++ commit-from-squashed.sh | 14 +++ shell.nix | 6 ++ start-rebase.sh | 10 +++ style.paths | 8 ++ sync.sh | 43 ++++++++++ 11 files changed, 286 insertions(+) create mode 100644 .github/workflows/main.yml create mode 100644 .github/workflows/mirror-to-release-branch.yml create mode 100644 .github/workflows/sync-upstream.yml create mode 100644 .gitignore create mode 100644 README.md create mode 100755 commit-from-merge.sh create mode 100755 commit-from-squashed.sh create mode 100644 shell.nix create mode 100755 start-rebase.sh create mode 100644 style.paths create mode 100755 sync.sh 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/README.md b/README.md new file mode 100644 index 0000000000..b280c0c4a7 --- /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" } +style = { path = "../stylo/style" } +stylo_config = { path = "../stylo/stylo_config" } +stylo_dom = { path = "../stylo/stylo_dom" } +style_malloc_size_of = { path = "../stylo/malloc_size_of", package = "malloc_size_of" } +style_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/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/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" From e8dbccb2542040aa871c7824b4ab4d3c48ecd4fb Mon Sep 17 00:00:00 2001 From: Delan Azabani Date: Thu, 15 Feb 2024 18:30:14 +0800 Subject: [PATCH 02/11] Commit our changes on top of upstream Stylo This is a rebase of da53c540faa7dd5556c6718d4644a6e957947893 Signed-off-by: Oriol Brufau --- .github/workflows/sync-upstream.yml | 2 +- Cargo.toml | 18 + README.md | 136 ++++--- SYNCING.md | 63 ++++ malloc_size_of/Cargo.toml | 14 +- selectors/Cargo.toml | 6 +- selectors/matching.rs | 2 +- servo_arc/Cargo.toml | 4 +- style/Cargo.toml | 47 +-- style/animation.rs | 336 +++++++++++++----- style/attr.rs | 26 ++ style/build.rs | 8 +- style/context.rs | 4 +- style/dom.rs | 7 +- style/lib.rs | 11 +- style/logical_geometry.rs | 13 - style/macros.rs | 6 +- style/matching.rs | 16 +- .../Mako-1.1.2-py2.py3-none-any.whl | Bin 0 -> 75521 bytes style/properties/build.py | 1 + style/properties/data.py | 2 +- style/properties/longhands/background.mako.rs | 8 + style/properties/longhands/border.mako.rs | 8 +- style/properties/longhands/box.mako.rs | 42 +-- style/properties/longhands/column.mako.rs | 4 +- style/properties/longhands/counters.mako.rs | 8 +- style/properties/longhands/effects.mako.rs | 4 +- style/properties/longhands/font.mako.rs | 14 +- .../longhands/inherited_box.mako.rs | 4 +- .../longhands/inherited_table.mako.rs | 8 +- .../longhands/inherited_text.mako.rs | 23 +- .../properties/longhands/inherited_ui.mako.rs | 2 + style/properties/longhands/list.mako.rs | 11 +- style/properties/longhands/margin.mako.rs | 2 +- style/properties/longhands/outline.mako.rs | 4 + style/properties/longhands/padding.mako.rs | 2 +- style/properties/longhands/position.mako.rs | 35 +- style/properties/longhands/svg.mako.rs | 1 + style/properties/longhands/table.mako.rs | 2 +- style/properties/longhands/text.mako.rs | 6 +- style/properties/longhands/ui.mako.rs | 1 + style/properties/properties.mako.rs | 36 +- style/servo/media_queries.rs | 5 + style/servo/restyle_damage.rs | 284 ++++++--------- style/servo/selector_parser.rs | 40 ++- style/servo/url.rs | 44 ++- style/shadow_parts.rs | 166 +++++++++ style/stylesheets/stylesheet.rs | 14 +- style/thread_state.rs | 81 ++--- style/values/computed/image.rs | 2 +- style/values/computed/length_percentage.rs | 1 + style/values/generics/image.rs | 2 +- style/values/specified/image.rs | 5 +- style/values/specified/text.rs | 18 + style_derive/Cargo.toml | 5 +- style_traits/Cargo.toml | 24 +- stylo_atoms/Cargo.toml | 20 ++ stylo_atoms/build.rs | 31 ++ stylo_atoms/lib.rs | 5 + stylo_atoms/predefined_counter_styles.rs | 66 ++++ stylo_atoms/static_atoms.txt | 184 ++++++++++ stylo_config/Cargo.toml | 15 + stylo_config/lib.rs | 91 +++++ stylo_dom/Cargo.toml | 18 + stylo_dom/lib.rs | 164 +++++++++ stylo_static_prefs/Cargo.toml | 11 + stylo_static_prefs/src/lib.rs | 45 +++ sync.sh | 2 +- to_shmem/Cargo.toml | 4 +- 69 files changed, 1672 insertions(+), 622 deletions(-) create mode 100644 Cargo.toml create mode 100644 SYNCING.md create mode 100644 style/properties/Mako-1.1.2-py2.py3-none-any.whl create mode 100644 style/shadow_parts.rs create mode 100644 stylo_atoms/Cargo.toml create mode 100644 stylo_atoms/build.rs create mode 100644 stylo_atoms/lib.rs create mode 100644 stylo_atoms/predefined_counter_styles.rs create mode 100644 stylo_atoms/static_atoms.txt create mode 100644 stylo_config/Cargo.toml create mode 100644 stylo_config/lib.rs create mode 100644 stylo_dom/Cargo.toml create mode 100644 stylo_dom/lib.rs create mode 100644 stylo_static_prefs/Cargo.toml create mode 100644 stylo_static_prefs/src/lib.rs diff --git a/.github/workflows/sync-upstream.yml b/.github/workflows/sync-upstream.yml index 992fe6d2ce..adf329ffa6 100644 --- a/.github/workflows/sync-upstream.yml +++ b/.github/workflows/sync-upstream.yml @@ -19,5 +19,5 @@ jobs: key: upstream - run: | ./sync.sh _filtered - git fetch -f --progress ./_filtered master:upstream + git fetch -f --progress ./_filtered main:upstream git push -fu --progress origin upstream 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 index b280c0c4a7..527db6b2f4 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,107 @@ Stylo ===== -This repo contains Servo’s downstream fork of [Stylo](https://searchfox.org/mozilla-central/source/servo). +**High-Performance CSS Style Engine** -The branches are as follows: +[![Build Status](https://github.com/servo/stylo/actions/workflows/main.yml/badge.svg)](https://github.com/servo/stylo/actions) +[![Crates.io](https://img.shields.io/crates/v/stylo.svg)](https://crates.io/crates/stylo) +[![Docs](https://docs.rs/stylo/badge.svg)](https://docs.rs/stylo) +![Crates.io License](https://img.shields.io/crates/l/stylo) -- [`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` +Stylo is a high-performance, browser-grade CSS style engine written in Rust that powers [Servo](https://servo.org) and [Firefox](https://firefox.com). This repo contains Servo’s downstream version of Stylo. The upstream version lives in mozilla-central with the rest of the Gecko/Firefox codebase. -## Building Servo against your local Stylo +Coordination of Stylo development happens: -Assuming your local `servo` and `stylo` directories are siblings, you can build `servo` against `stylo` by adding the following to `servo/Cargo.toml`: +- Here in Github Issues +- In the [#stylo](https://servo.zulipchat.com/#narrow/channel/417109-stylo) channel of the [Servo Zulip](https://servo.zulipchat.com/) +- In the [#layout](https://chat.mozilla.org/#/room/#layout:mozilla.org) room of the Mozilla Matrix instance (matrix.mozilla.org) -```toml -[patch."https://github.com/servo/stylo"] -selectors = { path = "../stylo/selectors" } -servo_arc = { path = "../stylo/servo_arc" } -stylo_atoms = { path = "../stylo/stylo_atoms" } -style = { path = "../stylo/style" } -stylo_config = { path = "../stylo/stylo_config" } -stylo_dom = { path = "../stylo/stylo_dom" } -style_malloc_size_of = { path = "../stylo/malloc_size_of", package = "malloc_size_of" } -style_traits = { path = "../stylo/style_traits" } -``` +## High-Level Documentation -## Syncing `upstream` with mozilla-central +- This [Mozilla Hacks article](https://hacks.mozilla.org/2017/08/inside-a-super-fast-css-engine-quantum-css-aka-stylo) contains a high-level overview of the Stylo architecture. +- There is a [chapter](https://book.servo.org/architecture/style.html) in the Servo Book (although it is a little out of date). -Start by generating a filtered copy of mozilla-central. This will cache the raw mozilla-central in `_cache/upstream`, storing the result in `_filtered`: +## Branches -```sh -$ ./sync.sh _filtered -``` +The branches are as follows: -If `_filtered` already exists, you will need to delete it and try again: +- [**upstream**](https://github.com/servo/style/tree/upstream) has upstream [mozilla-central](https://searchfox.org/mozilla-central/source/servo) filtered to the paths we care about ([style.paths](style.paths)), but is otherwise unmodified. +- [**main**](https://github.com/servo/style/tree/ci) adds our downstream patches, plus the scripts and workflows for syncing with mozilla-central on top of **upstream**. -```sh -$ rm -Rf _filtered -``` +> [!WARNING] +> This repo syncs from upstream by creating a new branch and then rebasing our changes on top of it. This means that `git pull` will not work across syncs (you will need to use `git fetch`, `git reset` and `git rebase`). -Now overwrite our `upstream` with those commits and push: +More information on the syncing process is available in [SYNCING.md](SYNCING.md) -```sh -$ git fetch -f --progress ./_filtered master:upstream -$ git push -fu --progress origin upstream -``` +## Crates -## Rebasing `main` onto `upstream` +A guide to the crates contained within this repo -Start by fetching `upstream` into your local repo: +### Stylo Crates -```sh -$ git fetch -f origin upstream:upstream -``` +These crates are largely implementation details of Stylo, although you may need to use some of them directly if you use Stylo. -In general, the filtering process is deterministic, yielding the same commit hashes each time, so we can rebase normally: +| Directory | Crate | Notes | +| --- | --- | --- | +| style | [![Crates.io](https://img.shields.io/crates/v/stylo.svg)](https://crates.io/crates/stylo) | The main Stylo crate containing the entire CSS engine | +| style_traits | [![Crates.io](https://img.shields.io/crates/v/stylo_traits.svg)](https://crates.io/crates/stylo_traits) | Types and traits which allow other code to interoperate with Stylo without depending on the main crate directly. | +| stylo_dom | [![Crates.io](https://img.shields.io/crates/v/stylo_dom.svg)](https://crates.io/crates/stylo_dom) | Similar to stylo_traits (but much smaller) | +| stylo_atoms | [![Crates.io](https://img.shields.io/crates/v/stylo_atoms.svg)](https://crates.io/crates/stylo_atoms) | [Atoms](https://docs.rs/string_cache/latest/string_cache/struct.Atom.html) for CSS and HTML event related strings | +| stylo_config | [![Crates.io](https://img.shields.io/crates/v/stylo_config.svg)](https://crates.io/crates/stylo_config) | Configuration for Stylo. Can be used to set runtime preferences (enabling/disabling properties, etc) | +| stylo_static_prefs | [![Crates.io](https://img.shields.io/crates/v/stylo_static_prefs.svg)](https://crates.io/crates/stylo_static_prefs) | Static configuration for Stylo. Config be overridden by patching in a replacement crate. | +| style_derive | [![Crates.io](https://img.shields.io/crates/v/stylo_derive.svg)](https://crates.io/crates/stylo_derive) | Internal derive macro for stylo crate | -```sh -$ git rebase upstream -``` +### Standalone Crates -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 `~`): +These crates form part of Stylo but are also be useful standalone. -```sh -$ git log --pretty=\%H --grep='Servo initial downstream commit' -e62d7f0090941496e392e1dc91df103a38e3f488 +| Directory | Crate | Notes | +| --- | --- | --- | +| selectors | [![Crates.io](https://img.shields.io/crates/v/selectors.svg)](https://crates.io/crates/selectors) | CSS Selector matching | +| servo_arc | [![Crates.io](https://img.shields.io/crates/v/servo_arc.svg)](https://crates.io/crates/servo_arc) | A variant on `std::Arc` | -$ git rebase --onto upstream e62d7f0090941496e392e1dc91df103a38e3f488~ -Successfully rebased and updated refs/heads/main. -``` +You may also be interested in the `cssparser` crate which lives in the [servo/rust-cssparser](https://github.com/servo/rust-cssparser) repo. -`start-rebase.sh` takes care of this automatically, but you should still use `git rebase` for subsequent steps like `--continue` and `--abort`: +### Support Crates -```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 -``` +Low-level crates which could technically be used standalone but are unlikely to be generally useful in practice. + +| Directory | Crate | Notes | +| --- | --- | --- | +| malloc_size_of | [![Crates.io](https://img.shields.io/crates/v/stylo_malloc_size_of.svg)](https://crates.io/crates/stylo_malloc_size_of) | Heap size measurement for Stylo values | +| to_shmem | [![Crates.io](https://img.shields.io/crates/v/to_shmem.svg)](https://crates.io/crates/to_shmem) | Internal utility crate for sharing memory across processes. | +| to_shmem_derive | [![Crates.io](https://img.shields.io/crates/v/to_shmem_derive.svg)](https://crates.io/crates/to_shmem_derive) | Internal derive macro for to_shmem crate | -Or if we aren’t ready to rebase onto the tip of upstream: +## Building Servo Against a Local Copy of Stylo + +Assuming your local `servo` and `stylo` directories are siblings, you can build `servo` against `stylo` by adding the following to `servo/Cargo.toml`: -```sh -$ ./start-rebase.sh upstream~10 -i +```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" } ``` + +## Releases + +Releases are made every time this repository rebases its changes on top of the latest version of upstream Stylo. There are a lot of crates here. In order to publish them, they must be done in order. One order that works is: + +- selectors +- stylo_static_prefs +- stylo_config +- stylo_atoms +- stylo_malloc_size_of +- stylo_dom +- stylo_derive +- stylo_traits +- stylo + +## License + +Stylo is licensed under MPL 2.0 diff --git a/SYNCING.md b/SYNCING.md new file mode 100644 index 0000000000..72a0a53d1d --- /dev/null +++ b/SYNCING.md @@ -0,0 +1,63 @@ +# Syncing + +This file documents the process of syncing this repository with the upstream copy of Stylo in mozilla-central. + +## 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 main: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/malloc_size_of/Cargo.toml b/malloc_size_of/Cargo.toml index a12c652662..612ff98c16 100644 --- a/malloc_size_of/Cargo.toml +++ b/malloc_size_of/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "malloc_size_of" -version = "0.0.1" +name = "stylo_malloc_size_of" +version = "0.4.0" authors = ["The Servo Project Developers"] license = "MIT OR Apache-2.0" repository = "https://github.com/servo/stylo" @@ -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" } +selectors = { version = "0.29", path = "../selectors" } +servo_arc = { version = "0.4", 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 8b3d39405e..6c5d3e5a32 100644 --- a/selectors/Cargo.toml +++ b/selectors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "selectors" -version = "0.26.0" +version = "0.29.0" authors = ["The Servo Project Developers"] documentation = "https://docs.rs/selectors/" description = "CSS Selectors matching for Rust" @@ -21,7 +21,7 @@ to_shmem = ["dep:to_shmem", "dep:to_shmem_derive"] [dependencies] bitflags = "2" -cssparser = "0.34" +cssparser = "0.35" derive_more = { version = "2", features = ["add", "add_assign"] } fxhash = "0.2" log = "0.4" @@ -29,7 +29,7 @@ phf = "0.11" precomputed-hash = "0.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 } +to_shmem = { version = "0.2", path = "../to_shmem", features = ["servo_arc"], optional = true } to_shmem_derive = { version = "0.1", path = "../to_shmem_derive", optional = true } new_debug_unreachable = "1" diff --git a/selectors/matching.rs b/selectors/matching.rs index e6694dad7a..152de53482 100644 --- a/selectors/matching.rs +++ b/selectors/matching.rs @@ -249,7 +249,7 @@ impl From for KleeneValue { /// partial selectors (indexed from the right). We use this API design, rather /// than having the callers pass a SelectorIter, because creating a SelectorIter /// requires dereferencing the selector to get the length, which adds an -/// unncessary cache miss for cases when we can fast-reject with AncestorHashes +/// unnecessary cache miss for cases when we can fast-reject with AncestorHashes /// (which the caller can store inline with the selector pointer). #[inline(always)] pub fn matches_selector( diff --git a/servo_arc/Cargo.toml b/servo_arc/Cargo.toml index 8b0976b75d..9f77b64b43 100644 --- a/servo_arc/Cargo.toml +++ b/servo_arc/Cargo.toml @@ -1,17 +1,19 @@ [package] name = "servo_arc" -version = "0.4.0" +version = "0.4.1" authors = ["The Servo Project Developers"] license = "MIT OR Apache-2.0" repository = "https://github.com/servo/stylo" description = "A fork of std::sync::Arc with some extra functionality and without weak references" edition = "2021" +readme = "../README.md" [lib] name = "servo_arc" path = "lib.rs" [features] +default = ["track_alloc_size"] gecko_refcount_logging = [] servo = ["serde", "track_alloc_size"] track_alloc_size = [] diff --git a/style/Cargo.toml b/style/Cargo.toml index ce36e85d0d..b47ddb3ba1 100644 --- a/style/Cargo.toml +++ b/style/Cargo.toml @@ -1,11 +1,12 @@ [package] -name = "style" -version = "0.0.1" +name = "stylo" +version = "0.4.0" authors = ["The Servo Project Developers"] license = "MPL-2.0" repository = "https://github.com/servo/stylo" edition = "2021" description = "The Stylo CSS engine" +readme = "../README.md" build = "build.rs" @@ -18,6 +19,7 @@ path = "lib.rs" doctest = false [features] +default = ["servo"] gecko = [ "bindgen", "malloc_size_of/gecko", @@ -31,15 +33,15 @@ gecko = [ "to_shmem/gecko", ] servo = [ - "arrayvec/use_union", "cssparser/serde", "encoding_rs", "malloc_size_of/servo", - "markup5ever", + "web_atoms", + "mime", "serde", "servo_arc/servo", "stylo_atoms", - "servo_config", + "style_config", "string_cache", "style_traits/servo", "url", @@ -48,6 +50,7 @@ servo = [ ] gecko_debug = [] gecko_refcount_logging = [] +nsstring = [] [dependencies] app_units = "0.7.8" @@ -55,9 +58,9 @@ arrayvec = "0.7" atomic_refcell = "0.1" bitflags = "2" byteorder = "1.0" -cssparser = "0.34" +cssparser = "0.35" derive_more = { version = "2", features = ["add", "add_assign", "deref", "deref_mut", "from"] } -dom = { path = "../../../dom/base/rust" } +dom = { version = "0.4", path = "../stylo_dom", package = "stylo_dom" } new_debug_unreachable = "1.0" encoding_rs = {version = "0.8", optional = true} euclid = "0.22" @@ -68,11 +71,11 @@ itertools = "0.14" 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 = { version = "0.4", path = "../malloc_size_of", package = "stylo_malloc_size_of" } +malloc_size_of_derive = "0.1" +web_atoms = { version = "0.1.3", 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 +84,23 @@ parking_lot = "0.12" precomputed-hash = "0.1.1" rayon = "1" rayon-core = "1" -selectors = { path = "../selectors" } +selectors = { version = "0.29.0", 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} +servo_arc = { version = "0.4.0", path = "../servo_arc" } +stylo_atoms = { version = "0.4", 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.4", 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"} -to_shmem = {path = "../to_shmem"} -to_shmem_derive = {path = "../to_shmem_derive"} -thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } +style_config = { version = "0.4", path = "../stylo_config", package = "stylo_config", optional = true } +style_derive = { version = "0.4", path = "../style_derive", package = "stylo_derive" } +style_traits = { version = "0.4", path = "../style_traits", package = "stylo_traits" } +to_shmem = { version = "0.2", path = "../to_shmem" } +to_shmem_derive = { version = "0.1", path = "../to_shmem_derive" } +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..9520810a98 100644 --- a/style/animation.rs +++ b/style/animation.rs @@ -25,7 +25,7 @@ use crate::style_resolver::StyleResolverForElement; use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue}; use crate::stylesheets::layer_rule::LayerOrder; use crate::values::animated::{Animate, Procedure}; -use crate::values::computed::{Time, TimingFunction}; +use crate::values::computed::TimingFunction; use crate::values::generics::easing::BeforeFlag; use crate::values::specified::TransitionBehavior; use crate::Atom; @@ -57,31 +57,6 @@ impl PropertyAnimation { self.from.id() } - fn from_property_declaration( - property_declaration: &PropertyDeclarationId, - timing_function: TimingFunction, - duration: Time, - old_style: &ComputedValues, - new_style: &ComputedValues, - ) -> Option { - // FIXME(emilio): Handle the case where old_style and new_style's writing mode differ. - let property_declaration = property_declaration.to_physical(new_style.writing_mode); - let from = AnimationValue::from_computed_values(property_declaration, old_style)?; - let to = AnimationValue::from_computed_values(property_declaration, new_style)?; - let duration = duration.seconds() as f64; - - if from == to || duration == 0.0 { - return None; - } - - Some(PropertyAnimation { - from, - to, - timing_function, - duration, - }) - } - /// The output of the timing function given the progress ration of this animation. fn timing_function_output(&self, progress: f64) -> f64 { let epsilon = 1. / (200. * self.duration); @@ -135,6 +110,11 @@ impl AnimationState { } } +enum IgnoreTransitions { + Canceled, + CanceledAndFinished, +} + /// This structure represents a keyframes animation current iteration state. /// /// If the iteration count is infinite, there's no other state, otherwise we @@ -762,6 +742,31 @@ pub struct Transition { } impl Transition { + fn new( + start_time: f64, + delay: f64, + duration: f64, + from: AnimationValue, + to: AnimationValue, + timing_function: &TimingFunction, + ) -> Self { + let property_animation = PropertyAnimation { + from: from.clone(), + to, + timing_function: timing_function.clone(), + duration, + }; + Self { + start_time, + delay, + property_animation, + state: AnimationState::Pending, + is_new: true, + reversing_adjusted_start_value: from, + reversing_shortening_factor: 1.0, + } + } + fn update_for_possibly_reversed_transition( &mut self, replaced_transition: &Transition, @@ -894,7 +899,7 @@ impl ElementAnimationSet { } } - if let Some(map) = self.get_value_map_for_active_transitions(now) { + if let Some(map) = self.get_value_map_for_transitions(now, IgnoreTransitions::Canceled) { for value in map.values() { value.set_in_style_for_servo(mutable_style); } @@ -1010,9 +1015,22 @@ impl ElementAnimationSet { self, ); - // Cancel any non-finished transitions that have properties which no longer transition. + // Cancel any non-finished transitions that have properties which no + // longer transition. + // + // Step 3 in https://drafts.csswg.org/css-transitions/#starting: + // > If the element has a running transition or completed transition for + // > the property, and there is not a matching transition-property value, + // > then implementations must cancel the running transition or remove the + // > completed transition from the set of completed transitions. + // + // TODO: This is happening here as opposed to in + // `start_transition_if_applicable` as an optimization, but maybe this + // code should be reworked to be more like the specification. for transition in self.transitions.iter_mut() { - if transition.state == AnimationState::Finished { + if transition.state == AnimationState::Finished + || transition.state == AnimationState::Canceled + { continue; } if transitioning_properties.contains(transition.property_animation.property_id()) { @@ -1032,86 +1050,192 @@ impl ElementAnimationSet { new_style: &Arc, ) { let style = new_style.get_ui(); - let allow_discrete = style.transition_behavior_mod(index) == TransitionBehavior::AllowDiscrete; + let allow_discrete = + style.transition_behavior_mod(index) == TransitionBehavior::AllowDiscrete; - if !property_declaration_id.is_animatable() - || (!allow_discrete && property_declaration_id.is_discrete_animatable()) - { + // FIXME(emilio): Handle the case where old_style and new_style's writing mode differ. + let Some(from) = AnimationValue::from_computed_values(*property_declaration_id, old_style) + else { return; - } + }; + let Some(to) = AnimationValue::from_computed_values(*property_declaration_id, new_style) + else { + return; + }; let timing_function = style.transition_timing_function_mod(index); - let duration = style.transition_duration_mod(index); + let duration = style.transition_duration_mod(index).seconds() as f64; let delay = style.transition_delay_mod(index).seconds() as f64; let now = context.current_time_for_animations; + let transitionable = property_declaration_id.is_animatable() + && (allow_discrete || !property_declaration_id.is_discrete_animatable()) + && (allow_discrete || from.interpolable_with(&to)); - // Only start a new transition if the style actually changes between - // the old style and the new style. - let property_animation = match PropertyAnimation::from_property_declaration( - property_declaration_id, - timing_function, - duration, - old_style, - new_style, - ) { - Some(property_animation) => property_animation, - None => return, - }; + let mut existing_transition = self.transitions.iter_mut().find(|transition| { + transition.property_animation.property_id() == *property_declaration_id + }); - // A property may have an animation type different than 'discrete', but still - // not be able to interpolate some values. In that case we would fall back to - // discrete interpolation, so we need to abort if `transition-behavior` doesn't - // allow discrete transitions. - if !allow_discrete && !property_animation.from.interpolable_with(&property_animation.to) { + // Step 1: + // > If all of the following are true: + // > - the element does not have a running transition for the property, + // > - the before-change style is different from the after-change style + // > for that property, and the values for the property are + // > transitionable, + // > - the element does not have a completed transition for the property + // > or the end value of the completed transition is different from the + // > after-change style for the property, + // > - there is a matching transition-property value, and + // > - the combined duration is greater than 0s, + // + // This function is only run if there is a matching transition-property + // value, so that check is skipped here. + let has_running_transition = existing_transition.as_ref().is_some_and(|transition| { + transition.state != AnimationState::Finished + && transition.state != AnimationState::Canceled + }); + let no_completed_transition_or_end_values_differ = existing_transition.as_ref().is_none_or(|transition| { + transition.state != AnimationState::Finished || transition.property_animation.to != to + }); + if !has_running_transition && + from != to && transitionable && + no_completed_transition_or_end_values_differ && + (duration + delay > 0.0) { + // > then implementations must remove the completed transition (if + // > present) from the set of completed transitions and start a + // > transition whose: + // > + // > - start time is the time of the style change event plus the matching transition delay, + // > - end time is the start time plus the matching transition duration, + // > - start value is the value of the transitioning property in the before-change style, + // > - end value is the value of the transitioning property in the after-change style, + // > - reversing-adjusted start value is the same as the start value, and + // > - reversing shortening factor is 1. + self.transitions.push(Transition::new( + now + delay, /* start_time */ + delay, + duration, + from, + to, + &timing_function, + )); + self.dirty = true; return; } - // Per [1], don't trigger a new transition if the end state for that - // transition is the same as that of a transition that's running or - // completed. We don't take into account any canceled animations. - // [1]: https://drafts.csswg.org/css-transitions/#starting - if self - .transitions - .iter() - .filter(|transition| transition.state != AnimationState::Canceled) - .any(|transition| transition.property_animation.to == property_animation.to) - { + // > Step 2: Otherwise, if the element has a completed transition for the + // > property and the end value of the completed transition is different + // > from the after-change style for the property, then implementations + // > must remove the completed transition from the set of completed + // > transitions. + // + // All completed transitions will be cleared from the `AnimationSet` in + // `process_animations_for_style in `matching.rs`. + + // > Step 3: If the element has a running transition or completed + // > transition for the property, and there is not a matching + // > transition-property value, then implementations must cancel the + // > running transition or remove the completed transition from the set + // > of completed transitions. + // + // - All completed transitions will be cleared cleared from the `AnimationSet` in + // `process_animations_for_style in `matching.rs`. + // - Transitions for properties that don't have a matching transition-property + // value will be canceled in `Self::update_transitions_for_new_style`. In addition, + // this method is only called for properties that do ahave a matching + // transition-property value. + + let Some(existing_transition) = existing_transition.as_mut() else { return; - } - - // We are going to start a new transition, but we might have to update - // it if we are replacing a reversed transition. - let reversing_adjusted_start_value = property_animation.from.clone(); - let mut new_transition = Transition { - start_time: now + delay, - delay, - property_animation, - state: AnimationState::Pending, - is_new: true, - reversing_adjusted_start_value, - reversing_shortening_factor: 1.0, }; - if let Some(old_transition) = self - .transitions - .iter_mut() - .filter(|transition| transition.state == AnimationState::Running) - .find(|transition| { - transition.property_animation.property_id() == *property_declaration_id - }) - { - // We always cancel any running transitions for the same property. - old_transition.state = AnimationState::Canceled; - new_transition.update_for_possibly_reversed_transition(old_transition, delay, now); - } + // > Step 4: If the element has a running transition for the property, + // > there is a matching transition-property value, and the end value of + // > the running transition is not equal to the value of the property in + // > the after-change style, then: + if has_running_transition && existing_transition.property_animation.to != to { + // > Step 4.1: If the current value of the property in the running transition is + // > equal to the value of the property in the after-change style, or + // > if these two values are not transitionable, then implementations + // > must cancel the running transition. + let current_value = existing_transition.calculate_value(now); + let transitionable_from_current_value = + transitionable && (allow_discrete || current_value.interpolable_with(&to)); + if current_value == to || !transitionable_from_current_value { + existing_transition.state = AnimationState::Canceled; + self.dirty = true; + return; + } - self.transitions.push(new_transition); - self.dirty = true; + // > Step 4.2: Otherwise, if the combined duration is less than or + // > equal to 0s, or if the current value of the property in the + // > running transition is not transitionable with the value of the + // > property in the after-change style, then implementations must + // > cancel the running transition. + if duration + delay <= 0.0 { + existing_transition.state = AnimationState::Canceled; + self.dirty = true; + return; + } + + // > Step 4.3: Otherwise, if the reversing-adjusted start value of the + // > running transition is the same as the value of the property in + // > the after-change style (see the section on reversing of + // > transitions for why these case exists), implementations must + // > cancel the running transition and start a new transition whose: + if existing_transition.reversing_adjusted_start_value == to { + existing_transition.state = AnimationState::Canceled; + + let mut transition = Transition::new( + now + delay, /* start_time */ + delay, + duration, + from, + to, + &timing_function, + ); + + // This function takes care of applying all of the modifications to the transition + // after "whose:" above. + transition.update_for_possibly_reversed_transition( + &existing_transition, + delay, + now, + ); + + self.transitions.push(transition); + self.dirty = true; + return; + } + + // > Step 4.4: Otherwise, implementations must cancel the running + // > transition and start a new transition whose: + // > - start time is the time of the style change event plus the matching transition delay, + // > - end time is the start time plus the matching transition duration, + // > - start value is the current value of the property in the running transition, + // > - end value is the value of the property in the after-change style, + // > - reversing-adjusted start value is the same as the start value, and + // > - reversing shortening factor is 1. + existing_transition.state = AnimationState::Canceled; + self.transitions.push(Transition::new( + now + delay, /* start_time */ + delay, + duration, + current_value, + to, + &timing_function, + )); + self.dirty = true; + } } /// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s - /// active transitions at the given time value. - pub fn get_value_map_for_active_transitions(&self, now: f64) -> Option { + /// transitions, ignoring those specified by the `ignore_transitions` + /// argument. + fn get_value_map_for_transitions( + &self, + now: f64, + ignore_transitions: IgnoreTransitions, + ) -> Option { if !self.has_active_transition() { return None; } @@ -1119,9 +1243,21 @@ impl ElementAnimationSet { let mut map = AnimationValueMap::with_capacity_and_hasher(self.transitions.len(), Default::default()); for transition in &self.transitions { - if transition.state == AnimationState::Canceled { - continue; + match ignore_transitions { + IgnoreTransitions::Canceled => { + if transition.state == AnimationState::Canceled { + continue; + } + }, + IgnoreTransitions::CanceledAndFinished => { + if transition.state == AnimationState::Canceled + || transition.state == AnimationState::Finished + { + continue; + } + }, } + let value = transition.calculate_value(now); map.insert(value.id().to_owned(), value); } @@ -1235,7 +1371,9 @@ impl DocumentAnimationSet { self.sets .read() .get(key) - .and_then(|set| set.get_value_map_for_active_transitions(time)) + .and_then(|set| { + set.get_value_map_for_transitions(time, IgnoreTransitions::CanceledAndFinished) + }) .map(|map| { let block = PropertyDeclarationBlock::from_animation_value_map(&map); Arc::new(shared_lock.wrap(block)) @@ -1260,10 +1398,12 @@ impl DocumentAnimationSet { let block = PropertyDeclarationBlock::from_animation_value_map(&map); Arc::new(shared_lock.wrap(block)) }); - let transitions = set.get_value_map_for_active_transitions(time).map(|map| { - let block = PropertyDeclarationBlock::from_animation_value_map(&map); - Arc::new(shared_lock.wrap(block)) - }); + let transitions = set + .get_value_map_for_transitions(time, IgnoreTransitions::CanceledAndFinished) + .map(|map| { + let block = PropertyDeclarationBlock::from_animation_value_map(&map); + Arc::new(shared_lock.wrap(block)) + }); AnimationDeclarations { animations, transitions, diff --git a/style/attr.rs b/style/attr.rs index 2121fe8619..74e01c326c 100644 --- a/style/attr.rs +++ b/style/attr.rs @@ -6,6 +6,7 @@ //! //! [attr]: https://dom.spec.whatwg.org/#interface-attr +use crate::shadow_parts::ShadowParts; use crate::color::{AbsoluteColor, parsing::parse_color_keyword}; use crate::properties::PropertyDeclarationBlock; use crate::shared_lock::Locked; @@ -72,6 +73,9 @@ pub enum AttrValue { String, #[ignore_malloc_size_of = "Arc"] Arc>, ), + + /// The value of an `exportparts` attribute. + ShadowParts(String, ShadowParts), } /// Shared implementation to parse an integer according to @@ -266,6 +270,11 @@ impl AttrValue { AttrValue::Dimension(string, parsed) } + pub fn from_shadow_parts(string: String) -> AttrValue { + let shadow_parts = ShadowParts::parse(&string); + AttrValue::ShadowParts(string, shadow_parts) + } + /// Assumes the `AttrValue` is a `TokenList` and returns its tokens /// /// ## Panics @@ -358,6 +367,22 @@ impl AttrValue { } } + /// Return the AttrValue as it's shadow-part representation. + /// + /// This corresponds to attribute values returned as `AttrValue::ShadowParts(_)` + /// by `VirtualMethods::parse_plain_attribute()`. + /// + /// ## Panics + /// + /// Panics if the `AttrValue` is not a shadow-part. + pub fn as_shadow_parts(&self) -> &ShadowParts { + if let AttrValue::ShadowParts(_, value) = &self { + value + } else { + panic!("Not a shadowpart attribute"); + } + } + pub fn eval_selector(&self, selector: &AttrSelectorOperation<&AtomString>) -> bool { // FIXME(SimonSapin) this can be more efficient by matching on `(self, selector)` variants // and doing Atom comparisons instead of string comparisons where possible, @@ -380,6 +405,7 @@ impl ::std::ops::Deref for AttrValue { AttrValue::Int(ref value, _) | AttrValue::ResolvedUrl(ref value, _) | AttrValue::Declaration(ref value, _) | + AttrValue::ShadowParts(ref value, _) | AttrValue::Dimension(ref value, _) => &value, AttrValue::Atom(ref value) => &value, } diff --git a/style/build.rs b/style/build.rs index 4b27edbe2c..2f12477133 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"] }; @@ -58,6 +58,12 @@ fn generate_properties(engine: &str) { .join("build.py"); let status = Command::new(&*PYTHON) + // `cargo publish` isn't happy with the `__pycache__` files that are created + // when we run the property generator. + // + // TODO(mrobinson): Is this happening because of how we run this script? It + // would be better to ensure are just placed in the output directory. + .env("PYTHONDONTWRITEBYTECODE", "1") .arg(&script) .arg(engine) .arg("style-crate") diff --git a/style/context.rs b/style/context.rs index e151967ca4..937fc4d72e 100644 --- a/style/context.rs +++ b/style/context.rs @@ -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/dom.rs b/style/dom.rs index b3a4951be2..4177021a36 100644 --- a/style/dom.rs +++ b/style/dom.rs @@ -14,7 +14,7 @@ use crate::context::UpdateAnimationsTasks; use crate::data::ElementData; use crate::media_queries::Device; use crate::properties::{AnimationDeclarations, ComputedValues, PropertyDeclarationBlock}; -use crate::selector_parser::{AttrValue, Lang, PseudoElement, SelectorImpl}; +use crate::selector_parser::{AttrValue, Lang, PseudoElement, RestyleDamage, SelectorImpl}; use crate::shared_lock::{Locked, SharedRwLock}; use crate::stylesheets::scope_rule::ImplicitScopeRoot; use crate::stylist::CascadeData; @@ -925,6 +925,11 @@ pub trait TElement: ) -> Option { None } + + /// Compute the damage incurred by the change from the `_old` to `_new`. + fn compute_layout_damage(_old: &ComputedValues, _new: &ComputedValues) -> RestyleDamage { + Default::default() + } } /// TNode and TElement aren't Send because we want to be careful and explicit diff --git a/style/lib.rs b/style/lib.rs index 0dff7117a9..9eb2b2a1d0 100644 --- a/style/lib.rs +++ b/style/lib.rs @@ -48,8 +48,7 @@ extern crate malloc_size_of; #[macro_use] extern crate malloc_size_of_derive; #[cfg(feature = "servo")] -#[macro_use] -extern crate markup5ever; +extern crate web_atoms; #[allow(unused_extern_crates)] #[macro_use] extern crate matches; @@ -159,13 +158,15 @@ pub use stylo_atoms::Atom; #[cfg(feature = "servo")] #[allow(missing_docs)] -pub type LocalName = crate::values::GenericAtomIdent; +pub type LocalName = crate::values::GenericAtomIdent; #[cfg(feature = "servo")] #[allow(missing_docs)] -pub type Namespace = crate::values::GenericAtomIdent; +pub type Namespace = crate::values::GenericAtomIdent; #[cfg(feature = "servo")] #[allow(missing_docs)] -pub type Prefix = crate::values::GenericAtomIdent; +pub type Prefix = crate::values::GenericAtomIdent; +#[cfg(feature = "servo")] +mod shadow_parts; pub use style_traits::arc_slice::ArcSlice; pub use style_traits::owned_slice::OwnedSlice; diff --git a/style/logical_geometry.rs b/style/logical_geometry.rs index 4b10d31e9c..623848badf 100644 --- a/style/logical_geometry.rs +++ b/style/logical_geometry.rs @@ -10,7 +10,6 @@ use euclid::num::Zero; use std::cmp::{max, min}; use std::fmt::{self, Debug, Error, Formatter}; use std::ops::{Add, Sub}; -use unicode_bidi as bidi; pub enum BlockFlowDirection { TopToBottom, @@ -345,18 +344,6 @@ impl WritingMode { } } - #[inline] - /// The default bidirectional embedding level for this writing mode. - /// - /// Returns bidi level 0 if the mode is LTR, or 1 otherwise. - pub fn to_bidi_level(&self) -> bidi::Level { - if self.is_bidi_ltr() { - bidi::Level::ltr() - } else { - bidi::Level::rtl() - } - } - #[inline] /// Is the text layout vertical? pub fn is_text_vertical(&self) -> bool { diff --git a/style/macros.rs b/style/macros.rs index eac54b9080..fdf3c30290 100644 --- a/style/macros.rs +++ b/style/macros.rs @@ -41,17 +41,17 @@ macro_rules! try_match_ident_ignore_ascii_case { #[cfg(feature = "servo")] macro_rules! local_name { ($s:tt) => { - $crate::values::GenericAtomIdent(markup5ever::local_name!($s)) + $crate::values::GenericAtomIdent(web_atoms::local_name!($s)) }; } #[cfg(feature = "servo")] macro_rules! ns { () => { - $crate::values::GenericAtomIdent(markup5ever::ns!()) + $crate::values::GenericAtomIdent(web_atoms::ns!()) }; ($s:tt) => { - $crate::values::GenericAtomIdent(markup5ever::ns!($s)) + $crate::values::GenericAtomIdent(web_atoms::ns!($s)) }; } diff --git a/style/matching.rs b/style/matching.rs index 0a9fe9fafb..42c604560a 100644 --- a/style/matching.rs +++ b/style/matching.rs @@ -605,7 +605,7 @@ trait PrivateMatchMethods: TElement { fn process_animations_for_pseudo( &self, context: &mut StyleContext, - old_styles: &mut ElementStyles, + old_styles: &ElementStyles, new_resolved_styles: &mut ResolvedElementStyles, pseudo_element: PseudoElement, ) { @@ -613,7 +613,7 @@ trait PrivateMatchMethods: TElement { use crate::dom::TDocument; let key = AnimationSetKey::new_for_pseudo(self.as_node().opaque(), pseudo_element.clone()); - let mut style = match new_resolved_styles.pseudos.get(&pseudo_element) { + let style = match new_resolved_styles.pseudos.get(&pseudo_element) { Some(style) => Arc::clone(style), None => { context @@ -624,11 +624,11 @@ trait PrivateMatchMethods: TElement { }, }; - let mut old_style = old_styles.pseudos.get(&pseudo_element).cloned(); + let old_style = old_styles.pseudos.get(&pseudo_element).cloned(); self.process_animations_for_style( context, - &mut old_style, - &mut style, + &old_style, + &style, Some(pseudo_element.clone()), ); @@ -687,8 +687,8 @@ trait PrivateMatchMethods: TElement { fn process_animations_for_style( &self, context: &mut StyleContext, - old_values: &mut Option>, - new_values: &mut Arc, + old_values: &Option>, + new_values: &Arc, pseudo_element: Option, ) -> bool { use crate::animation::{AnimationSetKey, AnimationState}; @@ -1164,7 +1164,7 @@ pub trait MatchMethods: TElement { pseudo: Option<&PseudoElement>, ) -> StyleDifference { debug_assert!(pseudo.map_or(true, |p| p.is_eager())); - RestyleDamage::compute_style_difference(old_values, new_values) + RestyleDamage::compute_style_difference::(old_values, new_values) } } 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 0000000000000000000000000000000000000000..9593025a4739374da2fde2966afdaffa1d0b8e05 GIT binary patch literal 75521 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

wOg(?)H>s{J*n4v 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%0A>{n;f&I{@ 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 literal 0 HcmV?d00001 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/data.py b/style/properties/data.py index b08e43572b..bba089e275 100644 --- a/style/properties/data.py +++ b/style/properties/data.py @@ -373,7 +373,7 @@ def __init__( ignored_when_colors_disabled=False, simple_vector_bindings=False, vector=False, - servo_restyle_damage="repaint", + servo_restyle_damage="rebuild_box", affects=None, ): Property.__init__( diff --git a/style/properties/longhands/background.mako.rs b/style/properties/longhands/background.mako.rs index 229b9e4e18..c5261110a0 100644 --- a/style/properties/longhands/background.mako.rs +++ b/style/properties/longhands/background.mako.rs @@ -14,6 +14,7 @@ ${helpers.predefined_type( ignored_when_colors_disabled=True, allow_quirks="Yes", flags="CAN_ANIMATE_ON_COMPOSITOR", + servo_restyle_damage="repaint", affects="paint", )} @@ -27,6 +28,7 @@ ${helpers.predefined_type( vector="True", animation_type="discrete", ignored_when_colors_disabled="True", + servo_restyle_damage="repaint", affects="paint", )} @@ -40,6 +42,7 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-" + axis, vector=True, vector_animation_type="repeatable_list", + servo_restyle_damage="repaint", affects="paint", )} % endfor @@ -53,6 +56,7 @@ ${helpers.predefined_type( animation_type="discrete", vector=True, spec="https://drafts.csswg.org/css-backgrounds/#the-background-repeat", + servo_restyle_damage="repaint", affects="paint", )} @@ -64,6 +68,7 @@ ${helpers.single_keyword( gecko_enum_prefix="StyleImageLayerAttachment", spec="https://drafts.csswg.org/css-backgrounds/#the-background-attachment", animation_type="discrete", + servo_restyle_damage="repaint", affects="paint", )} @@ -77,6 +82,7 @@ ${helpers.single_keyword( gecko_inexhaustive=True, spec="https://drafts.csswg.org/css-backgrounds/#the-background-clip", animation_type="discrete", + servo_restyle_damage="repaint", affects="paint", )} @@ -89,6 +95,7 @@ ${helpers.single_keyword( gecko_inexhaustive=True, spec="https://drafts.csswg.org/css-backgrounds/#the-background-origin", animation_type="discrete", + servo_restyle_damage="repaint", affects="paint", )} @@ -102,6 +109,7 @@ ${helpers.predefined_type( vector=True, vector_animation_type="repeatable_list", extra_prefixes="webkit", + servo_restyle_damage="repaint", affects="paint", )} diff --git a/style/properties/longhands/border.mako.rs b/style/properties/longhands/border.mako.rs index 5fd0e6573b..a956caf3d3 100644 --- a/style/properties/longhands/border.mako.rs +++ b/style/properties/longhands/border.mako.rs @@ -52,7 +52,7 @@ logical=is_logical, logical_group="border-width", allow_quirks="No" if is_logical else "Yes", - servo_restyle_damage="reflow rebuild_and_reflow_inline", + servo_restyle_damage="rebuild_box", affects="layout", )} % endfor @@ -112,8 +112,8 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", vector=False, animation_type="discrete", - boxed=engine == "servo", ignored_when_colors_disabled=True, + servo_restyle_damage="repaint", affects="paint", )} @@ -125,6 +125,7 @@ ${helpers.predefined_type( initial_specified_value="generics::rect::Rect::all(specified::NonNegativeLengthOrNumber::zero())", spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset", boxed=True, + servo_restyle_damage="repaint", affects="paint", )} @@ -136,6 +137,7 @@ ${helpers.predefined_type( initial_specified_value="specified::BorderImageRepeat::stretch()", animation_type="discrete", spec="https://drafts.csswg.org/css-backgrounds/#the-border-image-repeat", + servo_restyle_damage="repaint", affects="paint", )} @@ -147,6 +149,7 @@ ${helpers.predefined_type( initial_specified_value="specified::BorderImageWidth::all(specified::BorderImageSideWidth::one())", spec="https://drafts.csswg.org/css-backgrounds/#border-image-width", boxed=True, + servo_restyle_damage="repaint", affects="paint", )} @@ -158,5 +161,6 @@ ${helpers.predefined_type( initial_specified_value="specified::BorderImageSlice::hundred_percent()", spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice", boxed=True, + servo_restyle_damage="repaint", affects="paint", )} diff --git a/style/properties/longhands/box.mako.rs b/style/properties/longhands/box.mako.rs index 8490337cb8..4ef71416ea 100644 --- a/style/properties/longhands/box.mako.rs +++ b/style/properties/longhands/box.mako.rs @@ -13,7 +13,7 @@ ${helpers.predefined_type( initial_specified_value="specified::Display::inline()", animation_type="discrete", spec="https://drafts.csswg.org/css-display/#propdef-display", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -49,7 +49,7 @@ ${helpers.predefined_type( initial_specified_value="specified::PositionProperty::Static", animation_type="discrete", spec="https://drafts.csswg.org/css-position/#position-property", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -86,7 +86,7 @@ ${helpers.predefined_type( engines="gecko servo", animation_type="discrete", spec="https://drafts.csswg.org/css-box/#propdef-float", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -97,7 +97,7 @@ ${helpers.predefined_type( engines="gecko servo", animation_type="discrete", spec="https://drafts.csswg.org/css2/#propdef-clear", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -107,7 +107,7 @@ ${helpers.predefined_type( "computed::VerticalAlign::baseline()", engines="gecko servo", spec="https://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align", - servo_restyle_damage = "reflow", + servo_restyle_damage = "rebuild_box", affects="layout", )} @@ -118,7 +118,7 @@ ${helpers.predefined_type( engines="gecko servo", animation_type="discrete", spec="https://drafts.csswg.org/css-inline-3/#baseline-source", - servo_restyle_damage = "reflow", + servo_restyle_damage = "rebuild_box", affects="layout", )} @@ -161,7 +161,7 @@ ${helpers.single_keyword( logical=logical, animation_type="discrete", spec="https://drafts.csswg.org/css-overflow-3/#propdef-{}".format(full_name), - servo_restyle_damage = "reflow", + servo_restyle_damage = "rebuild_box", affects="layout", )} % endfor @@ -188,7 +188,7 @@ ${helpers.predefined_type( extra_prefixes=transform_extra_prefixes, flags="CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.csswg.org/css-transforms/#propdef-transform", - servo_restyle_damage="reflow_out_of_flow", + servo_restyle_damage="recalculate_overflow", affects="overflow", )} @@ -200,7 +200,7 @@ ${helpers.predefined_type( boxed=True, flags="CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms", - servo_restyle_damage = "reflow_out_of_flow", + servo_restyle_damage = "recalculate_overflow", affects="overflow", )} @@ -212,7 +212,7 @@ ${helpers.predefined_type( boxed=True, flags="CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms", - servo_restyle_damage = "reflow_out_of_flow", + servo_restyle_damage = "recalculate_overflow", affects="overflow", )} @@ -224,7 +224,7 @@ ${helpers.predefined_type( boxed=True, flags="CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms", - servo_restyle_damage="reflow_out_of_flow", + servo_restyle_damage="recalculate_overflow", affects="overflow", )} @@ -237,7 +237,7 @@ ${helpers.predefined_type( servo_pref="layout.unimplemented", flags="CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.fxtf.org/motion-1/#offset-path-property", - servo_restyle_damage="reflow_out_of_flow", + servo_restyle_damage="rebuild_box", affects="overflow", )} @@ -249,7 +249,7 @@ ${helpers.predefined_type( engines="gecko", flags="CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.fxtf.org/motion-1/#offset-distance-property", - servo_restyle_damage="reflow_out_of_flow", + servo_restyle_damage="rebuild_box", affects="overflow", )} @@ -261,7 +261,7 @@ ${helpers.predefined_type( engines="gecko", flags="CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.fxtf.org/motion-1/#offset-rotate-property", - servo_restyle_damage="reflow_out_of_flow", + servo_restyle_damage="rebuild_box", affects="overflow", )} @@ -273,7 +273,7 @@ ${helpers.predefined_type( engines="gecko", flags="CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.fxtf.org/motion-1/#offset-anchor-property", - servo_restyle_damage="reflow_out_of_flow", + servo_restyle_damage="rebuild_box", boxed=True, affects="overflow", )} @@ -286,7 +286,7 @@ ${helpers.predefined_type( engines="gecko", flags="CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.fxtf.org/motion-1/#offset-position-property", - servo_restyle_damage="reflow_out_of_flow", + servo_restyle_damage="rebuild_box", boxed=True, affects="overflow", )} @@ -358,6 +358,7 @@ ${helpers.single_keyword( gecko_enum_prefix="StyleIsolation", animation_type="discrete", affects="paint", + servo_restyle_damage="repaint", )} ${helpers.predefined_type( @@ -411,7 +412,7 @@ ${helpers.predefined_type( gecko_ffi_name="mChildPerspective", spec="https://drafts.csswg.org/css-transforms/#perspective", extra_prefixes=transform_extra_prefixes, - servo_restyle_damage = "reflow_out_of_flow", + servo_restyle_damage = "recalculate_overflow", affects="overflow", )} @@ -423,7 +424,7 @@ ${helpers.predefined_type( boxed=True, extra_prefixes=transform_extra_prefixes, spec="https://drafts.csswg.org/css-transforms-2/#perspective-origin-property", - servo_restyle_damage="reflow_out_of_flow", + servo_restyle_damage="recalculate_overflow", affects="overflow", )} @@ -435,6 +436,7 @@ ${helpers.single_keyword( spec="https://drafts.csswg.org/css-transforms/#backface-visibility-property", extra_prefixes=transform_extra_prefixes, animation_type="discrete", + servo_restyle_damage="repaint", affects="paint", )} @@ -456,7 +458,7 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-transforms-2/#transform-style-property", extra_prefixes=transform_extra_prefixes, animation_type="discrete", - servo_restyle_damage = "reflow_out_of_flow", + servo_restyle_damage = "recalculate_overflow", affects="overflow", )} @@ -469,7 +471,7 @@ ${helpers.predefined_type( gecko_ffi_name="mTransformOrigin", boxed=True, spec="https://drafts.csswg.org/css-transforms/#transform-origin-property", - servo_restyle_damage="reflow_out_of_flow", + servo_restyle_damage="recalculate_overflow", affects="overflow", )} diff --git a/style/properties/longhands/column.mako.rs b/style/properties/longhands/column.mako.rs index d1452fcc0f..50a544f715 100644 --- a/style/properties/longhands/column.mako.rs +++ b/style/properties/longhands/column.mako.rs @@ -12,7 +12,7 @@ ${helpers.predefined_type( initial_specified_value="specified::length::NonNegativeLengthOrAuto::auto()", servo_pref="layout.columns.enabled", spec="https://drafts.csswg.org/css-multicol/#propdef-column-width", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -24,7 +24,7 @@ ${helpers.predefined_type( initial_specified_value="specified::ColumnCount::Auto", servo_pref="layout.columns.enabled", spec="https://drafts.csswg.org/css-multicol/#propdef-column-count", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} diff --git a/style/properties/longhands/counters.mako.rs b/style/properties/longhands/counters.mako.rs index 85e479939e..d52f48533d 100644 --- a/style/properties/longhands/counters.mako.rs +++ b/style/properties/longhands/counters.mako.rs @@ -12,7 +12,7 @@ ${helpers.predefined_type( initial_specified_value="specified::Content::normal()", animation_type="discrete", spec="https://drafts.csswg.org/css-content/#propdef-content", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -24,7 +24,7 @@ ${helpers.predefined_type( initial_value="Default::default()", animation_type="discrete", spec="https://drafts.csswg.org/css-lists/#propdef-counter-increment", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -36,7 +36,7 @@ ${helpers.predefined_type( initial_value="Default::default()", animation_type="discrete", spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -47,6 +47,6 @@ ${helpers.predefined_type( initial_value="Default::default()", animation_type="discrete", spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-set", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} diff --git a/style/properties/longhands/effects.mako.rs b/style/properties/longhands/effects.mako.rs index 90d89e9cbc..16622eedb1 100644 --- a/style/properties/longhands/effects.mako.rs +++ b/style/properties/longhands/effects.mako.rs @@ -11,7 +11,7 @@ ${helpers.predefined_type( engines="gecko servo", flags="CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.csswg.org/css-color/#transparency", - servo_restyle_damage = "reflow_out_of_flow", + servo_restyle_damage="repaint", affects="paint", )} @@ -53,6 +53,7 @@ ${helpers.predefined_type( extra_prefixes="webkit", spec="https://drafts.fxtf.org/filters/#propdef-filter", affects="overflow", + servo_restyle_damage="repaint", )} ${helpers.predefined_type( @@ -81,4 +82,5 @@ ${helpers.single_keyword( animation_type="discrete", spec="https://drafts.fxtf.org/compositing/#propdef-mix-blend-mode", affects="paint", + servo_restyle_damage="repaint", )} diff --git a/style/properties/longhands/font.mako.rs b/style/properties/longhands/font.mako.rs index 74426ac61c..ef4c9bff3f 100644 --- a/style/properties/longhands/font.mako.rs +++ b/style/properties/longhands/font.mako.rs @@ -13,7 +13,7 @@ ${helpers.predefined_type( animation_type="discrete", spec="https://drafts.csswg.org/css-fonts/#propdef-font-family", gecko_ffi_name="mFont.family", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -25,7 +25,7 @@ ${helpers.predefined_type( initial_specified_value="specified::FontStyle::normal()", spec="https://drafts.csswg.org/css-fonts/#propdef-font-style", gecko_ffi_name="mFont.style", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -45,7 +45,7 @@ ${helpers.single_keyword( spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-caps", custom_consts=font_variant_caps_custom_consts, animation_type="discrete", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -57,7 +57,7 @@ ${helpers.predefined_type( initial_specified_value="specified::FontWeight::normal()", gecko_ffi_name="mFont.weight", spec="https://drafts.csswg.org/css-fonts/#propdef-font-weight", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -69,7 +69,7 @@ ${helpers.predefined_type( initial_specified_value="specified::FontSize::medium()", allow_quirks="Yes", spec="https://drafts.csswg.org/css-fonts/#propdef-font-size", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -140,7 +140,7 @@ ${helpers.predefined_type( initial_specified_value="specified::FontStretch::normal()", gecko_ffi_name="mFont.stretch", spec="https://drafts.csswg.org/css-fonts/#propdef-font-stretch", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -359,7 +359,7 @@ ${helpers.predefined_type( "computed::LineHeight::normal()", engines="gecko servo", spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height", - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} diff --git a/style/properties/longhands/inherited_box.mako.rs b/style/properties/longhands/inherited_box.mako.rs index b1961ade29..37a88c458f 100644 --- a/style/properties/longhands/inherited_box.mako.rs +++ b/style/properties/longhands/inherited_box.mako.rs @@ -25,7 +25,7 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-writing-modes/#propdef-writing-mode", servo_pref="layout.writing-mode.enabled", animation_type="none", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -36,7 +36,7 @@ ${helpers.single_keyword( animation_type="none", spec="https://drafts.csswg.org/css-writing-modes/#propdef-direction", gecko_enum_prefix="StyleDirection", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} diff --git a/style/properties/longhands/inherited_table.mako.rs b/style/properties/longhands/inherited_table.mako.rs index a242f288f5..3d9595bceb 100644 --- a/style/properties/longhands/inherited_table.mako.rs +++ b/style/properties/longhands/inherited_table.mako.rs @@ -11,7 +11,7 @@ ${helpers.single_keyword( gecko_enum_prefix="StyleBorderCollapse", animation_type="discrete", spec="https://drafts.csswg.org/css-tables/#propdef-border-collapse", - servo_restyle_damage = "reflow", + servo_restyle_damage = "rebuild_box", affects="layout", )} @@ -22,7 +22,7 @@ ${helpers.single_keyword( gecko_enum_prefix="StyleEmptyCells", animation_type="discrete", spec="https://drafts.csswg.org/css-tables/#propdef-empty-cells", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="paint", )} @@ -33,7 +33,7 @@ ${helpers.predefined_type( engines="gecko servo", animation_type="discrete", spec="https://drafts.csswg.org/css-tables/#propdef-caption-side", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -44,6 +44,6 @@ ${helpers.predefined_type( engines="gecko servo", boxed=True, spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing", - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} diff --git a/style/properties/longhands/inherited_text.mako.rs b/style/properties/longhands/inherited_text.mako.rs index 81bf34f361..b040715da0 100644 --- a/style/properties/longhands/inherited_text.mako.rs +++ b/style/properties/longhands/inherited_text.mako.rs @@ -11,6 +11,7 @@ ${helpers.predefined_type( engines="gecko servo", ignored_when_colors_disabled="True", spec="https://drafts.csswg.org/css-color/#color", + servo_restyle_damage="repaint", affects="paint", )} @@ -23,7 +24,7 @@ ${helpers.predefined_type( engines="gecko servo", animation_type="discrete", spec="https://drafts.csswg.org/css-text/#propdef-text-transform", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -57,7 +58,7 @@ ${helpers.predefined_type( "computed::TextIndent::zero()", engines="gecko servo", spec="https://drafts.csswg.org/css-text/#propdef-text-indent", - servo_restyle_damage = "reflow", + servo_restyle_damage = "rebuild_box", affects="layout", )} @@ -71,7 +72,7 @@ ${helpers.predefined_type( animation_type="discrete", spec="https://drafts.csswg.org/css-text/#propdef-overflow-wrap", aliases="word-wrap", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -82,7 +83,7 @@ ${helpers.predefined_type( engines="gecko servo", animation_type="discrete", spec="https://drafts.csswg.org/css-text/#propdef-word-break", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -93,7 +94,7 @@ ${helpers.predefined_type( engines="gecko servo", animation_type="discrete", spec="https://drafts.csswg.org/css-text/#propdef-text-justify", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -115,7 +116,7 @@ ${helpers.predefined_type( engines="gecko servo", animation_type="discrete", spec="https://drafts.csswg.org/css-text/#propdef-text-align", - servo_restyle_damage = "reflow", + servo_restyle_damage = "rebuild_box", affects="layout", )} @@ -125,7 +126,7 @@ ${helpers.predefined_type( "computed::LetterSpacing::normal()", engines="gecko servo", spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -135,7 +136,7 @@ ${helpers.predefined_type( "computed::WordSpacing::zero()", engines="gecko servo", spec="https://drafts.csswg.org/css-text/#propdef-word-spacing", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -149,7 +150,7 @@ ${helpers.single_keyword( gecko_enum_prefix="StyleWhiteSpaceCollapse", animation_type="discrete", spec="https://drafts.csswg.org/css-text-4/#propdef-white-space-collapse", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -296,7 +297,7 @@ ${helpers.single_keyword( gecko_enum_prefix="StyleTextRendering", animation_type="discrete", spec="https://svgwg.org/svg2-draft/painting.html#TextRenderingProperty", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -383,7 +384,7 @@ ${helpers.single_keyword( gecko_enum_prefix="StyleTextWrapMode", animation_type="discrete", spec="https://drafts.csswg.org/css-text-4/#propdef-text-wrap-mode", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} diff --git a/style/properties/longhands/inherited_ui.mako.rs b/style/properties/longhands/inherited_ui.mako.rs index 9adb260960..a0a2fc8e38 100644 --- a/style/properties/longhands/inherited_ui.mako.rs +++ b/style/properties/longhands/inherited_ui.mako.rs @@ -12,6 +12,7 @@ ${helpers.predefined_type( initial_specified_value="specified::Cursor::auto()", animation_type="discrete", spec="https://drafts.csswg.org/css-ui/#cursor", + servo_restyle_damage="repaint", affects="paint", )} @@ -22,6 +23,7 @@ ${helpers.predefined_type( engines="gecko servo", animation_type="discrete", spec="https://svgwg.org/svg2-draft/interact.html#PointerEventsProperty", + servo_restyle_damage="repaint", affects="paint", )} diff --git a/style/properties/longhands/list.mako.rs b/style/properties/longhands/list.mako.rs index 603b3b09d5..69c3bf1c7a 100644 --- a/style/properties/longhands/list.mako.rs +++ b/style/properties/longhands/list.mako.rs @@ -11,7 +11,7 @@ ${helpers.single_keyword( gecko_enum_prefix="StyleListStylePosition", animation_type="discrete", spec="https://drafts.csswg.org/css-lists/#propdef-list-style-position", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -33,7 +33,7 @@ ${helpers.single_keyword( engines="servo", animation_type="discrete", spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} % endif @@ -46,7 +46,7 @@ ${helpers.single_keyword( initial_specified_value="specified::ListStyleType::disc()", animation_type="discrete", spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} % endif @@ -59,8 +59,7 @@ ${helpers.predefined_type( initial_specified_value="specified::Image::None", animation_type="discrete", spec="https://drafts.csswg.org/css-lists/#propdef-list-style-image", - boxed=engine == "servo", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -71,6 +70,6 @@ ${helpers.predefined_type( engines="gecko servo", animation_type="discrete", spec="https://drafts.csswg.org/css-content/#propdef-quotes", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} diff --git a/style/properties/longhands/margin.mako.rs b/style/properties/longhands/margin.mako.rs index f063658ce8..853d8a710b 100644 --- a/style/properties/longhands/margin.mako.rs +++ b/style/properties/longhands/margin.mako.rs @@ -23,7 +23,7 @@ gecko_ffi_name="mMargin.{}".format(index), spec=spec, rule_types_allowed=(DEFAULT_RULES if side[1] else DEFAULT_RULES_AND_PAGE) | POSITION_TRY_RULE, - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} % endfor diff --git a/style/properties/longhands/outline.mako.rs b/style/properties/longhands/outline.mako.rs index 6416481f88..f1f3e103b6 100644 --- a/style/properties/longhands/outline.mako.rs +++ b/style/properties/longhands/outline.mako.rs @@ -12,6 +12,7 @@ ${helpers.predefined_type( initial_specified_value="specified::Color::currentcolor()", ignored_when_colors_disabled=True, spec="https://drafts.csswg.org/css-ui/#propdef-outline-color", + servo_restyle_damage="repaint", affects="paint", )} @@ -23,6 +24,7 @@ ${helpers.predefined_type( initial_specified_value="specified::OutlineStyle::none()", animation_type="discrete", spec="https://drafts.csswg.org/css-ui/#propdef-outline-style", + servo_restyle_damage="repaint", affects="overflow", )} @@ -33,6 +35,7 @@ ${helpers.predefined_type( engines="gecko servo", initial_specified_value="specified::BorderSideWidth::medium()", spec="https://drafts.csswg.org/css-ui/#propdef-outline-width", + servo_restyle_damage="repaint", affects="overflow", )} @@ -42,5 +45,6 @@ ${helpers.predefined_type( "crate::values::computed::Length::new(0.)", engines="gecko servo", spec="https://drafts.csswg.org/css-ui/#propdef-outline-offset", + servo_restyle_damage="repaint", affects="overflow", )} diff --git a/style/properties/longhands/padding.mako.rs b/style/properties/longhands/padding.mako.rs index 2b65264b0f..98d486aa5e 100644 --- a/style/properties/longhands/padding.mako.rs +++ b/style/properties/longhands/padding.mako.rs @@ -22,7 +22,7 @@ spec=spec, gecko_ffi_name="mPadding.{}".format(index), allow_quirks="No" if side[1] else "Yes", - servo_restyle_damage="reflow rebuild_and_reflow_inline", + servo_restyle_damage="rebuild_box", affects="layout", )} % endfor diff --git a/style/properties/longhands/position.mako.rs b/style/properties/longhands/position.mako.rs index fc13442228..f91f97ccb7 100644 --- a/style/properties/longhands/position.mako.rs +++ b/style/properties/longhands/position.mako.rs @@ -16,7 +16,7 @@ allow_quirks="Yes", rule_types_allowed=DEFAULT_RULES_AND_POSITION_TRY, gecko_ffi_name="mOffset.{}".format(index), - servo_restyle_damage="reflow_out_of_flow", + servo_restyle_damage="rebuild_box", logical_group="inset", affects="layout", )} @@ -43,6 +43,7 @@ ${helpers.predefined_type( engines="gecko servo", spec="https://www.w3.org/TR/CSS2/visuren.html#z-index", affects="paint", + servo_restyle_damage="rebuild_stacking_context", )} // CSS Flexible Box Layout Module Level 1 @@ -56,7 +57,7 @@ ${helpers.single_keyword( spec="https://drafts.csswg.org/css-flexbox/#flex-direction-property", extra_prefixes="webkit", animation_type="discrete", - servo_restyle_damage = "reflow", + servo_restyle_damage = "rebuild_box", gecko_enum_prefix = "StyleFlexDirection", affects="layout", )} @@ -68,7 +69,7 @@ ${helpers.single_keyword( spec="https://drafts.csswg.org/css-flexbox/#flex-wrap-property", extra_prefixes="webkit", animation_type="discrete", - servo_restyle_damage = "reflow", + servo_restyle_damage = "rebuild_box", gecko_enum_prefix = "StyleFlexWrap", affects="layout", )} @@ -81,7 +82,7 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-align/#propdef-justify-content", extra_prefixes="webkit", animation_type="discrete", - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -93,7 +94,7 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-align/#propdef-align-content", extra_prefixes="webkit", animation_type="discrete", - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -105,7 +106,7 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-align/#propdef-align-items", extra_prefixes="webkit", animation_type="discrete", - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -127,7 +128,7 @@ ${helpers.predefined_type( engines="gecko servo", spec="https://drafts.csswg.org/css-flexbox/#flex-grow-property", extra_prefixes="webkit", - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -138,7 +139,7 @@ ${helpers.predefined_type( engines="gecko servo", spec="https://drafts.csswg.org/css-flexbox/#flex-shrink-property", extra_prefixes="webkit", - servo_restyle_damage = "reflow", + servo_restyle_damage = "rebuild_box", affects="layout", )} @@ -173,7 +174,7 @@ ${helpers.predefined_type( engines="gecko servo", extra_prefixes="webkit", spec="https://drafts.csswg.org/css-flexbox/#order-property", - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -184,7 +185,7 @@ ${helpers.predefined_type( engines="gecko servo", spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property", extra_prefixes="webkit", - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", boxed=True, affects="layout", )} @@ -206,7 +207,7 @@ ${helpers.predefined_type( allow_quirks="No" if logical else "Yes", spec=spec % size, rule_types_allowed=DEFAULT_RULES_AND_POSITION_TRY, - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} // min-width, min-height, min-block-size, min-inline-size @@ -220,7 +221,7 @@ ${helpers.predefined_type( allow_quirks="No" if logical else "Yes", spec=spec % size, rule_types_allowed=DEFAULT_RULES_AND_POSITION_TRY, - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} ${helpers.predefined_type( @@ -233,7 +234,7 @@ ${helpers.predefined_type( allow_quirks="No" if logical else "Yes", spec=spec % size, rule_types_allowed=DEFAULT_RULES_AND_POSITION_TRY, - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} % endfor @@ -308,7 +309,7 @@ ${helpers.single_keyword( gecko_enum_prefix="StyleBoxSizing", custom_consts={ "content-box": "Content", "border-box": "Border" }, animation_type="discrete", - servo_restyle_damage = "reflow", + servo_restyle_damage = "rebuild_box", affects="layout", )} @@ -409,7 +410,7 @@ ${helpers.predefined_type( engines="gecko servo", aliases="grid-column-gap", spec="https://drafts.csswg.org/css-align-3/#propdef-column-gap", - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -421,7 +422,7 @@ ${helpers.predefined_type( engines="gecko servo", aliases="grid-row-gap", spec="https://drafts.csswg.org/css-align-3/#propdef-row-gap", - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -431,7 +432,7 @@ ${helpers.predefined_type( "computed::AspectRatio::auto()", engines="gecko servo", spec="https://drafts.csswg.org/css-sizing-4/#aspect-ratio", - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} diff --git a/style/properties/longhands/svg.mako.rs b/style/properties/longhands/svg.mako.rs index 7759118985..1e077d2f20 100644 --- a/style/properties/longhands/svg.mako.rs +++ b/style/properties/longhands/svg.mako.rs @@ -83,6 +83,7 @@ ${helpers.predefined_type( extra_prefixes="webkit", spec="https://drafts.fxtf.org/css-masking-1/#propdef-clip-path", affects="paint", + servo_restyle_damage="repaint", )} ${helpers.single_keyword( diff --git a/style/properties/longhands/table.mako.rs b/style/properties/longhands/table.mako.rs index 8b02d6f825..43dd65c33f 100644 --- a/style/properties/longhands/table.mako.rs +++ b/style/properties/longhands/table.mako.rs @@ -12,7 +12,7 @@ ${helpers.single_keyword( animation_type="discrete", gecko_enum_prefix="StyleTableLayout", spec="https://drafts.csswg.org/css-tables/#propdef-table-layout", - servo_restyle_damage="reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} diff --git a/style/properties/longhands/text.mako.rs b/style/properties/longhands/text.mako.rs index a0054b77c4..eb9cb21d6a 100644 --- a/style/properties/longhands/text.mako.rs +++ b/style/properties/longhands/text.mako.rs @@ -13,7 +13,7 @@ ${helpers.predefined_type( animation_type="discrete", boxed=True, spec="https://drafts.csswg.org/css-ui/#propdef-text-overflow", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="paint", )} @@ -24,7 +24,7 @@ ${helpers.single_keyword( gecko_enum_prefix="StyleUnicodeBidi", animation_type="none", spec="https://drafts.csswg.org/css-writing-modes/#propdef-unicode-bidi", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="layout", )} @@ -36,7 +36,7 @@ ${helpers.predefined_type( initial_specified_value="specified::TextDecorationLine::none()", animation_type="discrete", spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-line", - servo_restyle_damage="rebuild_and_reflow", + servo_restyle_damage="rebuild_box", affects="overflow", )} diff --git a/style/properties/longhands/ui.mako.rs b/style/properties/longhands/ui.mako.rs index 4579f33f3e..19f79fcbbe 100644 --- a/style/properties/longhands/ui.mako.rs +++ b/style/properties/longhands/ui.mako.rs @@ -188,6 +188,7 @@ ${helpers.predefined_type( vector=True, need_index=True, animation_type="none", + servo_pref="layout.css.transition-behavior.enabled", spec="https://drafts.csswg.org/css-transitions-2/#transition-behavior-property", affects="", )} diff --git a/style/properties/properties.mako.rs b/style/properties/properties.mako.rs index e18840434f..040a65da20 100644 --- a/style/properties/properties.mako.rs +++ b/style/properties/properties.mako.rs @@ -2224,40 +2224,6 @@ impl ComputedValuesInner { box_.transform_style } } - - /// Whether given this transform value, the compositor would require a - /// layer. - pub fn transform_requires_layer(&self) -> bool { - use crate::values::generics::transform::TransformOperation; - // Check if the transform matrix is 2D or 3D - for transform in &*self.get_box().transform.0 { - match *transform { - TransformOperation::Perspective(..) => { - return true; - } - TransformOperation::Matrix3D(m) => { - // See http://dev.w3.org/csswg/css-transforms/#2d-matrix - if m.m31 != 0.0 || m.m32 != 0.0 || - m.m13 != 0.0 || m.m23 != 0.0 || - m.m43 != 0.0 || m.m14 != 0.0 || - m.m24 != 0.0 || m.m34 != 0.0 || - m.m33 != 1.0 || m.m44 != 1.0 { - return true; - } - } - TransformOperation::Translate3D(_, _, z) | - TransformOperation::TranslateZ(z) => { - if z.px() != 0. { - return true; - } - } - _ => {} - } - } - - // Neither perspective nor transform present - false - } } /// A reference to a style struct of the parent, or our own style struct. @@ -2996,7 +2962,7 @@ const_assert!(std::mem::size_of::( % endfor % if engine == "servo": -% for effect_name in ["repaint", "reflow_out_of_flow", "reflow", "rebuild_and_reflow_inline", "rebuild_and_reflow"]: +% for effect_name in ["repaint", "recalculate_overflow", "rebuild_stacking_context", "rebuild_box"]: macro_rules! restyle_damage_${effect_name} { ($old: ident, $new: ident, $damage: ident, [ $($effect:expr),* ]) => ({ restyle_damage_${effect_name}!($old, $new, $damage, [$($effect),*], false) diff --git a/style/servo/media_queries.rs b/style/servo/media_queries.rs index 5707f6b1ba..b57199b093 100644 --- a/style/servo/media_queries.rs +++ b/style/servo/media_queries.rs @@ -252,6 +252,11 @@ impl Device { (AU_PER_PX as f32 / self.device_pixel_ratio.0) as i32 } + /// Returns the device pixel ratio, ignoring the full zoom factor. + pub fn device_pixel_ratio_ignoring_full_zoom(&self) -> Scale { + self.device_pixel_ratio + } + /// Returns the device pixel ratio. pub fn device_pixel_ratio(&self) -> Scale { self.device_pixel_ratio diff --git a/style/servo/restyle_damage.rs b/style/servo/restyle_damage.rs index 6355959805..054b55cc5c 100644 --- a/style/servo/restyle_damage.rs +++ b/style/servo/restyle_damage.rs @@ -5,55 +5,45 @@ //! The restyle damage is a hint that tells layout which kind of operations may //! be needed in presence of incremental style changes. -use crate::computed_values::display::T as Display; +use bitflags::Flags; + +use crate::computed_values::isolation::T as Isolation; +use crate::computed_values::mix_blend_mode::T as MixBlendMode; +use crate::computed_values::transform_style::T as TransformStyle; +use crate::dom::TElement; use crate::matching::{StyleChange, StyleDifference}; -use crate::properties::ComputedValues; +use crate::properties::{style_structs, ComputedValues}; +use crate::values::computed::basic_shape::ClipPath; +use crate::values::computed::Perspective; +use crate::values::generics::transform::{GenericRotate, GenericScale, GenericTranslate}; use std::fmt; bitflags! { - /// Individual layout actions that may be necessary after restyling. + /// Major phases of layout that need to be run due to the damage to a node during restyling. In + /// addition to the 4 bytes used for that, the rest of the `u16` is exposed as an extension point + /// for users of the crate to add their own custom types of damage that correspond to the + /// layout system they are implementing. #[derive(Clone, Copy, Debug, Eq, PartialEq)] - pub struct ServoRestyleDamage: u8 { + pub struct ServoRestyleDamage: u16 { /// Repaint the node itself. /// - /// Currently unused; need to decide how this propagates. - const REPAINT = 0x01; - - /// The stacking-context-relative position of this node or its - /// descendants has changed. - /// /// Propagates both up and down the flow tree. - const REPOSITION = 0x02; - - /// Recompute the overflow regions (bounding box of object and all descendants). - /// - /// Propagates down the flow tree because the computation is bottom-up. - const STORE_OVERFLOW = 0x04; + const REPAINT = 0b0001; - /// Recompute intrinsic inline_sizes (minimum and preferred). + /// Rebuilds the stacking contexts. /// - /// Propagates down the flow tree because the computation is. - /// bottom-up. - const BUBBLE_ISIZES = 0x08; - - /// Recompute actual inline-sizes and block-sizes, only taking - /// out-of-flow children into account. - /// - /// Propagates up the flow tree because the computation is top-down. - const REFLOW_OUT_OF_FLOW = 0x10; + /// Propagates both up and down the flow tree. + const REBUILD_STACKING_CONTEXT = 0b0011; - /// Recompute actual inline_sizes and block_sizes. + /// Recalculates the scrollable overflow. /// - /// Propagates up the flow tree because the computation is top-down. - const REFLOW = 0x20; + /// Propagates both up and down the flow tree. + const RECALCULATE_OVERFLOW = 0b0111; - /// Re-resolve generated content. + /// Any other type of damage, which requires running layout again. /// - /// Propagates up the flow tree because the computation is inorder. - const RESOLVE_GENERATED_CONTENT = 0x40; - - /// The entire flow needs to be reconstructed. - const RECONSTRUCT_FLOW = 0x80; + /// Propagates both up and down the flow tree. + const RELAYOUT = 0b1111; } } @@ -62,91 +52,35 @@ malloc_size_of_is_0!(ServoRestyleDamage); impl ServoRestyleDamage { /// Compute the `StyleDifference` (including the appropriate restyle damage) /// for a given style change between `old` and `new`. - pub fn compute_style_difference(old: &ComputedValues, new: &ComputedValues) -> StyleDifference { - let damage = compute_damage(old, new); - let change = if damage.is_empty() { - StyleChange::Unchanged - } else { - // FIXME(emilio): Differentiate between reset and inherited - // properties here, and set `reset_only` appropriately so the - // optimization to skip the cascade in those cases applies. - StyleChange::Changed { reset_only: false } - }; - StyleDifference { damage, change } - } + pub fn compute_style_difference( + old: &ComputedValues, + new: &ComputedValues, + ) -> StyleDifference { + let mut damage = compute_damage(old, new); + if damage.is_empty() { + return StyleDifference { + damage, + change: StyleChange::Unchanged, + }; + } - /// Returns a bitmask that represents a flow that needs to be rebuilt and - /// reflowed. - /// - /// FIXME(bholley): Do we ever actually need this? Shouldn't - /// RECONSTRUCT_FLOW imply everything else? - pub fn rebuild_and_reflow() -> ServoRestyleDamage { - ServoRestyleDamage::REPAINT | - ServoRestyleDamage::REPOSITION | - ServoRestyleDamage::STORE_OVERFLOW | - ServoRestyleDamage::BUBBLE_ISIZES | - ServoRestyleDamage::REFLOW_OUT_OF_FLOW | - ServoRestyleDamage::REFLOW | - ServoRestyleDamage::RECONSTRUCT_FLOW - } + if damage.contains(ServoRestyleDamage::RELAYOUT) { + damage |= E::compute_layout_damage(old, new); + } - /// Returns a bitmask indicating that the frame needs to be reconstructed. - pub fn reconstruct() -> ServoRestyleDamage { - ServoRestyleDamage::RECONSTRUCT_FLOW - } + // FIXME(emilio): Differentiate between reset and inherited + // properties here, and set `reset_only` appropriately so the + // optimization to skip the cascade in those cases applies. + let change = StyleChange::Changed { reset_only: false }; - /// Supposing a flow has the given `position` property and this damage, - /// returns the damage that we should add to the *parent* of this flow. - pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> ServoRestyleDamage { - if child_is_absolutely_positioned { - self & (ServoRestyleDamage::REPAINT | - ServoRestyleDamage::REPOSITION | - ServoRestyleDamage::STORE_OVERFLOW | - ServoRestyleDamage::REFLOW_OUT_OF_FLOW | - ServoRestyleDamage::RESOLVE_GENERATED_CONTENT) - } else { - self & (ServoRestyleDamage::REPAINT | - ServoRestyleDamage::REPOSITION | - ServoRestyleDamage::STORE_OVERFLOW | - ServoRestyleDamage::REFLOW | - ServoRestyleDamage::REFLOW_OUT_OF_FLOW | - ServoRestyleDamage::RESOLVE_GENERATED_CONTENT) - } + StyleDifference { damage, change } } - /// Supposing the *parent* of a flow with the given `position` property has - /// this damage, returns the damage that we should add to this flow. - pub fn damage_for_child( - self, - parent_is_absolutely_positioned: bool, - child_is_absolutely_positioned: bool, - ) -> ServoRestyleDamage { - match ( - parent_is_absolutely_positioned, - child_is_absolutely_positioned, - ) { - (false, true) => { - // Absolute children are out-of-flow and therefore insulated from changes. - // - // FIXME(pcwalton): Au contraire, if the containing block dimensions change! - self & (ServoRestyleDamage::REPAINT | ServoRestyleDamage::REPOSITION) - }, - (true, false) => { - // Changing the position of an absolutely-positioned block requires us to reflow - // its kids. - if self.contains(ServoRestyleDamage::REFLOW_OUT_OF_FLOW) { - self | ServoRestyleDamage::REFLOW - } else { - self - } - }, - _ => { - // TODO(pcwalton): Take floatedness into account. - self & (ServoRestyleDamage::REPAINT | - ServoRestyleDamage::REPOSITION | - ServoRestyleDamage::REFLOW) - }, - } + /// Returns a bitmask indicating that the frame needs to be reconstructed. + pub fn reconstruct() -> ServoRestyleDamage { + // There's no way of knowing what kind of damage system the embedder will use, but part of + // this interface is that a fully saturated restyle damage means to rebuild everything. + ServoRestyleDamage::from_bits_retain(::Bits::MAX) } } @@ -162,16 +96,15 @@ impl fmt::Display for ServoRestyleDamage { let to_iter = [ (ServoRestyleDamage::REPAINT, "Repaint"), - (ServoRestyleDamage::REPOSITION, "Reposition"), - (ServoRestyleDamage::STORE_OVERFLOW, "StoreOverflow"), - (ServoRestyleDamage::BUBBLE_ISIZES, "BubbleISizes"), - (ServoRestyleDamage::REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow"), - (ServoRestyleDamage::REFLOW, "Reflow"), ( - ServoRestyleDamage::RESOLVE_GENERATED_CONTENT, - "ResolveGeneratedContent", + ServoRestyleDamage::REBUILD_STACKING_CONTEXT, + "Rebuild stacking context", + ), + ( + ServoRestyleDamage::RECALCULATE_OVERFLOW, + "Recalculate overflow", ), - (ServoRestyleDamage::RECONSTRUCT_FLOW, "ReconstructFlow"), + (ServoRestyleDamage::RELAYOUT, "Relayout"), ]; for &(damage, damage_str) in &to_iter { @@ -195,76 +128,61 @@ impl fmt::Display for ServoRestyleDamage { fn compute_damage(old: &ComputedValues, new: &ComputedValues) -> ServoRestyleDamage { let mut damage = ServoRestyleDamage::empty(); - // This should check every CSS property, as enumerated in the fields of - // https://doc.servo.org/style/properties/struct.ComputedValues.html + let has_transform_or_perspective_style = |style_box: &style_structs::Box| { + !style_box.transform.0.is_empty() || + style_box.scale != GenericScale::None || + style_box.rotate != GenericRotate::None || + style_box.translate != GenericTranslate::None || + style_box.perspective != Perspective::None || + style_box.transform_style == TransformStyle::Preserve3d + }; + + let rebuild_box_extra = || { + let old_box = old.get_box(); + let new_box = new.get_box(); + old_box.original_display != new_box.original_display || + has_transform_or_perspective_style(old_box) != + has_transform_or_perspective_style(new_box) || + old.get_effects().filter.0.is_empty() != new.get_effects().filter.0.is_empty() + }; + + // Some properties establish a stacking context when they are set to a non-initial value. + // In that case, the damage is only set to `ServoRestyleDamage::REPAINT` because we don't + // need to rebuild stacking contexts when the style changes between different non-initial + // values. This function checks whether any of these properties is set to a value that + // guarantees a stacking context, so that we only do the work when this changes. + // Note that it's still possible to establish a stacking context when this returns false. + let guarantees_stacking_context = |style: &ComputedValues| { + style.get_effects().opacity != 1.0 || + old.get_effects().mix_blend_mode != MixBlendMode::Normal || + old.get_svg().clip_path != ClipPath::None || + style.get_box().isolation == Isolation::Isolate + }; // This uses short-circuiting boolean OR for its side effects and ignores the result. - let _ = restyle_damage_rebuild_and_reflow!( + let _ = restyle_damage_rebuild_box!( old, new, damage, - [ - ServoRestyleDamage::REPAINT, - ServoRestyleDamage::REPOSITION, - ServoRestyleDamage::STORE_OVERFLOW, - ServoRestyleDamage::BUBBLE_ISIZES, - ServoRestyleDamage::REFLOW_OUT_OF_FLOW, - ServoRestyleDamage::REFLOW, - ServoRestyleDamage::RECONSTRUCT_FLOW - ], - old.get_box().original_display != new.get_box().original_display - ) || (new.get_box().display == Display::Inline && - restyle_damage_rebuild_and_reflow_inline!( - old, - new, - damage, - [ - ServoRestyleDamage::REPAINT, - ServoRestyleDamage::REPOSITION, - ServoRestyleDamage::STORE_OVERFLOW, - ServoRestyleDamage::BUBBLE_ISIZES, - ServoRestyleDamage::REFLOW_OUT_OF_FLOW, - ServoRestyleDamage::REFLOW, - ServoRestyleDamage::RECONSTRUCT_FLOW - ] - )) || - restyle_damage_reflow!( - old, - new, - damage, - [ - ServoRestyleDamage::REPAINT, - ServoRestyleDamage::REPOSITION, - ServoRestyleDamage::STORE_OVERFLOW, - ServoRestyleDamage::BUBBLE_ISIZES, - ServoRestyleDamage::REFLOW_OUT_OF_FLOW, - ServoRestyleDamage::REFLOW - ] - ) || - restyle_damage_reflow_out_of_flow!( - old, - new, - damage, - [ - ServoRestyleDamage::REPAINT, - ServoRestyleDamage::REPOSITION, - ServoRestyleDamage::STORE_OVERFLOW, - ServoRestyleDamage::REFLOW_OUT_OF_FLOW - ] - ) || - restyle_damage_repaint!(old, new, damage, [ServoRestyleDamage::REPAINT]); + [ServoRestyleDamage::RELAYOUT], + rebuild_box_extra() + ) || restyle_damage_recalculate_overflow!( + old, + new, + damage, + [ServoRestyleDamage::RECALCULATE_OVERFLOW] + ) || restyle_damage_rebuild_stacking_context!( + old, + new, + damage, + [ServoRestyleDamage::REBUILD_STACKING_CONTEXT], + guarantees_stacking_context(old) != guarantees_stacking_context(new) + ) || restyle_damage_repaint!(old, new, damage, [ServoRestyleDamage::REPAINT]); // Paint worklets may depend on custom properties, // so if they have changed we should repaint. if !old.custom_properties_equal(new) { damage.insert(ServoRestyleDamage::REPAINT); } - - // If the layer requirements of this flow have changed due to the value - // of the transform, then reflow is required to rebuild the layers. - if old.transform_requires_layer() != new.transform_requires_layer() { - damage.insert(ServoRestyleDamage::rebuild_and_reflow()); - } - damage } diff --git a/style/servo/selector_parser.rs b/style/servo/selector_parser.rs index 6480bea4a2..23c73ca347 100644 --- a/style/servo/selector_parser.rs +++ b/style/servo/selector_parser.rs @@ -50,11 +50,11 @@ pub enum PseudoElement { // them. Also, make sure the UA sheet has the !important rules some of the // APPLIES_TO_PLACEHOLDER properties expect! - Backdrop, - // Non-eager pseudos. + Backdrop, DetailsSummary, DetailsContent, + Marker, ServoAnonymousBox, ServoAnonymousTable, ServoAnonymousTableCell, @@ -79,6 +79,7 @@ impl ToCss for PseudoElement { Backdrop => "::backdrop", DetailsSummary => "::-servo-details-summary", DetailsContent => "::-servo-details-content", + Marker => "::marker", ServoAnonymousBox => "::-servo-anonymous-box", ServoAnonymousTable => "::-servo-anonymous-table", ServoAnonymousTableCell => "::-servo-anonymous-table-cell", @@ -139,7 +140,7 @@ impl PseudoElement { /// Whether this pseudo-element is the ::marker pseudo. #[inline] pub fn is_marker(&self) -> bool { - false + *self == PseudoElement::Marker } /// Whether this pseudo-element is the ::selection pseudo. @@ -210,16 +211,20 @@ impl PseudoElement { /// Returns which kind of cascade type has this pseudo. /// - /// For more info on cascade types, see docs/components/style.md + /// See the documentation for `PseudoElementCascadeType` for how we choose + /// which cascade type to use. /// - /// Note: Keep this in sync with EAGER_PSEUDO_COUNT. + /// Note: Keep eager pseudos in sync with `EAGER_PSEUDO_COUNT` and + /// `EMPTY_PSEUDO_ARRAY` in `style/data.rs` #[inline] pub fn cascade_type(&self) -> PseudoElementCascadeType { match *self { PseudoElement::After | PseudoElement::Before | PseudoElement::Selection => { PseudoElementCascadeType::Eager }, - PseudoElement::Backdrop | PseudoElement::DetailsSummary => PseudoElementCascadeType::Lazy, + PseudoElement::Backdrop | + PseudoElement::DetailsSummary | + PseudoElement::Marker => PseudoElementCascadeType::Lazy, PseudoElement::DetailsContent | PseudoElement::ServoAnonymousBox | PseudoElement::ServoAnonymousTable | @@ -474,8 +479,8 @@ impl ::selectors::SelectorImpl for SelectorImpl { type LocalName = LocalName; type NamespacePrefix = Prefix; type NamespaceUrl = Namespace; - type BorrowedLocalName = markup5ever::LocalName; - type BorrowedNamespaceUrl = markup5ever::Namespace; + type BorrowedLocalName = web_atoms::LocalName; + type BorrowedNamespaceUrl = web_atoms::Namespace; } impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { @@ -499,7 +504,12 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { #[inline] fn parse_parent_selector(&self) -> bool { - false + true + } + + #[inline] + fn parse_part(&self) -> bool { + true } #[inline] @@ -584,8 +594,9 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { let pseudo_element = match_ignore_ascii_case! { &name, "before" => Before, "after" => After, - "selection" => Selection, "backdrop" => Backdrop, + "selection" => Selection, + "marker" => Marker, "-servo-details-summary" => { if !self.in_user_agent_stylesheet() { return Err(location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone()))) @@ -786,8 +797,13 @@ impl ElementSnapshot for ServoElementSnapshot { .map(|v| v.as_atom()) } - fn is_part(&self, _name: &AtomIdent) -> bool { - false + fn is_part(&self, part_name: &AtomIdent) -> bool { + self.get_attr(&ns!(), &local_name!("part")) + .is_some_and(|v| { + v.as_tokens() + .iter() + .any(|atom| CaseSensitivity::CaseSensitive.eq_atom(atom, part_name)) + }) } fn imported_part(&self, _: &AtomIdent) -> Option { diff --git a/style/servo/url.rs b/style/servo/url.rs index e475d15b79..63c4b42cd2 100644 --- a/style/servo/url.rs +++ b/style/servo/url.rs @@ -10,6 +10,7 @@ use crate::values::computed::{Context, ToComputedValue}; use cssparser::Parser; use servo_arc::Arc; use std::fmt::{self, Write}; +use std::ops::Deref; use style_traits::{CssWriter, ParseError, ToCss}; use to_shmem::{SharedMemoryBuilder, ToShmem}; use url::Url; @@ -22,11 +23,16 @@ use url::Url; /// /// However, this approach is still not necessarily optimal: See /// -/// -/// TODO(emilio): This should be shrunk by making CssUrl a wrapper type of an -/// arc, and keep the serialization in that Arc. See gecko/url.rs for example. #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize, SpecifiedValueInfo)] -pub struct CssUrl { +#[css(function = "url")] +#[repr(C)] +pub struct CssUrl(#[ignore_malloc_size_of = "Arc"] pub Arc); + +/// Data shared between CssUrls. +/// +#[derive(Debug, Deserialize, MallocSizeOf, Serialize, SpecifiedValueInfo)] +#[repr(C)] +pub struct CssUrlData { /// The original URI. This might be optional since we may insert computed /// values of images into the cascade directly, and we don't bother to /// convert their serialization. @@ -47,6 +53,13 @@ impl ToShmem for CssUrl { } } +impl Deref for CssUrl { + type Target = CssUrlData; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + impl CssUrl { /// Try to parse a URL from a string value that is a valid CSS token for a /// URL. @@ -55,10 +68,10 @@ impl CssUrl { pub fn parse_from_string(url: String, context: &ParserContext, _: CorsMode) -> Self { let serialization = Arc::new(url); let resolved = context.url_data.0.join(&serialization).ok().map(Arc::new); - CssUrl { + CssUrl(Arc::new(CssUrlData { original: Some(serialization), resolved: resolved, - } + })) } /// Returns true if the URL is definitely invalid. For Servo URLs, we can @@ -96,18 +109,18 @@ impl CssUrl { /// Creates an already specified url value from an already resolved URL /// for insertion in the cascade. pub fn for_cascade(url: Arc<::url::Url>) -> Self { - CssUrl { + CssUrl(Arc::new(CssUrlData { original: None, resolved: Some(url), - } + })) } /// Gets a new url from a string for unit tests. pub fn new_for_testing(url: &str) -> Self { - CssUrl { + CssUrl(Arc::new(CssUrlData { original: Some(Arc::new(url.into())), resolved: ::url::Url::parse(url).ok().map(Arc::new), - } + })) } /// Parses a URL request and records that the corresponding request needs to @@ -153,7 +166,7 @@ impl ToCss for CssUrl { where W: Write, { - let string = match self.original { + let string = match self.0.original { Some(ref original) => &**original, None => match self.resolved { Some(ref url) => url.as_str(), @@ -191,16 +204,17 @@ impl ToComputedValue for SpecifiedUrl { } fn from_computed_value(computed: &ComputedUrl) -> Self { - match *computed { - ComputedUrl::Valid(ref url) => SpecifiedUrl { + let data = match *computed { + ComputedUrl::Valid(ref url) => CssUrlData { original: None, resolved: Some(url.clone()), }, - ComputedUrl::Invalid(ref url) => SpecifiedUrl { + ComputedUrl::Invalid(ref url) => CssUrlData { original: Some(url.clone()), resolved: None, }, - } + }; + CssUrl(Arc::new(data)) } } diff --git a/style/shadow_parts.rs b/style/shadow_parts.rs new file mode 100644 index 0000000000..1daa97f442 --- /dev/null +++ b/style/shadow_parts.rs @@ -0,0 +1,166 @@ +/* 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 crate::Atom; +use crate::values::AtomIdent; + +type Mapping<'a> = (&'a str, &'a str); + +#[derive(Clone, Debug, MallocSizeOf)] +pub struct ShadowParts { + // FIXME: Consider a smarter data structure for this. + // Gecko uses a hashtable in both directions: + // https://searchfox.org/mozilla-central/rev/5d4178378f84c7130ccb8ac1723d33e380d7f7d7/layout/style/ShadowParts.h + mappings: Vec<(Atom, Atom)> +} + +/// +/// +/// Returns `None` in the failure case. +pub fn parse_part_mapping(input: &str) -> Option { + // Step 1. Let input be the string being parsed. + // Step 2. Let position be a pointer into input, initially pointing at the start of the string. + // NOTE: We don't need an explicit position, we just drop stuff from the input + + // Step 3. Collect a sequence of code points that are space characters + let input = input.trim_start_matches(|c| c == ' '); + + // Step 4. Collect a sequence of code points that are not space characters or U+003A COLON characters, + // and let first token be the result. + let space_or_colon_position = input.char_indices().find(|(_, c)| matches!(c, ' ' | ':')).map(|(index, _)| index).unwrap_or(input.len()); + let (first_token, input) = input.split_at(space_or_colon_position); + + // Step 5. If first token is empty then return error. + if first_token.is_empty() { + return None; + } + + // Step 6. Collect a sequence of code points that are space characters. + let input = input.trim_start_matches(|c| c == ' '); + + // Step 7. If the end of the input has been reached, return the tuple (first token, first token) + if input.is_empty() { + return Some((first_token, first_token)); + } + + // Step 8. If character at position is not a U+003A COLON character, return error. + // Step 9. Consume the U+003A COLON character. + let Some(input) = input.strip_prefix(':') else { + return None; + }; + + // Step 10. Collect a sequence of code points that are space characters. + let input = input.trim_start_matches(|c| c == ' '); + + // Step 11. Collect a sequence of code points that are not space characters or U+003A COLON characters. + // and let second token be the result. + let space_or_colon_position = input.char_indices().find(|(_, c)| matches!(c, ' ' | ':')).map(|(index, _)| index).unwrap_or(input.len()); + let (second_token, input) = input.split_at(space_or_colon_position); + + // Step 12. If second token is empty then return error. + if second_token.is_empty() { + return None; + } + + // Step 13. Collect a sequence of code points that are space characters. + let input = input.trim_start_matches(|c| c == ' '); + + // Step 14. If position is not past the end of input then return error. + if !input.is_empty() { + return None; + } + + // Step 14. Return the tuple (first token, second token). + Some((first_token, second_token)) +} + +/// +fn parse_mapping_list(input: &str) -> impl Iterator { + // Step 1. Let input be the string being parsed. + // Step 2. Split the string input on commas. Let unparsed mappings be the resulting list of strings. + let unparsed_mappings = input.split(','); + + // Step 3. Let mappings be an initially empty list of tuples of tokens. + // This list will be the result of this algorithm. + // NOTE: We return an iterator here - it is up to the caller to turn it into a list + + // Step 4. For each string unparsed mapping in unparsed mappings, run the following substeps: + unparsed_mappings.filter_map(|unparsed_mapping| { + // Step 4.1 If unparsed mapping is empty or contains only space characters, + // continue to the next iteration of the loop. + if unparsed_mapping.chars().all(|c| c == ' ') { + return None; + } + + // Step 4.2 Let mapping be the result of parsing unparsed mapping using the rules for parsing part mappings. + // Step 4.3 If mapping is an error then continue to the next iteration of the loop. + // This allows clients to skip over new syntax that is not understood. + // Step 4.4 Append mapping to mappings. + parse_part_mapping(unparsed_mapping) + }) +} + +impl ShadowParts { + pub fn parse(input: &str) -> Self { + Self { + mappings: parse_mapping_list(input).map(|(first,second)| (first.into(), second.into())).collect(), + } + } + + /// Call the provided callback for each exported part with the given name. + pub fn for_each_exported_part(&self, name: &Atom, mut callback: F) + where F: FnMut(&AtomIdent) { + for (from, to) in &self.mappings { + if from == name { + callback(AtomIdent::cast(to)); + } + } + } + + pub fn imported_part(&self, name: &Atom) -> Option<&Atom> { + self.mappings.iter().find(|(_, to)| { + to == name + }).map(|(from, _)| from) + } +} + + +#[cfg(test)] +mod tests { + use crate::shadow_parts::parse_mapping_list; + + use super::*; + + #[test] + fn parse_valid_mapping() { + assert_eq!(parse_part_mapping("foo"), Some(("foo", "foo")), "Single token"); + assert_eq!(parse_part_mapping(" foo"), Some(("foo", "foo")), "Single token with leading whitespace"); + assert_eq!(parse_part_mapping("foo "), Some(("foo", "foo")), "Single token with trailing whitespace"); + assert_eq!(parse_part_mapping("foo:bar"), Some(("foo", "bar")), "Two tokens"); + assert_eq!(parse_part_mapping("foo:bar "), Some(("foo", "bar")), "Two tokens with trailing whitespace"); + assert_eq!(parse_part_mapping("🦀:🚀"), Some(("🦀", "🚀")), "Two tokens consisting of non-ascii characters"); + } + + #[test] + fn reject_invalid_mapping() { + assert!(parse_part_mapping("").is_none(), "Empty input"); + assert!(parse_part_mapping(" ").is_none(), "Only whitespace"); + assert!(parse_part_mapping("foo bar").is_none(), "Missing colon"); + assert!(parse_part_mapping(":bar").is_none(), "Empty first token"); + assert!(parse_part_mapping("foo:").is_none(), "Empty second token"); + assert!(parse_part_mapping("foo:bar baz").is_none(), "Trailing input"); + } + + #[test] + fn parse_valid_mapping_list() { + let mut mappings = parse_mapping_list("foo: bar, totally-invalid-mapping,,"); + + // "foo: bar" is a valid mapping + assert_eq!(mappings.next(), Some(("foo", "bar")), "First mapping should be in the list"); + // "totally-invalid-mapping" is not a valid mapping and should be ignored + // "" is not valid (and consists of nothing but whitespace), so it should be ignored + assert!(mappings.next().is_none(), "No more mappings should exist"); + } + +} diff --git a/style/stylesheets/stylesheet.rs b/style/stylesheets/stylesheet.rs index 64d78fae46..e34e8d8e93 100644 --- a/style/stylesheets/stylesheet.rs +++ b/style/stylesheets/stylesheet.rs @@ -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/thread_state.rs b/style/thread_state.rs index e07a567fe7..e578287add 100644 --- a/style/thread_state.rs +++ b/style/thread_state.rs @@ -2,16 +2,16 @@ * 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/. */ -//! Supports dynamic assertions in about what sort of thread is running and +//! Supports dynamic assertions about what sort of thread is running and //! what state it's in. #![deny(missing_docs)] -use std::cell::RefCell; +use std::cell::Cell; bitflags! { /// A thread state flag, used for multiple assertions. - #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[derive(Clone, Copy, Default, Debug, Eq, PartialEq)] pub struct ThreadState: u32 { /// Whether we're in a script thread. const SCRIPT = 0x01; @@ -27,38 +27,34 @@ bitflags! { } } -macro_rules! thread_types ( ( $( $fun:ident = $flag:path ; )* ) => ( - impl ThreadState { - /// Whether the current thread is a worker thread. - pub fn is_worker(self) -> bool { - self.contains(ThreadState::IN_WORKER) - } +impl ThreadState { + /// Whether the current thread is a worker thread. + pub fn is_worker(self) -> bool { + self.contains(ThreadState::IN_WORKER) + } - $( - #[allow(missing_docs)] - pub fn $fun(self) -> bool { - self.contains($flag) - } - )* + /// Whether the current thread is a script thread. + pub fn is_script(self) -> bool { + self.contains(ThreadState::SCRIPT) } -)); -thread_types! { - is_script = ThreadState::SCRIPT; - is_layout = ThreadState::LAYOUT; + /// Whether the current thread is a layout thread. + pub fn is_layout(self) -> bool { + self.contains(ThreadState::LAYOUT) + } } -thread_local!(static STATE: RefCell> = RefCell::new(None)); +thread_local!(static STATE: Cell> = const { Cell::new(None) }); /// Initializes the current thread state. -pub fn initialize(x: ThreadState) { - STATE.with(|ref k| { - if let Some(ref s) = *k.borrow() { - if x != *s { - panic!("Thread state already initialized as {:?}", s); +pub fn initialize(initialize_to: ThreadState) { + STATE.with(|state| { + if let Some(current_state) = state.get() { + if initialize_to != current_state { + panic!("Thread state already initialized as {:?}", current_state); } } - *k.borrow_mut() = Some(x); + state.set(Some(initialize_to)); }); } @@ -69,30 +65,25 @@ pub fn initialize_layout_worker_thread() { /// Gets the current thread state. pub fn get() -> ThreadState { - let state = STATE.with(|ref k| { - match *k.borrow() { - None => ThreadState::empty(), // Unknown thread. - Some(s) => s, - } - }); - - state + STATE.with(|state| { + state.get().unwrap_or_default() + }) } -/// Enters into a given temporary state. Panics if re-entring. -pub fn enter(x: ThreadState) { - let state = get(); - debug_assert!(!state.intersects(x)); - STATE.with(|ref k| { - *k.borrow_mut() = Some(state | x); +/// Enters into a given temporary state. Panics if re-entering. +pub fn enter(additional_flags: ThreadState) { + STATE.with(|state| { + let current_state = state.get().unwrap_or_default(); + debug_assert!(!current_state.intersects(additional_flags)); + state.set(Some(current_state | additional_flags)); }) } /// Exits a given temporary state. -pub fn exit(x: ThreadState) { - let state = get(); - debug_assert!(state.contains(x)); - STATE.with(|ref k| { - *k.borrow_mut() = Some(state & !x); +pub fn exit(flags_to_remove: ThreadState) { + STATE.with(|state| { + let current_state = state.get().unwrap_or_default(); + debug_assert!(current_state.contains(flags_to_remove)); + state.set(Some(current_state & !flags_to_remove)); }) } diff --git a/style/values/computed/image.rs b/style/values/computed/image.rs index c55824127c..dc3c775b47 100644 --- a/style/values/computed/image.rs +++ b/style/values/computed/image.rs @@ -32,7 +32,7 @@ pub type Image = generic::GenericImage diff --git a/style/values/computed/length_percentage.rs b/style/values/computed/length_percentage.rs index 0cff0d4f72..606dd57cc4 100644 --- a/style/values/computed/length_percentage.rs +++ b/style/values/computed/length_percentage.rs @@ -30,6 +30,7 @@ use crate::gecko_bindings::structs::GeckoFontMetrics; use crate::values::animated::{Animate, Context as AnimatedContext, Procedure, ToAnimatedValue, ToAnimatedZero}; use crate::values::distance::{ComputeSquaredDistance, SquaredDistance}; use crate::values::generics::calc::{CalcUnits, PositivePercentageBasis}; +#[cfg(feature = "gecko")] use crate::values::generics::length::AnchorResolutionResult; use crate::values::generics::position::{AnchorSideKeyword, GenericAnchorSide}; use crate::values::generics::{calc, NonNegative}; diff --git a/style/values/generics/image.rs b/style/values/generics/image.rs index 8524e277c7..59a6ed68ed 100644 --- a/style/values/generics/image.rs +++ b/style/values/generics/image.rs @@ -47,7 +47,7 @@ pub enum GenericImage { /// A paint worklet image. /// #[cfg(feature = "servo")] - PaintWorklet(PaintWorklet), + PaintWorklet(Box), /// A `` image. Storing this directly inside of /// GenericImage increases the size by 8 bytes so we box it here diff --git a/style/values/specified/image.rs b/style/values/specified/image.rs index 72e5ccef25..61f5952c1a 100644 --- a/style/values/specified/image.rs +++ b/style/values/specified/image.rs @@ -43,10 +43,7 @@ fn gradient_color_interpolation_method_enabled() -> bool { pub type Image = generic::Image; // Images should remain small, see https://github.com/servo/servo/pull/18430 -#[cfg(feature = "gecko")] size_of_test!(Image, 16); -#[cfg(feature = "servo")] -size_of_test!(Image, 40); /// Specified values for a CSS gradient. /// @@ -246,7 +243,7 @@ impl Image { let function = input.expect_function()?.clone(); input.parse_nested_block(|input| Ok(match_ignore_ascii_case! { &function, #[cfg(feature = "servo")] - "paint" => Self::PaintWorklet(PaintWorklet::parse_args(context, input)?), + "paint" => Self::PaintWorklet(Box::new(::parse_args(context, input)?)), "cross-fade" if cross_fade_enabled() => Self::CrossFade(Box::new(CrossFade::parse_args(context, input, cors_mode, flags)?)), "light-dark" if image_light_dark_enabled(context) => Self::LightDark(Box::new(GenericLightDark::parse_args_with(input, |input| { Self::parse_with_cors_mode(context, input, cors_mode, flags) 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 8d8a85f62d..24b8491fe0 100644 --- a/style_derive/Cargo.toml +++ b/style_derive/Cargo.toml @@ -1,11 +1,12 @@ [package] -name = "style_derive" -version = "0.0.1" +name = "stylo_derive" +version = "0.4.0" authors = ["The Servo Project Developers"] license = "MPL-2.0" repository = "https://github.com/servo/stylo" edition = "2021" description = "Derive crate for Stylo CSS engine" +readme = "../README.md" [lib] path = "lib.rs" diff --git a/style_traits/Cargo.toml b/style_traits/Cargo.toml index 4d827aaffa..2c1b51edbc 100644 --- a/style_traits/Cargo.toml +++ b/style_traits/Cargo.toml @@ -1,11 +1,12 @@ [package] -name = "style_traits" -version = "0.0.1" +name = "stylo_traits" +version = "0.4.0" authors = ["The Servo Project Developers"] license = "MPL-2.0" repository = "https://github.com/servo/stylo" edition = "2021" description = "Types used by the Stylo CSS engine" +readme = "../README.md" [lib] name = "style_traits" @@ -13,21 +14,20 @@ 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} -selectors = { path = "../selectors" } +malloc_size_of = { version = "0.4", path = "../malloc_size_of", package = "stylo_malloc_size_of" } +malloc_size_of_derive = "0.1" +selectors = { version = "0.29", path = "../selectors" } serde = "1.0" -servo_arc = { path = "../servo_arc" } -stylo_atoms = { path = "../atoms", optional = true } +servo_arc = { version = "0.4", path = "../servo_arc" } +stylo_atoms = { version = "0.4", path = "../stylo_atoms", optional = true } thin-vec = "0.2" -to_shmem = { path = "../to_shmem" } -to_shmem_derive = { path = "../to_shmem_derive" } +to_shmem = { version = "0.2", path = "../to_shmem" } +to_shmem_derive = { version = "0.1", path = "../to_shmem_derive" } url = { version = "2.5", optional = true } diff --git a/stylo_atoms/Cargo.toml b/stylo_atoms/Cargo.toml new file mode 100644 index 0000000000..30edabe322 --- /dev/null +++ b/stylo_atoms/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "stylo_atoms" +version = "0.4.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" +readme = "../README.md" + +[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..dba1da08b7 --- /dev/null +++ b/stylo_atoms/static_atoms.txt @@ -0,0 +1,184 @@ +-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-csd-tooltip-radius +-moz-gtk-menu-radius +-moz-mac-titlebar-height +-moz-overlay-scrollbar-fade-duration +DOMContentLoaded +abort +activate +addtrack +animationcancel +animationend +animationiteration +animationstart +aspect-ratio +beforetoggle +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..5f31c515cf --- /dev/null +++ b/stylo_config/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "stylo_config" +version = "0.4.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" +readme = "../README.md" + +[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..df7ff3802c --- /dev/null +++ b/stylo_dom/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "stylo_dom" +version = "0.4.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" +readme = "../README.md" + +[lib] +path = "lib.rs" + +[dependencies] +bitflags = "2" +malloc_size_of = { version = "0.4", 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..be350e95d6 --- /dev/null +++ b/stylo_static_prefs/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "stylo_static_prefs" +version = "0.4.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" +readme = "../README.md" diff --git a/stylo_static_prefs/src/lib.rs b/stylo_static_prefs/src/lib.rs new file mode 100644 index 0000000000..ecd9253d31 --- /dev/null +++ b/stylo_static_prefs/src/lib.rs @@ -0,0 +1,45 @@ +/* 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.fit-content-function.enabled") => { + true + }; + ("layout.css.relative-color-syntax.enabled") => { + true + }; + ("layout.css.stretch-size-keyword.enabled") => { + true + }; + ("layout.css.transition-behavior.enabled") => { + true + }; + ("layout.css.marker.restricted") => { + true + }; + ($string:literal) => { + false + }; +} diff --git a/sync.sh b/sync.sh index e92182c746..68c8689c9c 100755 --- a/sync.sh +++ b/sync.sh @@ -30,7 +30,7 @@ fi step Cloning upstream if needed if ! [ -e upstream ]; then - git clone --bare --single-branch --progress https://github.com/mozilla/gecko-dev.git upstream + git clone --bare --single-branch --branch main --progress https://github.com/mozilla-firefox/firefox.git upstream fi step Updating upstream diff --git a/to_shmem/Cargo.toml b/to_shmem/Cargo.toml index fadd1e6e3a..58147a5e1d 100644 --- a/to_shmem/Cargo.toml +++ b/to_shmem/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "to_shmem" -version = "0.1.0" +version = "0.2.0" authors = ["The Servo Project Developers"] license = "MPL-2.0" repository = "https://github.com/servo/stylo" @@ -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 } From a3baf4ae7913826317f3f9bcfb05619c128490b7 Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Wed, 2 Jul 2025 01:24:19 +0200 Subject: [PATCH 03/11] Fixup for https://phabricator.services.mozilla.com/D253727 Just reverting a previous fixup which is no longer needed: bd707d7d952b807d48adfd7e4366b3c9e4109e9e Signed-off-by: Oriol Brufau --- style/properties/longhands/ui.mako.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/style/properties/longhands/ui.mako.rs b/style/properties/longhands/ui.mako.rs index 19f79fcbbe..4579f33f3e 100644 --- a/style/properties/longhands/ui.mako.rs +++ b/style/properties/longhands/ui.mako.rs @@ -188,7 +188,6 @@ ${helpers.predefined_type( vector=True, need_index=True, animation_type="none", - servo_pref="layout.css.transition-behavior.enabled", spec="https://drafts.csswg.org/css-transitions-2/#transition-behavior-property", affects="", )} From 45d54a889b8407c3ec39c310e07c5c63d053c2e5 Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Wed, 2 Jul 2025 01:34:58 +0200 Subject: [PATCH 04/11] Fixup for https://phabricator.services.mozilla.com/D252791 Signed-off-by: Oriol Brufau --- style/values/computed/image.rs | 2 ++ style/values/generics/image.rs | 2 ++ style/values/specified/image.rs | 1 + 3 files changed, 5 insertions(+) diff --git a/style/values/computed/image.rs b/style/values/computed/image.rs index dc3c775b47..de308015ab 100644 --- a/style/values/computed/image.rs +++ b/style/values/computed/image.rs @@ -217,6 +217,7 @@ impl ToComputedValue for specified::Image { Self::Gradient(g) => Image::Gradient(g.to_computed_value(context)), #[cfg(feature = "gecko")] Self::Element(e) => Image::Element(e.to_computed_value(context)), + #[cfg(feature = "gecko")] Self::MozSymbolicIcon(e) => Image::MozSymbolicIcon(e.to_computed_value(context)), #[cfg(feature = "servo")] Self::PaintWorklet(w) => Image::PaintWorklet(w.to_computed_value(context)), @@ -233,6 +234,7 @@ impl ToComputedValue for specified::Image { Image::Gradient(g) => Self::Gradient(ToComputedValue::from_computed_value(g)), #[cfg(feature = "gecko")] Image::Element(e) => Self::Element(ToComputedValue::from_computed_value(e)), + #[cfg(feature = "gecko")] Image::MozSymbolicIcon(e) => Self::MozSymbolicIcon(ToComputedValue::from_computed_value(e)), #[cfg(feature = "servo")] Image::PaintWorklet(w) => Self::PaintWorklet(ToComputedValue::from_computed_value(w)), diff --git a/style/values/generics/image.rs b/style/values/generics/image.rs index 59a6ed68ed..7b825ecd5d 100644 --- a/style/values/generics/image.rs +++ b/style/values/generics/image.rs @@ -41,6 +41,7 @@ pub enum GenericImage { /// A `-moz-symbolic-icon()` /// NOTE(emilio): #[css(skip)] only really affects SpecifiedValueInfo, which we want because /// this is chrome-only. + #[cfg(feature = "gecko")] #[css(function, skip)] MozSymbolicIcon(Atom), @@ -434,6 +435,7 @@ where serialize_atom_identifier(selector, dest)?; dest.write_char(')') }, + #[cfg(feature = "gecko")] Image::MozSymbolicIcon(ref id) => { dest.write_str("-moz-symbolic-icon(")?; serialize_atom_identifier(id, dest)?; diff --git a/style/values/specified/image.rs b/style/values/specified/image.rs index 61f5952c1a..b28237dc6e 100644 --- a/style/values/specified/image.rs +++ b/style/values/specified/image.rs @@ -250,6 +250,7 @@ impl Image { })?)), #[cfg(feature = "gecko")] "-moz-element" => Self::Element(Self::parse_element(input)?), + #[cfg(feature = "gecko")] "-moz-symbolic-icon" if context.chrome_rules_enabled() => Self::MozSymbolicIcon(input.expect_ident()?.as_ref().into()), _ => return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedFunction(function))), })) From a3ef6a2749b2c28a32c62cd9b8954950507dc437 Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Wed, 2 Jul 2025 01:50:31 +0200 Subject: [PATCH 05/11] Fixup for https://phabricator.services.mozilla.com/D254447 Signed-off-by: Oriol Brufau --- .../properties/Mako-1.1.2-py2.py3-none-any.whl | Bin 75521 -> 0 bytes style/properties/build.py | 2 +- style/properties/mako-1.3.10-py3-none-any.whl | Bin 0 -> 78509 bytes 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 style/properties/Mako-1.1.2-py2.py3-none-any.whl create mode 100644 style/properties/mako-1.3.10-py3-none-any.whl 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 deleted file mode 100644 index 9593025a4739374da2fde2966afdaffa1d0b8e05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75521 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

wOg(?)H>s{J*n4v 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%0A>{n;f&I{@ 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 diff --git a/style/properties/build.py b/style/properties/build.py index 1a92544bfd..636c84fe29 100644 --- a/style/properties/build.py +++ b/style/properties/build.py @@ -8,7 +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, os.path.join(BASE, "mako-1.3.10-py3-none-any.whl")) sys.path.insert(0, BASE) # For importing `data.py` from mako import exceptions diff --git a/style/properties/mako-1.3.10-py3-none-any.whl b/style/properties/mako-1.3.10-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..2f85cd7b576bf7998b55999cfe2f5519e3b75be3 GIT binary patch literal 78509 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

    X?O4`zuspQ{P-N3wH2jwQmX{zwD`%wDPR zKj;&WF$+qKV{ABBcYm@@`^RE-8~B*=$y;6u>M1&A+G>RxfP>!@UO+HVq0=10Mnruw4_)0vt88=en=d~>C2S2i^6-PG_6uApW<0AHtMB@y~KZP39ZS|KaovvNu!g^u~4f3R1s>pY}pGRADQ*V8~Zuob* z$mfu8?PYvYH7zZ?3cH~XTJ&x={96`1dZd~4EZUk9@YbBn-{vdZ>r4er20~Yih8QzL zTRa13;W9AT)T2)J?joB-X;gpK*sG3tEd`g}d9evvLI6|nWG$}rsuAu|x`iy1H&wOK zw=5G$BO{4CVLL?eTrQ$z;FX?fE2bC#WOq zq~C>N%&UR;6qLAA$X}=}dmifW za8XS|o;#0wzc``Lz+G+ZGzU3I63q$O-_3kl!hSXG_8=z!;B(74k{BaNwo*GOaPzPQ zbk|D^+o3^yMdh5st({(?gV4mdP7OmE;z>S0&>!eKh*w&6j9afDTFoxAEr7w9NNawV zW`pZXZElnkSYUh&A@)Fga9s&w=~ReU?S*eq3i1Ihl~wMiR8S5_v}i>x*&JAj#4DRg zRuO^8eTD55yF8=6oT(IeTbn>`Ezr22q4s3+GpHa#Si%kH!zq? z>J&WXHTeM&VwOQ3fFPsDlUE{proH-y&MUVGd`6gV?DDBm6;Y9xl|Hy{i)RRHTdDkl z(_w`*heMXdb9eKgWs@t z9MR(NYJU4iGkpZ7$6Aw+;B&Y1D)=+&REOi(jE8M_UH>Th@iN5n^q>@-r78Sae%((5 z?1n#Hi`zLu8uo%{I|;nXXL!#Q3@zU%XGYI6*%?o=9kbDdvD)zMUQZ7~07F)AaZnRU zS74Z{Qwj^K??x4-Q}I!sCx$doa5#x{K?Ftf$QG7e2tj(?iZBe;GIyxXURrh}R!VD1 zk98xQ{4YsA1Y27u)Fp1bE=n^cqzTQ^4Lxk2m}E@*vyQzD7SQ8DOim~;&|=Wsf!Z$e z2#U&}JCE<2D_HGyW41mD2Yr(G0n{3VE3cXkTM51GR{AC?g50EY8v$u3@_FxOrbOel z2GU8#g33}p(^w6r3E5S!l5JcdO91_MmMM|WkUYVNk9XUQ(?^d4A&4%OK@xO(W6}Zw zcMeHBSgelu(T4E964+Uw9{X`wc!^+y9Ac#~)0=g09Q6X!fMDg)Z{lU=t^z(4gjv$? zRW!2_(PCz>Vr936t&DhwUm%)Y=%A=7m8ckcyZFyKPc^*9!z|M1X#@YX28ZMxDNu#V zEkt^e=XQsIC7{6oA>YnNtxdqwWEu*}d=q*d%51f>&?;$vsF!5s30!)3^pSGzwo)s9 z8idD`=+oSULI`|f8<-|E>pn^q!FANL+!JW;*Uylje9?ifpX9gb9I6fi(l%_q(IF&%(=T*gxRu)^*4rVOS z#bB$F<4~rlAOP!i9LL4G!C?sT_M2*8T``p8z7O2y8 V0nvqmFhJJbC7)VJZ=kc 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

    hU}wVA9HjqE1mgo~JG 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 MOr})8 Date: Wed, 2 Jul 2025 01:57:02 +0200 Subject: [PATCH 06/11] Fixup for https://phabricator.services.mozilla.com/D254489 Signed-off-by: Oriol Brufau --- stylo_atoms/static_atoms.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/stylo_atoms/static_atoms.txt b/stylo_atoms/static_atoms.txt index dba1da08b7..8e18e69021 100644 --- a/stylo_atoms/static_atoms.txt +++ b/stylo_atoms/static_atoms.txt @@ -62,6 +62,7 @@ formdata fullscreenchange fullscreenerror gattserverdisconnected +hairline hashchange height hidden From 82b62bcf4f98e73a17ca1b19ffd6b5db9db0a5c1 Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Wed, 2 Jul 2025 16:14:55 +0200 Subject: [PATCH 07/11] Fixup for https://phabricator.services.mozilla.com/D252985 This reverts commit 3580e11894bcdb850fd055e70345d00c2fa87bdc to avoid duplicated crates, until we can coordinate the upgrade. --- style/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/style/Cargo.toml b/style/Cargo.toml index b47ddb3ba1..fcb72a82a0 100644 --- a/style/Cargo.toml +++ b/style/Cargo.toml @@ -65,7 +65,7 @@ new_debug_unreachable = "1.0" encoding_rs = {version = "0.8", optional = true} euclid = "0.22" fxhash = "0.2" -icu_segmenter = { version = "2.0", default-features = false, features = ["auto", "compiled_data"] } +icu_segmenter = { version = "1.5", default-features = false, features = ["auto", "compiled_data"] } indexmap = {version = "2", features = ["std"]} itertools = "0.14" itoa = "1.0" From 403f5575b69f1c8d2f7d41fe62df4bea170aa49a Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Wed, 2 Jul 2025 02:12:09 +0200 Subject: [PATCH 08/11] Fixup for https://phabricator.services.mozilla.com/D255407 Signed-off-by: Oriol Brufau --- style/invalidation/element/element_wrapper.rs | 1 + style/servo/selector_parser.rs | 4 ++-- stylo_dom/lib.rs | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/style/invalidation/element/element_wrapper.rs b/style/invalidation/element/element_wrapper.rs index 835adc22d7..9dbb414def 100644 --- a/style/invalidation/element/element_wrapper.rs +++ b/style/invalidation/element/element_wrapper.rs @@ -225,6 +225,7 @@ where }, // :heading should match against snapshot before element + #[cfg(feature = "gecko")] NonTSPseudoClass::Heading(ref levels) => { return levels.matches_state( self.snapshot() diff --git a/style/servo/selector_parser.rs b/style/servo/selector_parser.rs index 23c73ca347..4e72119c2a 100644 --- a/style/servo/selector_parser.rs +++ b/style/servo/selector_parser.rs @@ -389,7 +389,7 @@ impl ToCss for NonTSPseudoClass { Self::UserValid => ":user-valid", Self::Valid => ":valid", Self::Visited => ":visited", - Self::Lang(_) | Self::CustomState(_) | Self::Heading(_) => unreachable!(), + Self::Lang(_) | Self::CustomState(_) => unreachable!(), }) } } @@ -432,7 +432,7 @@ impl NonTSPseudoClass { Self::UserValid => ElementState::USER_VALID, Self::Valid => ElementState::VALID, Self::Visited => ElementState::VISITED, - Self::CustomState(_) | Self::Lang(_) | Self::Heading(_) | Self::ServoNonZeroBorder => ElementState::empty(), + Self::CustomState(_) | Self::Lang(_) | Self::ServoNonZeroBorder => ElementState::empty(), } } diff --git a/stylo_dom/lib.rs b/stylo_dom/lib.rs index 9137763491..d754b6f153 100644 --- a/stylo_dom/lib.rs +++ b/stylo_dom/lib.rs @@ -5,6 +5,8 @@ use bitflags::bitflags; use malloc_size_of::malloc_size_of_is_0; +pub const HEADING_LEVEL_OFFSET: usize = 51; + // DOM types to be shared between Rust and C++. bitflags! { /// Event-based element states. @@ -130,6 +132,19 @@ bitflags! { /// https://html.spec.whatwg.org/#selector-popover-open /// Match element's popover visibility state of showing const POPOVER_OPEN = 1u64 << 47; + /// https://drafts.csswg.org/css-scoping-1/#the-has-slotted-pseudo + /// Match whether a slot element has assigned nodes + const HAS_SLOTTED = 1u64 << 48; + /// https://drafts.csswg.org/selectors-4/#open-state + /// Match whether an openable element is currently open + const OPEN = 1u64 << 49; + /// For :active-view-transition. + /// + const ACTIVE_VIEW_TRANSITION = 1u64 << 50; + /// https://drafts.csswg.org/selectors-5/#headings + /// These 4 bits are used to pack the elements heading level into the element state + /// Heading levels can be from 1-9 so 4 bits allows us to express the full range. + const HEADING_LEVEL_BITS = 0b1111u64 << HEADING_LEVEL_OFFSET; /// Some convenience unions. const DIR_STATES = Self::LTR.bits() | Self::RTL.bits(); From f8a788e95f0394284b0704178486a7563df8ed02 Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Wed, 2 Jul 2025 02:53:58 +0200 Subject: [PATCH 09/11] Bump selectors version to 0.30.0 Signed-off-by: Oriol Brufau --- malloc_size_of/Cargo.toml | 2 +- selectors/Cargo.toml | 2 +- style/Cargo.toml | 2 +- style_traits/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/malloc_size_of/Cargo.toml b/malloc_size_of/Cargo.toml index 612ff98c16..d276fb9d87 100644 --- a/malloc_size_of/Cargo.toml +++ b/malloc_size_of/Cargo.toml @@ -17,7 +17,7 @@ servo = ["string_cache"] app_units = "0.7" cssparser = "0.35" euclid = "0.22" -selectors = { version = "0.29", path = "../selectors" } +selectors = { version = "0.30", path = "../selectors" } servo_arc = { version = "0.4", path = "../servo_arc" } smallbitvec = "2.3.0" smallvec = "1.13" diff --git a/selectors/Cargo.toml b/selectors/Cargo.toml index 6c5d3e5a32..fb3d70a753 100644 --- a/selectors/Cargo.toml +++ b/selectors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "selectors" -version = "0.29.0" +version = "0.30.0" authors = ["The Servo Project Developers"] documentation = "https://docs.rs/selectors/" description = "CSS Selectors matching for Rust" diff --git a/style/Cargo.toml b/style/Cargo.toml index fcb72a82a0..20cac1d4f1 100644 --- a/style/Cargo.toml +++ b/style/Cargo.toml @@ -84,7 +84,7 @@ parking_lot = "0.12" precomputed-hash = "0.1.1" rayon = "1" rayon-core = "1" -selectors = { version = "0.29.0", path = "../selectors" } +selectors = { version = "0.30.0", path = "../selectors" } serde = {version = "1.0", optional = true, features = ["derive"]} servo_arc = { version = "0.4.0", path = "../servo_arc" } stylo_atoms = { version = "0.4", path = "../stylo_atoms", optional = true} diff --git a/style_traits/Cargo.toml b/style_traits/Cargo.toml index 2c1b51edbc..3e96b146a5 100644 --- a/style_traits/Cargo.toml +++ b/style_traits/Cargo.toml @@ -23,7 +23,7 @@ cssparser = "0.35" euclid = "0.22" malloc_size_of = { version = "0.4", path = "../malloc_size_of", package = "stylo_malloc_size_of" } malloc_size_of_derive = "0.1" -selectors = { version = "0.29", path = "../selectors" } +selectors = { version = "0.30", path = "../selectors" } serde = "1.0" servo_arc = { version = "0.4", path = "../servo_arc" } stylo_atoms = { version = "0.4", path = "../stylo_atoms", optional = true } From 31a2c9cfa9a8fe8e980ada1a7502d07397a03873 Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Wed, 2 Jul 2025 03:04:36 +0200 Subject: [PATCH 10/11] Bump stylo_* version to 0.5.0 Signed-off-by: Oriol Brufau --- malloc_size_of/Cargo.toml | 2 +- style/Cargo.toml | 16 ++++++++-------- style_derive/Cargo.toml | 2 +- style_traits/Cargo.toml | 6 +++--- stylo_atoms/Cargo.toml | 2 +- stylo_config/Cargo.toml | 2 +- stylo_dom/Cargo.toml | 4 ++-- stylo_static_prefs/Cargo.toml | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/malloc_size_of/Cargo.toml b/malloc_size_of/Cargo.toml index d276fb9d87..e4894919c1 100644 --- a/malloc_size_of/Cargo.toml +++ b/malloc_size_of/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stylo_malloc_size_of" -version = "0.4.0" +version = "0.5.0" authors = ["The Servo Project Developers"] license = "MIT OR Apache-2.0" repository = "https://github.com/servo/stylo" diff --git a/style/Cargo.toml b/style/Cargo.toml index 20cac1d4f1..92046ef283 100644 --- a/style/Cargo.toml +++ b/style/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stylo" -version = "0.4.0" +version = "0.5.0" authors = ["The Servo Project Developers"] license = "MPL-2.0" repository = "https://github.com/servo/stylo" @@ -60,7 +60,7 @@ bitflags = "2" byteorder = "1.0" cssparser = "0.35" derive_more = { version = "2", features = ["add", "add_assign", "deref", "deref_mut", "from"] } -dom = { version = "0.4", path = "../stylo_dom", package = "stylo_dom" } +dom = { version = "0.5", path = "../stylo_dom", package = "stylo_dom" } new_debug_unreachable = "1.0" encoding_rs = {version = "0.8", optional = true} euclid = "0.22" @@ -71,7 +71,7 @@ itertools = "0.14" itoa = "1.0" lazy_static = "1" log = "0.4" -malloc_size_of = { version = "0.4", path = "../malloc_size_of", package = "stylo_malloc_size_of" } +malloc_size_of = { version = "0.5", path = "../malloc_size_of", package = "stylo_malloc_size_of" } malloc_size_of_derive = "0.1" web_atoms = { version = "0.1.3", optional = true } matches = "0.1" @@ -87,15 +87,15 @@ rayon-core = "1" selectors = { version = "0.30.0", path = "../selectors" } serde = {version = "1.0", optional = true, features = ["derive"]} servo_arc = { version = "0.4.0", path = "../servo_arc" } -stylo_atoms = { version = "0.4", path = "../stylo_atoms", optional = true} +stylo_atoms = { version = "0.5", path = "../stylo_atoms", optional = true} smallbitvec = "2.3.0" smallvec = "1.0" static_assertions = "1.1" -static_prefs = { version = "0.4", path = "../stylo_static_prefs", package = "stylo_static_prefs" } +static_prefs = { version = "0.5", path = "../stylo_static_prefs", package = "stylo_static_prefs" } string_cache = { version = "0.8", optional = true } -style_config = { version = "0.4", path = "../stylo_config", package = "stylo_config", optional = true } -style_derive = { version = "0.4", path = "../style_derive", package = "stylo_derive" } -style_traits = { version = "0.4", path = "../style_traits", package = "stylo_traits" } +style_config = { version = "0.5", path = "../stylo_config", package = "stylo_config", optional = true } +style_derive = { version = "0.5", path = "../style_derive", package = "stylo_derive" } +style_traits = { version = "0.5", path = "../style_traits", package = "stylo_traits" } to_shmem = { version = "0.2", path = "../to_shmem" } to_shmem_derive = { version = "0.1", path = "../to_shmem_derive" } thin-vec = "0.2.1" diff --git a/style_derive/Cargo.toml b/style_derive/Cargo.toml index 24b8491fe0..071664df00 100644 --- a/style_derive/Cargo.toml +++ b/style_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stylo_derive" -version = "0.4.0" +version = "0.5.0" authors = ["The Servo Project Developers"] license = "MPL-2.0" repository = "https://github.com/servo/stylo" diff --git a/style_traits/Cargo.toml b/style_traits/Cargo.toml index 3e96b146a5..be6fb54a93 100644 --- a/style_traits/Cargo.toml +++ b/style_traits/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stylo_traits" -version = "0.4.0" +version = "0.5.0" authors = ["The Servo Project Developers"] license = "MPL-2.0" repository = "https://github.com/servo/stylo" @@ -21,12 +21,12 @@ app_units = "0.7" bitflags = "2" cssparser = "0.35" euclid = "0.22" -malloc_size_of = { version = "0.4", path = "../malloc_size_of", package = "stylo_malloc_size_of" } +malloc_size_of = { version = "0.5", path = "../malloc_size_of", package = "stylo_malloc_size_of" } malloc_size_of_derive = "0.1" selectors = { version = "0.30", path = "../selectors" } serde = "1.0" servo_arc = { version = "0.4", path = "../servo_arc" } -stylo_atoms = { version = "0.4", path = "../stylo_atoms", optional = true } +stylo_atoms = { version = "0.5", path = "../stylo_atoms", optional = true } thin-vec = "0.2" to_shmem = { version = "0.2", path = "../to_shmem" } to_shmem_derive = { version = "0.1", path = "../to_shmem_derive" } diff --git a/stylo_atoms/Cargo.toml b/stylo_atoms/Cargo.toml index 30edabe322..63261e4fb1 100644 --- a/stylo_atoms/Cargo.toml +++ b/stylo_atoms/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stylo_atoms" -version = "0.4.0" +version = "0.5.0" authors = ["The Servo Project Developers"] documentation = "https://docs.rs/stylo_atoms/" description = "Interned string type for the Servo and Stylo projects" diff --git a/stylo_config/Cargo.toml b/stylo_config/Cargo.toml index 5f31c515cf..d89b20a3d4 100644 --- a/stylo_config/Cargo.toml +++ b/stylo_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stylo_config" -version = "0.4.0" +version = "0.5.0" authors = ["The Servo Project Developers"] documentation = "https://docs.rs/stylo_config/" description = "Runtime configuration for Stylo" diff --git a/stylo_dom/Cargo.toml b/stylo_dom/Cargo.toml index df7ff3802c..aa16ddfd92 100644 --- a/stylo_dom/Cargo.toml +++ b/stylo_dom/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stylo_dom" -version = "0.4.0" +version = "0.5.0" authors = ["The Servo Project Developers"] documentation = "https://docs.rs/stylo_dom/" description = "DOM state types for Stylo" @@ -15,4 +15,4 @@ path = "lib.rs" [dependencies] bitflags = "2" -malloc_size_of = { version = "0.4", path = "../malloc_size_of", package = "stylo_malloc_size_of" } +malloc_size_of = { version = "0.5", path = "../malloc_size_of", package = "stylo_malloc_size_of" } diff --git a/stylo_static_prefs/Cargo.toml b/stylo_static_prefs/Cargo.toml index be350e95d6..ff571caf1c 100644 --- a/stylo_static_prefs/Cargo.toml +++ b/stylo_static_prefs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stylo_static_prefs" -version = "0.4.0" +version = "0.5.0" authors = ["The Servo Project Developers"] documentation = "https://docs.rs/stylo_static_prefs/" description = "Static configuration for Stylo" From f7afb1517453e889f296b43825290d97c9c944eb Mon Sep 17 00:00:00 2001 From: Euclid Ye Date: Thu, 3 Jul 2025 12:17:15 +0800 Subject: [PATCH 11/11] Implement `DoubleEndedIterator`` for `TransitionPropertyIterator`` Signed-off-by: Euclid Ye --- style/animation.rs | 9 ++- .../helpers/animated_properties.mako.rs | 78 ++++++++++++++++++- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/style/animation.rs b/style/animation.rs index 9520810a98..7065b2972e 100644 --- a/style/animation.rs +++ b/style/animation.rs @@ -1427,7 +1427,14 @@ pub fn start_transitions_if_applicable( animation_state: &mut ElementAnimationSet, ) -> PropertyDeclarationIdSet { let mut properties_that_transition = PropertyDeclarationIdSet::default(); - for transition in new_style.transition_properties() { + // Reverse is needed + // See + // "If a property is specified multiple times in the value of transition-property + // (either on its own, via a shorthand that contains it, or via the all value), + // then the transition that starts uses the duration, delay, and timing function + // at the index corresponding to the last item in the value of transition-property + // that calls for animating that property." + for transition in new_style.transition_properties().rev() { let physical_property = transition .property .as_borrowed() diff --git a/style/properties/helpers/animated_properties.mako.rs b/style/properties/helpers/animated_properties.mako.rs index 513a198a6a..8bb2e325ac 100644 --- a/style/properties/helpers/animated_properties.mako.rs +++ b/style/properties/helpers/animated_properties.mako.rs @@ -718,11 +718,19 @@ impl ToAnimatedZero for AnimatedFilter { } } +#[cfg(feature = "servo")] +enum LonghandIteratorSource { + Front, + Back +} + /// An iterator over all the properties that transition on a given style. pub struct TransitionPropertyIterator<'a> { style: &'a ComputedValues, index_range: core::ops::Range, longhand_iterator: Option>, + #[cfg(feature = "servo")] + longhand_iterator_source: Option, } impl<'a> TransitionPropertyIterator<'a> { @@ -732,6 +740,8 @@ impl<'a> TransitionPropertyIterator<'a> { style, index_range: 0..style.get_ui().transition_property_count(), longhand_iterator: None, + #[cfg(feature = "servo")] + longhand_iterator_source: None, } } } @@ -756,10 +766,22 @@ impl<'a> Iterator for TransitionPropertyIterator<'a> { if let Some(longhand_id) = longhand_iterator.next() { return Some(TransitionPropertyIteration { property: OwnedPropertyDeclarationId::Longhand(longhand_id), - index: self.index_range.start - 1, + // the shorthand index that was consumed last + index: if cfg!(feature = "gecko") { + self.index_range.start - 1 + } else { + match self.longhand_iterator_source { + Some(LonghandIteratorSource::Front) => self.index_range.start - 1, + Some(LonghandIteratorSource::Back) => self.index_range.end, + None => unreachable!("Expected a longhand iterator source"), + } + } }); } self.longhand_iterator = None; + #[cfg(feature = "servo")] { + self.longhand_iterator_source = None; + } } let index = self.index_range.next()?; @@ -777,6 +799,9 @@ impl<'a> Iterator for TransitionPropertyIterator<'a> { // compute the next value of the iterator and then loop (equivalent // to calling self.next()). self.longhand_iterator = Some(shorthand_id.longhands()); + #[cfg(feature = "servo")] { + self.longhand_iterator_source = Some(LonghandIteratorSource::Front); + } }, } } @@ -791,3 +816,54 @@ impl<'a> Iterator for TransitionPropertyIterator<'a> { } } } + +#[cfg(feature = "servo")] +impl<'a> DoubleEndedIterator for TransitionPropertyIterator<'a> { + fn next_back(&mut self) -> Option { + use crate::values::computed::TransitionProperty; + loop { + if let Some(ref mut longhand_iterator) = self.longhand_iterator { + if let Some(longhand_id) = longhand_iterator.next() { + return Some(TransitionPropertyIteration { + property: OwnedPropertyDeclarationId::Longhand(longhand_id), + // the shorthand index that was consumed last + index: match self.longhand_iterator_source { + Some(LonghandIteratorSource::Front) => self.index_range.start - 1, + Some(LonghandIteratorSource::Back) => self.index_range.end, + None => unreachable!("Expected a longhand iterator source"), + }, + }); + } + self.longhand_iterator = None; + self.longhand_iterator_source = None; + } + + let index = self.index_range.next_back()?; + match self.style.get_ui().transition_property_at(index) { + TransitionProperty::NonCustom(id) => { + match id.longhand_or_shorthand() { + Ok(longhand_id) => { + return Some(TransitionPropertyIteration { + property: OwnedPropertyDeclarationId::Longhand(longhand_id), + index, + }); + }, + Err(shorthand_id) => { + // In the other cases, we set up our state so that we are ready to + // compute the next/next_back value of the iterator and then loop + self.longhand_iterator = Some(shorthand_id.longhands()); + self.longhand_iterator_source = Some(LonghandIteratorSource::Back); + }, + } + } + TransitionProperty::Custom(name) => { + return Some(TransitionPropertyIteration { + property: OwnedPropertyDeclarationId::Custom(name), + index, + }) + }, + TransitionProperty::Unsupported(..) => {}, + } + } + } +} \ No newline at end of file