extensions/spellcheck/src/mozInlineSpellChecker.h

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:20fe9cdc177b
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/. */
5
6 #ifndef __mozinlinespellchecker_h__
7 #define __mozinlinespellchecker_h__
8
9 #include "nsAutoPtr.h"
10 #include "nsRange.h"
11 #include "nsIEditorSpellCheck.h"
12 #include "nsIEditActionListener.h"
13 #include "nsIInlineSpellChecker.h"
14 #include "nsIDOMTreeWalker.h"
15 #include "nsWeakReference.h"
16 #include "nsEditor.h"
17 #include "nsIDOMEventListener.h"
18 #include "nsWeakReference.h"
19 #include "mozISpellI18NUtil.h"
20 #include "nsCycleCollectionParticipant.h"
21
22 // X.h defines KeyPress
23 #ifdef KeyPress
24 #undef KeyPress
25 #endif
26
27 class nsIDOMMouseEventListener;
28 class mozInlineSpellWordUtil;
29 class mozInlineSpellChecker;
30 class mozInlineSpellResume;
31 class InitEditorSpellCheckCallback;
32 class UpdateCurrentDictionaryCallback;
33 class mozInlineSpellResume;
34
35 class mozInlineSpellStatus
36 {
37 public:
38 mozInlineSpellStatus(mozInlineSpellChecker* aSpellChecker);
39
40 nsresult InitForEditorChange(EditAction aAction,
41 nsIDOMNode* aAnchorNode, int32_t aAnchorOffset,
42 nsIDOMNode* aPreviousNode, int32_t aPreviousOffset,
43 nsIDOMNode* aStartNode, int32_t aStartOffset,
44 nsIDOMNode* aEndNode, int32_t aEndOffset);
45 nsresult InitForNavigation(bool aForceCheck, int32_t aNewPositionOffset,
46 nsIDOMNode* aOldAnchorNode, int32_t aOldAnchorOffset,
47 nsIDOMNode* aNewAnchorNode, int32_t aNewAnchorOffset,
48 bool* aContinue);
49 nsresult InitForSelection();
50 nsresult InitForRange(nsRange* aRange);
51
52 nsresult FinishInitOnEvent(mozInlineSpellWordUtil& aWordUtil);
53
54 // Return true if we plan to spell-check everything
55 bool IsFullSpellCheck() const {
56 return mOp == eOpChange && !mRange;
57 }
58
59 nsRefPtr<mozInlineSpellChecker> mSpellChecker;
60
61 // The total number of words checked in this sequence, using this tally tells
62 // us when to stop. This count is preserved as we continue checking in new
63 // messages.
64 int32_t mWordCount;
65
66 // what happened?
67 enum Operation { eOpChange, // for SpellCheckAfterChange except deleteSelection
68 eOpChangeDelete, // for SpellCheckAfterChange deleteSelection
69 eOpNavigation, // for HandleNavigationEvent
70 eOpSelection, // re-check all misspelled words
71 eOpResume }; // for resuming a previously started check
72 Operation mOp;
73
74 // Used for events where we have already computed the range to use. It can
75 // also be nullptr in these cases where we need to check the entire range.
76 nsRefPtr<nsRange> mRange;
77
78 // If we happen to know something was inserted, this is that range.
79 // Can be nullptr (this only allows an optimization, so not setting doesn't hurt)
80 nsCOMPtr<nsIDOMRange> mCreatedRange;
81
82 // Contains the range computed for the current word. Can be nullptr.
83 nsRefPtr<nsRange> mNoCheckRange;
84
85 // Indicates the position of the cursor for the event (so we can compute
86 // mNoCheckRange). It can be nullptr if we don't care about the cursor position
87 // (such as for the intial check of everything).
88 //
89 // For mOp == eOpNavigation, this is the NEW position of the cursor
90 nsCOMPtr<nsIDOMRange> mAnchorRange;
91
92 // -----
93 // The following members are only for navigation events and are only
94 // stored for FinishNavigationEvent to initialize the other members.
95 // -----
96
97 // this is the OLD position of the cursor
98 nsCOMPtr<nsIDOMRange> mOldNavigationAnchorRange;
99
100 // Set when we should force checking the current word. See
101 // mozInlineSpellChecker::HandleNavigationEvent for a description of why we
102 // have this.
103 bool mForceNavigationWordCheck;
104
105 // Contains the offset passed in to HandleNavigationEvent
106 int32_t mNewNavigationPositionOffset;
107
108 protected:
109 nsresult FinishNavigationEvent(mozInlineSpellWordUtil& aWordUtil);
110
111 nsresult FillNoCheckRangeFromAnchor(mozInlineSpellWordUtil& aWordUtil);
112
113 nsresult GetDocument(nsIDOMDocument** aDocument);
114 nsresult PositionToCollapsedRange(nsIDOMDocument* aDocument,
115 nsIDOMNode* aNode, int32_t aOffset,
116 nsIDOMRange** aRange);
117 };
118
119 class mozInlineSpellChecker : public nsIInlineSpellChecker,
120 public nsIEditActionListener,
121 public nsIDOMEventListener,
122 public nsSupportsWeakReference
123 {
124 private:
125 friend class mozInlineSpellStatus;
126 friend class InitEditorSpellCheckCallback;
127 friend class UpdateCurrentDictionaryCallback;
128 friend class AutoChangeNumPendingSpellChecks;
129 friend class mozInlineSpellResume;
130
131 // Access with CanEnableInlineSpellChecking
132 enum SpellCheckingState { SpellCheck_Uninitialized = -1,
133 SpellCheck_NotAvailable = 0,
134 SpellCheck_Available = 1};
135 static SpellCheckingState gCanEnableSpellChecking;
136
137 nsWeakPtr mEditor;
138 nsCOMPtr<nsIEditorSpellCheck> mSpellCheck;
139 nsCOMPtr<nsIEditorSpellCheck> mPendingSpellCheck;
140 nsCOMPtr<nsIDOMTreeWalker> mTreeWalker;
141 nsCOMPtr<mozISpellI18NUtil> mConverter;
142
143 int32_t mNumWordsInSpellSelection;
144 int32_t mMaxNumWordsInSpellSelection;
145
146 // How many misspellings we can add at once. This is often less than the max
147 // total number of misspellings. When you have a large textarea prepopulated
148 // with text with many misspellings, we can hit this limit. By making it
149 // lower than the total number of misspelled words, new text typed by the
150 // user can also have spellchecking in it.
151 int32_t mMaxMisspellingsPerCheck;
152
153 // we need to keep track of the current text position in the document
154 // so we can spell check the old word when the user clicks around the document.
155 nsCOMPtr<nsIDOMNode> mCurrentSelectionAnchorNode;
156 int32_t mCurrentSelectionOffset;
157
158 // Tracks the number of pending spell checks *and* async operations that may
159 // lead to spell checks, like updating the current dictionary. This is
160 // necessary so that observers can know when to wait for spell check to
161 // complete.
162 int32_t mNumPendingSpellChecks;
163
164 // The number of calls to UpdateCurrentDictionary that haven't finished yet.
165 int32_t mNumPendingUpdateCurrentDictionary;
166
167 // This number is incremented each time the spell checker is disabled so that
168 // pending scheduled spell checks and UpdateCurrentDictionary calls can be
169 // ignored when they finish.
170 uint32_t mDisabledAsyncToken;
171
172 // When mPendingSpellCheck is non-null, this is the callback passed when
173 // it was initialized.
174 nsRefPtr<InitEditorSpellCheckCallback> mPendingInitEditorSpellCheckCallback;
175
176 // Set when we have spellchecked after the last edit operation. See the
177 // commment at the top of the .cpp file for more info.
178 bool mNeedsCheckAfterNavigation;
179
180 // Set when we have a pending mozInlineSpellResume which will check
181 // the whole document.
182 bool mFullSpellCheckScheduled;
183
184 // Maintains state during the asynchronous UpdateCurrentDictionary call.
185 nsString mPreviousDictionary;
186
187 public:
188
189 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
190 NS_DECL_NSIEDITACTIONLISTENER
191 NS_DECL_NSIINLINESPELLCHECKER
192 NS_DECL_NSIDOMEVENTLISTENER
193 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozInlineSpellChecker, nsIDOMEventListener)
194
195 // returns true if there are any spell checking dictionaries available
196 static bool CanEnableInlineSpellChecking();
197 // update the cached value whenever the list of available dictionaries changes
198 static void UpdateCanEnableInlineSpellChecking();
199
200 nsresult Blur(nsIDOMEvent* aEvent);
201 nsresult MouseClick(nsIDOMEvent* aMouseEvent);
202 nsresult KeyPress(nsIDOMEvent* aKeyEvent);
203
204 mozInlineSpellChecker();
205 virtual ~mozInlineSpellChecker();
206
207 // spell checks all of the words between two nodes
208 nsresult SpellCheckBetweenNodes(nsIDOMNode *aStartNode,
209 int32_t aStartOffset,
210 nsIDOMNode *aEndNode,
211 int32_t aEndOffset);
212
213 // examines the dom node in question and returns true if the inline spell
214 // checker should skip the node (i.e. the text is inside of a block quote
215 // or an e-mail signature...)
216 nsresult SkipSpellCheckForNode(nsIEditor* aEditor,
217 nsIDOMNode *aNode, bool * aCheckSpelling);
218
219 nsresult SpellCheckAfterChange(nsIDOMNode* aCursorNode, int32_t aCursorOffset,
220 nsIDOMNode* aPreviousNode, int32_t aPreviousOffset,
221 nsISelection* aSpellCheckSelection);
222
223 // spell check the text contained within aRange, potentially scheduling
224 // another check in the future if the time threshold is reached
225 nsresult ScheduleSpellCheck(const mozInlineSpellStatus& aStatus);
226
227 nsresult DoSpellCheckSelection(mozInlineSpellWordUtil& aWordUtil,
228 nsISelection* aSpellCheckSelection,
229 mozInlineSpellStatus* aStatus);
230 nsresult DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
231 nsISelection *aSpellCheckSelection,
232 mozInlineSpellStatus* aStatus,
233 bool* aDoneChecking);
234
235 // helper routine to determine if a point is inside of the passed in selection.
236 nsresult IsPointInSelection(nsISelection *aSelection,
237 nsIDOMNode *aNode,
238 int32_t aOffset,
239 nsIDOMRange **aRange);
240
241 nsresult CleanupRangesInSelection(nsISelection *aSelection);
242
243 nsresult RemoveRange(nsISelection *aSpellCheckSelection, nsIDOMRange * aRange);
244 nsresult AddRange(nsISelection *aSpellCheckSelection, nsIDOMRange * aRange);
245 bool SpellCheckSelectionIsFull() { return mNumWordsInSpellSelection >= mMaxNumWordsInSpellSelection; }
246
247 nsresult MakeSpellCheckRange(nsIDOMNode* aStartNode, int32_t aStartOffset,
248 nsIDOMNode* aEndNode, int32_t aEndOffset,
249 nsRange** aRange);
250
251 // DOM and editor event registration helper routines
252 nsresult RegisterEventListeners();
253 nsresult UnregisterEventListeners();
254 nsresult HandleNavigationEvent(bool aForceWordSpellCheck, int32_t aNewPositionOffset = 0);
255
256 nsresult GetSpellCheckSelection(nsISelection ** aSpellCheckSelection);
257 nsresult SaveCurrentSelectionPosition();
258
259 nsresult ResumeCheck(mozInlineSpellStatus* aStatus);
260
261 protected:
262
263 // called when async nsIEditorSpellCheck methods complete
264 nsresult EditorSpellCheckInited();
265 nsresult CurrentDictionaryUpdated();
266
267 // track the number of pending spell checks and async operations that may lead
268 // to spell checks, notifying observers accordingly
269 void ChangeNumPendingSpellChecks(int32_t aDelta,
270 nsIEditor* aEditor = nullptr);
271 void NotifyObservers(const char* aTopic, nsIEditor* aEditor);
272 };
273
274 #endif /* __mozinlinespellchecker_h__ */

mercurial