Skip to content

Commit

Permalink
Bug 1636998 - Only suppress auto-style outlines for widgets that pain…
Browse files Browse the repository at this point in the history
…t their own focus indicator. r=jfkthame

Turns out we did have a hook for this already! But it is used to draw or
not inner button styles, so not quite equivalent.

I had to expand the amount of things it applies to because buttons and
such do paint focus indicators in all widgets. This patch could cause
some undesired outlines in some widgets. I hope not (I tried to audit to
the best of my knowledge), but in that case they'd be just more values
to add to the list.

Differential Revision: https://phabricator.services.mozilla.com/D74733
  • Loading branch information
emilio committed May 13, 2020
1 parent d76da80 commit dbbe790
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 52 deletions.
11 changes: 11 additions & 0 deletions gfx/src/nsITheme.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,17 @@ class nsITheme : public nsISupports {
*/
virtual bool ThemeDrawsFocusForWidget(StyleAppearance aWidgetType) = 0;

/**
* Whether we want an inner focus ring for buttons and such.
*
* Usually, we don't want it if we have our own focus indicators, but windows
* is special, because it wants it even though focus also alters the border
* color and such.
*/
virtual bool ThemeWantsButtonInnerFocusRing(StyleAppearance aAppearance) {
return !ThemeDrawsFocusForWidget(aAppearance);
}

/**
* Should we insert a dropmarker inside of combobox button?
*/
Expand Down
4 changes: 2 additions & 2 deletions layout/forms/nsButtonFrameRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ void nsDisplayButtonForeground::Paint(nsDisplayListBuilder* aBuilder,
nsPresContext* presContext = mFrame->PresContext();
const nsStyleDisplay* disp = mFrame->StyleDisplay();
if (!mFrame->IsThemed(disp) ||
!presContext->Theme()->ThemeDrawsFocusForWidget(disp->mAppearance)) {
presContext->Theme()->ThemeWantsButtonInnerFocusRing(disp->mAppearance)) {
nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());

// Draw the -moz-focus-inner border
Expand All @@ -369,7 +369,7 @@ bool nsDisplayButtonForeground::CreateWebRenderCommands(
nsPresContext* presContext = mFrame->PresContext();
const nsStyleDisplay* disp = mFrame->StyleDisplay();
if (!mFrame->IsThemed(disp) ||
!presContext->Theme()->ThemeDrawsFocusForWidget(disp->mAppearance)) {
presContext->Theme()->ThemeWantsButtonInnerFocusRing(disp->mAppearance)) {
nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
br = mBFR->CreateInnerFocusBorderRenderer(aDisplayListBuilder, presContext,
nullptr, GetPaintRect(), r,
Expand Down
5 changes: 3 additions & 2 deletions layout/forms/nsComboboxControlFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1504,8 +1504,9 @@ void nsComboboxControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
if (window && window->ShouldShowFocusRing()) {
nsPresContext* presContext = PresContext();
const nsStyleDisplay* disp = StyleDisplay();
if ((!IsThemed(disp) || !presContext->Theme()->ThemeDrawsFocusForWidget(
disp->mAppearance)) &&
if ((!IsThemed(disp) ||
presContext->Theme()->ThemeWantsButtonInnerFocusRing(
disp->mAppearance)) &&
mDisplayFrame && IsVisibleForPainting()) {
aLists.Content()->AppendNewToTop<nsDisplayComboboxFocus>(aBuilder,
this);
Expand Down
7 changes: 5 additions & 2 deletions layout/forms/nsRangeFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,11 @@ void nsRangeFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
return;
}
if (IsThemed(disp) &&
PresContext()->Theme()->ThemeDrawsFocusForWidget(disp->mAppearance)) {
// 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
}
Expand Down
18 changes: 12 additions & 6 deletions layout/generic/nsFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2625,12 +2625,18 @@ void nsFrame::DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder,
return;
}

// We don't display outline-style: auto on themed frames.
//
// TODO(emilio): Maybe we want a theme hook to say which frames can handle it
// themselves. Non-native theme probably will want this.
if (outline.mOutlineStyle.IsAuto() && IsThemed()) {
return;
// We don't display outline-style: auto on themed frames that have their own
// 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)) {
return;
}
}

aLists.Outlines()->AppendNewToTop<nsDisplayOutline>(aBuilder, this);
Expand Down
20 changes: 8 additions & 12 deletions layout/style/res/forms.css
Original file line number Diff line number Diff line change
Expand Up @@ -470,10 +470,6 @@ input[type="image"]:disabled {
cursor: unset;
}

input[type="image"]:-moz-focusring {
/* Don't specify the outline-color, we should always use initial value. */
outline: 1px dotted;
}

/* file selector */
input[type="file"] {
Expand Down Expand Up @@ -562,15 +558,15 @@ input[type="checkbox"]:disabled:hover:active {
cursor: unset;
}

% On Mac, the native theme takes care of this.
% See nsNativeThemeCocoa::ThemeDrawsFocusForWidget.
%ifndef XP_MACOSX
input[type="checkbox"]:-moz-focusring,
input[type="radio"]:-moz-focusring {
/* Don't specify the outline-color, we should always use initial value. */
outline: 1px dotted;
input:not([type="file"]):not([type="image"]):-moz-focusring,
select:-moz-focusring,
button:-moz-focusring,
textarea:-moz-focusring {
/* These elements can handle outline themselves when themed, so we use
* outline-style: auto and skip rendering the outline only when themed and
* the theme allows so */
outline-style: auto;
}
%endif

input[type="search"] {
box-sizing: border-box;
Expand Down
10 changes: 0 additions & 10 deletions layout/style/res/html.css
Original file line number Diff line number Diff line change
Expand Up @@ -726,16 +726,6 @@ html:-moz-focusring {
outline-style: none;
}

input:not([type="file"]):-moz-focusring,
button:-moz-focusring,
select:-moz-focusring,
button:-moz-focusring,
textarea:-moz-focusring {
/* These elements can handle outline themselves when themed, so we use
* outline-style: auto and skip rendering the outline only when themed */
outline-style: auto;
}

/* hidden elements */
base, basefont, datalist, head, meta, script, style, title,
noembed, param, template {
Expand Down
27 changes: 18 additions & 9 deletions widget/cocoa/nsNativeThemeCocoa.mm
Original file line number Diff line number Diff line change
Expand Up @@ -4204,15 +4204,24 @@ static bool IsHiDPIContext(nsDeviceContext* aContext) {
}

bool nsNativeThemeCocoa::ThemeDrawsFocusForWidget(StyleAppearance aAppearance) {
if (aAppearance == StyleAppearance::MenulistButton || aAppearance == StyleAppearance::Button ||
aAppearance == StyleAppearance::MozMacHelpButton ||
aAppearance == StyleAppearance::MozMacDisclosureButtonOpen ||
aAppearance == StyleAppearance::MozMacDisclosureButtonClosed ||
aAppearance == StyleAppearance::Radio || aAppearance == StyleAppearance::Range ||
aAppearance == StyleAppearance::Checkbox)
return true;

return false;
switch (aAppearance) {
case StyleAppearance::Textarea:
case StyleAppearance::Textfield:
case StyleAppearance::Searchfield:
case StyleAppearance::NumberInput:
case StyleAppearance::Menulist:
case StyleAppearance::MenulistButton:
case StyleAppearance::Button:
case StyleAppearance::MozMacHelpButton:
case StyleAppearance::MozMacDisclosureButtonOpen:
case StyleAppearance::MozMacDisclosureButtonClosed:
case StyleAppearance::Radio:
case StyleAppearance::Range:
case StyleAppearance::Checkbox:
return true;
default:
return false;
}
}

bool nsNativeThemeCocoa::ThemeNeedsComboboxDropmarker() { return false; }
Expand Down
20 changes: 13 additions & 7 deletions widget/gtk/nsNativeThemeGTK.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1972,13 +1972,19 @@ nsNativeThemeGTK::WidgetIsContainer(StyleAppearance aAppearance) {
}

bool nsNativeThemeGTK::ThemeDrawsFocusForWidget(StyleAppearance aAppearance) {
if (aAppearance == StyleAppearance::Menulist ||
aAppearance == StyleAppearance::MenulistButton ||
aAppearance == StyleAppearance::Button ||
aAppearance == StyleAppearance::Treeheadercell)
return true;

return false;
switch (aAppearance) {
case StyleAppearance::Button:
case StyleAppearance::Menulist:
case StyleAppearance::MenulistButton:
case StyleAppearance::MenulistTextfield:
case StyleAppearance::Textarea:
case StyleAppearance::Textfield:
case StyleAppearance::Treeheadercell:
case StyleAppearance::NumberInput:
return true;
default:
return false;
}
}

bool nsNativeThemeGTK::ThemeNeedsComboboxDropmarker() { return false; }
Expand Down
10 changes: 9 additions & 1 deletion widget/nsNativeBasicTheme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,15 @@ bool nsNativeBasicTheme::WidgetIsContainer(StyleAppearance aAppearance) {
}

bool nsNativeBasicTheme::ThemeDrawsFocusForWidget(StyleAppearance aAppearance) {
return true;
switch (aAppearance) {
// TODO(emilio): Checkbox / Radio don't have focus indicators when checked.
// If they did, we could just return true here unconditionally.
case StyleAppearance::Checkbox:
case StyleAppearance::Radio:
return false;
default:
return true;
}
}

bool nsNativeBasicTheme::ThemeNeedsComboboxDropmarker() { return true; }
Expand Down
12 changes: 11 additions & 1 deletion widget/windows/nsNativeThemeWin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2601,7 +2601,17 @@ bool nsNativeThemeWin::WidgetIsContainer(StyleAppearance aAppearance) {
}

bool nsNativeThemeWin::ThemeDrawsFocusForWidget(StyleAppearance aAppearance) {
return false;
switch (aAppearance) {
case StyleAppearance::Menulist:
case StyleAppearance::MenulistButton:
case StyleAppearance::MenulistTextfield:
case StyleAppearance::Textarea:
case StyleAppearance::Textfield:
case StyleAppearance::NumberInput:
return true;
default:
return false;
}
}

bool nsNativeThemeWin::ThemeNeedsComboboxDropmarker() { return true; }
Expand Down
2 changes: 2 additions & 0 deletions widget/windows/nsNativeThemeWin.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class nsNativeThemeWin : private nsNativeTheme, public nsITheme {

bool ThemeDrawsFocusForWidget(StyleAppearance aAppearance) override;

bool ThemeWantsButtonInnerFocusRing(StyleAppearance) override { return true; }

bool ThemeNeedsComboboxDropmarker() override;

virtual bool WidgetAppearanceDependsOnWindowFocus(
Expand Down

0 comments on commit dbbe790

Please sign in to comment.