Bug 1443902 - Reinitilize selection after destroying nsIEditingSession. r=masayuki draft
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Mon, 09 Jul 2018 16:53:47 +0900
changeset 815883 9d90c12b3c93e4dfd95095ce29a26e5fdd83f952
parent 815812 9f03501341bf35bc502f69f870746ffac73992ae
child 815884 b4b53bfc9a18f30f1076a324950af0a1220a22c4
child 815885 760a7bde38632baabcd5caacacbd67021a3e8d27
child 816383 7131d59a2fd607494600cc3f51ca40c0024760d7
push id115680
push userbmo:m_kato@ga2.so-net.ne.jp
push dateTue, 10 Jul 2018 07:39:00 +0000
reviewersmasayuki
bugs1443902
milestone63.0a1
Bug 1443902 - Reinitilize selection after destroying nsIEditingSession. r=masayuki When setting contenteditable to false, editing session destroys HTMLEditor. Destroying HTMLEditor means that selection visibility is reset by FinalizeSelection. So after calling TearDownEditorOnWindow on nsHTMLDocument, we should initialize selection visibility if current focus is text control that has editor. MozReview-Commit-ID: 4V8kZtOtKO3
dom/html/nsHTMLDocument.cpp
editor/libeditor/EditorBase.cpp
editor/libeditor/EditorBase.h
editor/reftests/1443902-1-ref.html
editor/reftests/1443902-1.html
editor/reftests/1443902-2-ref.html
editor/reftests/1443902-2.html
editor/reftests/1443902-3-ref.html
editor/reftests/1443902-3.html
editor/reftests/1443902-4-ref.html
editor/reftests/1443902-4.html
editor/reftests/reftest.list
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -2334,16 +2334,30 @@ nsHTMLDocument::TurnEditingOff()
   NS_ENSURE_SUCCESS(rv, rv);
 
   // turn editing off
   rv = editSession->TearDownEditorOnWindow(window);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mEditingState = eOff;
 
+  // Editor resets selection since it is being destroyed.  But if focus is
+  // still into editable control, we have to initialize selection again.
+  nsFocusManager* fm = nsFocusManager::GetFocusManager();
+  if (fm) {
+    Element* element = fm->GetFocusedElement();
+    nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(element);
+    if (txtCtrl) {
+      RefPtr<TextEditor> textEditor = txtCtrl->GetTextEditor();
+      if (textEditor) {
+        textEditor->ReinitializeSelection(*element);
+      }
+    }
+  }
+
   return NS_OK;
 }
 
 static bool HasPresShell(nsPIDOMWindowOuter *aWindow)
 {
   nsIDocShell *docShell = aWindow->GetDocShell();
   if (!docShell)
     return false;
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -4794,16 +4794,33 @@ EditorBase::FinalizeSelection()
 
   // FinalizeSelection might be called from ContentRemoved even if selection
   // isn't updated.  So we need to call RepaintSelection after updated it.
   nsContentUtils::AddScriptRunner(
                     new RepaintSelectionRunner(selectionController));
   return NS_OK;
 }
 
+void
+EditorBase::ReinitializeSelection(Element& aElement)
+{
+  if (NS_WARN_IF(Destroyed())) {
+    return;
+  }
+
+  OnFocus(&aElement);
+
+  nsPresContext* context = GetPresContext();
+  if (NS_WARN_IF(!context)) {
+    return;
+  }
+  nsCOMPtr<nsIContent> focusedContent = GetFocusedContentForIME();
+  IMEStateManager::OnFocusInEditor(context, focusedContent, *this);
+}
+
 Element*
 EditorBase::GetEditorRoot()
 {
   return GetRoot();
 }
 
 Element*
 EditorBase::GetExposedRoot()
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -667,16 +667,24 @@ public:
   void OnFocus(dom::EventTarget* aFocusEventTarget);
 
   /** Resyncs spellchecking state (enabled/disabled).  This should be called
     * when anything that affects spellchecking state changes, such as the
     * spellcheck attribute value.
     */
   void SyncRealTimeSpell();
 
+ /**
+   * This method re-initializes the selection and caret state that are for
+   * current editor state. When editor session is destroyed, it always reset
+   * selection state even if this has no focus.  So if destroying editor,
+   * we have to call this method for focused editor to set selection state.
+   */
+ void ReinitializeSelection(Element& aElement);
+
 protected: // May be called by friends.
   /****************************************************************************
    * Some classes like TextEditRules, HTMLEditRules, WSRunObject which are
    * part of handling edit actions are allowed to call the following protected
    * methods.  However, those methods won't prepare caches of some objects
    * which are necessary for them.  So, if you want some following methods
    * to do that for you, you need to create a wrapper method in public scope
    * and call it.
new file mode 100644
--- /dev/null
+++ b/editor/reftests/1443902-1-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function init()
+{
+  document.getElementById("t1").focus();
+  document.getElementById("t1").setSelectionRange(4, 4);
+}
+</script>
+</head>
+<body onload="init()">
+<textarea id=t1 contenteditable=true>ABCD</textarea>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/1443902-1.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function init()
+{
+  document.getElementById("t1").focus();
+  document.getElementById("t1").setSelectionRange(4, 4);
+  document.getElementById("t1").setAttribute("contentEditable", "false");
+}
+</script>
+</head>
+<body onload="init()">
+<textarea id=t1 contenteditable=true>ABCD</textarea>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/1443902-2-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function init()
+{
+  document.getElementById("t1").focus();
+  document.getElementById("t1").setSelectionRange(4, 4);
+}
+</script>
+</head>
+<body onload="init()">
+<div id="d1">
+<input type="text" id=t1 value="ABCD">
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/1443902-2.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function init()
+{
+  document.getElementById("t1").focus();
+  document.getElementById("t1").setSelectionRange(4, 4);
+  document.getElementById("d1").setAttribute("contentEditable", "false");
+}
+</script>
+</head>
+<body onload="init()">
+<div contenteditable=true id="d1">
+<input type="text" id=t1 value="ABCD">
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/1443902-3-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function init()
+{
+  document.getElementById("t1").focus();
+  document.getElementById("t1").setSelectionRange(0, 1);
+}
+</script>
+</head>
+<body onload="init()">
+<div>
+<input type="text" id=t1 value="ABCD" readonly>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/1443902-3.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function init()
+{
+  document.getElementById("t1").focus();
+  document.getElementById("t1").setSelectionRange(0, 1);
+  document.getElementById("d1").setAttribute("contentEditable", "false");
+}
+</script>
+</head>
+<body onload="init()">
+<div contenteditable=true id="d1">
+<input type="text" id=t1 value="ABCD" readonly>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/1443902-4-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function init()
+{
+  document.getElementById("t1").focus();
+  document.getElementById("t1").setSelectionRange(4, 4);
+}
+</script>
+</head>
+<body onload="init()">
+<div id="d1">
+<input type="text">
+</div>
+<input type="text" id=t1 value="ABCD">
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/1443902-4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function init()
+{
+  document.getElementById("t1").focus();
+  document.getElementById("t1").setSelectionRange(4, 4);
+  document.getElementById("d1").setAttribute("contentEditable", "false");
+}
+</script>
+</head>
+<body onload="init()">
+<div contenteditable=true id="d1">
+<input type="text">
+</div>
+<input type="text" id=t1 value="ABCD">
+</body>
+</html>
--- a/editor/reftests/reftest.list
+++ b/editor/reftests/reftest.list
@@ -130,8 +130,12 @@ needs-focus == spellcheck-contenteditabl
 == spellcheck-contenteditable-attr-dynamic-override.html spellcheck-contenteditable-disabled-ref.html
 == spellcheck-contenteditable-attr-dynamic-override-inherit.html spellcheck-contenteditable-disabled-ref.html
 == spellcheck-contenteditable-property-dynamic-override.html spellcheck-contenteditable-disabled-ref.html
 == spellcheck-contenteditable-property-dynamic-override-inherit.html spellcheck-contenteditable-disabled-ref.html
 == 911201.html 911201-ref.html
 needs-focus == 969773.html 969773-ref.html
 fuzzy-if(skiaContent,1,220) == 997805.html 997805-ref.html
 fuzzy-if(skiaContent,1,220) skip-if(verify&&OSX) == 1088158.html 1088158-ref.html
+needs-focus == 1443902-1.html 1443902-1-ref.html
+needs-focus == 1443902-2.html 1443902-2-ref.html
+needs-focus == 1443902-3.html 1443902-3-ref.html
+needs-focus == 1443902-4.html 1443902-4-ref.html