This should help out quite a bit with uBO, which has lots of very
general attribute selectors. We invalidate per attribute name rather
than using a SelectorMap, which prevents matching for attribute
selectors that can't have changed.
The idea is that this should be generally cheaper, though there are
cases where this would be a slight pesimization. For example, if there's
an attribute selector like:
my-specific-element[my-attribute] { /* ... */ }
And you change `my-attribute` in an element that isn't a
`my-specific-element`, before that the SelectorMap would've prevented us
from selector-matching completely. Now we'd still run selector-matching
for that (though the matching would be pretty cheap).
However I think this should speed up things generally, let's see what
the perf tests think before landing this though.
Differential Revision: https://phabricator.services.mozilla.com/D76825
See the comment about why this is valuable. For a selector like:
.foo:is(.bar) > .baz
Before this patch we'd generate an Dependency for .bar like this:
Dependency {
selector: .bar,
offset: 0,
parent: Some(Dependency {
selector: .foo:is(.bar) > .baz,
offset: 1, // Pointing to the `>` combinator.
parent: None,
}),
}
After this patch we'd generate just:
Dependency {
selector: .foo:is(.bar) > .baz,
offset: 1, // Pointing to the `>` combinator.
parent: None,
}
This is not only less memory but also less work. The reason for that is that,
before this patch, when .bar changes, we'd look the dependency, and see there's
a parent, and then scan that, so we'd match `.bar` two times, one for the
initial dependency, and one for .foo:is(.bar).
Instead, with this we'd only check `.foo:is(.bar)` once.
Differential Revision: https://phabricator.services.mozilla.com/D71423
That way we can look at the parent dependency as described in the previous
patch. An alternative would be to add a:
parent_dependency: Option<&'a Dependency>
on construction to `Invalidation`, but this way seems slightly better to avoid
growing the struct. It's not even one more indirection because the selector is
contained directly in the Dependency struct.
Differential Revision: https://phabricator.services.mozilla.com/D71422
The tricky part of :is() and :where() is that they can have combinators inside,
so something like this is valid:
foo:is(#bar > .baz) ~ taz
The current invalidation logic is based on the assumption that you can
represent a combinator as a (selector, offset) tuple, which are stored in the
Dependency struct. This assumption breaks with :is() and :where(), so we need
to make them be able to represent a combinator in an "inner" selector.
For this purpose, we add a `parent` dependency. With it, when invalidating
inside the `:is()` we can represent combinators inside as a stack.
The basic idea is that, for the example above, when an id of "bar" is added or
removed, we'd find a dependency like:
Dependency {
selector: #bar > .baz,
offset: 1, // pointing to the `>` combinator
parent: Some(Dependency {
selector: foo:is(#bar > .baz) > taz,
offset: 1, // Pointing to the `~` combinator.
parent: None,
})
}
That way, we'd start matching at the element that changed, towards the right,
and if we find an element that matches .baz, instead of invalidating that
element, we'd look at the parent dependency, then double-check that the whole
left-hand-side of the selector (foo:is(#bar > .baz)) actually changed, and then
keep invalidating to the right using the parent dependency as usual.
This patch only builds the data structure and keeps the code compiling, the
actual invalidation work will come in a following patch.
Differential Revision: https://phabricator.services.mozilla.com/D71421
This implements the easy / straight-forward parts of the :where / :is
selectors.
The biggest missing piece is to handle properly invalidation when there
are combinators present inside the :where. That's the hard part of this,
actually.
But this is probably worth landing in the interim. This fixes some of
the visitors that were easy to fix.
Differential Revision: https://phabricator.services.mozilla.com/D70788
Still does nothing, since we still do not collect part rules, but this is all
the plumbing that should allow us to invalidate parts when attributes or state
change on their ancestors.
Differential Revision: https://phabricator.services.mozilla.com/D32642
We could invalidate in a slightly more fine-grained way, but I don't think it's
worth the churn vs. keeping the special-cases minimal.
Bug: 1452640
Reviewed-by: xidorn
MozReview-Commit-ID: 5DkQrgwg9GW
Servo currently uses `heapsize`, but Stylo/Gecko use `malloc_size_of`.
`malloc_size_of` is better -- it handles various cases that `heapsize` does not
-- so this patch changes Servo to use `malloc_size_of`.
This patch makes the following changes to the `malloc_size_of` crate.
- Adds `MallocSizeOf` trait implementations for numerous types, some built-in
(e.g. `VecDeque`), some external and Servo-only (e.g. `string_cache`).
- Makes `enclosing_size_of_op` optional, because vanilla jemalloc doesn't
support that operation.
- For `HashSet`/`HashMap`, falls back to a computed estimate when
`enclosing_size_of_op` isn't available.
- Adds an extern "C" `malloc_size_of` function that does the actual heap
measurement; this is based on the same functions from the `heapsize` crate.
This patch makes the following changes elsewhere.
- Converts all the uses of `heapsize` to instead use `malloc_size_of`.
- Disables the "heapsize"/"heap_size" feature for the external crates that
provide it.
- Removes the `HeapSizeOf` implementation from `hashglobe`.
- Adds `ignore` annotations to a few `Rc`/`Arc`, because `malloc_size_of`
doesn't derive those types, unlike `heapsize`.
This patch makes the MallocSizeOf stuff in Stylo work more like the HeapSizeOf
stuff already in Servo, except better. In particular, it adds deriving support
for MallocSizeOf, which will make it easier to improve coverage.
The patch does the following.
- Combines servo/components/style/stylesheets/memory.rs and the heapsize crate
into a new crate, malloc_size_of.
- Forks the heapsize_derive crate, calling it malloc_size_of, so that
MallocSizeOf can be derived.
- Both the new crates have MIT/Apache licenses, like heapsize, in case they are
incorporated into heapsize in the future.
- Renames the methods within MallocSizeOf and the related traits so they are
more concise.
- Removes MallocSizeOfWithGuard.
- Adds `derive(MallocSizeOf)` to a lot of types, in some cases replacing an
equivalent or almost-equivalent hand-written implementation.
- Adds stuff so that Rc/Arc can be handled properly.
This moves us to clear on rebuild, which allows us to remove yet another place
where we track stylist dirtiness.
Bug: 1390255
Reviewed-by: heycam
MozReview-Commit-ID: nihQbUAbh8
Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
This commit also removes the old restyle_hints module and splits it into
multiple modules under components/style/invalidation/element/.
The basic approach is to walk down the tree using compound selectors as needed,
in order to do as little selector-matching as possible.
Bug: 1368240
MozReview-Commit-ID: 2YO8fKFygZI