Bug 1343642 - Ensure to grab nsFrameSelection before calling its methods unless calling only const methods. r=smaug, a=abillings
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 06 Apr 2017 13:00:06 +0900
changeset 355603 a803be74843c16ca1b7841dc0318aa333e5ba915
parent 355602 f4802fea742c8b2c7083135f71b4ab252cfa52dd
child 355604 4ab6d5c43036602ca978833665453418104ce3a2
push id7010
push userryanvm@gmail.com
push dateFri, 07 Apr 2017 21:02:01 +0000
treeherdermozilla-esr52@143d5fa98ef7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, abillings
bugs1343642
milestone52.0.3
Bug 1343642 - Ensure to grab nsFrameSelection before calling its methods unless calling only const methods. r=smaug, a=abillings
dom/html/HTMLInputElement.cpp
layout/base/nsPresShell.cpp
layout/generic/nsSelection.cpp
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -3699,17 +3699,17 @@ HTMLInputElement::Select()
 
   FocusTristate state = FocusState();
   if (state == eUnfocusable) {
     return NS_OK;
   }
 
   nsTextEditorState* tes = GetEditorState();
   if (tes) {
-    nsFrameSelection* fs = tes->GetConstFrameSelection();
+    RefPtr<nsFrameSelection> fs = tes->GetConstFrameSelection();
     if (fs && fs->MouseDownRecorded()) {
       // This means that we're being called while the frame selection has a mouse
       // down event recorded to adjust the caret during the mouse up event.
       // We are probably called from the focus event handler.  We should override
       // the delayed caret data in this case to ensure that this select() call
       // takes effect.
       fs->SetDelayedCaretData(nullptr);
     }
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -919,17 +919,18 @@ PresShell::Init(nsIDocument* aDocument,
 
   if (AccessibleCaretEnabled(mDocument->GetDocShell())) {
     // Need to happen before nsFrameSelection has been set up.
     mAccessibleCaretEventHub = new AccessibleCaretEventHub(this);
   }
 
   mSelection = new nsFrameSelection();
 
-  mSelection->Init(this, nullptr);
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  frameSelection->Init(this, nullptr);
 
   // Important: this has to happen after the selection has been set up
 #ifdef SHOW_CARET
   // make the caret
   mCaret = new nsCaret();
   mCaret->Init(this);
   mOriginalCaret = mCaret;
 
@@ -1216,17 +1217,18 @@ PresShell::Destroy()
   ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DISCARD_IMAGES));
 
   if (mCaret) {
     mCaret->Terminate();
     mCaret = nullptr;
   }
 
   if (mSelection) {
-    mSelection->DisconnectFromPresShell();
+    RefPtr<nsFrameSelection> frameSelection = mSelection;
+    frameSelection->DisconnectFromPresShell();
   }
 
   if (mAccessibleCaretEventHub) {
     mAccessibleCaretEventHub->Terminate();
     mAccessibleCaretEventHub = nullptr;
   }
 
   // release our pref style sheet, if we have one still
@@ -1541,52 +1543,56 @@ PresShell::RemoveSheet(SheetType aType, 
 
   mStyleSet->RemoveStyleSheet(aType, sheet);
   RestyleForCSSRuleChanges();
 }
 
 NS_IMETHODIMP
 PresShell::SetDisplaySelection(int16_t aToggle)
 {
-  mSelection->SetDisplaySelection(aToggle);
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  frameSelection->SetDisplaySelection(aToggle);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresShell::GetDisplaySelection(int16_t *aToggle)
 {
-  *aToggle = mSelection->GetDisplaySelection();
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  *aToggle = frameSelection->GetDisplaySelection();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresShell::GetSelection(RawSelectionType aRawSelectionType,
                         nsISelection **aSelection)
 {
   if (!aSelection || !mSelection)
     return NS_ERROR_NULL_POINTER;
 
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
   nsCOMPtr<nsISelection> selection =
-    mSelection->GetSelection(ToSelectionType(aRawSelectionType));
+    frameSelection->GetSelection(ToSelectionType(aRawSelectionType));
 
   if (!selection) {
     return NS_ERROR_INVALID_ARG;
   }
 
   selection.forget(aSelection);
   return NS_OK;
 }
 
 Selection*
 PresShell::GetCurrentSelection(SelectionType aSelectionType)
 {
   if (!mSelection)
     return nullptr;
 
-  return mSelection->GetSelection(aSelectionType);
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  return frameSelection->GetSelection(aSelectionType);
 }
 
 already_AddRefed<nsISelectionController>
 PresShell::GetSelectionControllerForFocusedContent(nsIContent** aFocusedContent)
 {
   if (aFocusedContent) {
     *aFocusedContent = nullptr;
   }
@@ -1618,27 +1624,29 @@ PresShell::GetSelectionControllerForFocu
 NS_IMETHODIMP
 PresShell::ScrollSelectionIntoView(RawSelectionType aRawSelectionType,
                                    SelectionRegion aRegion,
                                    int16_t aFlags)
 {
   if (!mSelection)
     return NS_ERROR_NULL_POINTER;
 
-  return mSelection->ScrollSelectionIntoView(ToSelectionType(aRawSelectionType),
-                                             aRegion, aFlags);
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  return frameSelection->ScrollSelectionIntoView(
+                           ToSelectionType(aRawSelectionType), aRegion, aFlags);
 }
 
 NS_IMETHODIMP
 PresShell::RepaintSelection(RawSelectionType aRawSelectionType)
 {
   if (!mSelection)
     return NS_ERROR_NULL_POINTER;
 
-  return mSelection->RepaintSelection(ToSelectionType(aRawSelectionType));
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  return frameSelection->RepaintSelection(ToSelectionType(aRawSelectionType));
 }
 
 // Make shell be a document observer
 void
 PresShell::BeginObservingDocument()
 {
   if (mDocument && !mIsDestroying) {
     mDocument->AddObserver(this);
@@ -2168,82 +2176,91 @@ NS_IMETHODIMP PresShell::GetSelectionFla
   return NS_OK;
 }
 
 //implementation of nsISelectionController
 
 NS_IMETHODIMP
 PresShell::PhysicalMove(int16_t aDirection, int16_t aAmount, bool aExtend)
 {
-  return mSelection->PhysicalMove(aDirection, aAmount, aExtend);
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  return frameSelection->PhysicalMove(aDirection, aAmount, aExtend);
 }
 
 NS_IMETHODIMP
 PresShell::CharacterMove(bool aForward, bool aExtend)
 {
-  return mSelection->CharacterMove(aForward, aExtend);
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  return frameSelection->CharacterMove(aForward, aExtend);
 }
 
 NS_IMETHODIMP
 PresShell::CharacterExtendForDelete()
 {
-  return mSelection->CharacterExtendForDelete();
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  return frameSelection->CharacterExtendForDelete();
 }
 
 NS_IMETHODIMP
 PresShell::CharacterExtendForBackspace()
 {
-  return mSelection->CharacterExtendForBackspace();
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  return frameSelection->CharacterExtendForBackspace();
 }
 
 NS_IMETHODIMP
 PresShell::WordMove(bool aForward, bool aExtend)
 {
-  nsresult result = mSelection->WordMove(aForward, aExtend);
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  nsresult result = frameSelection->WordMove(aForward, aExtend);
 // if we can't go down/up any more we must then move caret completely to
 // end/beginning respectively.
   if (NS_FAILED(result))
     result = CompleteMove(aForward, aExtend);
   return result;
 }
 
 NS_IMETHODIMP
 PresShell::WordExtendForDelete(bool aForward)
 {
-  return mSelection->WordExtendForDelete(aForward);
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  return frameSelection->WordExtendForDelete(aForward);
 }
 
 NS_IMETHODIMP
 PresShell::LineMove(bool aForward, bool aExtend)
 {
-  nsresult result = mSelection->LineMove(aForward, aExtend);
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  nsresult result = frameSelection->LineMove(aForward, aExtend);
 // if we can't go down/up any more we must then move caret completely to
 // end/beginning respectively.
   if (NS_FAILED(result))
     result = CompleteMove(aForward,aExtend);
   return result;
 }
 
 NS_IMETHODIMP
 PresShell::IntraLineMove(bool aForward, bool aExtend)
 {
-  return mSelection->IntraLineMove(aForward, aExtend);
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  return frameSelection->IntraLineMove(aForward, aExtend);
 }
 
 
 
 NS_IMETHODIMP
 PresShell::PageMove(bool aForward, bool aExtend)
 {
   nsIScrollableFrame *scrollableFrame =
     GetFrameToScrollAsScrollable(nsIPresShell::eVertical);
   if (!scrollableFrame)
     return NS_OK;
 
-  mSelection->CommonPageMove(aForward, aExtend, scrollableFrame);
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  frameSelection->CommonPageMove(aForward, aExtend, scrollableFrame);
   // After ScrollSelectionIntoView(), the pending notifications might be
   // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
   return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
                                  nsISelectionController::SELECTION_FOCUS_REGION,
                                  nsISelectionController::SCROLL_SYNCHRONOUS |
                                  nsISelectionController::SCROLL_FOR_CARET_MOVE);
 }
 
@@ -2326,43 +2343,46 @@ PresShell::CompleteScroll(bool aForward)
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresShell::CompleteMove(bool aForward, bool aExtend)
 {
   // Beware! This may flush notifications via synchronous
   // ScrollSelectionIntoView.
-  nsIContent* limiter = mSelection->GetAncestorLimiter();
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  nsIContent* limiter = frameSelection->GetAncestorLimiter();
   nsIFrame* frame = limiter ? limiter->GetPrimaryFrame()
                             : FrameConstructor()->GetRootElementFrame();
   if (!frame)
     return NS_ERROR_FAILURE;
   nsIFrame::CaretPosition pos =
     frame->GetExtremeCaretPosition(!aForward);
-  mSelection->HandleClick(pos.mResultContent, pos.mContentOffset,
-                          pos.mContentOffset, aExtend, false,
-                          aForward ? CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE);
+  frameSelection->HandleClick(pos.mResultContent, pos.mContentOffset,
+                              pos.mContentOffset, aExtend, false,
+                              aForward ? CARET_ASSOCIATE_AFTER :
+                                         CARET_ASSOCIATE_BEFORE);
   if (limiter) {
     // HandleClick resets ancestorLimiter, so set it again.
-    mSelection->SetAncestorLimiter(limiter);
+    frameSelection->SetAncestorLimiter(limiter);
   }
 
   // After ScrollSelectionIntoView(), the pending notifications might be
   // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
   return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
                                  nsISelectionController::SELECTION_FOCUS_REGION,
                                  nsISelectionController::SCROLL_SYNCHRONOUS |
                                  nsISelectionController::SCROLL_FOR_CARET_MOVE);
 }
 
 NS_IMETHODIMP
 PresShell::SelectAll()
 {
-  return mSelection->SelectAll();
+  RefPtr<nsFrameSelection> frameSelection = mSelection;
+  return frameSelection->SelectAll();
 }
 
 static void
 DoCheckVisibility(nsPresContext* aPresContext,
                   nsIContent* aNode,
                   int16_t aStartOffset,
                   int16_t aEndOffset,
                   bool* aRetval)
@@ -3119,17 +3139,17 @@ PresShell::GoToAnchor(const nsAString& a
     RefPtr<nsIDOMRange> jumpToRange = new nsRange(mDocument);
     while (content && content->GetFirstChild()) {
       content = content->GetFirstChild();
     }
     nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
     NS_ASSERTION(node, "No nsIDOMNode for descendant of anchor");
     jumpToRange->SelectNodeContents(node);
     // Select the anchor
-    nsISelection* sel = mSelection->GetSelection(SelectionType::eNormal);
+    RefPtr<Selection> sel = mSelection->GetSelection(SelectionType::eNormal);
     if (sel) {
       sel->RemoveAllRanges();
       sel->AddRange(jumpToRange);
       if (!selectAnchor) {
         // Use a caret (collapsed selection) at the start of the anchor
         sel->CollapseToStart();
       }
     }
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -307,17 +307,18 @@ public:
       nsWeakFrame frame =
         mContent ? mPresContext->GetPrimaryFrameFor(mContent) : nullptr;
       if (!frame)
         return NS_OK;
       mContent = nullptr;
 
       nsPoint pt = mPoint -
         frame->GetOffsetTo(mPresContext->PresShell()->FrameManager()->GetRootFrame());
-      mFrameSelection->HandleDrag(frame, pt);
+      RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
+      frameSelection->HandleDrag(frame, pt);
       if (!frame.IsAlive())
         return NS_OK;
 
       NS_ASSERTION(frame->PresContext() == mPresContext, "document mismatch?");
       mSelection->DoAutoScroll(frame, pt);
     }
     return NS_OK;
   }
@@ -4769,18 +4770,20 @@ Selection::GetAncestorLimiter(nsIContent
     c.forget(aContent);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Selection::SetAncestorLimiter(nsIContent* aContent)
 {
-  if (mFrameSelection)
-    mFrameSelection->SetAncestorLimiter(aContent);
+  if (mFrameSelection) {
+    RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
+    frameSelection->SetAncestorLimiter(aContent);
+  }
   return NS_OK;
 }
 
 RangeData*
 Selection::FindRangeData(nsIDOMRange* aRange)
 {
   NS_ENSURE_TRUE(aRange, nullptr);
   for (uint32_t i = 0; i < mRanges.Length(); i++) {
@@ -4924,19 +4927,20 @@ Selection::RemoveAllRanges(ErrorResult& 
   RefPtr<nsPresContext>  presContext = GetPresContext();
   nsresult  result = Clear(presContext);
   if (NS_FAILED(result)) {
     aRv.Throw(result);
     return;
   }
 
   // Turn off signal for table selection
-  mFrameSelection->ClearTableCellSelection();
-
-  result = mFrameSelection->NotifySelectionListeners(GetType());
+  RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
+  frameSelection->ClearTableCellSelection();
+
+  result = frameSelection->NotifySelectionListeners(GetType());
   // Also need to notify the frames!
   // PresShell::CharacterDataChanged should do that on DocumentChanged
   if (NS_FAILED(result)) {
     aRv.Throw(result);
   }
 }
 
 /** AddRange adds the specified range to the selection
@@ -5003,17 +5007,18 @@ Selection::AddRangeInternal(nsRange& aRa
   }
 
   RefPtr<nsPresContext>  presContext = GetPresContext();
   selectFrames(presContext, &aRange, true);
 
   if (!mFrameSelection)
     return;//nothing to do
 
-  result = mFrameSelection->NotifySelectionListeners(GetType());
+  RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
+  result = frameSelection->NotifySelectionListeners(GetType());
   if (NS_FAILED(result)) {
     aRv.Throw(result);
   }
 }
 
 // Selection::RemoveRange
 //
 //    Removes the given range from the selection. The tricky part is updating
@@ -5097,17 +5102,18 @@ Selection::RemoveRange(nsRange& aRange, 
     // might appear to be moving randomly (bug 337871).
     if (mSelectionType != SelectionType::eSpellCheck && cnt > 0) {
       ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION);
     }
   }
 
   if (!mFrameSelection)
     return;//nothing to do
-  rv = mFrameSelection->NotifySelectionListeners(GetType());
+  RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
+  rv = frameSelection->NotifySelectionListeners(GetType());
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 }
 
 
 
 /*
@@ -5142,48 +5148,49 @@ Selection::Collapse(nsINode& aParentNode
 {
   if (!mFrameSelection) {
     aRv.Throw(NS_ERROR_NOT_INITIALIZED); // Can't do selection
     return;
   }
 
   nsCOMPtr<nsINode> parentNode = &aParentNode;
 
-  mFrameSelection->InvalidateDesiredPos();
-  if (!IsValidSelectionPoint(mFrameSelection, parentNode)) {
+  RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
+  frameSelection->InvalidateDesiredPos();
+  if (!IsValidSelectionPoint(frameSelection, parentNode)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
   nsresult result;
 
   RefPtr<nsPresContext> presContext = GetPresContext();
   if (!presContext || presContext->Document() != parentNode->OwnerDoc()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   // Delete all of the current ranges
   Clear(presContext);
 
   // Turn off signal for table selection
-  mFrameSelection->ClearTableCellSelection();
+  frameSelection->ClearTableCellSelection();
 
   // Hack to display the caret on the right line (bug 1237236).
-  if (mFrameSelection->GetHint() != CARET_ASSOCIATE_AFTER &&
+  if (frameSelection->GetHint() != CARET_ASSOCIATE_AFTER &&
       parentNode->IsContent()) {
     int32_t frameOffset;
     nsTextFrame* f =
       do_QueryFrame(nsCaret::GetFrameAndOffset(this, parentNode,
                                                aOffset, &frameOffset));
     if (f && f->IsAtEndOfLine() && f->HasSignificantTerminalNewline()) {
       if ((parentNode->AsContent() == f->GetContent() &&
            f->GetContentEnd() == int32_t(aOffset)) ||
           (parentNode == f->GetContent()->GetParentNode() &&
            parentNode->IndexOf(f->GetContent()) + 1 == int32_t(aOffset))) {
-        mFrameSelection->SetHint(CARET_ASSOCIATE_AFTER);
+        frameSelection->SetHint(CARET_ASSOCIATE_AFTER);
       }
     }
   }
 
   RefPtr<nsRange> range = new nsRange(parentNode);
   result = range->SetEnd(parentNode, aOffset);
   if (NS_FAILED(result)) {
     aRv.Throw(result);
@@ -5207,17 +5214,17 @@ Selection::Collapse(nsINode& aParentNode
   int32_t rangeIndex = -1;
   result = AddItem(range, &rangeIndex);
   if (NS_FAILED(result)) {
     aRv.Throw(result);
     return;
   }
   setAnchorFocusRange(0);
   selectFrames(presContext, range, true);
-  result = mFrameSelection->NotifySelectionListeners(GetType());
+  result = frameSelection->NotifySelectionListeners(GetType());
   if (NS_FAILED(result)) {
     aRv.Throw(result);
   }
 }
 
 /*
  * Sets the whole selection to be one point
  * at the start of the current selection
@@ -5763,17 +5770,18 @@ Selection::Extend(nsINode& aParentNode, 
   if (GetDirection() != oldDirection) {
     printf("    direction changed to %s\n",
            GetDirection() == eDirNext? "eDirNext":"eDirPrevious");
   }
   nsCOMPtr<nsIContent> content = do_QueryInterface(&aParentNode);
   printf ("Sel. Extend to %p %s %d\n", content.get(),
           nsAtomCString(content->NodeInfo()->NameAtom()).get(), aOffset);
 #endif
-  res = mFrameSelection->NotifySelectionListeners(GetType());
+  RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
+  res = frameSelection->NotifySelectionListeners(GetType());
   if (NS_FAILED(res)) {
     aRv.Throw(res);
   }
 }
 
 NS_IMETHODIMP
 Selection::SelectAllChildren(nsIDOMNode* aParentNode)
 {
@@ -6238,62 +6246,65 @@ Selection::RemoveSelectionListener(nsISe
   }
 }
 
 nsresult
 Selection::NotifySelectionListeners()
 {
   if (!mFrameSelection)
     return NS_OK;//nothing to do
- 
-  if (mFrameSelection->GetBatching()) {
-    mFrameSelection->SetDirty();
+
+  RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
+  if (frameSelection->GetBatching()) {
+    frameSelection->SetDirty();
     return NS_OK;
   }
   nsCOMArray<nsISelectionListener> selectionListeners(mSelectionListeners);
   int32_t cnt = selectionListeners.Count();
   if (cnt != mSelectionListeners.Count()) {
     return NS_ERROR_OUT_OF_MEMORY;  // nsCOMArray is fallible
   }
 
   nsCOMPtr<nsIDOMDocument> domdoc;
   nsIPresShell* ps = GetPresShell();
   if (ps) {
     domdoc = do_QueryInterface(ps->GetDocument());
   }
 
-  short reason = mFrameSelection->PopReason();
+  short reason = frameSelection->PopReason();
   for (int32_t i = 0; i < cnt; i++) {
     selectionListeners[i]->NotifySelectionChanged(domdoc, this, reason);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Selection::StartBatchChanges()
 {
-  if (mFrameSelection)
-    mFrameSelection->StartBatchChanges();
-
+  if (mFrameSelection) {
+    RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
+    frameSelection->StartBatchChanges();
+  }
   return NS_OK;
 }
 
 
 
 NS_IMETHODIMP
 Selection::EndBatchChanges()
 {
   return EndBatchChangesInternal();
 }
 
 nsresult
 Selection::EndBatchChangesInternal(int16_t aReason)
 {
   if (mFrameSelection) {
-    mFrameSelection->EndBatchChanges(aReason);
+    RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
+    frameSelection->EndBatchChanges(aReason);
   }
   return NS_OK;
 }
 
 void
 Selection::AddSelectionChangeBlocker()
 {
   mSelectionChangeBlockerCount++;
@@ -6322,17 +6333,18 @@ Selection::DeleteFromDocument()
   return result.StealNSResult();
 }
 
 void
 Selection::DeleteFromDocument(ErrorResult& aRv)
 {
   if (!mFrameSelection)
     return;//nothing to do
-  nsresult rv = mFrameSelection->DeleteFromDocument();
+  RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
+  nsresult rv = frameSelection->DeleteFromDocument();
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 }
 
 NS_IMETHODIMP
 Selection::Modify(const nsAString& aAlter, const nsAString& aDirection,
                   const nsAString& aGranularity)
@@ -6429,46 +6441,49 @@ Selection::Modify(const nsAString& aAlte
       }
     }
   }
 
   // MoveCaret will return an error if it can't move in the specified
   // direction, but we just ignore this error unless it's a line move, in which
   // case we call nsISelectionController::CompleteMove to move the cursor to
   // the beginning/end of the line.
-  rv = mFrameSelection->MoveCaret(forward ? eDirNext : eDirPrevious,
-                                  extend, amount,
-                                  visual ? nsFrameSelection::eVisual
-                                         : nsFrameSelection::eLogical);
+  RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
+  rv = frameSelection->MoveCaret(forward ? eDirNext : eDirPrevious,
+                                 extend, amount,
+                                 visual ? nsFrameSelection::eVisual
+                                        : nsFrameSelection::eLogical);
 
   if (aGranularity.LowerCaseEqualsLiteral("line") && NS_FAILED(rv)) {
     nsCOMPtr<nsISelectionController> shell =
-      do_QueryInterface(mFrameSelection->GetShell());
+      do_QueryInterface(frameSelection->GetShell());
     if (!shell)
       return;
     shell->CompleteMove(forward, extend);
   }
 }
 
 /** SelectionLanguageChange modifies the cursor Bidi level after a change in keyboard direction
  *  @param aLangRTL is true if the new language is right-to-left or false if the new language is left-to-right
  */
 NS_IMETHODIMP
 Selection::SelectionLanguageChange(bool aLangRTL)
 {
   if (!mFrameSelection)
     return NS_ERROR_NOT_INITIALIZED; // Can't do selection
 
+  RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
+
   // if the direction of the language hasn't changed, nothing to do
   nsBidiLevel kbdBidiLevel = aLangRTL ? NSBIDI_RTL : NSBIDI_LTR;
-  if (kbdBidiLevel == mFrameSelection->mKbdBidiLevel) {
+  if (kbdBidiLevel == frameSelection->mKbdBidiLevel) {
     return NS_OK;
   }
 
-  mFrameSelection->mKbdBidiLevel = kbdBidiLevel;
+  frameSelection->mKbdBidiLevel = kbdBidiLevel;
 
   nsresult result;
   nsIFrame *focusFrame = 0;
 
   result = GetPrimaryFrameForFocusNode(&focusFrame, nullptr, false);
   if (NS_FAILED(result)) {
     return result;
   }
@@ -6489,47 +6504,47 @@ Selection::SelectionLanguageChange(bool 
   if ((focusOffset != frameStart) && (focusOffset != frameEnd))
     // the cursor is not at a frame boundary, so the level of both the characters (logically) before and after the cursor
     //  is equal to the frame level
     levelBefore = levelAfter = level;
   else {
     // the cursor is at a frame boundary, so use GetPrevNextBidiLevels to find the level of the characters
     //  before and after the cursor
     nsCOMPtr<nsIContent> focusContent = do_QueryInterface(GetFocusNode());
-    nsPrevNextBidiLevels levels = mFrameSelection->
+    nsPrevNextBidiLevels levels = frameSelection->
       GetPrevNextBidiLevels(focusContent, focusOffset, false);
       
     levelBefore = levels.mLevelBefore;
     levelAfter = levels.mLevelAfter;
   }
 
   if (IS_SAME_DIRECTION(levelBefore, levelAfter)) {
     // if cursor is between two characters with the same orientation, changing the keyboard language
     //  must toggle the cursor level between the level of the character with the lowest level
     //  (if the new language corresponds to the orientation of that character) and this level plus 1
     //  (if the new language corresponds to the opposite orientation)
     if ((level != levelBefore) && (level != levelAfter))
       level = std::min(levelBefore, levelAfter);
     if (IS_SAME_DIRECTION(level, kbdBidiLevel))
-      mFrameSelection->SetCaretBidiLevel(level);
+      frameSelection->SetCaretBidiLevel(level);
     else
-      mFrameSelection->SetCaretBidiLevel(level + 1);
+      frameSelection->SetCaretBidiLevel(level + 1);
   }
   else {
     // if cursor is between characters with opposite orientations, changing the keyboard language must change
     //  the cursor level to that of the adjacent character with the orientation corresponding to the new language.
     if (IS_SAME_DIRECTION(levelBefore, kbdBidiLevel))
-      mFrameSelection->SetCaretBidiLevel(levelBefore);
+      frameSelection->SetCaretBidiLevel(levelBefore);
     else
-      mFrameSelection->SetCaretBidiLevel(levelAfter);
+      frameSelection->SetCaretBidiLevel(levelAfter);
   }
   
   // The caret might have moved, so invalidate the desired position
   // for future usages of up-arrow or down-arrow
-  mFrameSelection->InvalidateDesiredPos();
+  frameSelection->InvalidateDesiredPos();
   
   return NS_OK;
 }
 
 NS_IMETHODIMP_(nsDirection)
 Selection::GetSelectionDirection() {
   return mDirection;
 }
@@ -6775,17 +6790,17 @@ SelectionChangeListener::NotifySelection
   if (nsFrameSelection::sSelectionEventsOnTextControlsEnabled) {
     nsCOMPtr<nsINode> target;
 
     // Check if we should be firing this event to a different node than the
     // document. The limiter of the nsFrameSelection will be within the native
     // anonymous subtree of the node we want to fire the event on. We need to
     // climb up the parent chain to escape the native anonymous subtree, and then
     // fire the event.
-    if (nsFrameSelection* fs = sel->GetFrameSelection()) {
+    if (const nsFrameSelection* fs = sel->GetFrameSelection()) {
       if (nsCOMPtr<nsIContent> root = fs->GetLimiter()) {
         while (root && root->IsInNativeAnonymousSubtree()) {
           root = root->GetParent();
         }
 
         target = root.forget();
       }
     }
@@ -6797,17 +6812,17 @@ SelectionChangeListener::NotifySelection
     }
 
     if (target) {
       RefPtr<AsyncEventDispatcher> asyncDispatcher =
         new AsyncEventDispatcher(target, NS_LITERAL_STRING("selectionchange"), false);
       asyncDispatcher->PostDOMEvent();
     }
   } else {
-    if (nsFrameSelection* fs = sel->GetFrameSelection()) {
+    if (const nsFrameSelection* fs = sel->GetFrameSelection()) {
       if (nsCOMPtr<nsIContent> root = fs->GetLimiter()) {
         if (root->IsInNativeAnonymousSubtree()) {
           return NS_OK;
         }
       }
     }
 
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);