Back to index

lightning-sunbird  0.9+nobinonly
nsWSRunObject.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; 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 mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or 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 #ifndef __wsrunobject_h__
00039 #define __wsrunobject_h__
00040 
00041 #include "nsCOMPtr.h"
00042 #include "nsIDOMNode.h"
00043 #include "nsCOMArray.h"
00044 #include "nsITextContent.h"
00045 #include "nsIEditor.h"
00046 #include "nsEditorUtils.h"
00047 
00048 class nsIDOMDocument;
00049 class nsIDOMNode;
00050 class nsHTMLEditor;
00051 
00052 // class nsWSRunObject represents the entire whitespace situation
00053 // around a given point.  It collects up a list of nodes that contain
00054 // whitespace and categorizes in up to 3 different WSFragments (detailed
00055 // below).  Each WSFragment is a collection of whitespace that is
00056 // either all insignificant, or that is significant.  A WSFragment could
00057 // consist of insignificant whitespace because it is after a block
00058 // boundary or after a break.  Or it could be insignificant because it
00059 // is before a block.  Or it could be significant because it is
00060 // surrounded by text, or starts and ends with nbsps, etc.
00061 
00062 // Throughout I refer to LeadingWS, NormalWS, TrailingWS.  LeadingWS & TrailingWS
00063 // are runs of ascii ws that are insignificant (do not render) because they
00064 // are adjacent to block boundaries, or after a break.  NormalWS is ws that
00065 // does cause soem rendering.  Note that not all the ws in a NormalWS run need
00066 // render.  For example, two ascii spaces surrounded by text on both sides
00067 // will only render as one space (in non-preformatted stlye html), yet both
00068 // spaces count as NormalWS.  Together, they render as the one visible space.
00069 
00070 class nsWSRunObject
00071 {
00072   public:
00073 
00074     enum BlockBoundary
00075     {
00076       kBeforeBlock,
00077       kBlockStart,
00078       kBlockEnd,
00079       kAfterBlock
00080     };
00081 
00082     // constructor / destructor -----------------------------------------------
00083     nsWSRunObject(nsHTMLEditor *aEd, nsIDOMNode *aNode, PRInt32 aOffset);
00084     ~nsWSRunObject();
00085     
00086     // public methods ---------------------------------------------------------
00087 
00088     // ScrubBlockBoundary removes any non-visible whitespace at the specified
00089     // location relative to a block node.  
00090     static nsresult ScrubBlockBoundary(nsHTMLEditor *aHTMLEd, 
00091                                        nsCOMPtr<nsIDOMNode> *aBlock,
00092                                        BlockBoundary aBoundary,
00093                                        PRInt32 *aOffset = 0);
00094     
00095     // PrepareToJoinBlocks fixes up ws at the end of aLeftParent and the
00096     // beginning of aRightParent in preperation for them to be joined.
00097     // example of fixup: trailingws in aLeftParent needs to be removed.
00098     static nsresult PrepareToJoinBlocks(nsHTMLEditor *aEd, 
00099                                         nsIDOMNode *aLeftParent,
00100                                         nsIDOMNode *aRightParent);
00101 
00102     // PrepareToDeleteRange fixes up ws before {aStartNode,aStartOffset}
00103     // and after {aEndNode,aEndOffset} in preperation for content
00104     // in that range to be deleted.  Note that the nodes and offsets
00105     // are adjusted in response to any dom changes we make while 
00106     // adjusting ws.
00107     // example of fixup: trailingws before {aStartNode,aStartOffset}
00108     //                   needs to be removed.
00109     static nsresult PrepareToDeleteRange(nsHTMLEditor *aHTMLEd, 
00110                                          nsCOMPtr<nsIDOMNode> *aStartNode,
00111                                          PRInt32 *aStartOffset, 
00112                                          nsCOMPtr<nsIDOMNode> *aEndNode,
00113                                          PRInt32 *aEndOffset);
00114 
00115     // PrepareToDeleteNode fixes up ws before and after aNode in preperation 
00116     // for aNode to be deleted.
00117     // example of fixup: trailingws before aNode needs to be removed.
00118     static nsresult PrepareToDeleteNode(nsHTMLEditor *aHTMLEd, 
00119                                         nsIDOMNode *aNode);
00120 
00121     // PrepareToSplitAcrossBlocks fixes up ws before and after 
00122     // {aSplitNode,aSplitOffset} in preperation for a block
00123     // parent to be split.  Note that the aSplitNode and aSplitOffset
00124     // are adjusted in response to any dom changes we make while 
00125     // adjusting ws.
00126     // example of fixup: normalws before {aSplitNode,aSplitOffset} 
00127     //                   needs to end with nbsp.
00128     static nsresult PrepareToSplitAcrossBlocks(nsHTMLEditor *aHTMLEd, 
00129                                                nsCOMPtr<nsIDOMNode> *aSplitNode, 
00130                                                PRInt32 *aSplitOffset);
00131 
00132     // InsertBreak inserts a br node at {aInOutParent,aInOutOffset}
00133     // and makes any needed adjustments to ws around that point.
00134     // example of fixup: normalws after {aInOutParent,aInOutOffset}
00135     //                   needs to begin with nbsp.
00136     nsresult InsertBreak(nsCOMPtr<nsIDOMNode> *aInOutParent, 
00137                          PRInt32 *aInOutOffset, 
00138                          nsCOMPtr<nsIDOMNode> *outBRNode, 
00139                          nsIEditor::EDirection aSelect);
00140 
00141     // InsertText inserts a string at {aInOutParent,aInOutOffset}
00142     // and makes any needed adjustments to ws around that point.
00143     // example of fixup: trailingws before {aInOutParent,aInOutOffset}
00144     //                   needs to be removed.
00145     nsresult InsertText(const nsAString& aStringToInsert, 
00146                         nsCOMPtr<nsIDOMNode> *aInOutNode, 
00147                         PRInt32 *aInOutOffset,
00148                         nsIDOMDocument *aDoc);
00149 
00150     // DeleteWSBackward deletes a single visible piece of ws before
00151     // the ws point (the point to create the wsRunObject, passed to 
00152     // its constructor).  It makes any needed conversion to adjacent
00153     // ws to retain its significance.
00154     nsresult DeleteWSBackward();
00155 
00156     // DeleteWSForward deletes a single visible piece of ws after
00157     // the ws point (the point to create the wsRunObject, passed to 
00158     // its constructor).  It makes any needed conversion to adjacent
00159     // ws to retain its significance.
00160     nsresult DeleteWSForward();
00161 
00162     // PriorVisibleNode returns the first piece of visible thing
00163     // before {aNode,aOffset}.  If there is no visible ws qualifying
00164     // it returns what is before the ws run.  Note that 
00165     // {outVisNode,outVisOffset} is set to just AFTER the visible
00166     // object.
00167     nsresult PriorVisibleNode(nsIDOMNode *aNode, 
00168                               PRInt32 aOffset, 
00169                               nsCOMPtr<nsIDOMNode> *outVisNode, 
00170                               PRInt32 *outVisOffset,
00171                               PRInt16 *outType);
00172 
00173     // NextVisibleNode returns the first piece of visible thing
00174     // after {aNode,aOffset}.  If there is no visible ws qualifying
00175     // it returns what is after the ws run.  Note that 
00176     // {outVisNode,outVisOffset} is set to just BEFORE the visible
00177     // object.
00178     nsresult NextVisibleNode (nsIDOMNode *aNode, 
00179                               PRInt32 aOffset, 
00180                               nsCOMPtr<nsIDOMNode> *outVisNode, 
00181                               PRInt32 *outVisOffset,
00182                               PRInt16 *outType);
00183     
00184     // AdjustWhitespace examines the ws object for nbsp's that can
00185     // be safely converted to regular ascii space and converts them.
00186     nsresult AdjustWhitespace();
00187     
00188     // public enums ---------------------------------------------------------
00189     enum {eNone = 0};
00190     enum {eLeadingWS  = 1};          // leading insignificant ws, ie, after block or br
00191     enum {eTrailingWS = 1 << 1};     // trailing insignificant ws, ie, before block
00192     enum {eNormalWS   = 1 << 2};     // normal significant ws, ie, after text, image, ...
00193     enum {eText       = 1 << 3};     // indicates regular (non-ws) text
00194     enum {eSpecial    = 1 << 4};     // indicates an inline non-container, like image
00195     enum {eBreak      = 1 << 5};     // indicates a br node
00196     enum {eOtherBlock = 1 << 6};     // indicates a block other than one ws run is in
00197     enum {eThisBlock  = 1 << 7};     // indicates the block ws run is in
00198     enum {eBlock      = eOtherBlock | eThisBlock};   // block found
00199     
00200     enum {eBefore = 1};
00201     enum {eAfter  = 1 << 1};
00202     enum {eBoth   = eBefore | eAfter};
00203     
00204   protected:
00205     
00206     // WSFragment struct ---------------------------------------------------------
00207     // WSFragment represents a single run of ws (all leadingws, or all normalws,
00208     // or all trailingws, or all leading+trailingws).  Note that this single run may
00209     // still span multiple nodes.
00210     struct WSFragment
00211     {
00212       nsCOMPtr<nsIDOMNode> mStartNode;  // node where ws run starts
00213       nsCOMPtr<nsIDOMNode> mEndNode;    // node where ws run ends
00214       PRInt16 mStartOffset;             // offset where ws run starts
00215       PRInt16 mEndOffset;               // offset where ws run ends
00216       PRInt16 mType, mLeftType, mRightType;  // type of ws, and what is to left and right of it
00217       WSFragment *mLeft, *mRight;            // other ws runs to left or right.  may be null.
00218 
00219       WSFragment() : mStartNode(0),mEndNode(0),mStartOffset(0),
00220                      mEndOffset(0),mType(0),mLeftType(0),
00221                      mRightType(0),mLeft(0),mRight(0) {}
00222     };
00223     
00224     // WSPoint struct ------------------------------------------------------------
00225     // A WSPoint struct represents a unique location within the ws run.  It is 
00226     // always within a textnode that is one of the nodes stored in the list
00227     // in the wsRunObject.  For convenience, the character at that point is also 
00228     // stored in the struct.
00229     struct WSPoint
00230     {
00231       nsCOMPtr<nsITextContent> mTextNode;
00232       PRInt16 mOffset;
00233       PRUnichar mChar;
00234       
00235       WSPoint() : mTextNode(0),mOffset(0),mChar(0) {}
00236       WSPoint(nsIDOMNode *aNode, PRInt32 aOffset, PRUnichar aChar) : 
00237                      mTextNode(do_QueryInterface(aNode)),mOffset(aOffset),mChar(aChar) {}
00238       WSPoint(nsITextContent *aTextNode, PRInt32 aOffset, PRUnichar aChar) : 
00239                      mTextNode(aTextNode),mOffset(aOffset),mChar(aChar) {}
00240     };    
00241 
00242     enum AreaRestriction
00243     {
00244       eAnywhere, eOutsideUserSelectAll
00245     };    
00246     
00247     // protected methods ---------------------------------------------------------
00248     // tons of utility methods.  
00249     nsresult GetWSNodes();
00250     nsresult GetRuns();
00251     void     ClearRuns();
00252     nsresult MakeSingleWSRun(PRInt16 aType);
00253     nsresult PrependNodeToList(nsIDOMNode *aNode);
00254     nsresult AppendNodeToList(nsIDOMNode *aNode);
00255     nsresult GetPreviousWSNode(nsIDOMNode *aStartNode, 
00256                                nsIDOMNode *aBlockParent, 
00257                                nsCOMPtr<nsIDOMNode> *aPriorNode);
00258     nsresult GetPreviousWSNode(nsIDOMNode *aStartNode,
00259                                PRInt16      aOffset, 
00260                                nsIDOMNode  *aBlockParent, 
00261                                nsCOMPtr<nsIDOMNode> *aPriorNode);
00262     nsresult GetPreviousWSNode(DOMPoint aPoint,
00263                                nsIDOMNode  *aBlockParent, 
00264                                nsCOMPtr<nsIDOMNode> *aPriorNode);
00265     nsresult GetNextWSNode(nsIDOMNode *aStartNode, 
00266                            nsIDOMNode *aBlockParent, 
00267                            nsCOMPtr<nsIDOMNode> *aNextNode);
00268     nsresult GetNextWSNode(nsIDOMNode *aStartNode,
00269                            PRInt16     aOffset, 
00270                            nsIDOMNode *aBlockParent, 
00271                            nsCOMPtr<nsIDOMNode> *aNextNode);
00272     nsresult GetNextWSNode(DOMPoint aPoint,
00273                            nsIDOMNode  *aBlockParent, 
00274                            nsCOMPtr<nsIDOMNode> *aNextNode);
00275     nsresult PrepareToDeleteRangePriv(nsWSRunObject* aEndObject);
00276     nsresult PrepareToSplitAcrossBlocksPriv();
00277     nsresult DeleteChars(nsIDOMNode *aStartNode, PRInt32 aStartOffset, 
00278                          nsIDOMNode *aEndNode, PRInt32 aEndOffset,
00279                          AreaRestriction aAR = eAnywhere);
00280     nsresult GetCharAfter(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outPoint);
00281     nsresult GetCharBefore(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outPoint);
00282     nsresult GetCharAfter(WSPoint &aPoint, WSPoint *outPoint);
00283     nsresult GetCharBefore(WSPoint &aPoint, WSPoint *outPoint);
00284     nsresult ConvertToNBSP(WSPoint aPoint,
00285                            AreaRestriction aAR = eAnywhere);
00286     nsresult GetAsciiWSBounds(PRInt16 aDir, nsIDOMNode *aNode, PRInt32 aOffset,
00287                                 nsCOMPtr<nsIDOMNode> *outStartNode, PRInt32 *outStartOffset,
00288                                 nsCOMPtr<nsIDOMNode> *outEndNode, PRInt32 *outEndOffset);
00289     nsresult FindRun(nsIDOMNode *aNode, PRInt32 aOffset, WSFragment **outRun, PRBool after);
00290     PRUnichar GetCharAt(nsITextContent *aTextNode, PRInt32 aOffset);
00291     nsresult GetWSPointAfter(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outPoint);
00292     nsresult GetWSPointBefore(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outPoint);
00293     nsresult CheckTrailingNBSPOfRun(WSFragment *aRun);
00294     nsresult CheckTrailingNBSP(WSFragment *aRun, nsIDOMNode *aNode, PRInt32 aOffset);
00295     nsresult CheckLeadingNBSP(WSFragment *aRun, nsIDOMNode *aNode, PRInt32 aOffset);
00296     
00297     static nsresult ScrubBlockBoundaryInner(nsHTMLEditor *aHTMLEd, 
00298                                        nsCOMPtr<nsIDOMNode> *aBlock,
00299                                        BlockBoundary aBoundary);
00300     nsresult Scrub();
00301     
00302     // member variables ---------------------------------------------------------
00303     
00304     nsCOMPtr<nsIDOMNode> mNode;           // the node passed to our constructor
00305     PRInt32 mOffset;                      // the offset passed to our contructor
00306     // together, the above represent the point at which we are building up ws info.
00307     
00308     PRBool  mPRE;                         // true if we are in preformatted whitespace context
00309     nsCOMPtr<nsIDOMNode> mStartNode;      // node/offet where ws starts
00310     PRInt32 mStartOffset;                 // ...
00311     PRInt16 mStartReason;                 // reason why ws starts (eText, eOtherBlock, etc)
00312     nsCOMPtr<nsIDOMNode> mStartReasonNode;// the node that implicated by start reason
00313     
00314     nsCOMPtr<nsIDOMNode> mEndNode;        // node/offet where ws ends
00315     PRInt32 mEndOffset;                   // ...
00316     PRInt16 mEndReason;                   // reason why ws ends (eText, eOtherBlock, etc)
00317     nsCOMPtr<nsIDOMNode> mEndReasonNode;  // the node that implicated by end reason
00318     
00319     nsCOMPtr<nsIDOMNode> mFirstNBSPNode;  // location of first nbsp in ws run, if any
00320     PRInt32 mFirstNBSPOffset;             // ...
00321     
00322     nsCOMPtr<nsIDOMNode> mLastNBSPNode;   // location of last nbsp in ws run, if any
00323     PRInt32 mLastNBSPOffset;              // ...
00324     
00325     nsCOMArray<nsIDOMNode> mNodeArray;//the list of nodes containing ws in this run
00326     
00327     WSFragment *mStartRun;                // the first WSFragment in the run
00328     WSFragment *mEndRun;                  // the last WSFragment in the run, may be same as first
00329     
00330     nsHTMLEditor *mHTMLEditor;            // non-owning.
00331     
00332     friend class nsHTMLEditRules;  // opening this class up for pillaging
00333     friend class nsHTMLEditor;     // opening this class up for more pillaging
00334 };
00335 
00336 #endif
00337