Bug 1077515 - part 7 - Support physical caret movement and selection commands in nsGlobalWindowCommands. r=roc
authorJonathan Kew <jkew@mozilla.com>
Sat, 22 Nov 2014 14:39:04 +0000
changeset 217001 e8d6b1cf145c6ccc3badd355f2ccebb76cb96bba
parent 217000 b45361b7aab2976453598b289f355f2dd7ac25f4
child 217002 3260d0792a327498596855295ec32f604c8164a2
push id27871
push usercbook@mozilla.com
push dateMon, 24 Nov 2014 12:32:57 +0000
treeherdermozilla-central@b8e1741b7d5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1077515
milestone36.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 1077515 - part 7 - Support physical caret movement and selection commands in nsGlobalWindowCommands. r=roc
dom/base/nsGlobalWindowCommands.cpp
--- a/dom/base/nsGlobalWindowCommands.cpp
+++ b/dom/base/nsGlobalWindowCommands.cpp
@@ -78,16 +78,34 @@ const char * const sSelectLinePreviousSt
 const char * const sSelectLineNextString = "cmd_selectLineNext";
 
 const char * const sSelectPageUpString = "cmd_selectPageUp";
 const char * const sSelectPageDownString = "cmd_selectPageDown";
 
 const char * const sSelectTopString = "cmd_selectTop";
 const char * const sSelectBottomString = "cmd_selectBottom";
 
+// Physical-direction movement and selection commands
+const char * const sMoveLeftString = "cmd_moveLeft";
+const char * const sMoveRightString = "cmd_moveRight";
+const char * const sMoveUpString = "cmd_moveUp";
+const char * const sMoveDownString = "cmd_moveDown";
+const char * const sMoveLeft2String = "cmd_moveLeft2";
+const char * const sMoveRight2String = "cmd_moveRight2";
+const char * const sMoveUp2String = "cmd_moveUp2";
+const char * const sMoveDown2String = "cmd_moveDown2";
+
+const char * const sSelectLeftString = "cmd_selectLeft";
+const char * const sSelectRightString = "cmd_selectRight";
+const char * const sSelectUpString = "cmd_selectUp";
+const char * const sSelectDownString = "cmd_selectDown";
+const char * const sSelectLeft2String = "cmd_selectLeft2";
+const char * const sSelectRight2String = "cmd_selectRight2";
+const char * const sSelectUp2String = "cmd_selectUp2";
+const char * const sSelectDown2String = "cmd_selectDown2";
 
 #if 0
 #pragma mark -
 #endif
 
 // a base class for selection-related commands, for code sharing
 class nsSelectionCommandsBase : public nsIControllerCommand
 {
@@ -111,26 +129,46 @@ class nsSelectMoveScrollCommand : public
 {
 public:
 
   NS_IMETHOD DoCommand(const char * aCommandName, nsISupports *aCommandContext);
 
   // no member variables, please, we're stateless!
 };
 
+// this class implements physical-movement versions of the above
+class nsPhysicalSelectMoveScrollCommand : public nsSelectionCommandsBase
+{
+public:
+
+  NS_IMETHOD DoCommand(const char * aCommandName, nsISupports *aCommandContext);
+
+  // no member variables, please, we're stateless!
+};
+
 // this class implements other selection commands
 class nsSelectCommand : public nsSelectionCommandsBase
 {
 public:
 
   NS_IMETHOD DoCommand(const char * aCommandName, nsISupports *aCommandContext);
 
   // no member variables, please, we're stateless!
 };
 
+// this class implements physical-movement versions of selection commands
+class nsPhysicalSelectCommand : public nsSelectionCommandsBase
+{
+public:
+
+  NS_IMETHOD DoCommand(const char * aCommandName, nsISupports *aCommandContext);
+
+  // no member variables, please, we're stateless!
+};
+
 #if 0
 #pragma mark -
 #endif
 
 
 NS_IMPL_ISUPPORTS(nsSelectionCommandsBase, nsIControllerCommand)
 
 /* boolean isCommandEnabled (in string aCommandName, in nsISupports aCommandContext); */
@@ -189,16 +227,49 @@ nsSelectionCommandsBase::GetSelectionCon
 
   return NS_ERROR_FAILURE;
 }
 
 #if 0
 #pragma mark -
 #endif
 
+// Helpers for nsSelectMoveScrollCommand and nsPhysicalSelectMoveScrollCommand
+static void
+AdjustFocusAfterCaretMove(nsPIDOMWindow* aWindow)
+{
+  // adjust the focus to the new caret position
+  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
+  if (fm) {
+    nsCOMPtr<nsIDOMElement> result;
+    fm->MoveFocus(aWindow, nullptr, nsIFocusManager::MOVEFOCUS_CARET,
+                  nsIFocusManager::FLAG_NOSCROLL, getter_AddRefs(result));
+  }
+}
+
+static bool
+IsCaretOnInWindow(nsPIDOMWindow* aWindow, nsISelectionController* aSelCont)
+{
+  // We allow the caret to be moved with arrow keys on any window for which
+  // the caret is enabled. In particular, this includes caret-browsing mode
+  // in non-chrome documents.
+  bool caretOn = false;
+  aSelCont->GetCaretEnabled(&caretOn);
+  if (!caretOn) {
+    caretOn = Preferences::GetBool("accessibility.browsewithcaret");
+    if (caretOn) {
+      nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
+      if (docShell && docShell->ItemType() == nsIDocShellTreeItem::typeChrome) {
+        caretOn = false;
+      }
+    }
+  }
+  return caretOn;
+}
+
 static const struct BrowseCommand {
   const char *reverse, *forward;
   nsresult (NS_STDCALL nsISelectionController::*scroll)(bool);
   nsresult (NS_STDCALL nsISelectionController::*move)(bool, bool);
 } browseCommands[] = {
  { sScrollTopString, sScrollBottomString,
    &nsISelectionController::CompleteScroll },
  { sScrollPageUpString, sScrollPageDownString,
@@ -230,95 +301,168 @@ static const struct BrowseCommand {
 nsresult
 nsSelectMoveScrollCommand::DoCommand(const char *aCommandName, nsISupports *aCommandContext)
 {
   nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(aCommandContext));
   nsCOMPtr<nsISelectionController> selCont;
   GetSelectionControllerFromWindow(piWindow, getter_AddRefs(selCont));
   NS_ENSURE_TRUE(selCont, NS_ERROR_NOT_INITIALIZED);       
 
-  // We allow the caret to be moved with arrow keys on any window for which
-  // the caret is enabled. In particular, this includes caret-browsing mode
-  // in non-chrome documents.
-  bool caretOn = false;
-  selCont->GetCaretEnabled(&caretOn);
-  if (!caretOn) {
-    caretOn = Preferences::GetBool("accessibility.browsewithcaret");
-    if (caretOn) {
-      nsCOMPtr<nsIDocShell> docShell = piWindow->GetDocShell();
-      if (docShell && docShell->ItemType() == nsIDocShellTreeItem::typeChrome) {
-        caretOn = false;
-      }
-    }
-  }
+  bool caretOn = IsCaretOnInWindow(piWindow, selCont);
 
   for (size_t i = 0; i < ArrayLength(browseCommands); i++) {
     bool forward = !strcmp(aCommandName, browseCommands[i].forward);
     if (forward || !strcmp(aCommandName, browseCommands[i].reverse)) {
       if (caretOn && browseCommands[i].move &&
           NS_SUCCEEDED((selCont->*(browseCommands[i].move))(forward, false))) {
-        // adjust the focus to the new caret position
-        nsIFocusManager* fm = nsFocusManager::GetFocusManager();
-        if (fm) {
-          nsCOMPtr<nsIDOMElement> result;
-          fm->MoveFocus(piWindow, nullptr, nsIFocusManager::MOVEFOCUS_CARET,
-                        nsIFocusManager::FLAG_NOSCROLL,
-                        getter_AddRefs(result));
-        }
+        AdjustFocusAfterCaretMove(piWindow);
         return NS_OK;
       }
       return (selCont->*(browseCommands[i].scroll))(forward);
     }
   }
+
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-
-#if 0
-#pragma mark -
-#endif
+// XXX It's not clear to me yet how we should handle the "scroll" option
+// for these commands; for now, I'm mapping them back to ScrollCharacter,
+// ScrollLine, etc., as if for horizontal-mode content, but this may need
+// to be reconsidered once we have more experience with vertical content.
+static const struct PhysicalBrowseCommand {
+  const char *command;
+  int16_t direction, amount;
+  nsresult (NS_STDCALL nsISelectionController::*scroll)(bool);
+} physicalBrowseCommands[] = {
+ { sMoveLeftString, nsISelectionController::MOVE_LEFT, 0,
+   &nsISelectionController::ScrollCharacter },
+ { sMoveRightString, nsISelectionController::MOVE_RIGHT, 0,
+   &nsISelectionController::ScrollCharacter },
+ { sMoveUpString, nsISelectionController::MOVE_UP, 0,
+   &nsISelectionController::ScrollLine },
+ { sMoveDownString, nsISelectionController::MOVE_DOWN, 0,
+   &nsISelectionController::ScrollLine },
+ { sMoveLeft2String, nsISelectionController::MOVE_LEFT, 1,
+   &nsISelectionController::ScrollCharacter },
+ { sMoveRight2String, nsISelectionController::MOVE_RIGHT, 1,
+   &nsISelectionController::ScrollCharacter },
+ { sMoveUp2String, nsISelectionController::MOVE_UP, 1,
+   &nsISelectionController::CompleteScroll },
+ { sMoveDown2String, nsISelectionController::MOVE_DOWN, 1,
+   &nsISelectionController::CompleteScroll },
+};
 
 nsresult
-nsSelectCommand::DoCommand(const char *aCommandName, nsISupports *aCommandContext)
+nsPhysicalSelectMoveScrollCommand::DoCommand(const char *aCommandName,
+                                             nsISupports *aCommandContext)
 {
   nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(aCommandContext));
   nsCOMPtr<nsISelectionController> selCont;
   GetSelectionControllerFromWindow(piWindow, getter_AddRefs(selCont));
   NS_ENSURE_TRUE(selCont, NS_ERROR_NOT_INITIALIZED);       
 
-  nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
+  bool caretOn = IsCaretOnInWindow(piWindow, selCont);
+
+  for (size_t i = 0; i < ArrayLength(physicalBrowseCommands); i++) {
+    const PhysicalBrowseCommand& cmd = physicalBrowseCommands[i];
+    if (!strcmp(aCommandName, cmd.command)) {
+      int16_t dir = cmd.direction;
+      if (caretOn &&
+          NS_SUCCEEDED(selCont->PhysicalMove(dir, cmd.amount, false))) {
+        AdjustFocusAfterCaretMove(piWindow);
+        return NS_OK;
+      }
+
+      bool forward = (dir == nsISelectionController::MOVE_RIGHT ||
+                      dir == nsISelectionController::MOVE_DOWN);
+      return (selCont->*(cmd.scroll))(forward);
+    }
+  }
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+#if 0
+#pragma mark -
+#endif
+
+static const struct SelectCommand {
+  const char *reverse, *forward;
+  nsresult (NS_STDCALL nsISelectionController::*select)(bool, bool);
+} selectCommands[] = {
+ { sSelectCharPreviousString, sSelectCharNextString,
+   &nsISelectionController::CharacterMove },
+ { sSelectWordPreviousString, sSelectWordNextString,
+   &nsISelectionController::WordMove },
+ { sSelectBeginLineString, sSelectEndLineString,
+   &nsISelectionController::IntraLineMove },
+ { sSelectLinePreviousString, sSelectLineNextString,
+   &nsISelectionController::LineMove },
+ { sSelectPageUpString, sSelectPageDownString,
+   &nsISelectionController::PageMove },
+ { sSelectTopString, sSelectBottomString,
+   &nsISelectionController::CompleteMove }
+};
+
+nsresult
+nsSelectCommand::DoCommand(const char *aCommandName,
+                           nsISupports *aCommandContext)
+{
+  nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(aCommandContext));
+  nsCOMPtr<nsISelectionController> selCont;
+  GetSelectionControllerFromWindow(piWindow, getter_AddRefs(selCont));
+  NS_ENSURE_TRUE(selCont, NS_ERROR_NOT_INITIALIZED);       
 
   // These commands are so the browser can use caret navigation key bindings -
   // Helps with accessibility - aaronl@netscape.com
-  if (!nsCRT::strcmp(aCommandName, sSelectCharPreviousString))
-    rv = selCont->CharacterMove(false, true);
-  else if (!nsCRT::strcmp(aCommandName, sSelectCharNextString))
-    rv = selCont->CharacterMove(true, true);
-  else if (!nsCRT::strcmp(aCommandName, sSelectWordPreviousString))
-    rv = selCont->WordMove(false, true);
-  else if (!nsCRT::strcmp(aCommandName, sSelectWordNextString))
-    rv = selCont->WordMove(true, true);
-  else if (!nsCRT::strcmp(aCommandName, sSelectBeginLineString))
-    rv = selCont->IntraLineMove(false, true);
-  else if (!nsCRT::strcmp(aCommandName, sSelectEndLineString))
-    rv = selCont->IntraLineMove(true, true);
-  else if (!nsCRT::strcmp(aCommandName, sSelectLinePreviousString))
-    rv = selCont->LineMove(false, true);
-  else if (!nsCRT::strcmp(aCommandName, sSelectLineNextString))
-    rv = selCont->LineMove(true, true);
-  else if (!nsCRT::strcmp(aCommandName, sSelectPageUpString))
-    rv = selCont->PageMove(false, true);
-  else if (!nsCRT::strcmp(aCommandName, sSelectPageDownString))
-    rv = selCont->PageMove(true, true);
-  else if (!nsCRT::strcmp(aCommandName, sSelectTopString))
-    rv = selCont->CompleteMove(false, true);
-  else if (!nsCRT::strcmp(aCommandName, sSelectBottomString))
-    rv = selCont->CompleteMove(true, true);
+  for (size_t i = 0; i < ArrayLength(selectCommands); i++) {
+    bool forward = !strcmp(aCommandName, selectCommands[i].forward);
+    if (forward || !strcmp(aCommandName, selectCommands[i].reverse)) {
+      return (selCont->*(selectCommands[i].select))(forward, true);
+    }
+  }
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+#if 0
+#pragma mark -
+#endif
 
-  return rv;
+static const struct PhysicalSelectCommand {
+  const char *command;
+  int16_t direction, amount;
+} physicalSelectCommands[] = {
+ { sSelectLeftString, nsISelectionController::MOVE_LEFT, 0 },
+ { sSelectRightString, nsISelectionController::MOVE_RIGHT, 0 },
+ { sSelectUpString, nsISelectionController::MOVE_UP, 0 },
+ { sSelectDownString, nsISelectionController::MOVE_DOWN, 0 },
+ { sSelectLeft2String, nsISelectionController::MOVE_LEFT, 1 },
+ { sSelectRight2String, nsISelectionController::MOVE_RIGHT, 1 },
+ { sSelectUp2String, nsISelectionController::MOVE_UP, 1 },
+ { sSelectDown2String, nsISelectionController::MOVE_DOWN, 1 }
+};
+
+nsresult
+nsPhysicalSelectCommand::DoCommand(const char *aCommandName,
+                                   nsISupports *aCommandContext)
+{
+  nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(aCommandContext));
+  nsCOMPtr<nsISelectionController> selCont;
+  GetSelectionControllerFromWindow(piWindow, getter_AddRefs(selCont));
+  NS_ENSURE_TRUE(selCont, NS_ERROR_NOT_INITIALIZED);       
+
+  for (size_t i = 0; i < ArrayLength(physicalSelectCommands); i++) {
+    if (!strcmp(aCommandName, physicalSelectCommands[i].command)) {
+      return selCont->PhysicalMove(physicalSelectCommands[i].direction,
+                                   physicalSelectCommands[i].amount,
+                                   true);
+    }
+  }
+
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 #if 0
 #pragma mark -
 #endif
 
 class nsClipboardCommand MOZ_FINAL : public nsIControllerCommand
 {
@@ -863,29 +1007,47 @@ nsWindowCommandRegistration::RegisterWin
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sEndLineString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sMovePageUpString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sMovePageDownString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sLinePreviousString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sLineNextString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sCharPreviousString);
   NS_REGISTER_LAST_COMMAND(nsSelectMoveScrollCommand, sCharNextString);
 
+  NS_REGISTER_FIRST_COMMAND(nsPhysicalSelectMoveScrollCommand, sMoveLeftString);
+  NS_REGISTER_NEXT_COMMAND(nsPhysicalSelectMoveScrollCommand, sMoveRightString);
+  NS_REGISTER_NEXT_COMMAND(nsPhysicalSelectMoveScrollCommand, sMoveUpString);
+  NS_REGISTER_NEXT_COMMAND(nsPhysicalSelectMoveScrollCommand, sMoveDownString);
+  NS_REGISTER_NEXT_COMMAND(nsPhysicalSelectMoveScrollCommand, sMoveLeft2String);
+  NS_REGISTER_NEXT_COMMAND(nsPhysicalSelectMoveScrollCommand, sMoveRight2String);
+  NS_REGISTER_NEXT_COMMAND(nsPhysicalSelectMoveScrollCommand, sMoveUp2String);
+  NS_REGISTER_LAST_COMMAND(nsPhysicalSelectMoveScrollCommand, sMoveDown2String);
+
   NS_REGISTER_FIRST_COMMAND(nsSelectCommand, sSelectCharPreviousString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectCharNextString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectWordPreviousString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectWordNextString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectBeginLineString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectEndLineString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectLinePreviousString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectLineNextString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectPageUpString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectPageDownString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectTopString);
   NS_REGISTER_LAST_COMMAND(nsSelectCommand, sSelectBottomString);
 
+  NS_REGISTER_FIRST_COMMAND(nsPhysicalSelectCommand, sSelectLeftString);
+  NS_REGISTER_NEXT_COMMAND(nsPhysicalSelectCommand, sSelectRightString);
+  NS_REGISTER_NEXT_COMMAND(nsPhysicalSelectCommand, sSelectUpString);
+  NS_REGISTER_NEXT_COMMAND(nsPhysicalSelectCommand, sSelectDownString);
+  NS_REGISTER_NEXT_COMMAND(nsPhysicalSelectCommand, sSelectLeft2String);
+  NS_REGISTER_NEXT_COMMAND(nsPhysicalSelectCommand, sSelectRight2String);
+  NS_REGISTER_NEXT_COMMAND(nsPhysicalSelectCommand, sSelectUp2String);
+  NS_REGISTER_LAST_COMMAND(nsPhysicalSelectCommand, sSelectDown2String);
+
   NS_REGISTER_ONE_COMMAND(nsClipboardCommand, "cmd_cut");
   NS_REGISTER_ONE_COMMAND(nsClipboardCommand, "cmd_copy");
   NS_REGISTER_ONE_COMMAND(nsClipboardCommand, "cmd_paste");
   NS_REGISTER_ONE_COMMAND(nsClipboardCopyLinkCommand, "cmd_copyLink");
   NS_REGISTER_FIRST_COMMAND(nsClipboardImageCommands, sCopyImageLocationString);
   NS_REGISTER_NEXT_COMMAND(nsClipboardImageCommands, sCopyImageContentsString);
   NS_REGISTER_LAST_COMMAND(nsClipboardImageCommands, sCopyImageString);
   NS_REGISTER_FIRST_COMMAND(nsClipboardSelectAllNoneCommands, sSelectAllString);