accessible/src/base/SelectionManager.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/a11y/SelectionManager.h"
     8 #include "DocAccessible-inl.h"
     9 #include "nsAccessibilityService.h"
    10 #include "nsAccUtils.h"
    11 #include "nsCoreUtils.h"
    12 #include "nsEventShell.h"
    14 #include "nsIAccessibleTypes.h"
    15 #include "nsIDOMDocument.h"
    16 #include "nsIPresShell.h"
    17 #include "mozilla/dom/Selection.h"
    18 #include "mozilla/dom/Element.h"
    20 using namespace mozilla;
    21 using namespace mozilla::a11y;
    22 using mozilla::dom::Selection;
    24 struct mozilla::a11y::SelData MOZ_FINAL
    25 {
    26   SelData(Selection* aSel, int32_t aReason) :
    27     mSel(aSel), mReason(aReason) {}
    29   nsRefPtr<Selection> mSel;
    30   int16_t mReason;
    32   NS_INLINE_DECL_REFCOUNTING(SelData)
    34 private:
    35   // Private destructor, to discourage deletion outside of Release():
    36   ~SelData() {}
    37 };
    39 void
    40 SelectionManager::ClearControlSelectionListener()
    41 {
    42   if (!mCurrCtrlFrame)
    43     return;
    45   const nsFrameSelection* frameSel = mCurrCtrlFrame->GetConstFrameSelection();
    46   NS_ASSERTION(frameSel, "No frame selection for the element!");
    48   mCurrCtrlFrame = nullptr;
    49   if (!frameSel)
    50     return;
    52   // Remove 'this' registered as selection listener for the normal selection.
    53   Selection* normalSel =
    54     frameSel->GetSelection(nsISelectionController::SELECTION_NORMAL);
    55   normalSel->RemoveSelectionListener(this);
    57   // Remove 'this' registered as selection listener for the spellcheck
    58   // selection.
    59   Selection* spellSel =
    60     frameSel->GetSelection(nsISelectionController::SELECTION_SPELLCHECK);
    61   spellSel->RemoveSelectionListener(this);
    62 }
    64 void
    65 SelectionManager::SetControlSelectionListener(dom::Element* aFocusedElm)
    66 {
    67   // When focus moves such that the caret is part of a new frame selection
    68   // this removes the old selection listener and attaches a new one for
    69   // the current focus.
    70   ClearControlSelectionListener();
    72   mCurrCtrlFrame = aFocusedElm->GetPrimaryFrame();
    73   if (!mCurrCtrlFrame)
    74     return;
    76   const nsFrameSelection* frameSel = mCurrCtrlFrame->GetConstFrameSelection();
    77   NS_ASSERTION(frameSel, "No frame selection for focused element!");
    78   if (!frameSel)
    79     return;
    81   // Register 'this' as selection listener for the normal selection.
    82   Selection* normalSel =
    83     frameSel->GetSelection(nsISelectionController::SELECTION_NORMAL);
    84   normalSel->AddSelectionListener(this);
    86   // Register 'this' as selection listener for the spell check selection.
    87   Selection* spellSel =
    88     frameSel->GetSelection(nsISelectionController::SELECTION_SPELLCHECK);
    89   spellSel->AddSelectionListener(this);
    90 }
    92 void
    93 SelectionManager::AddDocSelectionListener(nsIPresShell* aPresShell)
    94 {
    95   const nsFrameSelection* frameSel = aPresShell->ConstFrameSelection();
    97   // Register 'this' as selection listener for the normal selection.
    98   Selection* normalSel =
    99     frameSel->GetSelection(nsISelectionController::SELECTION_NORMAL);
   100   normalSel->AddSelectionListener(this);
   102   // Register 'this' as selection listener for the spell check selection.
   103   Selection* spellSel =
   104     frameSel->GetSelection(nsISelectionController::SELECTION_SPELLCHECK);
   105   spellSel->AddSelectionListener(this);
   106 }
   108 void
   109 SelectionManager::RemoveDocSelectionListener(nsIPresShell* aPresShell)
   110 {
   111   const nsFrameSelection* frameSel = aPresShell->ConstFrameSelection();
   113   // Remove 'this' registered as selection listener for the normal selection.
   114   Selection* normalSel =
   115     frameSel->GetSelection(nsISelectionController::SELECTION_NORMAL);
   116   normalSel->RemoveSelectionListener(this);
   118   // Remove 'this' registered as selection listener for the spellcheck
   119   // selection.
   120   Selection* spellSel =
   121     frameSel->GetSelection(nsISelectionController::SELECTION_SPELLCHECK);
   122   spellSel->RemoveSelectionListener(this);
   123 }
   125 void
   126 SelectionManager::ProcessTextSelChangeEvent(AccEvent* aEvent)
   127 {
   128   // Fire selection change event if it's not pure caret-move selection change,
   129   // i.e. the accessible has or had not collapsed selection.
   130   AccTextSelChangeEvent* event = downcast_accEvent(aEvent);
   131   if (!event->IsCaretMoveOnly())
   132     nsEventShell::FireEvent(aEvent);
   134   // Fire caret move event if there's a caret in the selection.
   135   nsINode* caretCntrNode =
   136     nsCoreUtils::GetDOMNodeFromDOMPoint(event->mSel->GetFocusNode(),
   137                                         event->mSel->FocusOffset());
   138   if (!caretCntrNode)
   139     return;
   141   HyperTextAccessible* caretCntr = nsAccUtils::GetTextContainer(caretCntrNode);
   142   NS_ASSERTION(caretCntr,
   143                "No text container for focus while there's one for common ancestor?!");
   144   if (!caretCntr)
   145     return;
   147   int32_t caretOffset = caretCntr->CaretOffset();
   148   if (caretOffset != -1) {
   149     nsRefPtr<AccCaretMoveEvent> caretMoveEvent =
   150       new AccCaretMoveEvent(caretCntr, caretOffset, aEvent->FromUserInput());
   151     nsEventShell::FireEvent(caretMoveEvent);
   152   }
   153 }
   155 NS_IMETHODIMP
   156 SelectionManager::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
   157                                          nsISelection* aSelection,
   158                                          int16_t aReason)
   159 {
   160   NS_ENSURE_ARG(aDOMDocument);
   162   nsCOMPtr<nsIDocument> documentNode(do_QueryInterface(aDOMDocument));
   163   DocAccessible* document = GetAccService()->GetDocAccessible(documentNode);
   165 #ifdef A11Y_LOG
   166   if (logging::IsEnabled(logging::eSelection))
   167     logging::SelChange(aSelection, document, aReason);
   168 #endif
   170   // Don't fire events until document is loaded.
   171   if (document && document->IsContentLoaded()) {
   172     // Selection manager has longer lifetime than any document accessible,
   173     // so that we are guaranteed that the notification is processed before
   174     // the selection manager is destroyed.
   175     nsRefPtr<SelData> selData =
   176       new SelData(static_cast<Selection*>(aSelection), aReason);
   177     document->HandleNotification<SelectionManager, SelData>
   178       (this, &SelectionManager::ProcessSelectionChanged, selData);
   179   }
   181   return NS_OK;
   182 }
   184 void
   185 SelectionManager::ProcessSelectionChanged(SelData* aSelData)
   186 {
   187   Selection* selection = aSelData->mSel;
   188   if (!selection->GetPresShell())
   189     return;
   191   const nsRange* range = selection->GetAnchorFocusRange();
   192   nsINode* cntrNode = nullptr;
   193   if (range)
   194     cntrNode = range->GetCommonAncestor();
   196   if (!cntrNode) {
   197     cntrNode = selection->GetFrameSelection()->GetAncestorLimiter();
   198     if (!cntrNode) {
   199       cntrNode = selection->GetPresShell()->GetDocument();
   200       NS_ASSERTION(aSelData->mSel->GetPresShell()->ConstFrameSelection() == selection->GetFrameSelection(),
   201                    "Wrong selection container was used!");
   202     }
   203   }
   205   HyperTextAccessible* text = nsAccUtils::GetTextContainer(cntrNode);
   206   if (!text) {
   207     NS_NOTREACHED("We must reach document accessible implementing text interface!");
   208     return;
   209   }
   211   if (selection->GetType() == nsISelectionController::SELECTION_NORMAL) {
   212     nsRefPtr<AccEvent> event =
   213       new AccTextSelChangeEvent(text, selection, aSelData->mReason);
   214     text->Document()->FireDelayedEvent(event);
   216   } else if (selection->GetType() == nsISelectionController::SELECTION_SPELLCHECK) {
   217     // XXX: fire an event for container accessible of the focus/anchor range
   218     // of the spelcheck selection.
   219     text->Document()->FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED,
   220                                        text);
   221   }
   222 }

mercurial