Bug 1700051: part 1) Reduce accessibility of some members of `mozInlineSpellStatus...
[gecko.git] / extensions / spellcheck / src / mozInlineSpellChecker.h
blob93355a7510d5c4469352bc1db690fc6f8d1a733d
1 /* -*- Mode: C++; tab-width: 2; 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 #ifndef mozilla_mozInlineSpellChecker_h
7 #define mozilla_mozInlineSpellChecker_h
9 #include "nsCycleCollectionParticipant.h"
10 #include "nsIDOMEventListener.h"
11 #include "nsIEditorSpellCheck.h"
12 #include "nsIInlineSpellChecker.h"
13 #include "mozInlineSpellWordUtil.h"
14 #include "nsRange.h"
15 #include "nsWeakReference.h"
17 class InitEditorSpellCheckCallback;
18 class mozInlineSpellChecker;
19 class mozInlineSpellResume;
20 class UpdateCurrentDictionaryCallback;
22 namespace mozilla {
23 class EditorSpellCheck;
24 class TextEditor;
25 enum class EditSubAction : int32_t;
27 namespace dom {
28 class Event;
29 } // namespace dom
30 } // namespace mozilla
32 class mozInlineSpellStatus {
33 public:
34 explicit mozInlineSpellStatus(mozInlineSpellChecker* aSpellChecker);
36 nsresult InitForEditorChange(mozilla::EditSubAction aEditSubAction,
37 nsINode* aAnchorNode, uint32_t aAnchorOffset,
38 nsINode* aPreviousNode, uint32_t aPreviousOffset,
39 nsINode* aStartNode, uint32_t aStartOffset,
40 nsINode* aEndNode, uint32_t aEndOffset);
41 nsresult InitForNavigation(bool aForceCheck, int32_t aNewPositionOffset,
42 nsINode* aOldAnchorNode, uint32_t aOldAnchorOffset,
43 nsINode* aNewAnchorNode, uint32_t aNewAnchorOffset,
44 bool* aContinue);
45 nsresult InitForSelection();
46 nsresult InitForRange(nsRange* aRange);
48 nsresult FinishInitOnEvent(mozInlineSpellWordUtil& aWordUtil);
50 // Return true if we plan to spell-check everything
51 bool IsFullSpellCheck() const { return mOp == eOpChange && !mRange; }
53 RefPtr<mozInlineSpellChecker> mSpellChecker;
55 // what happened?
56 enum Operation {
57 eOpChange, // for SpellCheckAfterEditorChange except
58 // deleteSelection
59 eOpChangeDelete, // for SpellCheckAfterEditorChange with
60 // deleteSelection
61 eOpNavigation, // for HandleNavigationEvent
62 eOpSelection, // re-check all misspelled words
63 eOpResume
64 }; // for resuming a previously started check
65 Operation mOp;
67 // Used for events where we have already computed the range to use. It can
68 // also be nullptr in these cases where we need to check the entire range.
69 RefPtr<nsRange> mRange;
71 // If we happen to know something was inserted, this is that range.
72 // Can be nullptr (this only allows an optimization, so not setting doesn't
73 // hurt)
74 RefPtr<nsRange> mCreatedRange;
76 // Contains the range computed for the current word. Can be nullptr.
77 RefPtr<nsRange> mNoCheckRange;
79 private:
80 // Indicates the position of the cursor for the event (so we can compute
81 // mNoCheckRange). It can be nullptr if we don't care about the cursor
82 // position (such as for the intial check of everything).
84 // For mOp == eOpNavigation, this is the NEW position of the cursor
85 RefPtr<nsRange> mAnchorRange;
87 // -----
88 // The following members are only for navigation events and are only
89 // stored for FinishNavigationEvent to initialize the other members.
90 // -----
92 // this is the OLD position of the cursor
93 RefPtr<nsRange> mOldNavigationAnchorRange;
95 // Set when we should force checking the current word. See
96 // mozInlineSpellChecker::HandleNavigationEvent for a description of why we
97 // have this.
98 bool mForceNavigationWordCheck;
100 // Contains the offset passed in to HandleNavigationEvent
101 int32_t mNewNavigationPositionOffset;
103 nsresult FinishNavigationEvent(mozInlineSpellWordUtil& aWordUtil);
105 nsresult FillNoCheckRangeFromAnchor(mozInlineSpellWordUtil& aWordUtil);
107 mozilla::dom::Document* GetDocument() const;
108 already_AddRefed<nsRange> PositionToCollapsedRange(nsINode* aNode,
109 uint32_t aOffset);
112 class mozInlineSpellChecker final : public nsIInlineSpellChecker,
113 public nsIDOMEventListener,
114 public nsSupportsWeakReference {
115 private:
116 friend class mozInlineSpellStatus;
117 friend class InitEditorSpellCheckCallback;
118 friend class UpdateCurrentDictionaryCallback;
119 friend class AutoChangeNumPendingSpellChecks;
120 friend class mozInlineSpellResume;
122 // Access with CanEnableInlineSpellChecking
123 enum SpellCheckingState {
124 SpellCheck_Uninitialized = -1,
125 SpellCheck_NotAvailable = 0,
126 SpellCheck_Available = 1
128 static SpellCheckingState gCanEnableSpellChecking;
130 RefPtr<mozilla::TextEditor> mTextEditor;
131 RefPtr<mozilla::EditorSpellCheck> mSpellCheck;
132 RefPtr<mozilla::EditorSpellCheck> mPendingSpellCheck;
134 int32_t mNumWordsInSpellSelection;
135 int32_t mMaxNumWordsInSpellSelection;
137 // we need to keep track of the current text position in the document
138 // so we can spell check the old word when the user clicks around the
139 // document.
140 nsCOMPtr<nsINode> mCurrentSelectionAnchorNode;
141 uint32_t mCurrentSelectionOffset;
143 // Tracks the number of pending spell checks *and* async operations that may
144 // lead to spell checks, like updating the current dictionary. This is
145 // necessary so that observers can know when to wait for spell check to
146 // complete.
147 int32_t mNumPendingSpellChecks;
149 // The number of calls to UpdateCurrentDictionary that haven't finished yet.
150 int32_t mNumPendingUpdateCurrentDictionary;
152 // This number is incremented each time the spell checker is disabled so that
153 // pending scheduled spell checks and UpdateCurrentDictionary calls can be
154 // ignored when they finish.
155 uint32_t mDisabledAsyncToken;
157 // When mPendingSpellCheck is non-null, this is the callback passed when
158 // it was initialized.
159 RefPtr<InitEditorSpellCheckCallback> mPendingInitEditorSpellCheckCallback;
161 // Set when we have spellchecked after the last edit operation. See the
162 // commment at the top of the .cpp file for more info.
163 bool mNeedsCheckAfterNavigation;
165 // Set when we have a pending mozInlineSpellResume which will check
166 // the whole document.
167 bool mFullSpellCheckScheduled;
169 // Set to true when this instance needs to listen to edit actions of
170 // the editor.
171 bool mIsListeningToEditSubActions;
173 public:
174 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
175 NS_DECL_NSIINLINESPELLCHECKER
176 NS_DECL_NSIDOMEVENTLISTENER
177 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozInlineSpellChecker,
178 nsIDOMEventListener)
180 mozilla::EditorSpellCheck* GetEditorSpellCheck();
182 // returns true if there are any spell checking dictionaries available
183 static bool CanEnableInlineSpellChecking();
184 // update the cached value whenever the list of available dictionaries changes
185 static void UpdateCanEnableInlineSpellChecking();
187 nsresult OnBlur(mozilla::dom::Event* aEvent);
188 nsresult OnMouseClick(mozilla::dom::Event* aMouseEvent);
189 nsresult OnKeyPress(mozilla::dom::Event* aKeyEvent);
191 mozInlineSpellChecker();
193 // spell checks all of the words between two nodes
194 nsresult SpellCheckBetweenNodes(nsINode* aStartNode, int32_t aStartOffset,
195 nsINode* aEndNode, int32_t aEndOffset);
197 // examines the dom node in question and returns true if the inline spell
198 // checker should skip the node (i.e. the text is inside of a block quote
199 // or an e-mail signature...)
200 bool ShouldSpellCheckNode(mozilla::TextEditor* aTextEditor, nsINode* aNode);
202 // spell check the text contained within aRange, potentially scheduling
203 // another check in the future if the time threshold is reached
204 nsresult ScheduleSpellCheck(
205 mozilla::UniquePtr<mozInlineSpellStatus>&& aStatus);
207 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
208 DoSpellCheckSelection(mozInlineSpellWordUtil& aWordUtil,
209 mozilla::dom::Selection* aSpellCheckSelection);
210 nsresult DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
211 mozilla::dom::Selection* aSpellCheckSelection,
212 const mozilla::UniquePtr<mozInlineSpellStatus>& aStatus,
213 bool* aDoneChecking);
215 // helper routine to determine if a point is inside of the passed in
216 // selection.
217 nsresult IsPointInSelection(mozilla::dom::Selection& aSelection,
218 nsINode* aNode, int32_t aOffset,
219 nsRange** aRange);
221 nsresult CleanupRangesInSelection(mozilla::dom::Selection* aSelection);
224 * @param aRange needs to be kept alive by the caller.
226 // TODO: annotate with `MOZ_CAN_RUN_SCRIPT` instead
227 // (https://bugzilla.mozilla.org/show_bug.cgi?id=1620540).
228 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
229 RemoveRange(mozilla::dom::Selection* aSpellCheckSelection, nsRange* aRange);
230 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
231 AddRange(mozilla::dom::Selection* aSpellCheckSelection, nsRange* aRange);
232 bool SpellCheckSelectionIsFull() {
233 return mNumWordsInSpellSelection >= mMaxNumWordsInSpellSelection;
236 nsresult MakeSpellCheckRange(nsINode* aStartNode, int32_t aStartOffset,
237 nsINode* aEndNode, int32_t aEndOffset,
238 nsRange** aRange);
240 // DOM and editor event registration helper routines
241 nsresult RegisterEventListeners();
242 nsresult UnregisterEventListeners();
243 nsresult HandleNavigationEvent(bool aForceWordSpellCheck,
244 int32_t aNewPositionOffset = 0);
246 already_AddRefed<mozilla::dom::Selection> GetSpellCheckSelection();
247 nsresult SaveCurrentSelectionPosition();
249 nsresult ResumeCheck(mozilla::UniquePtr<mozInlineSpellStatus>&& aStatus);
251 // Those methods are called when mTextEditor splits a node or joins the
252 // given nodes.
253 void DidSplitNode(nsINode* aExistingRightNode, nsINode* aNewLeftNode);
254 void DidJoinNodes(nsINode& aRightNode, nsINode& aLeftNode);
256 nsresult SpellCheckAfterEditorChange(mozilla::EditSubAction aEditSubAction,
257 mozilla::dom::Selection& aSelection,
258 nsINode* aPreviousSelectedNode,
259 uint32_t aPreviousSelectedOffset,
260 nsINode* aStartNode,
261 uint32_t aStartOffset, nsINode* aEndNode,
262 uint32_t aEndOffset);
264 protected:
265 virtual ~mozInlineSpellChecker();
267 // called when async nsIEditorSpellCheck methods complete
268 nsresult EditorSpellCheckInited();
269 nsresult CurrentDictionaryUpdated();
271 // track the number of pending spell checks and async operations that may lead
272 // to spell checks, notifying observers accordingly
273 void ChangeNumPendingSpellChecks(int32_t aDelta,
274 mozilla::TextEditor* aTextEditor = nullptr);
275 void NotifyObservers(const char* aTopic, mozilla::TextEditor* aTextEditor);
277 void StartToListenToEditSubActions() { mIsListeningToEditSubActions = true; }
278 void EndListeningToEditSubActions() { mIsListeningToEditSubActions = false; }
280 void CheckCurrentWordsNoSuggest(mozilla::dom::Selection* aSpellCheckSelection,
281 nsTArray<nsString>&& aWords,
282 nsTArray<NodeOffsetRange>&& aRanges);
285 #endif // #ifndef mozilla_mozInlineSpellChecker_h