1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/extensions/spellcheck/src/mozInlineSpellChecker.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,274 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef __mozinlinespellchecker_h__ 1.10 +#define __mozinlinespellchecker_h__ 1.11 + 1.12 +#include "nsAutoPtr.h" 1.13 +#include "nsRange.h" 1.14 +#include "nsIEditorSpellCheck.h" 1.15 +#include "nsIEditActionListener.h" 1.16 +#include "nsIInlineSpellChecker.h" 1.17 +#include "nsIDOMTreeWalker.h" 1.18 +#include "nsWeakReference.h" 1.19 +#include "nsEditor.h" 1.20 +#include "nsIDOMEventListener.h" 1.21 +#include "nsWeakReference.h" 1.22 +#include "mozISpellI18NUtil.h" 1.23 +#include "nsCycleCollectionParticipant.h" 1.24 + 1.25 +// X.h defines KeyPress 1.26 +#ifdef KeyPress 1.27 +#undef KeyPress 1.28 +#endif 1.29 + 1.30 +class nsIDOMMouseEventListener; 1.31 +class mozInlineSpellWordUtil; 1.32 +class mozInlineSpellChecker; 1.33 +class mozInlineSpellResume; 1.34 +class InitEditorSpellCheckCallback; 1.35 +class UpdateCurrentDictionaryCallback; 1.36 +class mozInlineSpellResume; 1.37 + 1.38 +class mozInlineSpellStatus 1.39 +{ 1.40 +public: 1.41 + mozInlineSpellStatus(mozInlineSpellChecker* aSpellChecker); 1.42 + 1.43 + nsresult InitForEditorChange(EditAction aAction, 1.44 + nsIDOMNode* aAnchorNode, int32_t aAnchorOffset, 1.45 + nsIDOMNode* aPreviousNode, int32_t aPreviousOffset, 1.46 + nsIDOMNode* aStartNode, int32_t aStartOffset, 1.47 + nsIDOMNode* aEndNode, int32_t aEndOffset); 1.48 + nsresult InitForNavigation(bool aForceCheck, int32_t aNewPositionOffset, 1.49 + nsIDOMNode* aOldAnchorNode, int32_t aOldAnchorOffset, 1.50 + nsIDOMNode* aNewAnchorNode, int32_t aNewAnchorOffset, 1.51 + bool* aContinue); 1.52 + nsresult InitForSelection(); 1.53 + nsresult InitForRange(nsRange* aRange); 1.54 + 1.55 + nsresult FinishInitOnEvent(mozInlineSpellWordUtil& aWordUtil); 1.56 + 1.57 + // Return true if we plan to spell-check everything 1.58 + bool IsFullSpellCheck() const { 1.59 + return mOp == eOpChange && !mRange; 1.60 + } 1.61 + 1.62 + nsRefPtr<mozInlineSpellChecker> mSpellChecker; 1.63 + 1.64 + // The total number of words checked in this sequence, using this tally tells 1.65 + // us when to stop. This count is preserved as we continue checking in new 1.66 + // messages. 1.67 + int32_t mWordCount; 1.68 + 1.69 + // what happened? 1.70 + enum Operation { eOpChange, // for SpellCheckAfterChange except deleteSelection 1.71 + eOpChangeDelete, // for SpellCheckAfterChange deleteSelection 1.72 + eOpNavigation, // for HandleNavigationEvent 1.73 + eOpSelection, // re-check all misspelled words 1.74 + eOpResume }; // for resuming a previously started check 1.75 + Operation mOp; 1.76 + 1.77 + // Used for events where we have already computed the range to use. It can 1.78 + // also be nullptr in these cases where we need to check the entire range. 1.79 + nsRefPtr<nsRange> mRange; 1.80 + 1.81 + // If we happen to know something was inserted, this is that range. 1.82 + // Can be nullptr (this only allows an optimization, so not setting doesn't hurt) 1.83 + nsCOMPtr<nsIDOMRange> mCreatedRange; 1.84 + 1.85 + // Contains the range computed for the current word. Can be nullptr. 1.86 + nsRefPtr<nsRange> mNoCheckRange; 1.87 + 1.88 + // Indicates the position of the cursor for the event (so we can compute 1.89 + // mNoCheckRange). It can be nullptr if we don't care about the cursor position 1.90 + // (such as for the intial check of everything). 1.91 + // 1.92 + // For mOp == eOpNavigation, this is the NEW position of the cursor 1.93 + nsCOMPtr<nsIDOMRange> mAnchorRange; 1.94 + 1.95 + // ----- 1.96 + // The following members are only for navigation events and are only 1.97 + // stored for FinishNavigationEvent to initialize the other members. 1.98 + // ----- 1.99 + 1.100 + // this is the OLD position of the cursor 1.101 + nsCOMPtr<nsIDOMRange> mOldNavigationAnchorRange; 1.102 + 1.103 + // Set when we should force checking the current word. See 1.104 + // mozInlineSpellChecker::HandleNavigationEvent for a description of why we 1.105 + // have this. 1.106 + bool mForceNavigationWordCheck; 1.107 + 1.108 + // Contains the offset passed in to HandleNavigationEvent 1.109 + int32_t mNewNavigationPositionOffset; 1.110 + 1.111 +protected: 1.112 + nsresult FinishNavigationEvent(mozInlineSpellWordUtil& aWordUtil); 1.113 + 1.114 + nsresult FillNoCheckRangeFromAnchor(mozInlineSpellWordUtil& aWordUtil); 1.115 + 1.116 + nsresult GetDocument(nsIDOMDocument** aDocument); 1.117 + nsresult PositionToCollapsedRange(nsIDOMDocument* aDocument, 1.118 + nsIDOMNode* aNode, int32_t aOffset, 1.119 + nsIDOMRange** aRange); 1.120 +}; 1.121 + 1.122 +class mozInlineSpellChecker : public nsIInlineSpellChecker, 1.123 + public nsIEditActionListener, 1.124 + public nsIDOMEventListener, 1.125 + public nsSupportsWeakReference 1.126 +{ 1.127 +private: 1.128 + friend class mozInlineSpellStatus; 1.129 + friend class InitEditorSpellCheckCallback; 1.130 + friend class UpdateCurrentDictionaryCallback; 1.131 + friend class AutoChangeNumPendingSpellChecks; 1.132 + friend class mozInlineSpellResume; 1.133 + 1.134 + // Access with CanEnableInlineSpellChecking 1.135 + enum SpellCheckingState { SpellCheck_Uninitialized = -1, 1.136 + SpellCheck_NotAvailable = 0, 1.137 + SpellCheck_Available = 1}; 1.138 + static SpellCheckingState gCanEnableSpellChecking; 1.139 + 1.140 + nsWeakPtr mEditor; 1.141 + nsCOMPtr<nsIEditorSpellCheck> mSpellCheck; 1.142 + nsCOMPtr<nsIEditorSpellCheck> mPendingSpellCheck; 1.143 + nsCOMPtr<nsIDOMTreeWalker> mTreeWalker; 1.144 + nsCOMPtr<mozISpellI18NUtil> mConverter; 1.145 + 1.146 + int32_t mNumWordsInSpellSelection; 1.147 + int32_t mMaxNumWordsInSpellSelection; 1.148 + 1.149 + // How many misspellings we can add at once. This is often less than the max 1.150 + // total number of misspellings. When you have a large textarea prepopulated 1.151 + // with text with many misspellings, we can hit this limit. By making it 1.152 + // lower than the total number of misspelled words, new text typed by the 1.153 + // user can also have spellchecking in it. 1.154 + int32_t mMaxMisspellingsPerCheck; 1.155 + 1.156 + // we need to keep track of the current text position in the document 1.157 + // so we can spell check the old word when the user clicks around the document. 1.158 + nsCOMPtr<nsIDOMNode> mCurrentSelectionAnchorNode; 1.159 + int32_t mCurrentSelectionOffset; 1.160 + 1.161 + // Tracks the number of pending spell checks *and* async operations that may 1.162 + // lead to spell checks, like updating the current dictionary. This is 1.163 + // necessary so that observers can know when to wait for spell check to 1.164 + // complete. 1.165 + int32_t mNumPendingSpellChecks; 1.166 + 1.167 + // The number of calls to UpdateCurrentDictionary that haven't finished yet. 1.168 + int32_t mNumPendingUpdateCurrentDictionary; 1.169 + 1.170 + // This number is incremented each time the spell checker is disabled so that 1.171 + // pending scheduled spell checks and UpdateCurrentDictionary calls can be 1.172 + // ignored when they finish. 1.173 + uint32_t mDisabledAsyncToken; 1.174 + 1.175 + // When mPendingSpellCheck is non-null, this is the callback passed when 1.176 + // it was initialized. 1.177 + nsRefPtr<InitEditorSpellCheckCallback> mPendingInitEditorSpellCheckCallback; 1.178 + 1.179 + // Set when we have spellchecked after the last edit operation. See the 1.180 + // commment at the top of the .cpp file for more info. 1.181 + bool mNeedsCheckAfterNavigation; 1.182 + 1.183 + // Set when we have a pending mozInlineSpellResume which will check 1.184 + // the whole document. 1.185 + bool mFullSpellCheckScheduled; 1.186 + 1.187 + // Maintains state during the asynchronous UpdateCurrentDictionary call. 1.188 + nsString mPreviousDictionary; 1.189 + 1.190 +public: 1.191 + 1.192 + NS_DECL_CYCLE_COLLECTING_ISUPPORTS 1.193 + NS_DECL_NSIEDITACTIONLISTENER 1.194 + NS_DECL_NSIINLINESPELLCHECKER 1.195 + NS_DECL_NSIDOMEVENTLISTENER 1.196 + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozInlineSpellChecker, nsIDOMEventListener) 1.197 + 1.198 + // returns true if there are any spell checking dictionaries available 1.199 + static bool CanEnableInlineSpellChecking(); 1.200 + // update the cached value whenever the list of available dictionaries changes 1.201 + static void UpdateCanEnableInlineSpellChecking(); 1.202 + 1.203 + nsresult Blur(nsIDOMEvent* aEvent); 1.204 + nsresult MouseClick(nsIDOMEvent* aMouseEvent); 1.205 + nsresult KeyPress(nsIDOMEvent* aKeyEvent); 1.206 + 1.207 + mozInlineSpellChecker(); 1.208 + virtual ~mozInlineSpellChecker(); 1.209 + 1.210 + // spell checks all of the words between two nodes 1.211 + nsresult SpellCheckBetweenNodes(nsIDOMNode *aStartNode, 1.212 + int32_t aStartOffset, 1.213 + nsIDOMNode *aEndNode, 1.214 + int32_t aEndOffset); 1.215 + 1.216 + // examines the dom node in question and returns true if the inline spell 1.217 + // checker should skip the node (i.e. the text is inside of a block quote 1.218 + // or an e-mail signature...) 1.219 + nsresult SkipSpellCheckForNode(nsIEditor* aEditor, 1.220 + nsIDOMNode *aNode, bool * aCheckSpelling); 1.221 + 1.222 + nsresult SpellCheckAfterChange(nsIDOMNode* aCursorNode, int32_t aCursorOffset, 1.223 + nsIDOMNode* aPreviousNode, int32_t aPreviousOffset, 1.224 + nsISelection* aSpellCheckSelection); 1.225 + 1.226 + // spell check the text contained within aRange, potentially scheduling 1.227 + // another check in the future if the time threshold is reached 1.228 + nsresult ScheduleSpellCheck(const mozInlineSpellStatus& aStatus); 1.229 + 1.230 + nsresult DoSpellCheckSelection(mozInlineSpellWordUtil& aWordUtil, 1.231 + nsISelection* aSpellCheckSelection, 1.232 + mozInlineSpellStatus* aStatus); 1.233 + nsresult DoSpellCheck(mozInlineSpellWordUtil& aWordUtil, 1.234 + nsISelection *aSpellCheckSelection, 1.235 + mozInlineSpellStatus* aStatus, 1.236 + bool* aDoneChecking); 1.237 + 1.238 + // helper routine to determine if a point is inside of the passed in selection. 1.239 + nsresult IsPointInSelection(nsISelection *aSelection, 1.240 + nsIDOMNode *aNode, 1.241 + int32_t aOffset, 1.242 + nsIDOMRange **aRange); 1.243 + 1.244 + nsresult CleanupRangesInSelection(nsISelection *aSelection); 1.245 + 1.246 + nsresult RemoveRange(nsISelection *aSpellCheckSelection, nsIDOMRange * aRange); 1.247 + nsresult AddRange(nsISelection *aSpellCheckSelection, nsIDOMRange * aRange); 1.248 + bool SpellCheckSelectionIsFull() { return mNumWordsInSpellSelection >= mMaxNumWordsInSpellSelection; } 1.249 + 1.250 + nsresult MakeSpellCheckRange(nsIDOMNode* aStartNode, int32_t aStartOffset, 1.251 + nsIDOMNode* aEndNode, int32_t aEndOffset, 1.252 + nsRange** aRange); 1.253 + 1.254 + // DOM and editor event registration helper routines 1.255 + nsresult RegisterEventListeners(); 1.256 + nsresult UnregisterEventListeners(); 1.257 + nsresult HandleNavigationEvent(bool aForceWordSpellCheck, int32_t aNewPositionOffset = 0); 1.258 + 1.259 + nsresult GetSpellCheckSelection(nsISelection ** aSpellCheckSelection); 1.260 + nsresult SaveCurrentSelectionPosition(); 1.261 + 1.262 + nsresult ResumeCheck(mozInlineSpellStatus* aStatus); 1.263 + 1.264 +protected: 1.265 + 1.266 + // called when async nsIEditorSpellCheck methods complete 1.267 + nsresult EditorSpellCheckInited(); 1.268 + nsresult CurrentDictionaryUpdated(); 1.269 + 1.270 + // track the number of pending spell checks and async operations that may lead 1.271 + // to spell checks, notifying observers accordingly 1.272 + void ChangeNumPendingSpellChecks(int32_t aDelta, 1.273 + nsIEditor* aEditor = nullptr); 1.274 + void NotifyObservers(const char* aTopic, nsIEditor* aEditor); 1.275 +}; 1.276 + 1.277 +#endif /* __mozinlinespellchecker_h__ */