/src/mozilla-central/editor/libeditor/WSRunObject.h
Line | Count | Source (jump to first uncovered line) |
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 | | #include "mozilla/EditorDOMPoint.h" // for EditorDOMPoint |
16 | | |
17 | | namespace mozilla { |
18 | | |
19 | | class HTMLEditor; |
20 | | class HTMLEditRules; |
21 | | |
22 | | // class WSRunObject 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. |
31 | | |
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. |
39 | | |
40 | | /** |
41 | | * A type-safe bitfield indicating various types of whitespace or other things. |
42 | | * Used as a member variable in WSRunObject 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 | | { |
49 | | public: |
50 | | enum Enum |
51 | | { |
52 | | none = 0, |
53 | | leadingWS = 1, // leading insignificant ws, ie, after block or br |
54 | | trailingWS = 1 << 1, // trailing insignificant ws, ie, before block |
55 | | normalWS = 1 << 2, // normal significant ws, ie, after text, image, ... |
56 | | text = 1 << 3, // indicates regular (non-ws) text |
57 | | special = 1 << 4, // indicates an inline non-container, like image |
58 | | br = 1 << 5, // indicates a br node |
59 | | otherBlock = 1 << 6, // indicates a block other than one ws run is in |
60 | | thisBlock = 1 << 7, // indicates the block ws run is in |
61 | | block = otherBlock | thisBlock // block found |
62 | | }; |
63 | | |
64 | | /** |
65 | | * Implicit constructor, because the enums are logically just WSTypes |
66 | | * themselves, and are only a separate type because there's no other obvious |
67 | | * way to name specific WSType values. |
68 | | */ |
69 | | MOZ_IMPLICIT WSType(const Enum& aEnum = none) |
70 | | : mEnum(aEnum) |
71 | 0 | {} |
72 | | |
73 | | // operator==, &, and | need to access mEnum |
74 | | friend bool operator==(const WSType& aLeft, const WSType& aRight); |
75 | | friend const WSType operator&(const WSType& aLeft, const WSType& aRight); |
76 | | friend const WSType operator|(const WSType& aLeft, const WSType& aRight); |
77 | | WSType& operator=(const WSType& aOther) |
78 | 0 | { |
79 | 0 | // This handles self-assignment fine |
80 | 0 | mEnum = aOther.mEnum; |
81 | 0 | return *this; |
82 | 0 | } |
83 | | WSType& operator&=(const WSType& aOther) |
84 | 0 | { |
85 | 0 | mEnum &= aOther.mEnum; |
86 | 0 | return *this; |
87 | 0 | } |
88 | | WSType& operator|=(const WSType& aOther) |
89 | 0 | { |
90 | 0 | mEnum |= aOther.mEnum; |
91 | 0 | return *this; |
92 | 0 | } |
93 | | |
94 | | private: |
95 | | uint16_t mEnum; |
96 | 0 | void bool_conversion_helper() {} |
97 | | |
98 | | public: |
99 | | // Allow boolean conversion with no numeric conversion |
100 | | typedef void (WSType::*bool_type)(); |
101 | | operator bool_type() const |
102 | 0 | { |
103 | 0 | return mEnum ? &WSType::bool_conversion_helper : nullptr; |
104 | 0 | } |
105 | | }; |
106 | | |
107 | | /** |
108 | | * These are declared as global functions so "WSType::Enum == WSType" et al. |
109 | | * will work using the implicit constructor. |
110 | | */ |
111 | | inline bool operator==(const WSType& aLeft, const WSType& aRight) |
112 | 0 | { |
113 | 0 | return aLeft.mEnum == aRight.mEnum; |
114 | 0 | } |
115 | | |
116 | | inline bool operator!=(const WSType& aLeft, const WSType& aRight) |
117 | 0 | { |
118 | 0 | return !(aLeft == aRight); |
119 | 0 | } |
120 | | |
121 | | inline const WSType operator&(const WSType& aLeft, const WSType& aRight) |
122 | 0 | { |
123 | 0 | WSType ret; |
124 | 0 | ret.mEnum = aLeft.mEnum & aRight.mEnum; |
125 | 0 | return ret; |
126 | 0 | } |
127 | | |
128 | | inline const WSType operator|(const WSType& aLeft, const WSType& aRight) |
129 | 0 | { |
130 | 0 | WSType ret; |
131 | 0 | ret.mEnum = aLeft.mEnum | aRight.mEnum; |
132 | 0 | return ret; |
133 | 0 | } |
134 | | |
135 | | /** |
136 | | * Make sure that & and | of WSType::Enum creates a WSType instead of an int, |
137 | | * because operators between WSType and int shouldn't work |
138 | | */ |
139 | | inline const WSType operator&(const WSType::Enum& aLeft, |
140 | | const WSType::Enum& aRight) |
141 | 0 | { |
142 | 0 | return WSType(aLeft) & WSType(aRight); |
143 | 0 | } |
144 | | |
145 | | inline const WSType operator|(const WSType::Enum& aLeft, |
146 | | const WSType::Enum& aRight) |
147 | 0 | { |
148 | 0 | return WSType(aLeft) | WSType(aRight); |
149 | 0 | } |
150 | | |
151 | | class MOZ_STACK_CLASS WSRunObject final |
152 | | { |
153 | | public: |
154 | | enum BlockBoundary |
155 | | { |
156 | | kBeforeBlock, |
157 | | kBlockStart, |
158 | | kBlockEnd, |
159 | | kAfterBlock |
160 | | }; |
161 | | |
162 | | enum {eBefore = 1}; |
163 | | enum {eAfter = 1 << 1}; |
164 | | enum {eBoth = eBefore | eAfter}; |
165 | | |
166 | | template<typename PT, typename CT> |
167 | | WSRunObject(HTMLEditor* aHTMLEditor, |
168 | | const EditorDOMPointBase<PT, CT>& aPoint); |
169 | | WSRunObject(HTMLEditor* aHTMLEditor, nsINode* 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 | | /** |
215 | | * InsertBreak() inserts a <br> node at (before) aPointToInsert and delete |
216 | | * unnecessary whitespaces around there and/or replaces whitespaces with |
217 | | * non-breaking spaces. Note that if the point is in a text node, the |
218 | | * text node will be split and insert new <br> node between the left node |
219 | | * and the right node. |
220 | | * |
221 | | * @param aSelection The selection for the editor. |
222 | | * @param aPointToInsert The point to insert new <br> element. Note that |
223 | | * it'll be inserted before this point. I.e., the |
224 | | * point will be the point of new <br>. |
225 | | * @param aSelect If eNone, this won't change selection. |
226 | | * If eNext, selection will be collapsed after the |
227 | | * <br> element. |
228 | | * If ePrevious, selection will be collapsed at the |
229 | | * <br> element. |
230 | | * @return The new <br> node. If failed to create new <br> |
231 | | * node, returns nullptr. |
232 | | */ |
233 | | template<typename PT, typename CT> |
234 | | already_AddRefed<dom::Element> |
235 | | InsertBreak(Selection& aSelection, |
236 | | const EditorDOMPointBase<PT, CT>& aPointToInsert, |
237 | | nsIEditor::EDirection aSelect); |
238 | | |
239 | | /** |
240 | | * InsertText() inserts aStringToInsert to aPointToInsert and makes any |
241 | | * needed adjustments to white spaces around that point. E.g., trailing white |
242 | | * spaces before aPointToInsert needs to be removed. |
243 | | * This calls EditorBase::InsertTextWithTransaction() after adjusting white |
244 | | * spaces. So, please refer the method's explanation to know what this |
245 | | * method exactly does. |
246 | | * |
247 | | * @param aDocument The document of this editor. |
248 | | * @param aStringToInsert The string to insert. |
249 | | * @param aPointToInser The point to insert aStringToInsert. |
250 | | * Must be valid DOM point. |
251 | | * @param aPointAfterInsertedString |
252 | | * The point after inserted aStringToInsert. |
253 | | * So, when this method actually inserts string, |
254 | | * this is set to a point in the text node. |
255 | | * Otherwise, this may be set to aPointToInsert. |
256 | | * @return When this succeeds to insert the string or |
257 | | * does nothing during composition, returns NS_OK. |
258 | | * Otherwise, an error code. |
259 | | */ |
260 | | template<typename PT, typename CT> |
261 | | nsresult InsertText(nsIDocument& aDocument, |
262 | | const nsAString& aStringToInsert, |
263 | | const EditorDOMPointBase<PT, CT>& aPointToInsert, |
264 | | EditorRawDOMPoint* aPointAfterInsertedString = nullptr); |
265 | | |
266 | | // DeleteWSBackward deletes a single visible piece of ws before the ws |
267 | | // point (the point to create the wsRunObject, passed to its constructor). |
268 | | // It makes any needed conversion to adjacent ws to retain its |
269 | | // significance. |
270 | | nsresult DeleteWSBackward(); |
271 | | |
272 | | // DeleteWSForward deletes a single visible piece of ws after the ws point |
273 | | // (the point to create the wsRunObject, passed to its constructor). It |
274 | | // makes any needed conversion to adjacent ws to retain its significance. |
275 | | nsresult DeleteWSForward(); |
276 | | |
277 | | // PriorVisibleNode() returns the first piece of visible thing before aPoint. |
278 | | // If there is no visible ws qualifying it returns what is before the ws run. |
279 | | // If outVisNode and/or outvisOffset is unused, callers can use nullptr. |
280 | | // Note that {outVisNode,outVisOffset} is set to just AFTER the visible |
281 | | // object. Also outVisOffset might be invalid offset unless outVisNode is |
282 | | // start reason node. |
283 | | template<typename PT, typename CT> |
284 | | void PriorVisibleNode(const EditorDOMPointBase<PT, CT>& aPoint, |
285 | | nsCOMPtr<nsINode>* outVisNode, |
286 | | int32_t* outVisOffset, |
287 | | WSType* outType) const; |
288 | | |
289 | | template<typename PT, typename CT> |
290 | | void PriorVisibleNode(const EditorDOMPointBase<PT, CT>& aPoint, |
291 | | WSType* outType) const |
292 | 0 | { |
293 | 0 | PriorVisibleNode(aPoint, nullptr, nullptr, outType); |
294 | 0 | } Unexecuted instantiation: void mozilla::WSRunObject::PriorVisibleNode<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >(mozilla::EditorDOMPointBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> > const&, mozilla::WSType*) const Unexecuted instantiation: void mozilla::WSRunObject::PriorVisibleNode<nsINode*, nsIContent*>(mozilla::EditorDOMPointBase<nsINode*, nsIContent*> const&, mozilla::WSType*) const |
295 | | |
296 | | |
297 | | // NextVisibleNode() returns the first piece of visible thing after aPoint. |
298 | | // If there is no visible ws qualifying it returns what is after the ws run. |
299 | | // If outVisNode and/or outvisOffset is unused, callers can use nullptr. |
300 | | // Note that {outVisNode,outVisOffset} is set to just BEFORE the visible |
301 | | // object. Also outVisOffset might be invalid offset unless outVisNode is |
302 | | // end reason node. |
303 | | template<typename PT, typename CT> |
304 | | void NextVisibleNode(const EditorDOMPointBase<PT, CT>& aPoint, |
305 | | nsCOMPtr<nsINode>* outVisNode, |
306 | | int32_t* outVisOffset, |
307 | | WSType* outType) const; |
308 | | |
309 | | template<typename PT, typename CT> |
310 | | void NextVisibleNode(const EditorDOMPointBase<PT, CT>& aPoint, |
311 | | WSType* outType) const |
312 | 0 | { |
313 | 0 | NextVisibleNode(aPoint, nullptr, nullptr, outType); |
314 | 0 | } Unexecuted instantiation: void mozilla::WSRunObject::NextVisibleNode<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >(mozilla::EditorDOMPointBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> > const&, mozilla::WSType*) const Unexecuted instantiation: void mozilla::WSRunObject::NextVisibleNode<nsINode*, nsIContent*>(mozilla::EditorDOMPointBase<nsINode*, nsIContent*> const&, mozilla::WSType*) const |
315 | | |
316 | | // AdjustWhitespace examines the ws object for nbsp's that can |
317 | | // be safely converted to regular ascii space and converts them. |
318 | | nsresult AdjustWhitespace(); |
319 | | |
320 | | protected: |
321 | | // WSFragment represents a single run of ws (all leadingws, or all normalws, |
322 | | // or all trailingws, or all leading+trailingws). Note that this single run |
323 | | // may still span multiple nodes. |
324 | | struct WSFragment final |
325 | | { |
326 | | nsCOMPtr<nsINode> mStartNode; // node where ws run starts |
327 | | nsCOMPtr<nsINode> mEndNode; // node where ws run ends |
328 | | int32_t mStartOffset; // offset where ws run starts |
329 | | int32_t mEndOffset; // offset where ws run ends |
330 | | // type of ws, and what is to left and right of it |
331 | | WSType mType, mLeftType, mRightType; |
332 | | // other ws runs to left or right. may be null. |
333 | | WSFragment *mLeft, *mRight; |
334 | | |
335 | | WSFragment() |
336 | | : mStartOffset(0) |
337 | | , mEndOffset(0) |
338 | | , mLeft(nullptr) |
339 | | , mRight(nullptr) |
340 | 0 | {} |
341 | | |
342 | | EditorRawDOMPoint StartPoint() const |
343 | 0 | { |
344 | 0 | return EditorRawDOMPoint(mStartNode, mStartOffset); |
345 | 0 | } |
346 | | EditorRawDOMPoint EndPoint() const |
347 | 0 | { |
348 | 0 | return EditorRawDOMPoint(mEndNode, mEndOffset); |
349 | 0 | } |
350 | | }; |
351 | | |
352 | | // A WSPoint struct represents a unique location within the ws run. It is |
353 | | // always within a textnode that is one of the nodes stored in the list |
354 | | // in the wsRunObject. For convenience, the character at that point is also |
355 | | // stored in the struct. |
356 | | struct MOZ_STACK_CLASS WSPoint final |
357 | | { |
358 | | RefPtr<dom::Text> mTextNode; |
359 | | uint32_t mOffset; |
360 | | char16_t mChar; |
361 | | |
362 | | WSPoint() |
363 | | : mTextNode(nullptr) |
364 | | , mOffset(0) |
365 | | , mChar(0) |
366 | 0 | {} |
367 | | |
368 | | WSPoint(dom::Text* aTextNode, int32_t aOffset, char16_t aChar) |
369 | | : mTextNode(aTextNode) |
370 | | , mOffset(aOffset) |
371 | | , mChar(aChar) |
372 | 0 | {} |
373 | | }; |
374 | | |
375 | | /** |
376 | | * Return the node which we will handle white-space under. This is the |
377 | | * closest block within the DOM subtree we're editing, or if none is |
378 | | * found, the (inline) root of the editable subtree. |
379 | | */ |
380 | | nsINode* GetWSBoundingParent(); |
381 | | |
382 | | nsresult GetWSNodes(); |
383 | | void GetRuns(); |
384 | | void ClearRuns(); |
385 | | void MakeSingleWSRun(WSType aType); |
386 | | nsIContent* GetPreviousWSNodeInner(nsINode* aStartNode, |
387 | | nsINode* aBlockParent); |
388 | | nsIContent* GetPreviousWSNode(const EditorDOMPoint& aPoint, |
389 | | nsINode* aBlockParent); |
390 | | nsIContent* GetNextWSNodeInner(nsINode* aStartNode, nsINode* aBlockParent); |
391 | | nsIContent* GetNextWSNode(const EditorDOMPoint& aPoint, |
392 | | nsINode* aBlockParent); |
393 | | nsresult PrepareToDeleteRangePriv(WSRunObject* aEndObject); |
394 | | nsresult PrepareToSplitAcrossBlocksPriv(); |
395 | | |
396 | | /** |
397 | | * DeleteRange() removes the range between aStartPoint and aEndPoint. |
398 | | * When aStartPoint and aEndPoint are same point, does nothing. |
399 | | * When aStartPoint and aEndPoint are in same text node, removes characters |
400 | | * between them. |
401 | | * When aStartPoint is in a text node, removes the text data after the point. |
402 | | * When aEndPoint is in a text node, removes the text data before the point. |
403 | | * Removes any nodes between them. |
404 | | */ |
405 | | template<typename PT1, typename CT1, typename PT2, typename CT2> |
406 | | nsresult DeleteRange(const EditorDOMPointBase<PT1, CT1>& aStartPoint, |
407 | | const EditorDOMPointBase<PT2, CT2>& aEndPoint); |
408 | | |
409 | | /** |
410 | | * GetNextCharPoint() returns next character's point of aPoint. If there is |
411 | | * no character after aPoint, mTextNode is set to nullptr. |
412 | | */ |
413 | | template<typename PT, typename CT> |
414 | | WSPoint GetNextCharPoint(const EditorDOMPointBase<PT, CT>& aPoint) const; |
415 | | WSPoint GetNextCharPoint(const WSPoint& aPoint) const; |
416 | | |
417 | | /** |
418 | | * GetPreviousCharPoint() returns previous character's point of of aPoint. |
419 | | * If there is no character before aPoint, mTextNode is set to nullptr. |
420 | | */ |
421 | | template<typename PT, typename CT> |
422 | | WSPoint GetPreviousCharPoint(const EditorDOMPointBase<PT, CT>& aPoint) const; |
423 | | WSPoint GetPreviousCharPoint(const WSPoint& aPoint) const; |
424 | | |
425 | | /** |
426 | | * GetNextCharPointInternal() and GetPreviousCharPointInternal() are |
427 | | * helper methods of GetNextCharPoint(const EditorRawDOMPoint&) and |
428 | | * GetPreviousCharPoint(const EditorRawDOMPoint&). When the container |
429 | | * isn't in mNodeArray, they call one of these methods. Then, these |
430 | | * methods look for nearest text node in mNodeArray from aPoint. |
431 | | * Then, will call GetNextCharPoint(const WSPoint&) or |
432 | | * GetPreviousCharPoint(const WSPoint&) and returns its result. |
433 | | */ |
434 | | template<typename PT, typename CT> |
435 | | WSPoint |
436 | | GetNextCharPointInternal(const EditorDOMPointBase<PT, CT>& aPoint) const; |
437 | | template<typename PT, typename CT> |
438 | | WSPoint |
439 | | GetPreviousCharPointInternal(const EditorDOMPointBase<PT, CT>& aPoint) const; |
440 | | |
441 | | /** |
442 | | * InsertNBSPAndRemoveFollowingASCIIWhitespaces() inserts an NBSP first. |
443 | | * Then, if following characters are ASCII whitespaces, will remove them. |
444 | | */ |
445 | | nsresult InsertNBSPAndRemoveFollowingASCIIWhitespaces(WSPoint aPoint); |
446 | | |
447 | | /** |
448 | | * GetASCIIWhitespacesBounds() retrieves whitespaces before and/or after the |
449 | | * point specified by aNode and aOffset. |
450 | | * |
451 | | * @param aDir Specify eBefore if you want to scan text backward. |
452 | | * Specify eAfter if you want to scan text forward. |
453 | | * Specify eBoth if you want to scan text to both |
454 | | * direction. |
455 | | * @param aNode The container node where you want to start to scan |
456 | | * whitespaces from. |
457 | | * @param aOffset The offset in aNode where you want to start to scan |
458 | | * whitespaces from. |
459 | | * @param outStartNode [out] The container of first ASCII whitespace. |
460 | | * If there is no whitespaces, returns nullptr. |
461 | | * @param outStartOffset [out] The offset of first ASCII whitespace in |
462 | | * outStartNode. |
463 | | * @param outEndNode [out] The container of last ASCII whitespace. |
464 | | * If there is no whitespaces, returns nullptr. |
465 | | * @param outEndOffset [out] The offset of last ASCII whitespace in |
466 | | * outEndNode. |
467 | | */ |
468 | | void GetASCIIWhitespacesBounds(int16_t aDir, |
469 | | nsINode* aNode, |
470 | | int32_t aOffset, |
471 | | dom::Text** outStartNode, |
472 | | int32_t* outStartOffset, |
473 | | dom::Text** outEndNode, |
474 | | int32_t* outEndOffset); |
475 | | |
476 | | /** |
477 | | * FindNearestRun() looks for a WSFragment which is closest to specified |
478 | | * direction from aPoint. |
479 | | * |
480 | | * @param aPoint The point to start to look for. |
481 | | * @param aForward true if caller needs to look for a WSFragment after the |
482 | | * point in the DOM tree. Otherwise, i.e., before the |
483 | | * point, false. |
484 | | * @return Found WSFragment instance. |
485 | | * If aForward is true and: |
486 | | * if aPoint is end of a run, returns next run. |
487 | | * if aPoint is start of a run, returns the run. |
488 | | * if aPoint is before the first run, returns the first |
489 | | * run. |
490 | | * If aPoint is after the last run, returns nullptr. |
491 | | * If aForward is false and: |
492 | | * if aPoint is end of a run, returns the run. |
493 | | * if aPoint is start of a run, returns its next run. |
494 | | * if aPoint is before the first run, returns nullptr. |
495 | | * if aPoint is after the last run, returns the last run. |
496 | | */ |
497 | | template<typename PT, typename CT> |
498 | | WSFragment* FindNearestRun(const EditorDOMPointBase<PT, CT>& aPoint, |
499 | | bool aForward) const; |
500 | | |
501 | | char16_t GetCharAt(dom::Text* aTextNode, int32_t aOffset) const; |
502 | | nsresult CheckTrailingNBSPOfRun(WSFragment *aRun); |
503 | | |
504 | | /** |
505 | | * ReplacePreviousNBSPIfUnncessary() replaces previous character of aPoint |
506 | | * if it's a NBSP and it's unnecessary. |
507 | | * |
508 | | * @param aRun Current text run. aPoint must be in this run. |
509 | | * @param aPoint Current insertion point. Its previous character is |
510 | | * unnecessary NBSP will be checked. |
511 | | */ |
512 | | template<typename PT, typename CT> |
513 | | nsresult |
514 | | ReplacePreviousNBSPIfUnncessary(WSFragment* aRun, |
515 | | const EditorDOMPointBase<PT, CT>& aPoint); |
516 | | |
517 | | nsresult CheckLeadingNBSP(WSFragment* aRun, nsINode* aNode, |
518 | | int32_t aOffset); |
519 | | |
520 | | nsresult Scrub(); |
521 | | bool IsBlockNode(nsINode* aNode); |
522 | | |
523 | | EditorRawDOMPoint Point() const |
524 | 0 | { |
525 | 0 | return EditorRawDOMPoint(mNode, mOffset); |
526 | 0 | } |
527 | | EditorRawDOMPoint StartPoint() const |
528 | 0 | { |
529 | 0 | return EditorRawDOMPoint(mStartNode, mStartOffset); |
530 | 0 | } |
531 | | EditorRawDOMPoint EndPoint() const |
532 | 0 | { |
533 | 0 | return EditorRawDOMPoint(mEndNode, mEndOffset); |
534 | 0 | } |
535 | | |
536 | | // The node passed to our constructor. |
537 | | nsCOMPtr<nsINode> mNode; |
538 | | // The offset passed to our contructor. |
539 | | int32_t mOffset; |
540 | | // Together, the above represent the point at which we are building up ws info. |
541 | | |
542 | | // true if we are in preformatted whitespace context. |
543 | | bool mPRE; |
544 | | // Node/offset where ws starts. |
545 | | nsCOMPtr<nsINode> mStartNode; |
546 | | int32_t mStartOffset; |
547 | | // Reason why ws starts (eText, eOtherBlock, etc.). |
548 | | WSType mStartReason; |
549 | | // The node that implicated by start reason. |
550 | | nsCOMPtr<nsINode> mStartReasonNode; |
551 | | |
552 | | // Node/offset where ws ends. |
553 | | nsCOMPtr<nsINode> mEndNode; |
554 | | int32_t mEndOffset; |
555 | | // Reason why ws ends (eText, eOtherBlock, etc.). |
556 | | WSType mEndReason; |
557 | | // The node that implicated by end reason. |
558 | | nsCOMPtr<nsINode> mEndReasonNode; |
559 | | |
560 | | // Location of first nbsp in ws run, if any. |
561 | | RefPtr<dom::Text> mFirstNBSPNode; |
562 | | int32_t mFirstNBSPOffset; |
563 | | |
564 | | // Location of last nbsp in ws run, if any. |
565 | | RefPtr<dom::Text> mLastNBSPNode; |
566 | | int32_t mLastNBSPOffset; |
567 | | |
568 | | // The list of nodes containing ws in this run. |
569 | | nsTArray<RefPtr<dom::Text>> mNodeArray; |
570 | | |
571 | | // The first WSFragment in the run. |
572 | | WSFragment* mStartRun; |
573 | | // The last WSFragment in the run, may be same as first. |
574 | | WSFragment* mEndRun; |
575 | | |
576 | | // Non-owning. |
577 | | HTMLEditor* mHTMLEditor; |
578 | | |
579 | | // Opening this class up for pillaging. |
580 | | friend class HTMLEditRules; |
581 | | // Opening this class up for more pillaging. |
582 | | friend class HTMLEditor; |
583 | | }; |
584 | | |
585 | | } // namespace mozilla |
586 | | |
587 | | #endif // #ifndef WSRunObject_h |