style: no-op visited changes earlier if visited links are disabled.

We force a repaint from ContentStateChangedInternal if visited links are
disabled, and that's observable. Let's cut it off as early as we can to avoid
timing attacks even when :visited is disabled.

Differential Revision: https://phabricator.services.mozilla.com/D3304
This commit is contained in:
Emilio Cobos Álvarez 2018-08-14 10:47:25 +02:00
parent cc1897597c
commit 87b1e1cdc9
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
2 changed files with 14 additions and 41 deletions

View file

@ -8,7 +8,7 @@ use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use context::QuirksMode;
use dom::TElement;
use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{self, RawGeckoPresContextOwned, ServoStyleSetSizes, StyleSheet as DomStyleSheet};
use gecko_bindings::structs::{RawGeckoPresContextOwned, ServoStyleSetSizes, StyleSheet as DomStyleSheet};
use gecko_bindings::structs::{StyleSheetInfo, nsIDocument};
use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
use invalidation::media_queries::{MediaListKey, ToMediaListKey};
@ -185,52 +185,20 @@ impl PerDocumentStyleDataImpl {
.flush(&StylesheetGuards::same(guard), document_element, snapshots)
}
/// Returns whether private browsing is enabled.
fn is_private_browsing_enabled(&self) -> bool {
let doc = self.stylist
.device()
.pres_context()
.mDocument
.raw::<nsIDocument>();
unsafe { bindings::Gecko_IsPrivateBrowsingEnabled(doc) }
}
/// Returns whether the document is being used as an image.
fn is_being_used_as_an_image(&self) -> bool {
let doc = self.stylist
.device()
.pres_context()
.mDocument
.raw::<nsIDocument>();
unsafe { (*doc).mIsBeingUsedAsImage() }
}
/// Get the default computed values for this document.
pub fn default_computed_values(&self) -> &Arc<ComputedValues> {
self.stylist.device().default_computed_values_arc()
}
/// Returns whether visited links are enabled.
fn visited_links_enabled(&self) -> bool {
unsafe { structs::StaticPrefs_sVarCache_layout_css_visited_links_enabled }
}
/// Returns whether visited styles are enabled.
#[inline]
pub fn visited_styles_enabled(&self) -> bool {
if !self.visited_links_enabled() {
return false;
}
if self.is_private_browsing_enabled() {
return false;
}
if self.is_being_used_as_an_image() {
return false;
}
true
let doc = self.stylist
.device()
.pres_context()
.mDocument
.raw::<nsIDocument>();
unsafe { bindings::Gecko_VisitedStylesEnabled(doc) }
}
/// Measure heap usage.

View file

@ -167,8 +167,13 @@ where
// do for this case.
if state_changes.intersects(ElementState::IN_VISITED_OR_UNVISITED_STATE) {
trace!(" > visitedness change, force subtree restyle");
// If we get here with visited links disabled, we should probably
// just avoid the restyle and remove the state change here, not only
// as an optimization, but also because it kind of would kill the
// point of disabling visited links.
debug_assert!(self.shared_context.visited_styles_enabled);
// We can't just return here because there may also be attribute
// changes as well that imply additional hints.
// changes as well that imply additional hints for siblings.
self.data.hint.insert(RestyleHint::restyle_subtree());
}