Bug 824080 HTML editor shouldn't set selection state as inactive at losing focus but the document has focus r=ehsan
authorMasayuki Nakano <masayuki@d-toybox.com>
Sat, 18 May 2013 09:07:46 +0900
changeset 143784 8a53b2daa50e60c1b736af2ca43012cd152f40cb
parent 143783 584cfff7da90920ed3a212fc470def2310b9efd4
child 143785 e4d4cbfcbfeacb36a41481302b9f6390795b9576
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs824080
milestone24.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 824080 HTML editor shouldn't set selection state as inactive at losing focus but the document has focus r=ehsan
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsEditor.h
editor/libeditor/base/nsEditorEventListener.cpp
editor/reftests/824080-1-ref.html
editor/reftests/824080-1.html
editor/reftests/824080-2-ref.html
editor/reftests/824080-2.html
editor/reftests/824080-3-ref.html
editor/reftests/824080-3.html
editor/reftests/824080-4-ref.html
editor/reftests/824080-4.html
editor/reftests/824080-5-ref.html
editor/reftests/824080-5.html
editor/reftests/824080-6-ref.html
editor/reftests/824080-6.html
editor/reftests/824080-7-ref.html
editor/reftests/824080-7.html
editor/reftests/reftest.list
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -4952,16 +4952,73 @@ nsEditor::InitializeSelection(nsIDOMEven
     if (rangeCount == 0) {
       BeginningOfDocument();
     }
   }
 
   return NS_OK;
 }
 
+void
+nsEditor::FinalizeSelection()
+{
+  nsCOMPtr<nsISelectionController> selCon;
+  nsresult rv = GetSelectionController(getter_AddRefs(selCon));
+  NS_ENSURE_SUCCESS_VOID(rv);
+
+  nsCOMPtr<nsISelection> selection;
+  rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
+                            getter_AddRefs(selection));
+  NS_ENSURE_SUCCESS_VOID(rv);
+
+  nsCOMPtr<nsISelectionPrivate> selectionPrivate = do_QueryInterface(selection);
+  NS_ENSURE_TRUE_VOID(selectionPrivate);
+
+  selectionPrivate->SetAncestorLimiter(nullptr);
+
+  nsCOMPtr<nsIPresShell> presShell = GetPresShell();
+  NS_ENSURE_TRUE_VOID(presShell);
+
+  nsRefPtr<nsCaret> caret = presShell->GetCaret();
+  if (caret) {
+    caret->SetIgnoreUserModify(true);
+  }
+
+  selCon->SetCaretEnabled(false);
+
+  if (!HasIndependentSelection()) {
+    // If this editor doesn't have an independent selection, i.e., it must
+    // mean that it is an HTML editor, the selection controller is shared with
+    // presShell.  So, even this editor loses focus, other part of the document
+    // may still have focus.
+    nsCOMPtr<nsIDocument> doc = GetDocument();
+    ErrorResult ret;
+    if (!doc || !doc->HasFocus(ret)) {
+      // If the document already lost focus, mark the selection as disabled.
+      selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
+    } else {
+      // Otherwise, mark selection as normal because outside of a
+      // contenteditable element should be selected with normal selection
+      // color after here.
+      selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
+    }
+  } else if (IsFormWidget() || IsPasswordEditor() ||
+             IsReadonly() || IsDisabled() || IsInputFiltered()) {
+    // In <input> or <textarea>, the independent selection should be hidden
+    // while this editor doesn't have focus.
+    selCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
+  } else {
+    // Otherwise, although we're not sure how this case happens, the
+    // independent selection should be marked as disabled.
+    selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
+  }
+
+  selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
+}
+
 dom::Element *
 nsEditor::GetRoot()
 {
   if (!mRootElement)
   {
     nsCOMPtr<nsIDOMElement> root;
 
     // Let GetRootElement() do the work
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -735,16 +735,21 @@ public:
   }
 
   bool IsTabbable() const
   {
     return IsSingleLineEditor() || IsPasswordEditor() || IsFormWidget() ||
            IsInteractionAllowed();
   }
 
+  bool HasIndependentSelection() const
+  {
+    return !!mSelConWeak;
+  }
+
   // Get the input event target. This might return null.
   virtual already_AddRefed<nsIContent> GetInputEventTargetContent() = 0;
 
   // Get the focused content, if we're focused.  Returns null otherwise.
   virtual already_AddRefed<nsIContent> GetFocusedContent();
 
   // Get the focused content for the argument of some nsIMEStateManager's
   // methods.
@@ -768,16 +773,19 @@ public:
   // element in the document has focus.
   virtual already_AddRefed<nsIContent> FindSelectionRoot(nsINode* aNode);
 
   // Initializes selection and caret for the editor.  If aEventTarget isn't
   // a host of the editor, i.e., the editor doesn't get focus, this does
   // nothing.
   nsresult InitializeSelection(nsIDOMEventTarget* aFocusEventTarget);
 
+  // Finalizes selection and caret for the editor.
+  void FinalizeSelection();
+
   // This method has to be called by nsEditorEventListener::Focus.
   // All actions that have to be done when the editor is focused needs to be
   // added here.
   void OnFocus(nsIDOMEventTarget* aFocusEventTarget);
 
   // Used to insert content from a data transfer into the editable area.
   // This is called for each item in the data transfer, with the index of
   // each item passed as aIndex.
--- a/editor/libeditor/base/nsEditorEventListener.cpp
+++ b/editor/libeditor/base/nsEditorEventListener.cpp
@@ -892,55 +892,17 @@ nsEditorEventListener::Blur(nsIDOMEvent*
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   NS_ENSURE_TRUE(fm, NS_OK);
 
   nsCOMPtr<nsIDOMElement> element;
   fm->GetFocusedElement(getter_AddRefs(element));
   if (element)
     return NS_OK;
 
-  // turn off selection and caret
-  nsCOMPtr<nsISelectionController>selCon;
-  mEditor->GetSelectionController(getter_AddRefs(selCon));
-  if (selCon)
-  {
-    nsCOMPtr<nsISelection> selection;
-    selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
-                         getter_AddRefs(selection));
-
-    nsCOMPtr<nsISelectionPrivate> selectionPrivate =
-      do_QueryInterface(selection);
-    if (selectionPrivate) {
-      selectionPrivate->SetAncestorLimiter(nullptr);
-    }
-
-    nsCOMPtr<nsIPresShell> presShell = GetPresShell();
-    if (presShell) {
-      nsRefPtr<nsCaret> caret = presShell->GetCaret();
-      if (caret) {
-        caret->SetIgnoreUserModify(true);
-      }
-    }
-
-    selCon->SetCaretEnabled(false);
-
-    if(mEditor->IsFormWidget() || mEditor->IsPasswordEditor() ||
-       mEditor->IsReadonly() || mEditor->IsDisabled() ||
-       mEditor->IsInputFiltered())
-    {
-      selCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);//hide but do NOT turn off
-    }
-    else
-    {
-      selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
-    }
-
-    selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
-  }
-
+  mEditor->FinalizeSelection();
   return NS_OK;
 }
 
 void
 nsEditorEventListener::SpellCheckIfNeeded() {
   // If the spell check skip flag is still enabled from creation time,
   // disable it because focused editors are allowed to spell check.
   uint32_t currentFlags = 0;
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-1-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      var editor = document.getElementById("editor");
+      document.getSelection().selectAllChildren(document.body);
+    }
+  </script>
+</head>
+<body onload="doTest();">
+<p>normal text</p>
+<div id="editor">editable text</div>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-1.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      var editor = document.getElementById("editor");
+      editor.focus();
+      editor.blur();
+      document.getSelection().selectAllChildren(document.body);
+    }
+  </script>
+</head>
+<body onload="doTest();">
+<p>normal text</p>
+<div id="editor" contenteditable>editable text</div>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-2-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      document.getSelection().selectAllChildren(document.getElementById("text"));
+      var editor = document.getElementById("editor");
+      var editorBody = editor.contentDocument.body;
+      editor.contentDocument.getSelection().selectAllChildren(editorBody);
+      editor.focus();
+      editor.blur();
+    }
+  </script>
+</head>
+<body>
+<p id="text">normal text</p>
+<iframe id="editor" onload="doTest();"
+  src="data:text/html,<body>editable text</body>"></iframe>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-2.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      document.getSelection().selectAllChildren(document.getElementById("text"));
+      var editor = document.getElementById("editor");
+      var editorBody = editor.contentDocument.body;
+      editor.contentDocument.getSelection().selectAllChildren(editorBody);
+      editor.focus();
+      editor.blur();
+    }
+  </script>
+</head>
+<body>
+<p id="text">normal text</p>
+<iframe id="editor" onload="doTest();"
+  src="data:text/html,<script>document.designMode='on';</script><body>editable text</body>"></iframe>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-3-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      document.getSelection().selectAllChildren(document.getElementById("text"));
+      var editor = document.getElementById("editor");
+      var editorBody = editor.contentDocument.body;
+      editor.contentDocument.getSelection().selectAllChildren(editorBody);
+      editor.focus();
+    }
+  </script>
+</head>
+<body>
+<p id="text">normal text</p>
+<iframe id="editor" onload="doTest();"
+  src="data:text/html,<body>editable text</body>"></iframe>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-3.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      document.getSelection().selectAllChildren(document.getElementById("text"));
+      var editor = document.getElementById("editor");
+      var editorBody = editor.contentDocument.body;
+      editor.contentDocument.getSelection().selectAllChildren(editorBody);
+      editor.focus();
+    }
+  </script>
+</head>
+<body>
+<p id="text">normal text</p>
+<iframe id="editor" onload="doTest();"
+  src="data:text/html,<script>document.designMode='on';</script><body>editable text</body>"></iframe>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-4-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      document.getSelection().selectAllChildren(document.body);
+      var editor = document.getElementById("editor");
+      var editorBody = editor.contentDocument.body;
+      editor.contentDocument.getSelection().selectAllChildren(editorBody);
+    }
+  </script>
+</head>
+<body>
+<p id="text">normal text</p>
+<div>content editable</div>
+<iframe id="editor" onload="doTest();"
+  src="data:text/html,<body>editable text</body>"></iframe>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-4.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      var editor1 = document.getElementById("editor1");
+      editor1.focus();
+      editor1.blur();
+      document.getSelection().selectAllChildren(document.body);
+      var editor2 = document.getElementById("editor2");
+      var editorBody = editor2.contentDocument.body;
+      editor2.contentDocument.getSelection().selectAllChildren(editorBody);
+      editor2.focus();
+      editor2.blur();
+    }
+  </script>
+</head>
+<body>
+<p>normal text</p>
+<div id="editor1" contenteditable>content editable</div>
+<iframe id="editor2" onload="doTest();"
+  src="data:text/html,<script>document.designMode='on';</script><body>editable text</body>"></iframe>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-5-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      document.getSelection().selectAllChildren(document.body);
+      var editor = document.getElementById("editor");
+      var editorBody = editor.contentDocument.body;
+      editor.contentDocument.getSelection().selectAllChildren(editorBody);
+      editor.focus();
+    }
+  </script>
+</head>
+<body>
+<p id="text">normal text</p>
+<div>content editable</div>
+<iframe id="editor" onload="doTest();"
+  src="data:text/html,<body>editable text</body>"></iframe>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-5.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      var editor1 = document.getElementById("editor1");
+      editor1.focus();
+      editor1.blur();
+      document.getSelection().selectAllChildren(document.body);
+      var editor2 = document.getElementById("editor2");
+      var editorBody = editor2.contentDocument.body;
+      editor2.contentDocument.getSelection().selectAllChildren(editorBody);
+      editor2.focus();
+    }
+  </script>
+</head>
+<body>
+<p>normal text</p>
+<div id="editor1" contenteditable>content editable</div>
+<iframe id="editor2" onload="doTest();"
+  src="data:text/html,<script>document.designMode='on';</script><body>editable text</body>"></iframe>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-6-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      var editor = document.getElementById("editor");
+      editor.focus();
+      editor.blur();
+    }
+  </script>
+</head>
+<body onload="doTest()">
+<p>normal text</p>
+<textarea id="editor">textarea</textarea>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-6.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      document.getSelection().selectAllChildren(document.body);
+      var editor = document.getElementById("editor");
+      editor.focus();
+      editor.select();
+      editor.blur();
+    }
+  </script>
+</head>
+<body onload="doTest()">
+<p>normal text</p>
+<textarea id="editor">textarea</textarea>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-7-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      var editor = document.getElementById("editor");
+      editor.focus();
+      editor.selectionStart = 2;
+      editor.selectionEnd = 4;
+    }
+  </script>
+</head>
+<body onload="doTest()">
+<p>normal text</p>
+<textarea id="editor">textarea</textarea>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/editor/reftests/824080-7.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    function doTest()
+    {
+      document.getSelection().selectAllChildren(document.body);
+      var editor = document.getElementById("editor");
+      editor.focus();
+      editor.selectionStart = 2;
+      editor.selectionEnd = 4;
+      editor.blur();
+      editor.focus();
+    }
+  </script>
+</head>
+<body onload="doTest()">
+<p>normal text</p>
+<textarea id="editor">textarea</textarea>
+</body>
+</html>
+
--- a/editor/reftests/reftest.list
+++ b/editor/reftests/reftest.list
@@ -93,8 +93,18 @@ skip-if(Android||B2G) needs-focus == 462
 == readonly-editable.html readonly-editable-ref.html
 == dynamic-overflow-change.html dynamic-overflow-change-ref.html
 == 694880-1.html 694880-ref.html
 == 694880-2.html 694880-ref.html
 == 694880-3.html 694880-ref.html
 == 388980-1.html 388980-1-ref.html
 needs-focus == spellcheck-superscript-1.html spellcheck-superscript-1-ref.html
 skip-if(B2G) fails-if(Android) needs-focus != spellcheck-superscript-2.html spellcheck-superscript-2-ref.html # bug 783658
+== 824080-1.html 824080-1-ref.html
+== 824080-2.html 824080-2-ref.html
+== 824080-3.html 824080-3-ref.html
+!= 824080-2.html 824080-3.html
+== 824080-4.html 824080-4-ref.html
+== 824080-5.html 824080-5-ref.html
+!= 824080-4.html 824080-5.html
+== 824080-6.html 824080-6-ref.html
+== 824080-7.html 824080-7-ref.html
+!= 824080-6.html 824080-7.html