Tue, 06 Jan 2015 21:39:09 +0100
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 }