Bug 1506842 - Always restyle / repaint when a visited query finishes. r=dholbert

Differential Revision: https://phabricator.services.mozilla.com/D50810

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2019-11-04 16:55:33 +00:00
parent 0207ce5451
commit a57fd16889
4 changed files with 41 additions and 8 deletions

View File

@ -10,6 +10,8 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/Element.h"
#include "mozilla/IHistory.h"
#include "mozilla/StaticPrefs_layout.h"
#include "nsLayoutUtils.h"
#include "nsIURL.h"
#include "nsIURIMutator.h"
#include "nsISizeOf.h"
@ -109,7 +111,12 @@ void Link::VisitedQueryFinished(bool aVisited) {
// Tell the element to update its visited state
mElement->UpdateState(true);
// FIXME(emilio, bug 1506842): Repaint here unconditionally.
if (StaticPrefs::layout_css_always_repaint_on_unvisited()) {
// Even if the state didn't actually change, we need to repaint in order for
// the visited state not to be observable.
nsLayoutUtils::PostRestyleEvent(GetElement(), RestyleHint::RestyleSubtree(),
nsChangeHint_RepaintFrame);
}
}
EventStates Link::LinkState() const {

View File

@ -3205,13 +3205,25 @@ void RestyleManager::ContentStateChanged(nsIContent* aContent,
const EventStates kVisitedAndUnvisited =
NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED;
// NOTE: We want to return ASAP for visitedness changes, but we don't want to
// mess up the situation where the element became a link or stopped being one.
if (aChangedBits.HasAllStates(kVisitedAndUnvisited) &&
!Gecko_VisitedStylesEnabled(element.OwnerDoc())) {
aChangedBits &= ~kVisitedAndUnvisited;
if (aChangedBits.IsEmpty()) {
return;
// When visited links are disabled, they cannot influence style for obvious
// reasons.
//
// When layout.css.always-repaint-on-unvisited is true, we'll restyle when the
// relevant visited query finishes, regardless of the style (see
// Link::VisitedQueryFinished). So there's no need to do anything as a result
// of this state change just yet.
//
// Note that this check checks for _both_ bits: This is only true when visited
// changes to unvisited or vice-versa, but not when we start or stop being a
// link itself.
if (aChangedBits.HasAllStates(kVisitedAndUnvisited)) {
if (!Gecko_VisitedStylesEnabled(element.OwnerDoc()) ||
StaticPrefs::layout_css_always_repaint_on_unvisited()) {
aChangedBits &= ~kVisitedAndUnvisited;
if (aChangedBits.IsEmpty()) {
return;
}
}
}

View File

@ -4720,6 +4720,12 @@
value: @IS_NIGHTLY_BUILD@
mirror: always
# Whether we always restyle / repaint as a result of a visited query
- name: layout.css.always-repaint-on-unvisited
type: RelaxedAtomicBool
value: false
mirror: always
# Make `zoom` a `transform` + `transform-origin` alias.
- name: layout.css.zoom-transform-hack.enabled
type: RelaxedAtomicBool

View File

@ -158,6 +158,14 @@ where
// If we the visited state changed, we force a restyle here. Matching
// doesn't depend on the actual visited state at all, so we can't look
// at matching results to decide what to do for this case.
//
// TODO(emilio): This should be contains(), to avoid doing subtree
// restyles when adding or removing an href attribute, but invalidation
// for that case is broken right now (bug 1591987).
//
// This piece of code should be removed when
// layout.css.always-repaint-on-unvisited is true, since we cannot get
// into this situation in that case.
if state_changes.intersects(ElementState::IN_VISITED_OR_UNVISITED_STATE) {
trace!(" > visitedness change, force subtree restyle");
// We can't just return here because there may also be attribute