Bug 862693 - Stop the :-moz-focusring pseudo-class from matching if an element is themed and the theme will display a visual indication of focus for the element. r=roc
authorJonathan Watt <jwatt@jwatt.org>
Wed, 17 Apr 2013 09:22:55 +0100
changeset 129032 23d89270390d369c265a8389099cc9a4cf6c9e78
parent 129031 259703edf5af8e5118bfe7b0a6df3e2e9c093abb
child 129033 4363de95b961c7e8582f0c784b8ee9a197a5e276
push id26633
push userjwatt@jwatt.org
push dateWed, 17 Apr 2013 08:25:11 +0000
treeherdermozilla-inbound@4363de95b961 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs862693
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 862693 - Stop the :-moz-focusring pseudo-class from matching if an element is themed and the theme will display a visual indication of focus for the element. r=roc
dom/base/nsFocusManager.cpp
dom/base/nsFocusManager.h
dom/base/nsGlobalWindow.cpp
dom/tests/mochitest/general/test_focusrings.xul
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1013,27 +1013,46 @@ nsFocusManager::FireDelayedEvents(nsIDoc
 NS_IMETHODIMP
 nsFocusManager::FocusPlugin(nsIContent* aContent)
 {
   NS_ENSURE_ARG(aContent);
   SetFocusInner(aContent, 0, true, false);
   return NS_OK;
 }
 
+/* static */ bool
+nsFocusManager::ThemeDisplaysFocusForContent(nsIContent* aContent)
+{
+  // We don't want to draw the focusring if the element is themed and
+  // the theme displays an indication of focus for the element.
+  nsIFrame* frame = aContent->GetPrimaryFrame();
+  if (frame) {
+    nsPresContext *presContext = frame->PresContext();
+    const nsStyleDisplay *disp = frame->StyleDisplay();
+    if (frame->IsThemed(disp) &&
+        presContext->GetTheme()->ThemeDrawsFocusForWidget(presContext, frame, disp->mAppearance)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 /* static */
 void
 nsFocusManager::NotifyFocusStateChange(nsIContent* aContent,
                                        bool aWindowShouldShowFocusRing,
                                        bool aGettingFocus)
 {
   if (!aContent->IsElement()) {
     return;
   }
   nsEventStates eventState = NS_EVENT_STATE_FOCUS;
-  if (aWindowShouldShowFocusRing) {
+  if (!aGettingFocus ||
+      (aWindowShouldShowFocusRing &&
+       !ThemeDisplaysFocusForContent(aContent))) {
     eventState |= NS_EVENT_STATE_FOCUSRING;
   }
   if (aGettingFocus) {
     aContent->AsElement()->AddStates(eventState);
   } else {
     aContent->AsElement()->RemoveStates(eventState);
   }
 }
--- a/dom/base/nsFocusManager.h
+++ b/dom/base/nsFocusManager.h
@@ -111,16 +111,18 @@ public:
 
   /**
    * Returns an InputContextAction cause for aFlags.
    */
   static InputContextAction::Cause GetFocusMoveActionCause(uint32_t aFlags);
 
   static bool sMouseFocusesFormControl;
 
+  static bool ThemeDisplaysFocusForContent(nsIContent* aContent);
+
 protected:
 
   nsFocusManager();
   ~nsFocusManager();
 
   /**
    * Ensure that the widget associated with the currently focused window is
    * focused at the widget level.
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8458,17 +8458,18 @@ nsGlobalWindow::SetKeyboardIndicators(UI
     }
   }
 
   bool newShouldShowFocusRing = ShouldShowFocusRing();
   if (mHasFocus && mFocusedNode &&
       oldShouldShowFocusRing != newShouldShowFocusRing &&
       mFocusedNode->IsElement()) {
     // Update mFocusedNode's state.
-    if (newShouldShowFocusRing) {
+    if (newShouldShowFocusRing &&
+        !nsFocusManager::ThemeDisplaysFocusForContent(mFocusedNode.get())) {
       mFocusedNode->AsElement()->AddStates(NS_EVENT_STATE_FOCUSRING);
     } else {
       mFocusedNode->AsElement()->RemoveStates(NS_EVENT_STATE_FOCUSRING);
     }
   }
 }
 
 void
--- a/dom/tests/mochitest/general/test_focusrings.xul
+++ b/dom/tests/mochitest/general/test_focusrings.xul
@@ -44,16 +44,17 @@ function snapShot(element) {
 }
 
 function runTest()
 {
   setOrRestoreTabFocus(7);
 
   var isMac = (navigator.platform.indexOf("Mac") >= 0);
   var isWin = (navigator.platform.indexOf("Win") >= 0);
+  var isLinux = (navigator.platform.indexOf("Linux") >= 0);
 
   function checkFocus(element, visible, testid)
   {
     var outline = getComputedStyle(element, "").outlineWidth;
     is(outline, visible ? "2px" : "0px", testid);
   }
 
   // make sure that a focus ring appears on the focused button
@@ -95,17 +96,17 @@ function runTest()
   is(getComputedStyle($("l1"), "").outlineWidth, "0px", "appearance on previous list after focus() with :focus");
 
   synthesizeMouse($("l1"), 4, 4, { });
   checkFocus($("l1"), expectedVisible, "appearance on list after mouse focus with :moz-focusring");
   synthesizeMouse($("l2"), 4, 4, { });
   checkFocus($("l2"), true, "appearance on list after mouse focus with :focus");
 
   synthesizeMouse($("b1"), 4, 4, { });
-  checkFocus($("b1"), !isMac && expectedVisible, "appearance on button after mouse focus with :moz-focusring");
+  checkFocus($("b1"), !isMac && !isLinux && expectedVisible, "appearance on button after mouse focus with :moz-focusring");
   if (navigator.platform.indexOf("Mac") >= 0) {
     ok(compareSnapshots(snapShot($("b1")), snapShot($("b2")), false)[0], "focus after mouse shows no ring");
   }
 
   synthesizeMouse($("b2"), 4, 4, { });
   checkFocus($("b2"), !isMac, "appearance on button after mouse focus with :focus");
 
   // after a key is pressed, the focus ring will always be visible