Back to index

lightning-sunbird  0.9+nobinonly
mozInlineSpellWordUtil.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is inline spellchecker code.
00016  *
00017  * The Initial Developer of the Original Code is Google Inc.
00018  * Portions created by the Initial Developer are Copyright (C) 2004-2006
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Brett Wilson <brettw@gmail.com> (original author)
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsCOMPtr.h"
00039 #include "nsIDOMDocument.h"
00040 #include "nsIDOMDocumentRange.h"
00041 #include "nsIDOMViewCSS.h"
00042 #include "nsIDocument.h"
00043 #include "nsString.h"
00044 #include "nsTArray.h"
00045 
00046 //#define DEBUG_SPELLCHECK
00047 
00048 class nsIDOMRange;
00049 class nsIDOMNode;
00050 
00071 class mozInlineSpellWordUtil
00072 {
00073 public:
00074   struct NodeOffset {
00075     nsIDOMNode* mNode;
00076     PRInt32     mOffset;
00077     
00078     NodeOffset(nsIDOMNode* aNode, PRInt32 aOffset) :
00079       mNode(aNode), mOffset(aOffset) {}
00080   };
00081 
00082   mozInlineSpellWordUtil()
00083     : mRootNode(nsnull),
00084       mSoftBegin(nsnull, 0), mSoftEnd(nsnull, 0),
00085       mNextWordIndex(-1), mSoftTextValid(PR_FALSE) {}
00086 
00087   nsresult Init(nsWeakPtr aWeakEditor);
00088 
00089   nsresult SetEnd(nsIDOMNode* aEndNode, PRInt32 aEndOffset);
00090 
00091   // sets the current position, this should be inside the range. If we are in
00092   // the middle of a word, we'll move to its start.
00093   nsresult SetPosition(nsIDOMNode* aNode, PRInt32 aOffset);
00094 
00095   // Given a point inside or immediately following a word, this returns the
00096   // DOM range that exactly encloses that word's characters. The current
00097   // position will be at the end of the word. This will find the previous
00098   // word if the current position is space, so if you care that the point is
00099   // inside the word, you should check the range.
00100   //
00101   // THIS CHANGES THE CURRENT POSITION AND RANGE. It is designed to be called
00102   // before you actually generate the range you are interested in and iterate
00103   // the words in it.
00104   nsresult GetRangeForWord(nsIDOMNode* aWordNode, PRInt32 aWordOffset,
00105                            nsIDOMRange** aRange);
00106 
00107   // Moves to the the next word in the range, and retrieves it's text and range.
00108   // An empty word and a NULL range are returned when we are done checking.
00109   // aSkipChecking will be set if the word is "special" and shouldn't be
00110   // checked (e.g., an email address).
00111   nsresult GetNextWord(nsAString& aText, nsIDOMRange** aRange,
00112                        PRBool* aSkipChecking);
00113 
00114   // Call to normalize some punctuation. This function takes an autostring
00115   // so we can access characters directly.
00116   static void NormalizeWord(nsSubstring& aWord);
00117 
00118   nsIDOMDocumentRange* GetDocumentRange() const { return mDOMDocumentRange; }
00119   nsIDocument* GetDocument() const { return mDocument; }
00120   nsIDOMNode* GetRootNode() { return mRootNode; }
00121 
00122 private:
00123 
00124   // cached stuff for the editor, set by Init
00125   nsCOMPtr<nsIDOMDocumentRange> mDOMDocumentRange;
00126   nsCOMPtr<nsIDocument>         mDocument;
00127   nsCOMPtr<nsIDOMViewCSS>       mCSSView;
00128 
00129   // range to check, see SetRange
00130   nsIDOMNode* mRootNode;
00131   NodeOffset  mSoftBegin;
00132   NodeOffset  mSoftEnd;
00133 
00134   // DOM text covering the soft range, with newlines added at block boundaries
00135   nsString mSoftText;
00136   // A list of where we extracted text from, ordered by mSoftTextOffset. A given
00137   // DOM node appears at most once in this list.
00138   struct DOMTextMapping {
00139     NodeOffset mNodeOffset;
00140     PRInt32    mSoftTextOffset;
00141     PRInt32    mLength;
00142     
00143     DOMTextMapping(NodeOffset aNodeOffset, PRInt32 aSoftTextOffset, PRInt32 aLength)
00144       : mNodeOffset(aNodeOffset), mSoftTextOffset(aSoftTextOffset),
00145         mLength(aLength) {}
00146   };
00147   nsTArray<DOMTextMapping> mSoftTextDOMMapping;
00148   
00149   // A list of the "real words" in mSoftText, ordered by mSoftTextOffset
00150   struct RealWord {
00151     PRInt32      mSoftTextOffset;
00152     PRInt32      mLength;
00153     PRPackedBool mCheckableWord;
00154     
00155     RealWord(PRInt32 aOffset, PRInt32 aLength, PRPackedBool aCheckable)
00156       : mSoftTextOffset(aOffset), mLength(aLength), mCheckableWord(aCheckable) {}
00157     PRInt32 EndOffset() const { return mSoftTextOffset + mLength; }
00158   };
00159   nsTArray<RealWord> mRealWords;
00160   PRInt32            mNextWordIndex;
00161 
00162   PRPackedBool mSoftTextValid;
00163 
00164   void InvalidateWords() { mSoftTextValid = PR_FALSE; }
00165   void EnsureWords();
00166   
00167   PRInt32 MapDOMPositionToSoftTextOffset(NodeOffset aNodeOffset);
00168   // Map an offset into mSoftText to a DOM position. Note that two DOM positions
00169   // can map to the same mSoftText offset, e.g. given nodes A=aaaa and B=bbbb
00170   // forming aaaabbbb, (A,4) and (B,0) give the same string offset. So,
00171   // aHintBefore controls which position we return ... if aHint is eEnd
00172   // then the position indicates the END of a range so we return (A,4). Otherwise
00173   // the position indicates the START of a range so we return (B,0).
00174   enum DOMMapHint { HINT_BEGIN, HINT_END };
00175   NodeOffset MapSoftTextOffsetToDOMPosition(PRInt32 aSoftTextOffset,
00176                                             DOMMapHint aHint);
00177   // Finds the index of the real word containing aSoftTextOffset, or -1 if none
00178   // If it's exactly between two words, then if aHint is HINT_BEGIN, return the
00179   // later word (favouring the assumption that it's the BEGINning of a word),
00180   // otherwise return the earlier word (assuming it's the END of a word).
00181   // If aSearchForward is true, then if we don't find a word at the given
00182   // position, search forward until we do find a word and return that (if found).
00183   PRInt32 FindRealWordContaining(PRInt32 aSoftTextOffset, DOMMapHint aHint,
00184                                  PRBool aSearchForward);
00185     
00186   // build mSoftText and mSoftTextDOMMapping
00187   void BuildSoftText();
00188   // Build mRealWords array
00189   void BuildRealWords();
00190 
00191   void SplitDOMWord(PRInt32 aStart, PRInt32 aEnd);
00192 
00193   // Convenience functions, object must be initialized
00194   nsresult MakeRange(NodeOffset aBegin, NodeOffset aEnd, nsIDOMRange** aRange);
00195   nsresult MakeRangeForWord(const RealWord& aWord, nsIDOMRange** aRange);
00196 };