Bug 1636998 - Make ::-moz-focus-outer a no-op, and remove it on Nightly. r=jwatt

See https://bugzilla.mozilla.org/show_bug.cgi?id=932410#c2 for the
context for which this pseudo-element was added.

In the previous patch, I had to special-case range appearance because of
this pseudo-class, but that patch makes this pseudo-class completely
redundant, as now all form controls, themed and unthemed, display
outlines, unless the native theme displays a focus indicator on its own.

Remove the special case, and make ranges use outlines like everything
else rather than this bespoke pseudo-element.

Differential Revision: https://phabricator.services.mozilla.com/D74734
This commit is contained in:
Emilio Cobos Álvarez 2020-05-18 07:59:32 +00:00
Родитель 5a8027aef4
Коммит 36b46408b8
11 изменённых файлов: 23 добавлений и 159 удалений

Просмотреть файл

@ -417,10 +417,6 @@
outline: none;
}
.font-value-slider::-moz-focus-outer {
border: 0;
}
.font-value-slider::-moz-range-thumb {
background-color: var(--slider-thumb-color);
border: 0;

Просмотреть файл

@ -10685,7 +10685,6 @@ exports.PSEUDO_ELEMENTS = [
":first-line",
":selection",
":-moz-focus-inner",
":-moz-focus-outer",
":-moz-progress-bar",
":-moz-range-track",
":-moz-range-progress",

Просмотреть файл

@ -72,11 +72,6 @@ void nsRangeFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
aContent->AddEventListener(NS_LITERAL_STRING("touchstart"),
mDummyTouchListener, false);
ServoStyleSet* styleSet = PresContext()->StyleSet();
mOuterFocusStyle = styleSet->ProbePseudoElementStyle(
*aContent->AsElement(), PseudoStyleType::mozFocusOuter, Style());
return nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
}
@ -148,78 +143,6 @@ void nsRangeFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
}
}
class nsDisplayRangeFocusRing final : public nsPaintedDisplayItem {
public:
nsDisplayRangeFocusRing(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
: nsPaintedDisplayItem(aBuilder, aFrame) {
MOZ_COUNT_CTOR(nsDisplayRangeFocusRing);
}
MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayRangeFocusRing)
nsDisplayItemGeometry* AllocateGeometry(
nsDisplayListBuilder* aBuilder) override;
void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) const override;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override;
virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
NS_DISPLAY_DECL_NAME("RangeFocusRing", TYPE_RANGE_FOCUS_RING)
};
nsDisplayItemGeometry* nsDisplayRangeFocusRing::AllocateGeometry(
nsDisplayListBuilder* aBuilder) {
return new nsDisplayItemGenericImageGeometry(this, aBuilder);
}
void nsDisplayRangeFocusRing::ComputeInvalidationRegion(
nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) const {
auto geometry =
static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
if (aBuilder->ShouldSyncDecodeImages() &&
geometry->ShouldInvalidateToSyncDecodeImages()) {
bool snap;
aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
}
nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
}
nsRect nsDisplayRangeFocusRing::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const {
*aSnap = false;
nsRect rect(ToReferenceFrame(), Frame()->GetSize());
// We want to paint as if specifying a border for ::-moz-focus-outer
// specifies an outline for our frame, so inflate by the border widths:
ComputedStyle* computedStyle =
static_cast<nsRangeFrame*>(mFrame)->mOuterFocusStyle;
MOZ_ASSERT(computedStyle, "We only exist if mOuterFocusStyle is non-null");
rect.Inflate(computedStyle->StyleBorder()->GetComputedBorder());
return rect;
}
void nsDisplayRangeFocusRing::Paint(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx) {
bool unused;
ComputedStyle* computedStyle =
static_cast<nsRangeFrame*>(mFrame)->mOuterFocusStyle;
MOZ_ASSERT(computedStyle, "We only exist if mOuterFocusStyle is non-null");
PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
? PaintBorderFlags::SyncDecodeImages
: PaintBorderFlags();
ImgDrawResult result = nsCSSRendering::PaintBorder(
mFrame->PresContext(), *aCtx, mFrame, GetPaintRect(),
GetBounds(aBuilder, &unused), computedStyle, flags);
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
}
void nsRangeFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) {
const nsStyleDisplay* disp = StyleDisplay();
@ -240,36 +163,6 @@ void nsRangeFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
} else {
BuildDisplayListForInline(aBuilder, aLists);
}
// Draw a focus outline if appropriate:
if (!aBuilder->IsForPainting() || !IsVisibleForPainting()) {
// we don't want the focus ring item for hit-testing or if the item isn't
// in the area being [re]painted
return;
}
EventStates eventStates = mContent->AsElement()->State();
if (eventStates.HasState(NS_EVENT_STATE_DISABLED) ||
!eventStates.HasState(NS_EVENT_STATE_FOCUSRING)) {
return; // can't have focus or doesn't match :-moz-focusring
}
if (!mOuterFocusStyle || !mOuterFocusStyle->StyleBorder()->HasBorder()) {
// no ::-moz-focus-outer specified border (how style specifies a focus ring
// for range)
return;
}
// FIXME(emilio): This is using ThemeWantsButtonInnerFocusRing even though
// it's painting the ::-moz-focus-outer pseudo-class... But why is
// ::-moz-focus-outer useful, instead of outline?
if (IsThemed(disp) && !PresContext()->Theme()->ThemeWantsButtonInnerFocusRing(
disp->mAppearance)) {
return; // the native theme displays its own visual indication of focus
}
aLists.Content()->AppendNewToTop<nsDisplayRangeFocusRing>(aBuilder, this);
}
void nsRangeFrame::Reflow(nsPresContext* aPresContext,
@ -821,22 +714,3 @@ bool nsRangeFrame::ShouldUseNativeStyle() const {
!PresContext()->HasAuthorSpecifiedRules(
thumbFrame, STYLES_DISABLING_NATIVE_THEMING);
}
ComputedStyle* nsRangeFrame::GetAdditionalComputedStyle(int32_t aIndex) const {
// We only implement this so that SetAdditionalComputedStyle will be
// called if style changes that would change the -moz-focus-outer
// pseudo-element have occurred.
if (aIndex != 0) {
return nullptr;
}
return mOuterFocusStyle;
}
void nsRangeFrame::SetAdditionalComputedStyle(int32_t aIndex,
ComputedStyle* aComputedStyle) {
MOZ_ASSERT(aIndex == 0,
"GetAdditionalComputedStyle is handling other indexes?");
// The -moz-focus-outer pseudo-element's style has changed.
mOuterFocusStyle = aComputedStyle;
}

Просмотреть файл

@ -88,10 +88,6 @@ class nsRangeFrame final : public nsContainerFrame,
aFlags & ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
}
ComputedStyle* GetAdditionalComputedStyle(int32_t aIndex) const override;
void SetAdditionalComputedStyle(int32_t aIndex,
ComputedStyle* aComputedStyle) override;
/**
* Returns true if the slider's thumb moves horizontally, or else false if it
* moves vertically.
@ -180,11 +176,6 @@ class nsRangeFrame final : public nsContainerFrame,
*/
nsCOMPtr<Element> mThumbDiv;
/**
* Cached ComputedStyle for -moz-focus-outer CSS pseudo-element style.
*/
RefPtr<ComputedStyle> mOuterFocusStyle;
class DummyTouchListener final : public nsIDOMEventListener {
private:
~DummyTouchListener() = default;

Просмотреть файл

@ -2623,12 +2623,8 @@ void nsFrame::DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder,
// focus indicators.
if (outline.mOutlineStyle.IsAuto()) {
auto* disp = StyleDisplay();
// FIXME(emilio): The range special-case is needed because <input
// type=range> displays its own outline with ::-moz-focus-outer, and this
// would show two outlines instead of one.
if (IsThemed(disp) &&
(PresContext()->Theme()->ThemeDrawsFocusForWidget(disp->mAppearance) ||
disp->mAppearance != StyleAppearance::Range)) {
PresContext()->Theme()->ThemeDrawsFocusForWidget(disp->mAppearance)) {
return;
}
}

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/CSSEnabledState.h"
#include "mozilla/Compiler.h"
#include "mozilla/PseudoStyleType.h"
#include "mozilla/StaticPrefs_layout.h"
// Is this pseudo-element a CSS2 pseudo-element that can be specified
// with the single colon syntax (in addition to the double-colon syntax,
@ -120,6 +121,9 @@ class nsCSSPseudoElements {
static bool IsEnabled(Type aType, EnabledState aEnabledState) {
if (!PseudoElementHasAnyFlag(
aType, CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME)) {
if (aType == Type::mozFocusOuter) {
return mozilla::StaticPrefs::layout_css_moz_focus_outer_enabled();
}
return true;
}

Просмотреть файл

@ -873,16 +873,6 @@ input[type=range] {
user-select: none !important;
}
/**
* Ideally we'd also require :-moz-focusring here, but that doesn't currently
* work. Instead we only use the -moz-focus-outer border style if
* NS_EVENT_STATE_FOCUSRING is set (the check is in
* nsRangeFrame::BuildDisplayList).
*/
input[type=range]::-moz-focus-outer {
border: 1px dotted black;
}
/**
* Layout handles positioning of this pseudo-element specially (so that content
* authors can concentrate on styling the thumb without worrying about the

Просмотреть файл

@ -5714,6 +5714,13 @@
mirror: always
rust: true
# Whether the ::-moz-focus-outer pseudo-class is parsed.
- name: layout.css.moz-focus-outer.enabled
type: RelaxedAtomicBool
value: @IS_NOT_NIGHTLY_BUILD@
mirror: always
rust: true
# Pref to control whether @-moz-document url-prefix() is parsed in content
# pages. Only effective when layout.css.moz-document.content.enabled is false.
- name: layout.css.moz-document.url-prefix-hack.enabled

Просмотреть файл

@ -159,7 +159,13 @@ impl PseudoElement {
/// Whether this pseudo-element is enabled for all content.
pub fn enabled_in_content(&self) -> bool {
(self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME) == 0
if (self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME) != 0 {
return false;
}
match *self {
PseudoElement::MozFocusOuter => static_prefs::pref!("layout.css.moz-focus-outer.enabled"),
_ => true,
}
}
/// Whether this pseudo is enabled explicitly in UA sheets.

Просмотреть файл

@ -224,9 +224,9 @@
filter: drop-shadow(0px 0px 2px rgba(0,0,0,0.65));
}
.volumeControl::-moz-focus-outer,
.scrubber::-moz-focus-outer {
border: 0;
.volumeControl,
.scrubber {
outline: none;
}
.progressBackgroundBar {

Просмотреть файл

@ -911,6 +911,7 @@ bool nsNativeBasicTheme::WidgetIsContainer(StyleAppearance aAppearance) {
bool nsNativeBasicTheme::ThemeDrawsFocusForWidget(StyleAppearance aAppearance) {
switch (aAppearance) {
case StyleAppearance::Range:
// TODO(emilio): Checkbox / Radio don't have focus indicators when checked.
// If they did, we could just return true here unconditionally.
case StyleAppearance::Checkbox: