Bug 1328509 - Style sharing cache for visited. r=emilio
The style sharing cache stores the regular `ComputedValues`, so it would also
have the visited values as well for anything inserted into the cache (since they
are nested inside). Unlike all other element states, a change in state of
unvisited vs. visited does not change the style system's output, since we have
already computed both possible outputs up front.
We change the element state checks when looking for style sharing cache hits to
ignore visitedness, since that's handled by the two separate sets of values.
MozReview-Commit-ID: Dt8uK8gSQSP
--- a/servo/components/style/sharing/checks.rs
+++ b/servo/components/style/sharing/checks.rs
@@ -3,16 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Different checks done during the style sharing process in order to determine
//! quickly whether it's worth to share style, and whether two different
//! elements can indeed share the same style.
use context::{CurrentElementInfo, SelectorFlagsMap, SharedStyleContext};
use dom::TElement;
+use element_state::*;
use matching::MatchMethods;
use selectors::bloom::BloomFilter;
use selectors::matching::{ElementSelectorFlags, StyleRelations};
use sharing::StyleSharingCandidate;
use sink::ForgetfulSink;
use stylearc::Arc;
/// Determines, based on the results of selector matching, whether it's worth to
@@ -75,16 +76,30 @@ pub fn have_same_class<E>(element: E,
let mut attrs = vec![];
candidate.element.each_class(|c| attrs.push(c.clone()));
candidate.class_attributes = Some(attrs)
}
element_class_attributes == *candidate.class_attributes.as_ref().unwrap()
}
+/// Compare element and candidate state, but ignore visitedness. Styles don't
+/// actually changed based on visitedness (since both possibilities are computed
+/// up front), so it's safe to share styles if visitedness differs.
+pub fn have_same_state_ignoring_visitedness<E>(element: E,
+ candidate: &StyleSharingCandidate<E>)
+ -> bool
+ where E: TElement,
+{
+ let state_mask = !IN_VISITED_OR_UNVISITED_STATE;
+ let state = element.get_state() & state_mask;
+ let candidate_state = candidate.element.get_state() & state_mask;
+ state == candidate_state
+}
+
/// Whether a given element and a candidate match the same set of "revalidation"
/// selectors.
///
/// Revalidation selectors are those that depend on the DOM structure, like
/// :first-child, etc, or on attributes that we don't check off-hand (pretty
/// much every attribute selector except `id` and `class`.
#[inline]
pub fn revalidate<E>(element: E,
--- a/servo/components/style/sharing/mod.rs
+++ b/servo/components/style/sharing/mod.rs
@@ -344,17 +344,17 @@ impl<E: TElement> StyleSharingCandidateC
miss!(Link)
}
if element.matches_user_and_author_rules() !=
candidate.element.matches_user_and_author_rules() {
miss!(UserAndAuthorRules)
}
- if element.get_state() != candidate.element.get_state() {
+ if !checks::have_same_state_ignoring_visitedness(element, candidate) {
miss!(State)
}
if element.get_id() != candidate.element.get_id() {
miss!(IdAttr)
}
if element.style_attribute().is_some() {