Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mstange/9e7b750b175d2703d14dc39500318dac to your computer and use it in GitHub Desktop.
Save mstange/9e7b750b175d2703d14dc39500318dac to your computer and use it in GitHub Desktop.
Random outline:auto focus ring patches I found from August 2016
# HG changeset patch
# User Markus Stange <mstange@themasta.com>
# Date 1470168508 14400
# Tue Aug 02 16:08:28 2016 -0400
# Node ID 292431b7e17ba071794065fdf3e35b3655daab49
# Parent 786a1bc7436e30f9ed9c54873b1ba1c7808972e2
Make NS_THEME_FOCUS (for outline-style:auto) look good on macOS.
MozReview-Commit-ID: 9vFl1kBQI8i
diff --git a/layout/style/res/forms.css b/layout/style/res/forms.css
--- a/layout/style/res/forms.css
+++ b/layout/style/res/forms.css
@@ -460,17 +460,17 @@ input[type="image"] {
}
input[type="image"]:disabled {
cursor: inherit;
}
input[type="image"]:-moz-focusring {
/* Don't specify the outline-color, we should always use initial value. */
- outline: 1px dotted;
+ outline: 1px auto;
}
/* file selector */
input[type="file"] {
display: inline-block;
white-space: nowrap;
overflow: hidden;
overflow-clip-box: padding-box;
diff --git a/layout/style/res/html.css b/layout/style/res/html.css
--- a/layout/style/res/html.css
+++ b/layout/style/res/html.css
@@ -703,17 +703,17 @@ canvas {
-moz-user-select: none;
}
/* focusable content: anything w/ tabindex >=0 is focusable, but we
skip drawing a focus outline on a few things that handle it
themselves. */
:-moz-focusring:not(input):not(button):not(select):not(textarea):not(iframe):not(frame):not(body):not(html) {
/* Don't specify the outline-color, we should always use initial value. */
- outline: 1px dotted;
+ outline: 1px auto;
}
/* hidden elements */
base, basefont, datalist, head, meta, script, style, title,
noembed, param, template {
display: none;
}
diff --git a/layout/style/res/ua.css b/layout/style/res/ua.css
--- a/layout/style/res/ua.css
+++ b/layout/style/res/ua.css
@@ -113,17 +113,17 @@
/* Links */
*|*:any-link {
cursor: pointer;
}
*|*:any-link:-moz-focusring {
/* Don't specify the outline-color, we should always use initial value. */
- outline: 1px dotted;
+ outline: 1px auto;
}
/* Miscellaneous */
*|*::-moz-anonymous-block, *|*::-moz-cell-content {
display: block !important;
position: static !important;
unicode-bidi: inherit;
diff --git a/widget/cocoa/nsNativeThemeCocoa.h b/widget/cocoa/nsNativeThemeCocoa.h
--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -129,17 +129,17 @@ protected:
const NSSize& aIconSize, NSString* aImageName,
bool aCenterHorizontally);
void DrawButton(CGContextRef context, ThemeButtonKind inKind,
const HIRect& inBoxRect, bool inIsDefault,
ThemeButtonValue inValue, ThemeButtonAdornment inAdornment,
mozilla::EventStates inState, nsIFrame* aFrame);
void DrawFocusOutline(CGContextRef cgContext, const HIRect& inBoxRect,
mozilla::EventStates inState, uint8_t aWidgetType,
- nsIFrame* aFrame);
+ nsIFrame* aFrame, nscoord aAppUnitsPerPixel);
void DrawDropdown(CGContextRef context, const HIRect& inBoxRect,
mozilla::EventStates inState, uint8_t aWidgetType,
nsIFrame* aFrame);
void DrawSpinButtons(CGContextRef context, ThemeButtonKind inKind,
const HIRect& inBoxRect, ThemeDrawState inDrawState,
ThemeButtonAdornment inAdornment,
mozilla::EventStates inState, nsIFrame* aFrame);
void DrawSpinButton(CGContextRef context, ThemeButtonKind inKind,
diff --git a/widget/cocoa/nsNativeThemeCocoa.mm b/widget/cocoa/nsNativeThemeCocoa.mm
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -1240,35 +1240,105 @@ nsNativeThemeCocoa::DrawPushButton(CGCon
#if DRAW_IN_FRAME_DEBUG
CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
CGContextFillRect(cgContext, inBoxRect);
#endif
NS_OBJC_END_TRY_ABORT_BLOCK;
}
+// Cribbed from PathHelpers.cpp, and adapted for NSRect / NSBezierPath.
+static NSBezierPath*
+BezierPathWithRoundedRect(NSRect aRect, CGFloat aRadii[8])
+{
+ // See AppendRoundedRectToPath in PathHelpers.cpp for an explanation.
+ const CGFloat alpha = 0.55191497064665766025;
+
+ typedef struct { CGFloat a, b; } twoFloats;
+
+ twoFloats cornerMults[4] = { { -1, 0 },
+ { 0, -1 },
+ { +1, 0 },
+ { 0, +1 } };
+
+ NSPoint cornerCoords[] = {
+ { NSMinX(aRect), NSMinY(aRect) },
+ { NSMaxX(aRect), NSMinY(aRect) },
+ { NSMaxX(aRect), NSMaxY(aRect) },
+ { NSMinX(aRect), NSMaxY(aRect) }
+ };
+
+ NSPoint pc, p0, p1, p2, p3;
+
+ NSBezierPath* path = [NSBezierPath bezierPath];
+ [path moveToPoint:NSMakePoint(aRect.origin.x + aRadii[0],
+ aRect.origin.y)];
+
+ for (int i = 0; i < 4; ++i) {
+ int c = ((i+1) % 4);
+ int cw = NS_FULL_TO_HALF_CORNER(c, false);
+ int ch = NS_FULL_TO_HALF_CORNER(c, true);
+
+ int i2 = (i+2) % 4;
+ int i3 = (i+3) % 4;
+
+ pc = cornerCoords[c];
+
+ if (aRadii[cw] > 0.0 && aRadii[ch] > 0.0) {
+ p0.x = pc.x + cornerMults[i].a * aRadii[cw];
+ p0.y = pc.y + cornerMults[i].b * aRadii[ch];
+
+ p3.x = pc.x + cornerMults[i3].a * aRadii[cw];
+ p3.y = pc.y + cornerMults[i3].b * aRadii[ch];
+
+ p1.x = p0.x + alpha * cornerMults[i2].a * aRadii[cw];
+ p1.y = p0.y + alpha * cornerMults[i2].b * aRadii[ch];
+
+ p2.x = p3.x - alpha * cornerMults[i3].a * aRadii[cw];
+ p2.y = p3.y - alpha * cornerMults[i3].b * aRadii[ch];
+
+ [path lineToPoint:p0];
+ [path curveToPoint:p3 controlPoint1:p1 controlPoint2:p2];
+ } else {
+ [path lineToPoint:pc];
+ }
+ }
+
+ [path closePath];
+ return path;
+}
+
void
nsNativeThemeCocoa::DrawFocusOutline(CGContextRef cgContext, const HIRect& inBoxRect,
EventStates inState, uint8_t aWidgetType,
- nsIFrame* aFrame)
+ nsIFrame* aFrame, nscoord aAppUnitsPerPixel)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
- HIThemeFrameDrawInfo fdi;
- fdi.version = 0;
- fdi.kind = kHIThemeFrameTextFieldSquare;
- fdi.state = kThemeStateActive;
- fdi.isFocused = TRUE;
-
-#if DRAW_IN_FRAME_DEBUG
- CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
- CGContextFillRect(cgContext, inBoxRect);
-#endif
-
- HIThemeDrawFrame(&inBoxRect, &fdi, cgContext, HITHEME_ORIENTATION);
+ nscoord twipsRadii[8];
+ nsSize sz(inBoxRect.size.width * aAppUnitsPerPixel, inBoxRect.size.height * aAppUnitsPerPixel);
+ bool hasBorderRadius = aFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
+
+ NSGraphicsContext* savedContext = [NSGraphicsContext currentContext];
+ [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:YES]];
+ CGContextSaveGState(cgContext);
+ NSSetFocusRingStyle(NSFocusRingOnly);
+ if (!hasBorderRadius) {
+ NSRectFill(NSRectFromCGRect(inBoxRect));
+ } else {
+ CGFloat radii[8] = {
+ CGFloat(twipsRadii[0]) / aAppUnitsPerPixel, CGFloat(twipsRadii[1]) / aAppUnitsPerPixel,
+ CGFloat(twipsRadii[2]) / aAppUnitsPerPixel, CGFloat(twipsRadii[3]) / aAppUnitsPerPixel,
+ CGFloat(twipsRadii[4]) / aAppUnitsPerPixel, CGFloat(twipsRadii[5]) / aAppUnitsPerPixel,
+ CGFloat(twipsRadii[6]) / aAppUnitsPerPixel, CGFloat(twipsRadii[7]) / aAppUnitsPerPixel
+ };
+ [BezierPathWithRoundedRect(NSRectFromCGRect(inBoxRect), radii) fill];
+ }
+ CGContextRestoreGState(cgContext);
+ [NSGraphicsContext setCurrentContext:savedContext];
NS_OBJC_END_TRY_ABORT_BLOCK;
}
typedef void (*RenderHIThemeControlFunction)(CGContextRef cgContext, const HIRect& aRenderRect, void* aData);
static void
RenderTransformedHIThemeControl(CGContextRef aCGContext, const HIRect& aRect,
@@ -2285,22 +2355,25 @@ nsNativeThemeCocoa::DrawWidgetBackground
gfxRect nativeWidgetRect(aRect.x, aRect.y, aRect.width, aRect.height);
nativeWidgetRect.ScaleInverse(gfxFloat(p2a));
nativeWidgetRect.Round();
if (nativeWidgetRect.IsEmpty())
return NS_OK; // Don't attempt to draw invisible widgets.
AutoRestoreTransform autoRestoreTransform(&aDrawTarget);
+ nscoord appUnitsPerPixel = p2a; // "pixel" here is one user space unit in the cgContext.
+
bool hidpi = IsHiDPIContext(aFrame->PresContext());
if (hidpi) {
// Use high-resolution drawing.
nativeWidgetRect.Scale(0.5f);
nativeDirtyRect.Scale(0.5f);
aDrawTarget.SetTransform(aDrawTarget.GetTransform().PreScale(2.0f, 2.0f));
+ appUnitsPerPixel *= 2;
}
gfxQuartzNativeDrawing nativeDrawing(aDrawTarget, nativeDirtyRect);
CGContextRef cgContext = nativeDrawing.BeginNativeDrawing();
if (cgContext == nullptr) {
// The Quartz surface handles 0x0 surfaces by internally
// making all operations no-ops; there's no cgcontext created for them.
@@ -2472,17 +2545,17 @@ nsNativeThemeCocoa::DrawWidgetBackground
} else if (IsButtonTypeMenu(aFrame)) {
DrawDropdown(cgContext, macRect, eventState, aWidgetType, aFrame);
} else {
DrawPushButton(cgContext, macRect, eventState, aWidgetType, aFrame);
}
break;
case NS_THEME_FOCUS_OUTLINE:
- DrawFocusOutline(cgContext, macRect, eventState, aWidgetType, aFrame);
+ DrawFocusOutline(cgContext, macRect, eventState, aWidgetType, aFrame, appUnitsPerPixel);
break;
case NS_THEME_MAC_HELP_BUTTON:
case NS_THEME_MAC_DISCLOSURE_BUTTON_OPEN:
case NS_THEME_MAC_DISCLOSURE_BUTTON_CLOSED:
DrawPushButton(cgContext, macRect, eventState, aWidgetType, aFrame);
break;
@@ -3106,17 +3179,17 @@ nsNativeThemeCocoa::GetWidgetOverflow(ns
{
// Progress bars draw a 2 pixel white shadow under their progress indicators
nsMargin m(0, 0, NSIntPixelsToAppUnits(2, p2a), 0);
aOverflowRect->Inflate(m);
return true;
}
case NS_THEME_FOCUS_OUTLINE:
{
- aOverflowRect->Inflate(NSIntPixelsToAppUnits(2, p2a));
+ aOverflowRect->Inflate(NSIntPixelsToAppUnits(kMaxFocusRingWidth, p2a));
return true;
}
}
return false;
}
static const int32_t kRegularScrollbarThumbMinSize = 26;
# HG changeset patch
# User Markus Stange <mstange@themasta.com>
# Date 1470175636 14400
# Tue Aug 02 18:07:16 2016 -0400
# Node ID e28ccf4ed4d473c29c395af04829975670263d77
# Parent 292431b7e17ba071794065fdf3e35b3655daab49
Animate outline:auto on focused elements.
MozReview-Commit-ID: IGNhqTrEkku
diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -1501,25 +1501,17 @@ toolbar .toolbarbutton-1 > .toolbarbutto
#urlbar:-moz-window-inactive {
box-shadow: none;
border-color: rgba(0,0,0,0.1);
}
}
#urlbar[focused="true"],
.searchbar-textbox[focused="true"] {
- border-color: -moz-mac-focusring;
- box-shadow: @focusRingShadow@;
-}
-
-@media (-moz-mac-yosemite-theme) {
- #urlbar[focused="true"],
- .searchbar-textbox[focused="true"] {
- box-shadow: @yosemiteFocusRingShadow@;
- }
+ outline: auto;
}
#urlbar-container {
-moz-box-align: center;
}
#urlbar {
border-radius: @toolbarbuttonCornerRadius@;
diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1893,18 +1893,20 @@ nsFocusManager::Focus(nsPIDOMWindowOuter
aWindow->SetFocusedNode(aContent, focusMethod);
bool sendFocusEvent =
aContent && aContent->IsInComposedDoc() && !IsNonFocusableRoot(aContent);
nsPresContext* presContext = presShell->GetPresContext();
if (sendFocusEvent) {
// if the focused element changed, scroll it into view
- if (aFocusChanged)
+ if (aFocusChanged) {
ScrollIntoView(presShell, aContent, aFlags);
+ mLastFocusTimeStamp = TimeStamp::Now();
+ }
NotifyFocusStateChange(aContent, aWindow->ShouldShowFocusRing(), true);
// if this is an object/plug-in/remote browser, focus its widget. Note that we might
// no longer be in the same document, due to the events we fired above when
// aIsNewDocument.
if (presShell->GetDocument() == aContent->GetComposedDoc()) {
if (aAdjustWidgets && objectFrameWidget && !sTestMode)
diff --git a/dom/base/nsFocusManager.h b/dom/base/nsFocusManager.h
--- a/dom/base/nsFocusManager.h
+++ b/dom/base/nsFocusManager.h
@@ -9,16 +9,17 @@
#include "nsCycleCollectionParticipant.h"
#include "nsIDocument.h"
#include "nsIFocusManager.h"
#include "nsIObserver.h"
#include "nsIWidget.h"
#include "nsWeakReference.h"
#include "mozilla/Attributes.h"
+#include "mozilla/TimeStamp.h"
#define FOCUSMETHOD_MASK 0xF000
#define FOCUSMETHODANDRING_MASK 0xF0F000
#define FOCUSMANAGER_CONTRACTID "@mozilla.org/focus-manager;1"
class nsIContent;
class nsIDocShellTreeItem;
@@ -72,16 +73,18 @@ public:
*/
nsPIDOMWindowOuter* GetFocusedWindow() const { return mFocusedWindow; }
/**
* Return an active window. Version of nsIFocusManager::GetActiveWindow.
*/
nsPIDOMWindowOuter* GetActiveWindow() const { return mActiveWindow; }
+ mozilla::TimeStamp GetLastFocusTimeStamp() const { return mLastFocusTimeStamp; }
+
/**
* Called when content has been removed.
*/
nsresult ContentRemoved(nsIDocument* aDocument, nsIContent* aContent);
/**
* Called when mouse button event handling is started and finished.
*/
@@ -511,16 +514,18 @@ private:
// content if it's not consumed. Therefore, while DOM event handlers are
// handling mouse down events or preceding mosue down event is consumed but
// handling mouse up events, they should be able to steal focus from any
// elements even if focus is in chrome content. So, if this isn't nullptr
// and the caller can access the document node, the caller should succeed in
// moving focus.
nsCOMPtr<nsIDocument> mMouseButtonEventHandlingDocument;
+ mozilla::TimeStamp mLastFocusTimeStamp;
+
static bool sTestMode;
// the single focus manager
static nsFocusManager* sInstance;
};
nsresult
NS_NewFocusManager(nsIFocusManager** aResult);
diff --git a/layout/base/nsDisplayItemTypesList.h b/layout/base/nsDisplayItemTypesList.h
--- a/layout/base/nsDisplayItemTypesList.h
+++ b/layout/base/nsDisplayItemTypesList.h
@@ -31,16 +31,17 @@ DECLARE_DISPLAY_ITEM_TYPE(STICKY_POSITIO
DECLARE_DISPLAY_ITEM_TYPE(FRAMESET_BORDER)
DECLARE_DISPLAY_ITEM_TYPE(FRAMESET_BLANK)
DECLARE_DISPLAY_ITEM_TYPE(HEADER_FOOTER)
DECLARE_DISPLAY_ITEM_TYPE(IMAGE)
DECLARE_DISPLAY_ITEM_TYPE(LIST_FOCUS)
DECLARE_DISPLAY_ITEM_TYPE(OPACITY)
DECLARE_DISPLAY_ITEM_TYPE(OPTION_EVENT_GRABBER)
DECLARE_DISPLAY_ITEM_TYPE(OUTLINE)
+DECLARE_DISPLAY_ITEM_TYPE(OUTLINE_ANIMATION)
DECLARE_DISPLAY_ITEM_TYPE(OWN_LAYER)
DECLARE_DISPLAY_ITEM_TYPE(PAGE_CONTENT)
DECLARE_DISPLAY_ITEM_TYPE(PAGE_SEQUENCE)
DECLARE_DISPLAY_ITEM_TYPE(PLUGIN)
DECLARE_DISPLAY_ITEM_TYPE(PLUGIN_READBACK)
DECLARE_DISPLAY_ITEM_TYPE(PLUGIN_VIDEO)
DECLARE_DISPLAY_ITEM_TYPE(PRINT_PLUGIN)
DECLARE_DISPLAY_ITEM_TYPE(REMOTE)
diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -65,16 +65,17 @@
#include "nsContentUtils.h"
#include "nsPrintfCString.h"
#include "UnitTransforms.h"
#include "LayersLogging.h"
#include "FrameLayerBuilder.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/RestyleManager.h"
#include "nsCaret.h"
+#include "nsFocusManager.h"
#include "nsISelection.h"
#include "nsDOMTokenList.h"
#include "mozilla/RuleNodeCacheConditions.h"
#include "nsCSSProps.h"
#include "nsPluginFrame.h"
#include "DisplayItemScrollClip.h"
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
@@ -5121,16 +5122,88 @@ bool nsDisplayFixedPosition::TryMerge(ns
if (other->mFrame != mFrame)
return false;
if (aItem->GetClip() != GetClip())
return false;
MergeFromTrackingMergedFrames(other);
return true;
}
+already_AddRefed<Layer>
+nsDisplayOutlineAnimation::BuildLayer(nsDisplayListBuilder* aBuilder,
+ LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) {
+ RefPtr<Layer> layer =
+ nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
+
+ if (layer->Manager()->GetBackendType() == layers::LayersBackend::LAYERS_CLIENT) {
+
+ nsFocusManager* focusManager = nsFocusManager::GetFocusManager();
+ nsIContent* focusedContent = focusManager->GetFocusedContent();
+ TimeStamp animationStart = focusManager->GetLastFocusTimeStamp();
+ if (focusedContent && !animationStart.IsNull() &&
+ nsContentUtils::ContentIsDescendantOf(focusedContent, mFrame->GetContent())) {
+ nsRect r = mFrame->GetRectRelativeToSelf() + ToReferenceFrame();
+ nsPoint midPoint = r.Center();
+ nscoord appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
+ LayoutDevicePoint midPointDev = LayoutDevicePixel::FromAppUnits(midPoint, appUnitsPerDevPixel);
+ Point3D midPoint3D(midPointDev.x, midPointDev.y, 0);
+
+ layer->ClearAnimations();
+ layers::Animation* transformAnimation = layer->AddAnimation();
+
+ transformAnimation->startTime() = animationStart;
+ transformAnimation->initialCurrentTime() = TimeDuration::FromSeconds(0.0);
+ transformAnimation->duration() = TimeDuration::FromSeconds(0.25);
+ transformAnimation->iterations() = 1;
+ transformAnimation->iterationStart() = 0;
+ transformAnimation->direction() = int32_t(PlaybackDirection::Normal);
+ transformAnimation->property() = eCSSProperty_transform;
+ transformAnimation->playbackRate() = 1;
+ transformAnimation->data() = TransformData(nsPoint(), midPoint3D, nsRect(), appUnitsPerDevPixel);
+ transformAnimation->easingFunction() = TimingFunction(CubicBezierFunction(0, 0, 1, 1));
+
+ AnimationSegment* transformAnimSegment = transformAnimation->segments().AppendElement();
+ transformAnimSegment->startState() = InfallibleTArray<TransformFunction>();
+ transformAnimSegment->endState() = InfallibleTArray<TransformFunction>();
+ transformAnimSegment->startState().get_ArrayOfTransformFunction().AppendElement(Scale(3, 3, 1));
+ transformAnimSegment->endState().get_ArrayOfTransformFunction().AppendElement(Scale(1, 1, 1));
+ transformAnimSegment->startPortion() = 0;
+ transformAnimSegment->endPortion() = 1;
+ transformAnimSegment->sampleFn() = TimingFunction(CubicBezierFunction(0.19, 1, 0.22, 1));
+
+ layers::Animation* opacityAnimation = layer->AddAnimation();
+ opacityAnimation->startTime() = animationStart;
+ opacityAnimation->initialCurrentTime() = TimeDuration::FromSeconds(0.0);
+ opacityAnimation->duration() = TimeDuration::FromSeconds(0.25);
+ opacityAnimation->iterations() = 1;
+ opacityAnimation->iterationStart() = 0;
+ opacityAnimation->direction() = int32_t(PlaybackDirection::Normal);
+ opacityAnimation->property() = eCSSProperty_opacity;
+ opacityAnimation->playbackRate() = 1;
+ opacityAnimation->data() = AnimationData(null_t());
+ opacityAnimation->easingFunction() = TimingFunction(CubicBezierFunction(0, 0, 1, 1));
+
+ AnimationSegment* opacityAnimSegment = opacityAnimation->segments().AppendElement();
+ opacityAnimSegment->startState() = 0.0f;
+ opacityAnimSegment->endState() = 0.7f;
+ opacityAnimSegment->startPortion() = 0;
+ opacityAnimSegment->endPortion() = 1;
+ opacityAnimSegment->sampleFn() = TimingFunction(CubicBezierFunction(0, 0, 1, 1));
+
+ layer->SetOpacity(0.0f);
+ layer->SetUserData(nsIFrame::LayerIsPrerenderedDataKey(),
+ /*the value is irrelevant*/nullptr);
+ layer->SetContentFlags(layer->GetContentFlags() | Layer::CONTENT_MAY_CHANGE_TRANSFORM);
+ }
+ }
+
+ return layer.forget();
+}
+
nsDisplayStickyPosition::nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
nsDisplayList* aList)
: nsDisplayOwnLayer(aBuilder, aFrame, aList)
{
MOZ_COUNT_CTOR(nsDisplayStickyPosition);
}
diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -3685,16 +3685,28 @@ private:
nsDisplayList* aList, uint32_t aIndex);
void Init(nsDisplayListBuilder* aBuilder);
AnimatedGeometryRoot* mAnimatedGeometryRootForScrollMetadata;
uint32_t mIndex;
bool mIsFixedBackground;
};
+class nsDisplayOutlineAnimation : public nsDisplayOwnLayer {
+public:
+ nsDisplayOutlineAnimation(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ nsDisplayList* aList)
+ : nsDisplayOwnLayer(aBuilder, aFrame, aList /*, aBuilder->CurrentActiveScrolledRoot() */)
+ {}
+ NS_DISPLAY_DECL_NAME("OutlineAnimation", TYPE_OUTLINE_ANIMATION)
+ virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
+ LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters) override;
+};
+
/**
* This creates an empty scrollable layer. It has no child layers.
* It is used to record the existence of a scrollable frame in the layer
* tree.
*/
class nsDisplayScrollInfoLayer : public nsDisplayWrapList
{
public:
diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1844,18 +1844,24 @@ nsFrame::DisplaySelectionOverlay(nsDispl
void
nsFrame::DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists)
{
if (StyleOutline()->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE)
return;
- aLists.Outlines()->AppendNewToTop(
- new (aBuilder) nsDisplayOutline(aBuilder, this));
+ nsDisplayItem* outline = new (aBuilder) nsDisplayOutline(aBuilder, this);
+ if (StyleOutline()->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_AUTO) {
+ nsDisplayList temp;
+ temp.AppendToTop(outline);
+ outline = new (aBuilder) nsDisplayOutlineAnimation(aBuilder, this, &temp);
+ }
+
+ aLists.Outlines()->AppendNewToTop(outline);
}
void
nsFrame::DisplayOutline(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists)
{
if (!IsVisibleForPainting(aBuilder))
return;
diff --git a/layout/style/res/forms.css b/layout/style/res/forms.css
--- a/layout/style/res/forms.css
+++ b/layout/style/res/forms.css
@@ -708,24 +708,36 @@ input[type="submit"]::-moz-focus-inner,
input[type="file"] > button[type="button"]::-moz-focus-inner {
padding-block-start: 0px;
padding-inline-end: 2px;
padding-block-end: 0px;
padding-inline-start: 2px;
border: 1px dotted transparent;
}
+%ifndef XP_MACOSX
button:-moz-focusring::-moz-focus-inner,
input[type="color"]:-moz-system-metric(color-picker-available):-moz-focusring::-moz-focus-inner,
input[type="reset"]:-moz-focusring::-moz-focus-inner,
input[type="button"]:-moz-focusring::-moz-focus-inner,
input[type="submit"]:-moz-focusring::-moz-focus-inner,
input[type="file"] > button[type="button"]:-moz-focusring::-moz-focus-inner {
border-color: ButtonText;
}
+%endif
+
+%ifdef XP_MACOSX
+button:-moz-focusring,
+textarea:-moz-focusring,
+input:not([type="color"]):not([type="file"]):-moz-focusring,
+input[type="color"]:-moz-system-metric(color-picker-available):-moz-focusring,
+input[type="file"] > button[type="button"]:-moz-focusring {
+ outline: auto;
+}
+%endif
button:disabled:active, button:disabled,
input[type="color"]:-moz-system-metric(color-picker-available):disabled:active,
input[type="color"]:-moz-system-metric(color-picker-available):disabled,
input[type="reset"]:disabled:active,
input[type="reset"]:disabled,
input[type="button"]:disabled:active,
input[type="button"]:disabled,
@@ -912,17 +924,19 @@ input[type=range][orient=vertical] {
/**
* 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 {
+%ifndef XP_MACOSX
border: 1px dotted black;
+%endif
}
/**
* Layout handles positioning of this pseudo-element specially (so that content
* authors can concentrate on styling the thumb without worrying about the
* logic to position it). Specifically the 'margin', 'top' and 'left'
* properties are ignored.
*
diff --git a/toolkit/content/textbox.css b/toolkit/content/textbox.css
--- a/toolkit/content/textbox.css
+++ b/toolkit/content/textbox.css
@@ -5,23 +5,25 @@
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); /* set default namespace to XUL */
@namespace html url("http://www.w3.org/1999/xhtml"); /* namespace for HTML elements */
html|*.textbox-input {
-moz-appearance: none !important;
text-align: inherit;
text-shadow: inherit;
box-sizing: border-box;
+ outline: none;
-moz-box-flex: 1;
}
html|*.textbox-textarea {
-moz-appearance: none !important;
text-shadow: inherit;
box-sizing: border-box;
+ outline: none;
-moz-box-flex: 1;
}
/*
html|*.textbox-input::-moz-placeholder,
html|*.textbox-textarea::-moz-placeholder {
text-align: left;
direction: ltr;
diff --git a/toolkit/themes/osx/global/findBar.css b/toolkit/themes/osx/global/findBar.css
--- a/toolkit/themes/osx/global/findBar.css
+++ b/toolkit/themes/osx/global/findBar.css
@@ -83,16 +83,24 @@ label.findbar-find-fast:-moz-lwtheme,
}
@media (-moz-mac-yosemite-theme) {
.findbar-find-previous,
.findbar-find-next {
border-radius: 3px;
box-shadow: none;
}
+
+ .findbar-find-next,
+ .findbar-find-previous,
+ .findbar-highlight,
+ .findbar-case-sensitive,
+ .findbar-entire-word {
+ border-width: 0.5px;
+ }
}
.findbar-highlight,
.findbar-case-sensitive,
.findbar-entire-word {
margin-inline-end: 5px;
padding: 2px 9px;
}
@@ -100,17 +108,17 @@ label.findbar-find-fast:-moz-lwtheme,
.findbar-highlight {
margin-inline-start: 8px;
}
.findbar-container > toolbarbutton:-moz-focusring,
.findbar-find-next:-moz-focusring,
.findbar-find-previous:-moz-focusring {
position: relative;
- box-shadow: @focusRingShadow@, @roundButtonShadow@;
+ outline: auto;
}
.findbar-container > toolbarbutton[disabled] {
color: GrayText !important;
}
.findbar-find-next:not([disabled]):hover:active,
.findbar-find-previous:not([disabled]):hover:active,
@@ -120,50 +128,36 @@ label.findbar-find-fast:-moz-lwtheme,
.findbar-highlight:not([disabled])[checked="true"],
.findbar-case-sensitive:not([disabled])[checked="true"],
.findbar-entire-word:not([disabled])[checked="true"] {
text-shadow: @loweredShadow@;
background: @roundButtonPressedBackground@;
box-shadow: @roundButtonPressedShadow@;
}
-.findbar-find-next:hover:active:-moz-focusring,
-.findbar-find-previous:hover:active:-moz-focusring {
- text-shadow: @loweredShadow@;
- background: @roundButtonPressedBackground@;
- box-shadow: @focusRingShadow@, @roundButtonPressedShadow@;
-}
-
-@media (-moz-mac-yosemite-theme) {
- .findbar-container > toolbarbutton:-moz-focusring,
- .findbar-find-next:-moz-focusring,
- .findbar-find-previous:-moz-focusring {
- box-shadow: @yosemiteFocusRingShadow@, @roundButtonShadow@;
- }
-
- .findbar-find-next:hover:active:-moz-focusring,
- .findbar-find-previous:hover:active:-moz-focusring {
- box-shadow: @yosemiteFocusRingShadow@, @roundButtonPressedShadow@;
- }
-}
-
/* Search field */
.findbar-textbox {
position: relative;
-moz-appearance: none;
border: @roundButtonBorder@;
border-radius: 10000px 0 0 10000px;
box-shadow: @roundButtonShadow@;
background: url("chrome://global/skin/icons/search-textbox.svg") -moz-Field no-repeat 5px center;
margin: 0;
padding: 2px 8px;
padding-inline-start: 19px;
}
+@media (-moz-mac-yosemite-theme) {
+ .findbar-textbox {
+ border-width: 0.5px;
+ }
+}
+
.findbar-textbox:-moz-locale-dir(rtl) {
border-radius: 0 10000px 10000px 0;
}
@media (-moz-mac-yosemite-theme) {
.findbar-textbox {
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
@@ -175,23 +169,17 @@ label.findbar-find-fast:-moz-lwtheme,
}
}
.findbar-textbox:not([focused="true"]):-moz-lwtheme {
opacity: 0.9;
}
.findbar-textbox[focused="true"] {
- box-shadow: @focusRingShadow@;
-}
-
-@media (-moz-mac-yosemite-theme) {
- .findbar-textbox[focused="true"] {
- box-shadow: @yosemiteFocusRingShadow@;
- }
+ outline: auto;
}
.findbar-textbox[flash="true"] {
background-color: #F7E379;
}
.findbar-textbox[status="notfound"] {
background-color: #FD919B;
# HG changeset patch
# User Markus Stange <mstange@themasta.com>
# Date 1468851056 14400
# Mon Jul 18 10:10:56 2016 -0400
# Node ID abc9ff143d42432b634e8484c55849ae3015945c
# Parent e28ccf4ed4d473c29c395af04829975670263d77
Don't draw outlines for themed frames. We don't want double focus rings, and we don't want outline:none to turn off focus rings for themed frames.
MozReview-Commit-ID: 4GVfvSBwIQZ
diff --git a/layout/forms/nsFieldSetFrame.cpp b/layout/forms/nsFieldSetFrame.cpp
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -165,25 +165,27 @@ nsFieldSetFrame::BuildDisplayList(nsDisp
// we need to paint the outline
if (!(GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) &&
IsVisibleForPainting(aBuilder)) {
if (StyleEffects()->mBoxShadow) {
aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
nsDisplayBoxShadowOuter(aBuilder, this));
}
- nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
+ bool isThemed = nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
aBuilder, this, VisualBorderRectRelativeToSelf(),
aLists.BorderBackground(),
/* aAllowWillPaintBorderOptimization = */ false);
aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
nsDisplayFieldSetBorderBackground(aBuilder, this));
- DisplayOutlineUnconditional(aBuilder, aLists);
+ if (!isThemed) {
+ DisplayOutlineUnconditional(aBuilder, aLists);
+ }
DO_GLOBAL_REFLOW_COUNT_DSP("nsFieldSetFrame");
}
if (GetPrevInFlow()) {
DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
}
diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1858,18 +1858,19 @@ nsFrame::DisplayOutlineUnconditional(nsD
aLists.Outlines()->AppendNewToTop(outline);
}
void
nsFrame::DisplayOutline(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists)
{
- if (!IsVisibleForPainting(aBuilder))
+ if (!IsVisibleForPainting(aBuilder) || IsThemed()) {
return;
+ }
DisplayOutlineUnconditional(aBuilder, aLists);
}
void
nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect, nsDisplayList* aList)
{
@@ -1930,17 +1931,19 @@ nsFrame::DisplayBorderBackgroundOutline(
// If there's a themed background, we should not create a border item.
// It won't be rendered.
if (!bgIsThemed && StyleBorder()->HasBorder()) {
aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
nsDisplayBorder(aBuilder, this));
}
- DisplayOutlineUnconditional(aBuilder, aLists);
+ if (!bgIsThemed) {
+ DisplayOutlineUnconditional(aBuilder, aLists);
+ }
}
inline static bool IsSVGContentWithCSSClip(const nsIFrame *aFrame)
{
// The CSS spec says that the 'clip' property only applies to absolutely
// positioned elements, whereas the SVG spec says that it applies to SVG
// elements regardless of the value of the 'position' property. Here we obey
// the CSS spec for outer-<svg> (since that's what we generally do), but
# HG changeset patch
# User Markus Stange <mstange@themasta.com>
# Date 1468869224 14400
# Mon Jul 18 15:13:44 2016 -0400
# Node ID c6f55b3c98bad2e369752aad915ac15d92f9b8da
# Parent abc9ff143d42432b634e8484c55849ae3015945c
Most of the way to drawing animated widget focus rings.
MozReview-Commit-ID: Zp762FDmFz
diff --git a/gfx/src/nsITheme.h b/gfx/src/nsITheme.h
--- a/gfx/src/nsITheme.h
+++ b/gfx/src/nsITheme.h
@@ -56,16 +56,22 @@ public:
* @param aDirtyRect the rectangle that needs to be drawn
*/
NS_IMETHOD DrawWidgetBackground(nsRenderingContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
const nsRect& aRect,
const nsRect& aDirtyRect) = 0;
+ virtual void DrawWidgetFocusRing(nsRenderingContext* aContext,
+ nsIFrame* aFrame,
+ uint8_t aWidgetType,
+ const nsRect& aRect,
+ const nsRect& aDirtyRect) {}
+
/**
* Get the computed CSS border for the widget, in pixels.
*/
NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
nsIntMargin* aResult)=0;
@@ -180,17 +186,20 @@ public:
uint8_t aWidgetType)=0;
virtual bool WidgetIsContainer(uint8_t aWidgetType)=0;
/**
* Does the nsITheme implementation draw its own focus ring for this widget?
*/
virtual bool ThemeDrawsFocusForWidget(uint8_t aWidgetType)=0;
-
+
+ virtual bool DrawsSeparateFocusRingForWidget(nsIFrame* aFrame, uint8_t aWidgetType)
+ { return false; }
+
/**
* Should we insert a dropmarker inside of combobox button?
*/
virtual bool ThemeNeedsComboboxDropmarker()=0;
/**
* Should we hide scrollbars?
*/
diff --git a/layout/base/nsDisplayItemTypesList.h b/layout/base/nsDisplayItemTypesList.h
--- a/layout/base/nsDisplayItemTypesList.h
+++ b/layout/base/nsDisplayItemTypesList.h
@@ -1,12 +1,11 @@
// IWYU pragma: private, include "nsDisplayList.h"
DECLARE_DISPLAY_ITEM_TYPE(ALT_FEEDBACK)
DECLARE_DISPLAY_ITEM_TYPE(BACKGROUND)
-DECLARE_DISPLAY_ITEM_TYPE(THEMED_BACKGROUND)
DECLARE_DISPLAY_ITEM_TYPE_FLAGS(BACKGROUND_COLOR,TYPE_RENDERS_NO_IMAGES)
DECLARE_DISPLAY_ITEM_TYPE(BLEND_CONTAINER)
DECLARE_DISPLAY_ITEM_TYPE(BLEND_MODE)
DECLARE_DISPLAY_ITEM_TYPE(BORDER)
DECLARE_DISPLAY_ITEM_TYPE(BOX_SHADOW_OUTER)
DECLARE_DISPLAY_ITEM_TYPE(BOX_SHADOW_INNER)
DECLARE_DISPLAY_ITEM_TYPE(BULLET)
DECLARE_DISPLAY_ITEM_TYPE(BUTTON_BORDER_BACKGROUND)
@@ -60,16 +59,18 @@ DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_BAC
DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_SELECTION)
DECLARE_DISPLAY_ITEM_TYPE(TABLE_ROW_BACKGROUND)
DECLARE_DISPLAY_ITEM_TYPE(TABLE_ROW_GROUP_BACKGROUND)
DECLARE_DISPLAY_ITEM_TYPE(TABLE_BORDER_BACKGROUND)
DECLARE_DISPLAY_ITEM_TYPE(TEXT)
DECLARE_DISPLAY_ITEM_TYPE(TEXT_DECORATION)
DECLARE_DISPLAY_ITEM_TYPE(TEXT_OVERFLOW)
DECLARE_DISPLAY_ITEM_TYPE(TEXT_SHADOW)
+DECLARE_DISPLAY_ITEM_TYPE(THEMED_BACKGROUND)
+DECLARE_DISPLAY_ITEM_TYPE(THEME_FOCUS_RING)
DECLARE_DISPLAY_ITEM_TYPE_FLAGS(TRANSFORM,TYPE_RENDERS_NO_IMAGES)
DECLARE_DISPLAY_ITEM_TYPE_FLAGS(PERSPECTIVE,TYPE_RENDERS_NO_IMAGES)
DECLARE_DISPLAY_ITEM_TYPE(VIDEO)
DECLARE_DISPLAY_ITEM_TYPE(WRAP_LIST)
DECLARE_DISPLAY_ITEM_TYPE(ZOOM)
DECLARE_DISPLAY_ITEM_TYPE(EXCLUDE_GLASS_FRAME)
#if defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF)
diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -3273,17 +3273,61 @@ nsDisplayThemedBackground::GetBounds(nsD
nsRect
nsDisplayThemedBackground::GetBoundsInternal() {
nsPresContext* presContext = mFrame->PresContext();
nsRect r = mBackgroundRect - ToReferenceFrame();
presContext->GetTheme()->
GetWidgetOverflow(presContext->DeviceContext(), mFrame,
- mFrame->StyleDisplay()->mAppearance, &r);
+ mAppearance, &r);
+ return r + ToReferenceFrame();
+}
+
+nsDisplayThemeFocusRing::nsDisplayThemeFocusRing(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const nsRect& aBackgroundRect, uint8_t aAppearance)
+ : nsDisplayItem(aBuilder, aFrame)
+ , mBackgroundRect(aBackgroundRect)
+ , mAppearance(aAppearance)
+{
+ MOZ_COUNT_CTOR(nsDisplayThemeFocusRing);
+
+ mBounds = GetBoundsInternal();
+}
+
+nsDisplayThemeFocusRing::~nsDisplayThemeFocusRing()
+{
+#ifdef NS_BUILD_REFCNT_LOGGING
+ MOZ_COUNT_DTOR(nsDisplayThemeFocusRing);
+#endif
+}
+
+nsRect
+nsDisplayThemeFocusRing::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
+{
+ *aSnap = true;
+ return mBounds;
+}
+
+void
+nsDisplayThemeFocusRing::Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx)
+{
+ nsITheme *theme = mFrame->PresContext()->GetTheme();
+ theme->DrawWidgetFocusRing(aCtx, mFrame, mAppearance, mBackgroundRect, mBounds);
+}
+
+nsRect
+nsDisplayThemeFocusRing::GetBoundsInternal()
+{
+ nsPresContext* presContext = mFrame->PresContext();
+
+ nsRect r = mBackgroundRect - ToReferenceFrame();
+ presContext->GetTheme()->
+ GetWidgetOverflow(presContext->DeviceContext(), mFrame,
+ mAppearance, &r);
return r + ToReferenceFrame();
}
void
nsDisplayImageContainer::ConfigureLayer(ImageLayer* aLayer,
const ContainerLayerParameters& aParameters)
{
aLayer->SetSamplingFilter(nsLayoutUtils::GetSamplingFilterForFrame(mFrame));
diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -2841,16 +2841,39 @@ protected:
void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx,
const nsRect& aBounds, nsRect* aClipRect);
nsRect mBackgroundRect;
nsRect mBounds;
nsITheme::Transparency mThemeTransparency;
uint8_t mAppearance;
};
+/**
+ * A display item to paint the native theme background for a frame.
+ */
+class nsDisplayThemeFocusRing : public nsDisplayItem {
+public:
+ nsDisplayThemeFocusRing(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ const nsRect& aBackgroundRect, uint8_t aAppearance);
+ virtual ~nsDisplayThemeFocusRing();
+
+ /**
+ * GetBounds() returns the background painting area.
+ */
+ virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override;
+ virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override;
+ NS_DISPLAY_DECL_NAME("ThemeFocusRing", TYPE_THEMED_BACKGROUND)
+
+protected:
+ nsRect GetBoundsInternal();
+
+ nsRect mBackgroundRect;
+ nsRect mBounds;
+ uint8_t mAppearance;
+};
class nsDisplayBackgroundColor : public nsDisplayItem
{
typedef mozilla::gfx::Color Color;
public:
nsDisplayBackgroundColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
const nsRect& aBackgroundRect,
diff --git a/layout/forms/nsFieldSetFrame.cpp b/layout/forms/nsFieldSetFrame.cpp
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -173,17 +173,19 @@ nsFieldSetFrame::BuildDisplayList(nsDisp
bool isThemed = nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
aBuilder, this, VisualBorderRectRelativeToSelf(),
aLists.BorderBackground(),
/* aAllowWillPaintBorderOptimization = */ false);
aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
nsDisplayFieldSetBorderBackground(aBuilder, this));
- if (!isThemed) {
+ if (isThemed) {
+ DisplayThemeFocus(aBuilder, aLists);
+ } else {
DisplayOutlineUnconditional(aBuilder, aLists);
}
DO_GLOBAL_REFLOW_COUNT_DSP("nsFieldSetFrame");
}
if (GetPrevInFlow()) {
DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
diff --git a/layout/forms/nsHTMLButtonControlFrame.cpp b/layout/forms/nsHTMLButtonControlFrame.cpp
--- a/layout/forms/nsHTMLButtonControlFrame.cpp
+++ b/layout/forms/nsHTMLButtonControlFrame.cpp
@@ -137,16 +137,20 @@ nsHTMLButtonControlFrame::BuildDisplayLi
}
// Put the foreground outline and focus rects on top of the children
set.Content()->AppendToTop(&onTop);
set.MoveTo(aLists);
DisplayOutline(aBuilder, aLists);
+ if (IsThemed()) {
+ DisplayThemeFocus(aBuilder, aLists);
+ }
+
// to draw border when selected in editor
DisplaySelectionOverlay(aBuilder, aLists.Content());
}
nscoord
nsHTMLButtonControlFrame::GetMinISize(nsRenderingContext* aRenderingContext)
{
nscoord result;
diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1866,16 +1866,33 @@ nsFrame::DisplayOutline(nsDisplayListBui
if (!IsVisibleForPainting(aBuilder) || IsThemed()) {
return;
}
DisplayOutlineUnconditional(aBuilder, aLists);
}
void
+nsFrame::DisplayThemeFocus(nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aLists)
+{
+ MOZ_ASSERT(IsThemed(), "Only call this for themed frames.");
+ nsITheme *theme = PresContext()->GetTheme();
+ uint8_t appearance = StyleDisplay()->mAppearance;
+ if (!theme->DrawsSeparateFocusRingForWidget(this, appearance)) {
+ return;
+ }
+
+ nsDisplayList temp;
+ temp.AppendToTop(new (aBuilder) nsDisplayThemeFocusRing(aBuilder, this, GetRectRelativeToSelf(), appearance));
+ aLists.Outlines()->AppendNewToTop(
+ new (aBuilder) nsDisplayOutlineAnimation(aBuilder, this, &temp));
+}
+
+void
nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect, nsDisplayList* aList)
{
if (!IsVisibleForPainting(aBuilder))
return;
aList->AppendNewToTop(new (aBuilder) nsDisplayCaret(aBuilder, this));
}
@@ -1931,17 +1948,19 @@ nsFrame::DisplayBorderBackgroundOutline(
// If there's a themed background, we should not create a border item.
// It won't be rendered.
if (!bgIsThemed && StyleBorder()->HasBorder()) {
aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
nsDisplayBorder(aBuilder, this));
}
- if (!bgIsThemed) {
+ if (bgIsThemed) {
+ DisplayThemeFocus(aBuilder, aLists);
+ } else {
DisplayOutlineUnconditional(aBuilder, aLists);
}
}
inline static bool IsSVGContentWithCSSClip(const nsIFrame *aFrame)
{
// The CSS spec says that the 'clip' property only applies to absolutely
// positioned elements, whereas the SVG spec says that it applies to SVG
diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h
--- a/layout/generic/nsFrame.h
+++ b/layout/generic/nsFrame.h
@@ -538,16 +538,23 @@ public:
/**
* Add a display item for the CSS outline, after calling
* IsVisibleForPainting to confirm we are visible.
*/
void DisplayOutline(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists);
/**
+ * Add a display item for a focus ring provided by nsITheme, if the frame
+ * wants to show one. Only call this if IsThemed().
+ */
+ void DisplayThemeFocus(nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aLists);
+
+ /**
* Adjust the given parent frame to the right style context parent frame for
* the child, given the pseudo-type of the prospective child. This handles
* things like walking out of table pseudos and so forth.
*
* @param aProspectiveParent what GetParent() on the child returns.
* Must not be null.
* @param aChildPseudo the child's pseudo type, if any.
*/
diff --git a/widget/cocoa/nsNativeThemeCocoa.h b/widget/cocoa/nsNativeThemeCocoa.h
--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -48,16 +48,21 @@ public:
NS_DECL_ISUPPORTS_INHERITED
// The nsITheme interface.
NS_IMETHOD DrawWidgetBackground(nsRenderingContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
const nsRect& aRect,
const nsRect& aDirtyRect) override;
+ void DrawWidgetFocusRing(nsRenderingContext* aContext,
+ nsIFrame* aFrame,
+ uint8_t aWidgetType,
+ const nsRect& aRect,
+ const nsRect& aDirtyRect) override;
NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
nsIntMargin* aResult) override;
virtual bool GetWidgetPadding(nsDeviceContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
@@ -71,16 +76,17 @@ public:
mozilla::LayoutDeviceIntSize* aResult, bool* aIsOverridable) override;
NS_IMETHOD WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType,
nsIAtom* aAttribute, bool* aShouldRepaint,
const nsAttrValue* aOldValue) override;
NS_IMETHOD ThemeChanged() override;
bool ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* aFrame, uint8_t aWidgetType) override;
bool WidgetIsContainer(uint8_t aWidgetType) override;
bool ThemeDrawsFocusForWidget(uint8_t aWidgetType) override;
+ bool DrawsSeparateFocusRingForWidget(nsIFrame* aFrame, uint8_t aWidgetType) override;
bool ThemeNeedsComboboxDropmarker() override;
virtual bool WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType) override;
virtual bool NeedToClearBackgroundBehindWidget(nsIFrame* aFrame,
uint8_t aWidgetType) override;
virtual bool WidgetProvidesFontSmoothingBackgroundColor(nsIFrame* aFrame, uint8_t aWidgetType,
nscolor* aColor) override;
virtual ThemeGeometryType ThemeGeometryTypeForWidget(nsIFrame* aFrame,
uint8_t aWidgetType) override;
@@ -154,16 +160,29 @@ protected:
void DrawResizer(CGContextRef cgContext, const HIRect& aRect, nsIFrame *aFrame);
// Scrollbars
void GetScrollbarPressStates(nsIFrame *aFrame,
mozilla::EventStates aButtonStates[]);
nsIFrame* GetParentScrollbarFrame(nsIFrame *aFrame);
bool IsParentScrollbarRolledOver(nsIFrame* aFrame);
+ enum class WidgetOrFocusRing : uint8_t {
+ eWidgetOnly,
+ eFocusRingOnly,
+ eBoth
+ };
+
+ nsresult DrawWidgetOrFocusRing(nsRenderingContext* aContext,
+ nsIFrame* aFrame,
+ uint8_t aWidgetType,
+ const nsRect& aRect,
+ const nsRect& aDirtyRect,
+ WidgetOrFocusRing aWidgetOrFocusRing);
+
private:
NSButtonCell* mDisclosureButtonCell;
NSButtonCell* mHelpButtonCell;
NSButtonCell* mPushButtonCell;
NSButtonCell* mRadioButtonCell;
NSButtonCell* mCheckboxCell;
ContextAwareSearchFieldCell* mSearchFieldCell;
NSPopUpButtonCell* mDropdownCell;
diff --git a/widget/cocoa/nsNativeThemeCocoa.mm b/widget/cocoa/nsNativeThemeCocoa.mm
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -2341,16 +2341,45 @@ NS_IMETHODIMP
nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
const nsRect& aRect,
const nsRect& aDirtyRect)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+ return DrawWidgetOrFocusRing(aContext, aFrame, aWidgetType, aRect, aDirtyRect, WidgetOrFocusRing::eWidgetOnly);
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
+}
+
+void
+nsNativeThemeCocoa::DrawWidgetFocusRing(nsRenderingContext* aContext,
+ nsIFrame* aFrame,
+ uint8_t aWidgetType,
+ const nsRect& aRect,
+ const nsRect& aDirtyRect)
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+ DrawWidgetOrFocusRing(aContext, aFrame, aWidgetType, aRect, aDirtyRect, WidgetOrFocusRing::eFocusRingOnly);
+
+ NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
+nsresult
+nsNativeThemeCocoa::DrawWidgetOrFocusRing(nsRenderingContext* aContext,
+ nsIFrame* aFrame,
+ uint8_t aWidgetType,
+ const nsRect& aRect,
+ const nsRect& aDirtyRect,
+ WidgetOrFocusRing aWidgetOrFocusRing)
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
DrawTarget& aDrawTarget = *aContext->GetDrawTarget();
// setup to draw into the correct port
int32_t p2a = aFrame->PresContext()->AppUnitsPerDevPixel();
gfx::Rect nativeDirtyRect = NSRectToRect(aDirtyRect, p2a);
gfxRect nativeWidgetRect(aRect.x, aRect.y, aRect.width, aRect.height);
nativeWidgetRect.ScaleInverse(gfxFloat(p2a));
@@ -3750,16 +3779,22 @@ nsNativeThemeCocoa::ThemeDrawsFocusForWi
aWidgetType == NS_THEME_RANGE ||
aWidgetType == NS_THEME_CHECKBOX)
return true;
return false;
}
bool
+nsNativeThemeCocoa::DrawsSeparateFocusRingForWidget(nsIFrame* aFrame, uint8_t aWidgetType)
+{
+ return false;
+}
+
+bool
nsNativeThemeCocoa::ThemeNeedsComboboxDropmarker()
{
return false;
}
bool
nsNativeThemeCocoa::WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType)
{
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment