editor/libeditor/html/nsWSRunObject.h

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     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 __wsrunobject_h__
     7 #define __wsrunobject_h__
     9 #include "nsCOMArray.h"
    10 #include "nsCOMPtr.h"
    11 #include "nsIContent.h"
    12 #include "nsIDOMNode.h"
    13 #include "nsIEditor.h"
    14 #include "nsINode.h"
    15 #include "nscore.h"
    17 class nsHTMLEditor;
    18 class nsIDOMDocument;
    19 class nsIDOMNode;
    20 struct DOMPoint;
    22 // class nsWSRunObject represents the entire whitespace situation
    23 // around a given point.  It collects up a list of nodes that contain
    24 // whitespace and categorizes in up to 3 different WSFragments (detailed
    25 // below).  Each WSFragment is a collection of whitespace that is
    26 // either all insignificant, or that is significant.  A WSFragment could
    27 // consist of insignificant whitespace because it is after a block
    28 // boundary or after a break.  Or it could be insignificant because it
    29 // is before a block.  Or it could be significant because it is
    30 // surrounded by text, or starts and ends with nbsps, etc.
    32 // Throughout I refer to LeadingWS, NormalWS, TrailingWS.  LeadingWS & TrailingWS
    33 // are runs of ascii ws that are insignificant (do not render) because they
    34 // are adjacent to block boundaries, or after a break.  NormalWS is ws that
    35 // does cause soem rendering.  Note that not all the ws in a NormalWS run need
    36 // render.  For example, two ascii spaces surrounded by text on both sides
    37 // will only render as one space (in non-preformatted stlye html), yet both
    38 // spaces count as NormalWS.  Together, they render as the one visible space.
    40 /**
    41  * A type-safe bitfield indicating various types of whitespace or other things.
    42  * Used as a member variable in nsWSRunObject and WSFragment.
    43  *
    44  * XXX: If this idea is useful in other places, we should generalize it using a
    45  * template.
    46  */
    47 class WSType {
    48 public:
    49   enum Enum {
    50     none       = 0,
    51     leadingWS  = 1,      // leading insignificant ws, ie, after block or br
    52     trailingWS = 1 << 1, // trailing insignificant ws, ie, before block
    53     normalWS   = 1 << 2, // normal significant ws, ie, after text, image, ...
    54     text       = 1 << 3, // indicates regular (non-ws) text
    55     special    = 1 << 4, // indicates an inline non-container, like image
    56     br         = 1 << 5, // indicates a br node
    57     otherBlock = 1 << 6, // indicates a block other than one ws run is in
    58     thisBlock  = 1 << 7, // indicates the block ws run is in
    59     block      = otherBlock | thisBlock // block found
    60   };
    62   /**
    63    * Implicit constructor, because the enums are logically just WSTypes
    64    * themselves, and are only a separate type because there's no other obvious
    65    * way to name specific WSType values.
    66    */
    67   WSType(const Enum& aEnum = none) : mEnum(aEnum) {}
    68   // operator==, &, and | need to access mEnum
    69   friend bool operator==(const WSType& aLeft, const WSType& aRight);
    70   friend const WSType operator&(const WSType& aLeft, const WSType& aRight);
    71   friend const WSType operator|(const WSType& aLeft, const WSType& aRight);
    72   WSType& operator=(const WSType& aOther) {
    73     // This handles self-assignment fine
    74     mEnum = aOther.mEnum;
    75     return *this;
    76   }
    77   WSType& operator&=(const WSType& aOther) {
    78     mEnum &= aOther.mEnum;
    79     return *this;
    80   }
    81   WSType& operator|=(const WSType& aOther) {
    82     mEnum |= aOther.mEnum;
    83     return *this;
    84   }
    85 private:
    86   uint16_t mEnum;
    87   void bool_conversion_helper() {}
    88 public:
    89   // Allow boolean conversion with no numeric conversion
    90   typedef void (WSType::*bool_type)();
    91   operator bool_type() const
    92   {
    93     return mEnum ? &WSType::bool_conversion_helper : nullptr;
    94   }
    95 };
    97 /**
    98  * These are declared as global functions so "WSType::Enum == WSType" et al.
    99  * will work using the implicit constructor.
   100  */
   101 inline bool operator==(const WSType& aLeft, const WSType& aRight)
   102 {
   103   return aLeft.mEnum == aRight.mEnum;
   104 }
   105 inline bool operator!=(const WSType& aLeft, const WSType& aRight)
   106 {
   107   return !(aLeft == aRight);
   108 }
   109 inline const WSType operator&(const WSType& aLeft, const WSType& aRight)
   110 {
   111   WSType ret;
   112   ret.mEnum = aLeft.mEnum & aRight.mEnum;
   113   return ret;
   114 }
   115 inline const WSType operator|(const WSType& aLeft, const WSType& aRight)
   116 {
   117   WSType ret;
   118   ret.mEnum = aLeft.mEnum | aRight.mEnum;
   119   return ret;
   120 }
   122 /**
   123  * Make sure that & and | of WSType::Enum creates a WSType instead of an int,
   124  * because operators between WSType and int shouldn't work
   125  */
   126 inline const WSType operator&(const WSType::Enum& aLeft,
   127                               const WSType::Enum& aRight)
   128 {
   129   return WSType(aLeft) & WSType(aRight);
   130 }
   131 inline const WSType operator|(const WSType::Enum& aLeft,
   132                               const WSType::Enum& aRight)
   133 {
   134   return WSType(aLeft) | WSType(aRight);
   135 }
   138 class MOZ_STACK_CLASS nsWSRunObject
   139 {
   140   public:
   142     // public enums ---------------------------------------------------------
   143     enum BlockBoundary
   144     {
   145       kBeforeBlock,
   146       kBlockStart,
   147       kBlockEnd,
   148       kAfterBlock
   149     };
   151     enum {eBefore = 1};
   152     enum {eAfter  = 1 << 1};
   153     enum {eBoth   = eBefore | eAfter};
   155     // constructor / destructor -----------------------------------------------
   156     nsWSRunObject(nsHTMLEditor *aEd, nsIDOMNode *aNode, int32_t aOffset);
   157     ~nsWSRunObject();
   159     // public methods ---------------------------------------------------------
   161     // ScrubBlockBoundary removes any non-visible whitespace at the specified
   162     // location relative to a block node.  
   163     static nsresult ScrubBlockBoundary(nsHTMLEditor *aHTMLEd, 
   164                                        nsCOMPtr<nsIDOMNode> *aBlock,
   165                                        BlockBoundary aBoundary,
   166                                        int32_t *aOffset = 0);
   168     // PrepareToJoinBlocks fixes up ws at the end of aLeftParent and the
   169     // beginning of aRightParent in preperation for them to be joined.
   170     // example of fixup: trailingws in aLeftParent needs to be removed.
   171     static nsresult PrepareToJoinBlocks(nsHTMLEditor *aEd, 
   172                                         nsIDOMNode *aLeftParent,
   173                                         nsIDOMNode *aRightParent);
   175     // PrepareToDeleteRange fixes up ws before {aStartNode,aStartOffset}
   176     // and after {aEndNode,aEndOffset} in preperation for content
   177     // in that range to be deleted.  Note that the nodes and offsets
   178     // are adjusted in response to any dom changes we make while 
   179     // adjusting ws.
   180     // example of fixup: trailingws before {aStartNode,aStartOffset}
   181     //                   needs to be removed.
   182     static nsresult PrepareToDeleteRange(nsHTMLEditor *aHTMLEd, 
   183                                          nsCOMPtr<nsIDOMNode> *aStartNode,
   184                                          int32_t *aStartOffset, 
   185                                          nsCOMPtr<nsIDOMNode> *aEndNode,
   186                                          int32_t *aEndOffset);
   188     // PrepareToDeleteNode fixes up ws before and after aNode in preperation 
   189     // for aNode to be deleted.
   190     // example of fixup: trailingws before aNode needs to be removed.
   191     static nsresult PrepareToDeleteNode(nsHTMLEditor *aHTMLEd, 
   192                                         nsIDOMNode *aNode);
   194     // PrepareToSplitAcrossBlocks fixes up ws before and after 
   195     // {aSplitNode,aSplitOffset} in preperation for a block
   196     // parent to be split.  Note that the aSplitNode and aSplitOffset
   197     // are adjusted in response to any dom changes we make while 
   198     // adjusting ws.
   199     // example of fixup: normalws before {aSplitNode,aSplitOffset} 
   200     //                   needs to end with nbsp.
   201     static nsresult PrepareToSplitAcrossBlocks(nsHTMLEditor *aHTMLEd, 
   202                                                nsCOMPtr<nsIDOMNode> *aSplitNode, 
   203                                                int32_t *aSplitOffset);
   205     // InsertBreak inserts a br node at {aInOutParent,aInOutOffset}
   206     // and makes any needed adjustments to ws around that point.
   207     // example of fixup: normalws after {aInOutParent,aInOutOffset}
   208     //                   needs to begin with nbsp.
   209     nsresult InsertBreak(nsCOMPtr<nsIDOMNode> *aInOutParent, 
   210                          int32_t *aInOutOffset, 
   211                          nsCOMPtr<nsIDOMNode> *outBRNode, 
   212                          nsIEditor::EDirection aSelect);
   214     // InsertText inserts a string at {aInOutParent,aInOutOffset}
   215     // and makes any needed adjustments to ws around that point.
   216     // example of fixup: trailingws before {aInOutParent,aInOutOffset}
   217     //                   needs to be removed.
   218     nsresult InsertText(const nsAString& aStringToInsert, 
   219                         nsCOMPtr<nsIDOMNode> *aInOutNode, 
   220                         int32_t *aInOutOffset,
   221                         nsIDOMDocument *aDoc);
   223     // DeleteWSBackward deletes a single visible piece of ws before
   224     // the ws point (the point to create the wsRunObject, passed to 
   225     // its constructor).  It makes any needed conversion to adjacent
   226     // ws to retain its significance.
   227     nsresult DeleteWSBackward();
   229     // DeleteWSForward deletes a single visible piece of ws after
   230     // the ws point (the point to create the wsRunObject, passed to 
   231     // its constructor).  It makes any needed conversion to adjacent
   232     // ws to retain its significance.
   233     nsresult DeleteWSForward();
   235     // PriorVisibleNode returns the first piece of visible thing
   236     // before {aNode,aOffset}.  If there is no visible ws qualifying
   237     // it returns what is before the ws run.  Note that 
   238     // {outVisNode,outVisOffset} is set to just AFTER the visible
   239     // object.
   240     void PriorVisibleNode(nsIDOMNode *aNode,
   241                           int32_t aOffset,
   242                           nsCOMPtr<nsIDOMNode> *outVisNode,
   243                           int32_t *outVisOffset,
   244                           WSType *outType);
   246     // NextVisibleNode returns the first piece of visible thing
   247     // after {aNode,aOffset}.  If there is no visible ws qualifying
   248     // it returns what is after the ws run.  Note that 
   249     // {outVisNode,outVisOffset} is set to just BEFORE the visible
   250     // object.
   251     void NextVisibleNode(nsIDOMNode *aNode,
   252                          int32_t aOffset,
   253                          nsCOMPtr<nsIDOMNode> *outVisNode,
   254                          int32_t *outVisOffset,
   255                          WSType *outType);
   257     // AdjustWhitespace examines the ws object for nbsp's that can
   258     // be safely converted to regular ascii space and converts them.
   259     nsresult AdjustWhitespace();
   261   protected:
   263     // WSFragment struct ---------------------------------------------------------
   264     // WSFragment represents a single run of ws (all leadingws, or all normalws,
   265     // or all trailingws, or all leading+trailingws).  Note that this single run may
   266     // still span multiple nodes.
   267     struct WSFragment
   268     {
   269       nsCOMPtr<nsIDOMNode> mStartNode;  // node where ws run starts
   270       nsCOMPtr<nsIDOMNode> mEndNode;    // node where ws run ends
   271       int32_t mStartOffset;             // offset where ws run starts
   272       int32_t mEndOffset;               // offset where ws run ends
   273       // type of ws, and what is to left and right of it
   274       WSType mType, mLeftType, mRightType;
   275       // other ws runs to left or right.  may be null.
   276       WSFragment *mLeft, *mRight;
   278       WSFragment() : mStartNode(0), mEndNode(0),
   279                      mStartOffset(0), mEndOffset(0),
   280                      mType(), mLeftType(), mRightType(),
   281                      mLeft(0), mRight(0)
   282       {
   283       }
   284     };
   286     // WSPoint struct ------------------------------------------------------------
   287     // A WSPoint struct represents a unique location within the ws run.  It is 
   288     // always within a textnode that is one of the nodes stored in the list
   289     // in the wsRunObject.  For convenience, the character at that point is also 
   290     // stored in the struct.
   291     struct MOZ_STACK_CLASS WSPoint
   292     {
   293       nsCOMPtr<nsIContent> mTextNode;
   294       uint32_t mOffset;
   295       char16_t mChar;
   297       WSPoint() : mTextNode(0),mOffset(0),mChar(0) {}
   298       WSPoint(nsIDOMNode *aNode, int32_t aOffset, char16_t aChar) : 
   299                      mTextNode(do_QueryInterface(aNode)),mOffset(aOffset),mChar(aChar)
   300       {
   301         if (!mTextNode->IsNodeOfType(nsINode::eDATA_NODE)) {
   302           // Not sure if this is needed, but it'll maintain the same
   303           // functionality
   304           mTextNode = nullptr;
   305         }
   306       }
   307       WSPoint(nsIContent *aTextNode, int32_t aOffset, char16_t aChar) : 
   308                      mTextNode(aTextNode),mOffset(aOffset),mChar(aChar) {}
   309     };    
   311     enum AreaRestriction
   312     {
   313       eAnywhere, eOutsideUserSelectAll
   314     };    
   316     // protected methods ---------------------------------------------------------
   317     // tons of utility methods.  
   319     /**
   320      * Return the node which we will handle white-space under. This is the
   321      * closest block within the DOM subtree we're editing, or if none is
   322      * found, the (inline) root of the editable subtree.
   323      */
   324     already_AddRefed<nsIDOMNode> GetWSBoundingParent();
   326     nsresult GetWSNodes();
   327     void     GetRuns();
   328     void     ClearRuns();
   329     void     MakeSingleWSRun(WSType aType);
   330     nsresult PrependNodeToList(nsIDOMNode *aNode);
   331     nsresult AppendNodeToList(nsIDOMNode *aNode);
   332     nsresult GetPreviousWSNode(nsIDOMNode *aStartNode, 
   333                                nsIDOMNode *aBlockParent, 
   334                                nsCOMPtr<nsIDOMNode> *aPriorNode);
   335     nsresult GetPreviousWSNode(nsIDOMNode *aStartNode,
   336                                int32_t      aOffset,
   337                                nsIDOMNode  *aBlockParent, 
   338                                nsCOMPtr<nsIDOMNode> *aPriorNode);
   339     nsresult GetPreviousWSNode(::DOMPoint aPoint,
   340                                nsIDOMNode  *aBlockParent, 
   341                                nsCOMPtr<nsIDOMNode> *aPriorNode);
   342     nsresult GetNextWSNode(nsIDOMNode *aStartNode, 
   343                            nsIDOMNode *aBlockParent, 
   344                            nsCOMPtr<nsIDOMNode> *aNextNode);
   345     nsresult GetNextWSNode(nsIDOMNode *aStartNode,
   346                            int32_t     aOffset,
   347                            nsIDOMNode *aBlockParent, 
   348                            nsCOMPtr<nsIDOMNode> *aNextNode);
   349     nsresult GetNextWSNode(::DOMPoint aPoint,
   350                            nsIDOMNode  *aBlockParent, 
   351                            nsCOMPtr<nsIDOMNode> *aNextNode);
   352     nsresult PrepareToDeleteRangePriv(nsWSRunObject* aEndObject);
   353     nsresult PrepareToSplitAcrossBlocksPriv();
   354     nsresult DeleteChars(nsIDOMNode *aStartNode, int32_t aStartOffset, 
   355                          nsIDOMNode *aEndNode, int32_t aEndOffset,
   356                          AreaRestriction aAR = eAnywhere);
   357     WSPoint  GetCharAfter(nsIDOMNode *aNode, int32_t aOffset);
   358     WSPoint  GetCharBefore(nsIDOMNode *aNode, int32_t aOffset);
   359     WSPoint  GetCharAfter(const WSPoint &aPoint);
   360     WSPoint  GetCharBefore(const WSPoint &aPoint);
   361     nsresult ConvertToNBSP(WSPoint aPoint,
   362                            AreaRestriction aAR = eAnywhere);
   363     void     GetAsciiWSBounds(int16_t aDir, nsIDOMNode *aNode, int32_t aOffset,
   364                                 nsCOMPtr<nsIDOMNode> *outStartNode, int32_t *outStartOffset,
   365                                 nsCOMPtr<nsIDOMNode> *outEndNode, int32_t *outEndOffset);
   366     void     FindRun(nsIDOMNode *aNode, int32_t aOffset, WSFragment **outRun, bool after);
   367     char16_t GetCharAt(nsIContent *aTextNode, int32_t aOffset);
   368     WSPoint  GetWSPointAfter(nsIDOMNode *aNode, int32_t aOffset);
   369     WSPoint  GetWSPointBefore(nsIDOMNode *aNode, int32_t aOffset);
   370     nsresult CheckTrailingNBSPOfRun(WSFragment *aRun);
   371     nsresult CheckTrailingNBSP(WSFragment *aRun, nsIDOMNode *aNode, int32_t aOffset);
   372     nsresult CheckLeadingNBSP(WSFragment *aRun, nsIDOMNode *aNode, int32_t aOffset);
   374     static nsresult ScrubBlockBoundaryInner(nsHTMLEditor *aHTMLEd, 
   375                                        nsCOMPtr<nsIDOMNode> *aBlock,
   376                                        BlockBoundary aBoundary);
   377     nsresult Scrub();
   379     // member variables ---------------------------------------------------------
   381     nsCOMPtr<nsIDOMNode> mNode;           // the node passed to our constructor
   382     int32_t mOffset;                      // the offset passed to our contructor
   383     // together, the above represent the point at which we are building up ws info.
   385     bool    mPRE;                         // true if we are in preformatted whitespace context
   386     nsCOMPtr<nsIDOMNode> mStartNode;      // node/offset where ws starts
   387     int32_t mStartOffset;                 // ...
   388     WSType mStartReason;                  // reason why ws starts (eText, eOtherBlock, etc)
   389     nsCOMPtr<nsIDOMNode> mStartReasonNode;// the node that implicated by start reason
   391     nsCOMPtr<nsIDOMNode> mEndNode;        // node/offset where ws ends
   392     int32_t mEndOffset;                   // ...
   393     WSType mEndReason;                    // reason why ws ends (eText, eOtherBlock, etc)
   394     nsCOMPtr<nsIDOMNode> mEndReasonNode;  // the node that implicated by end reason
   396     nsCOMPtr<nsIDOMNode> mFirstNBSPNode;  // location of first nbsp in ws run, if any
   397     int32_t mFirstNBSPOffset;             // ...
   399     nsCOMPtr<nsIDOMNode> mLastNBSPNode;   // location of last nbsp in ws run, if any
   400     int32_t mLastNBSPOffset;              // ...
   402     nsCOMArray<nsIDOMNode> mNodeArray;//the list of nodes containing ws in this run
   404     WSFragment *mStartRun;                // the first WSFragment in the run
   405     WSFragment *mEndRun;                  // the last WSFragment in the run, may be same as first
   407     nsHTMLEditor *mHTMLEditor;            // non-owning.
   409     friend class nsHTMLEditRules;  // opening this class up for pillaging
   410     friend class nsHTMLEditor;     // opening this class up for more pillaging
   411 };
   413 #endif

mercurial