Bug 1061468 - Notify the editor when removing the focused element is its ancestor limiter. r=ehsan
authorMats Palmgren <mats@mozilla.com>
Tue, 09 Sep 2014 23:27:56 +0000
changeset 228977 004917420079b488f6d7c7ee1f8cc03ac9c99b5a
parent 228976 96a507248c53660de032c3e821ba7a612afa1cf6
child 228978 0ba3143c153cdfd967f5ed7e26bf2554ec5fc6e0
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1061468
milestone35.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 1061468 - Notify the editor when removing the focused element is its ancestor limiter. r=ehsan
content/base/public/nsISelectionPrivate.idl
dom/base/nsFocusManager.cpp
editor/libeditor/nsEditor.cpp
editor/libeditor/nsEditor.h
editor/nsIEditor.idl
layout/generic/nsSelection.cpp
--- a/content/base/public/nsISelectionPrivate.idl
+++ b/content/base/public/nsISelectionPrivate.idl
@@ -23,23 +23,24 @@ template<class T> class nsTArray;
 
 [ptr] native nsIFrame(nsIFrame);
 [ptr] native RangeArray(nsTArray<nsRange*>);
 [ref] native constTextRangeStyleRef(const mozilla::TextRangeStyle);
 [ref] native nsPointRef(nsPoint);
 native nsDirection(nsDirection);
 native ScrollAxis(nsIPresShell::ScrollAxis);
 
-[scriptable, builtinclass, uuid(52629837-7b3f-4434-940d-a14de7ef9b7a)]
+[scriptable, builtinclass, uuid(5a82ee9a-35ce-11e4-8c3e-b7043d68ad70)]
 interface nsISelectionPrivate : nsISelection
  {
     const short ENDOFPRECEDINGLINE=0;
     const short STARTOFNEXTLINE=1;
 
     attribute boolean interlinePosition;
+    [noscript] attribute nsIContent ancestorLimiter;
 
     /* startBatchChanges
        match this up with endbatchChanges. will stop ui updates while multiple selection methods are called
     */
     [noscript] void  startBatchChanges();
 
     /* endBatchChanges
        match this up with startBatchChanges
@@ -76,18 +77,16 @@ interface nsISelectionPrivate : nsISelec
      */
     [noscript] attribute boolean canCacheFrameOffset;
 
     /* GetCachedOffsetForFrame
      * Returns cached value for nsTextFrame::GetPointFromOffset.
      */
     [noscript] void getCachedFrameOffset(in nsIFrame aFrame, in int32_t inOffset, in nsPointRef aPoint);
 
-    [noscript] void setAncestorLimiter(in nsIContent aContent);
-
     /**
      * Set the painting style for the range. The range must be a range in
      * the selection. The textRangeStyle will be used by text frame
      * when it is painting the selection.
      */
     [noscript] void setTextRangeStyle(in nsIDOMRange range,
                       in constTextRangeStyleRef textRangeStyle);
 
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -7,16 +7,17 @@
 
 #include "nsFocusManager.h"
 
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsGkAtoms.h"
 #include "nsContentUtils.h"
 #include "nsIDocument.h"
 #include "nsIDOMWindow.h"
+#include "nsIEditor.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMRange.h"
 #include "nsIHTMLDocument.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsLayoutUtils.h"
@@ -810,18 +811,17 @@ nsFocusManager::ContentRemoved(nsIDocume
   if (content && nsContentUtils::ContentIsDescendantOf(content, aContent)) {
     bool shouldShowFocusRing = window->ShouldShowFocusRing();
     window->SetFocusedNode(nullptr);
 
     // if this window is currently focused, clear the global focused
     // element as well, but don't fire any events.
     if (window == mFocusedWindow) {
       mFocusedContent = nullptr;
-    }
-    else {
+    } else {
       // Check if the node that was focused is an iframe or similar by looking
       // if it has a subdocument. This would indicate that this focused iframe
       // and its descendants will be going away. We will need to move the
       // focus somewhere else, so just clear the focus in the toplevel window
       // so that no element is focused.
       nsIDocument* subdoc = aDocument->GetSubDocumentFor(content);
       if (subdoc) {
         nsCOMPtr<nsIDocShell> docShell = subdoc->GetDocShell();
@@ -829,16 +829,37 @@ nsFocusManager::ContentRemoved(nsIDocume
           nsCOMPtr<nsPIDOMWindow> childWindow = docShell->GetWindow();
           if (childWindow && IsSameOrAncestor(childWindow, mFocusedWindow)) {
             ClearFocus(mActiveWindow);
           }
         }
       }
     }
 
+    // Notify the editor in case we removed its ancestor limiter.
+    if (content->IsEditable()) {
+      nsCOMPtr<nsIDocShell> docShell = aDocument->GetDocShell();
+      if (docShell) {
+        nsCOMPtr<nsIEditor> editor;
+        docShell->GetEditor(getter_AddRefs(editor));
+        if (editor) {
+          nsCOMPtr<nsISelection> s;
+          editor->GetSelection(getter_AddRefs(s));
+          nsCOMPtr<nsISelectionPrivate> selection = do_QueryInterface(s);
+          if (selection) {
+            nsCOMPtr<nsIContent> limiter;
+            selection->GetAncestorLimiter(getter_AddRefs(limiter));
+            if (limiter == content) {
+              editor->FinalizeSelection();
+            }
+          }
+        }
+      }
+    }
+
     NotifyFocusStateChange(content, shouldShowFocusRing, false);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFocusManager::WindowShown(nsIDOMWindow* aWindow, bool aNeedsFocus)
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -4801,40 +4801,40 @@ nsEditor::InitializeSelection(nsIDOMEven
     if (rangeCount == 0) {
       BeginningOfDocument();
     }
   }
 
   return NS_OK;
 }
 
-void
+NS_IMETHODIMP
 nsEditor::FinalizeSelection()
 {
   nsCOMPtr<nsISelectionController> selCon;
   nsresult rv = GetSelectionController(getter_AddRefs(selCon));
-  NS_ENSURE_SUCCESS_VOID(rv);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsISelection> selection;
   rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
                             getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS_VOID(rv);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsISelectionPrivate> selectionPrivate = do_QueryInterface(selection);
-  NS_ENSURE_TRUE_VOID(selectionPrivate);
+  NS_ENSURE_TRUE(selectionPrivate, rv);
 
   selectionPrivate->SetAncestorLimiter(nullptr);
 
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
-  NS_ENSURE_TRUE_VOID(presShell);
+  NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_INITIALIZED);
 
   selCon->SetCaretEnabled(false);
 
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
-  NS_ENSURE_TRUE_VOID(fm);
+  NS_ENSURE_TRUE(fm, NS_ERROR_NOT_INITIALIZED);
   fm->UpdateCaretForCaretBrowsingMode();
 
   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();
@@ -4855,16 +4855,17 @@ nsEditor::FinalizeSelection()
     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);
+  return NS_OK;
 }
 
 dom::Element *
 nsEditor::GetRoot()
 {
   if (!mRootElement)
   {
     nsCOMPtr<nsIDOMElement> root;
--- a/editor/libeditor/nsEditor.h
+++ b/editor/libeditor/nsEditor.h
@@ -796,19 +796,16 @@ 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/nsIEditor.idl
+++ b/editor/nsIEditor.idl
@@ -16,17 +16,17 @@ interface nsIDocumentStateListener;
 interface nsIOutputStream;
 interface nsITransactionManager;
 interface nsITransaction;
 interface nsIEditorObserver;
 interface nsIEditActionListener;
 interface nsIInlineSpellChecker;
 interface nsITransferable;
 
-[scriptable, uuid(04714a01-e02f-4ef5-a388-612451d0db16)]
+[scriptable, uuid(a1ddae68-35d0-11e4-9329-cb55463f21c9)]
 
 interface nsIEditor  : nsISupports
 {
 %{C++
   typedef short EDirection;
   typedef short EStripWrappers;
 %}
   const short eNone = 0;
@@ -38,16 +38,21 @@ interface nsIEditor  : nsISupports
   const short eToEndOfLine = 6;
 
   const short eStrip = 0;
   const short eNoStrip = 1;
 
   readonly attribute nsISelection selection;
 
   /**
+   * Finalizes selection and caret for the editor.
+   */
+  [noscript] void finalizeSelection();
+
+  /**
    * Init is to tell the implementation of nsIEditor to begin its services
    * @param aDoc          The dom document interface being observed
    * @param aRoot         This is the root of the editable section of this
    *                      document. If it is null then we get root
    *                      from document body.
    * @param aSelCon       this should be used to get the selection location
    *                      (will be null for HTML editors)
    * @param aFlags        A bitmask of flags for specifying the behavior
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -4261,16 +4261,26 @@ Selection::GetCachedFrameOffset(nsIFrame
        mCachedOffsetForFrame->mLastContentOffset = inOffset; 
      }
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
+Selection::GetAncestorLimiter(nsIContent** aContent)
+{
+  if (mFrameSelection) {
+    nsCOMPtr<nsIContent> c = mFrameSelection->GetAncestorLimiter();
+    c.forget(aContent);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 Selection::SetAncestorLimiter(nsIContent* aContent)
 {
   if (mFrameSelection)
     mFrameSelection->SetAncestorLimiter(aContent);
   return NS_OK;
 }
 
 RangeData*