Bug 422981, if the focused element is clear after focusing an element, still update the caret position. Additional fix when shift-tabbing from a caret position inside a focusable element to skip over that outer element r=smaug draft blur
authorNeil Deakin <neil@mozilla.com>
Sat, 18 Jan 2020 22:15:56 +0100
branchblur
changeset 2601519 7875e129a8c1265c9dfc45e62b2b1c3044158e33
parent 2601352 29c9a00754c183c83c7c378eae4aa82accd21b34
child 2601520 989339613060b144d2d68d3d89353aceb2dea18d
push id477648
push usersamuel.thibault@ens-lyon.org
push dateSat, 18 Jan 2020 21:18:37 +0000
treeherdertry@989339613060 [default view] [failures only]
reviewerssmaug
bugs422981
milestone74.0a1
Bug 422981, if the focused element is clear after focusing an element, still update the caret position. Additional fix when shift-tabbing from a caret position inside a focusable element to skip over that outer element r=smaug
dom/base/nsFocusManager.cpp
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1976,19 +1976,22 @@ void nsFocusManager::Focus(nsPIDOMWindow
   }
 
   // update the caret visibility and position to match the newly focused
   // element. However, don't update the position if this was a focus due to a
   // mouse click as the selection code would already have moved the caret as
   // needed. If this is a different document than was focused before, also
   // update the caret's visibility. If this is the same document, the caret
   // visibility should be the same as before so there is no need to update it.
-  if (mFocusedElement == aElement)
+  // As a special case when there is no focused element (implying that the
+  // element was likely blurred during focus), still update the caret position.
+  if (!mFocusedElement || mFocusedElement == aElement) {
     UpdateCaret(aFocusChanged && !(aFlags & FLAG_BYMOUSE), aIsNewDocument,
-                mFocusedElement);
+                aElement);
+  }
 
   if (clearFirstFocusEvent) mFirstFocusEvent = nullptr;
 }
 
 class FocusBlurEvent : public Runnable {
  public:
   FocusBlurEvent(nsISupports* aTarget, EventMessage aEventMessage,
                  nsPresContext* aContext, bool aWindowRaised, bool aIsRefocus,
@@ -2693,16 +2696,31 @@ nsresult nsFocusManager::DetermineElemen
       doc = startContent ? startContent->GetComposedDoc() : nullptr;
     } else {
       // Otherwise, for content shells, start from the location of the caret.
       nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
       if (docShell && docShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
         nsCOMPtr<nsIContent> endSelectionContent;
         GetSelectionLocation(doc, presShell, getter_AddRefs(startContent),
                              getter_AddRefs(endSelectionContent));
+
+        // If we are going backwards from the caret point, locate an enclosing
+        // focusable element and use that instead.
+        if (startContent && !forward && !forDocumentNavigation) {
+          nsIContent* focusableContent = startContent;
+          while (focusableContent) {
+            if (focusableContent->GetPrimaryFrame() &&
+                focusableContent->GetPrimaryFrame()->IsFocusable()) {
+              startContent = focusableContent;
+              break;
+            }
+            focusableContent = focusableContent->GetParent();
+          }
+        }
+
         // If the selection is on the rootContent, then there is no selection
         if (startContent == rootContent) {
           startContent = nullptr;
         }
 
         if (aType == MOVEFOCUS_CARET) {
           // GetFocusInSelection finds a focusable link near the caret.
           // If there is no start content though, don't do this to avoid