Created
March 5, 2020 19:37
-
-
Save mstange/9e7b750b175d2703d14dc39500318dac to your computer and use it in GitHub Desktop.
Random outline:auto focus ring patches I found from August 2016
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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