editor/libeditor/html/nsWSRunObject.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial