LCOV - code coverage report
Current view: top level - editor/libeditor - WSRunObject.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 40 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 19 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13