Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/EditorUtils.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
7
#ifndef mozilla_EditorUtils_h
8
#define mozilla_EditorUtils_h
9
10
#include "mozilla/dom/Selection.h"
11
#include "mozilla/EditAction.h"
12
#include "mozilla/EditorBase.h"
13
#include "mozilla/EditorDOMPoint.h"
14
#include "mozilla/GuardObjects.h"
15
#include "nsCOMPtr.h"
16
#include "nsDebug.h"
17
#include "nsIEditor.h"
18
#include "nscore.h"
19
20
class nsAtom;
21
class nsIContentIterator;
22
class nsISimpleEnumerator;
23
class nsITransferable;
24
class nsRange;
25
26
namespace mozilla {
27
template <class T> class OwningNonNull;
28
29
namespace dom {
30
class Element;
31
class Text;
32
} // namespace dom
33
34
/***************************************************************************
35
 * EditActionResult is useful to return multiple results of an editor
36
 * action handler without out params.
37
 * Note that when you return an anonymous instance from a method, you should
38
 * use EditActionIgnored(), EditActionHandled() or EditActionCanceled() for
39
 * easier to read.  In other words, EditActionResult should be used when
40
 * declaring return type of a method, being an argument or defined as a local
41
 * variable.
42
 */
43
class MOZ_STACK_CLASS EditActionResult final
44
{
45
public:
46
0
  bool Succeeded() const { return NS_SUCCEEDED(mRv); }
47
0
  bool Failed() const { return NS_FAILED(mRv); }
48
0
  nsresult Rv() const { return mRv; }
49
0
  bool Canceled() const { return mCanceled; }
50
0
  bool Handled() const { return mHandled; }
51
0
  bool EditorDestroyed() const { return mRv == NS_ERROR_EDITOR_DESTROYED; }
52
53
  EditActionResult SetResult(nsresult aRv)
54
0
  {
55
0
    mRv = aRv;
56
0
    return *this;
57
0
  }
58
  EditActionResult MarkAsCanceled()
59
0
  {
60
0
    mCanceled = true;
61
0
    return *this;
62
0
  }
63
  EditActionResult MarkAsHandled()
64
0
  {
65
0
    mHandled = true;
66
0
    return *this;
67
0
  }
68
69
  explicit EditActionResult(nsresult aRv)
70
    : mRv(aRv)
71
    , mCanceled(false)
72
    , mHandled(false)
73
0
  {
74
0
  }
75
76
  EditActionResult& operator|=(const EditActionResult& aOther)
77
0
  {
78
0
    mCanceled |= aOther.mCanceled;
79
0
    mHandled |= aOther.mHandled;
80
0
    // When both result are same, keep the result.
81
0
    if (mRv == aOther.mRv) {
82
0
      return *this;
83
0
    }
84
0
    // If one of the result is NS_ERROR_EDITOR_DESTROYED, use it since it's
85
0
    // the most important error code for editor.
86
0
    if (EditorDestroyed() || aOther.EditorDestroyed()) {
87
0
      mRv = NS_ERROR_EDITOR_DESTROYED;
88
0
    }
89
0
    // If one of the results is error, use NS_ERROR_FAILURE.
90
0
    else if (Failed() || aOther.Failed()) {
91
0
      mRv = NS_ERROR_FAILURE;
92
0
    } else {
93
0
      // Otherwise, use generic success code, NS_OK.
94
0
      mRv = NS_OK;
95
0
    }
96
0
    return *this;
97
0
  }
98
99
private:
100
  nsresult mRv;
101
  bool mCanceled;
102
  bool mHandled;
103
104
  EditActionResult(nsresult aRv, bool aCanceled, bool aHandled)
105
    : mRv(aRv)
106
    , mCanceled(aCanceled)
107
    , mHandled(aHandled)
108
0
  {
109
0
  }
110
111
  EditActionResult()
112
    : mRv(NS_ERROR_NOT_INITIALIZED)
113
    , mCanceled(false)
114
    , mHandled(false)
115
0
  {
116
0
  }
117
118
  friend EditActionResult EditActionIgnored(nsresult aRv);
119
  friend EditActionResult EditActionHandled(nsresult aRv);
120
  friend EditActionResult EditActionCanceled(nsresult aRv);
121
};
122
123
/***************************************************************************
124
 * When an edit action handler (or its helper) does nothing,
125
 * EditActionIgnored should be returned.
126
 */
127
inline EditActionResult
128
EditActionIgnored(nsresult aRv = NS_OK)
129
0
{
130
0
  return EditActionResult(aRv, false, false);
131
0
}
132
133
/***************************************************************************
134
 * When an edit action handler (or its helper) handled and not canceled,
135
 * EditActionHandled should be returned.
136
 */
137
inline EditActionResult
138
EditActionHandled(nsresult aRv = NS_OK)
139
0
{
140
0
  return EditActionResult(aRv, false, true);
141
0
}
142
143
/***************************************************************************
144
 * When an edit action handler (or its helper) handled and canceled,
145
 * EditActionHandled should be returned.
146
 */
147
inline EditActionResult
148
EditActionCanceled(nsresult aRv = NS_OK)
149
0
{
150
0
  return EditActionResult(aRv, true, true);
151
0
}
152
153
/***************************************************************************
154
 * CreateNodeResultBase is a simple class for CreateSomething() methods
155
 * which want to return new node.
156
 */
157
template<typename NodeType>
158
class CreateNodeResultBase;
159
160
typedef CreateNodeResultBase<dom::Element> CreateElementResult;
161
162
template<typename NodeType>
163
class MOZ_STACK_CLASS CreateNodeResultBase final
164
{
165
  typedef CreateNodeResultBase<NodeType> SelfType;
166
public:
167
  bool Succeeded() const { return NS_SUCCEEDED(mRv); }
168
0
  bool Failed() const { return NS_FAILED(mRv); }
169
0
  nsresult Rv() const { return mRv; }
170
0
  NodeType* GetNewNode() const { return mNode; }
171
172
  CreateNodeResultBase() = delete;
173
174
  explicit CreateNodeResultBase(nsresult aRv)
175
    : mRv(aRv)
176
0
  {
177
0
    MOZ_DIAGNOSTIC_ASSERT(NS_FAILED(mRv));
178
0
  }
179
180
  explicit CreateNodeResultBase(NodeType* aNode)
181
    : mNode(aNode)
182
    , mRv(aNode ? NS_OK : NS_ERROR_FAILURE)
183
0
  {
184
0
  }
185
186
  explicit CreateNodeResultBase(already_AddRefed<NodeType>&& aNode)
187
    : mNode(aNode)
188
    , mRv(mNode.get() ? NS_OK : NS_ERROR_FAILURE)
189
0
  {
190
0
  }
191
192
  CreateNodeResultBase(const SelfType& aOther) = delete;
193
  SelfType& operator=(const SelfType& aOther) = delete;
194
  CreateNodeResultBase(SelfType&& aOther) = default;
195
  SelfType& operator=(SelfType&& aOther) = default;
196
197
  already_AddRefed<NodeType> forget()
198
0
  {
199
0
    mRv = NS_ERROR_NOT_INITIALIZED;
200
0
    return mNode.forget();
201
0
  }
202
203
private:
204
  RefPtr<NodeType> mNode;
205
  nsresult mRv;
206
};
207
208
/***************************************************************************
209
 * SplitNodeResult is a simple class for
210
 * EditorBase::SplitNodeDeepWithTransaction().
211
 * This makes the callers' code easier to read.
212
 */
213
class MOZ_STACK_CLASS SplitNodeResult final
214
{
215
public:
216
0
  bool Succeeded() const { return NS_SUCCEEDED(mRv); }
217
0
  bool Failed() const { return NS_FAILED(mRv); }
218
0
  nsresult Rv() const { return mRv; }
219
220
  /**
221
   * DidSplit() returns true if a node was actually split.
222
   */
223
  bool DidSplit() const
224
0
  {
225
0
    return mPreviousNode && mNextNode;
226
0
  }
227
228
  /**
229
   * GetLeftNode() simply returns the left node which was created at splitting.
230
   * This returns nullptr if the node wasn't split.
231
   */
232
  nsIContent* GetLeftNode() const
233
0
  {
234
0
    return mPreviousNode && mNextNode ? mPreviousNode.get() : nullptr;
235
0
  }
236
237
  /**
238
   * GetRightNode() simply returns the right node which was split.
239
   * This won't return nullptr unless failed to split due to invalid arguments.
240
   */
241
  nsIContent* GetRightNode() const
242
0
  {
243
0
    if (mGivenSplitPoint.IsSet()) {
244
0
      return mGivenSplitPoint.GetChild();
245
0
    }
246
0
    return mPreviousNode && !mNextNode ? mPreviousNode : mNextNode;
247
0
  }
248
249
  /**
250
   * GetPreviousNode() returns previous node at the split point.
251
   */
252
  nsIContent* GetPreviousNode() const
253
0
  {
254
0
    if (mGivenSplitPoint.IsSet()) {
255
0
      return mGivenSplitPoint.IsEndOfContainer() ?
256
0
               mGivenSplitPoint.GetChild() : nullptr;
257
0
    }
258
0
    return mPreviousNode;
259
0
  }
260
261
  /**
262
   * GetNextNode() returns next node at the split point.
263
   */
264
  nsIContent* GetNextNode() const
265
0
  {
266
0
    if (mGivenSplitPoint.IsSet()) {
267
0
      return !mGivenSplitPoint.IsEndOfContainer() ?
268
0
                mGivenSplitPoint.GetChild() : nullptr;
269
0
    }
270
0
    return mNextNode;
271
0
  }
272
273
  /**
274
   * SplitPoint() returns the split point in the container.
275
   * This is useful when callers insert an element at split point with
276
   * EditorBase::CreateNodeWithTransaction() or something similar methods.
277
   *
278
   * Note that the result is EditorRawDOMPoint but the nodes are grabbed
279
   * by this instance.  Therefore, the life time of both container node
280
   * and child node are guaranteed while using the result temporarily.
281
   */
282
  EditorRawDOMPoint SplitPoint() const
283
0
  {
284
0
    if (Failed()) {
285
0
      return EditorRawDOMPoint();
286
0
    }
287
0
    if (mGivenSplitPoint.IsSet()) {
288
0
      return EditorRawDOMPoint(mGivenSplitPoint);
289
0
    }
290
0
    if (!mPreviousNode) {
291
0
      return EditorRawDOMPoint(mNextNode);
292
0
    }
293
0
    EditorRawDOMPoint point(mPreviousNode);
294
0
    DebugOnly<bool> advanced = point.AdvanceOffset();
295
0
    NS_WARNING_ASSERTION(advanced,
296
0
      "Failed to advance offset to after previous node");
297
0
    return point;
298
0
  }
299
300
  /**
301
   * This constructor shouldn't be used by anybody except methods which
302
   * use this as result when it succeeds.
303
   *
304
   * @param aPreviousNodeOfSplitPoint   Previous node immediately before
305
   *                                    split point.
306
   * @param aNextNodeOfSplitPoint       Next node immediately after split
307
   *                                    point.
308
   */
309
  SplitNodeResult(nsIContent* aPreviousNodeOfSplitPoint,
310
                  nsIContent* aNextNodeOfSplitPoint)
311
    : mPreviousNode(aPreviousNodeOfSplitPoint)
312
    , mNextNode(aNextNodeOfSplitPoint)
313
    , mRv(NS_OK)
314
0
  {
315
0
    MOZ_DIAGNOSTIC_ASSERT(mPreviousNode || mNextNode);
316
0
  }
317
318
  /**
319
   * This constructor should be used when the method didn't split any nodes
320
   * but want to return given split point as right point.
321
   */
322
  explicit SplitNodeResult(const EditorRawDOMPoint& aGivenSplitPoint)
323
    : mGivenSplitPoint(aGivenSplitPoint)
324
    , mRv(NS_OK)
325
0
  {
326
0
    MOZ_DIAGNOSTIC_ASSERT(mGivenSplitPoint.IsSet());
327
0
  }
328
329
  /**
330
   * This constructor shouldn't be used by anybody except methods which
331
   * use this as error result when it fails.
332
   */
333
  explicit SplitNodeResult(nsresult aRv)
334
    : mRv(aRv)
335
0
  {
336
0
    MOZ_DIAGNOSTIC_ASSERT(NS_FAILED(mRv));
337
0
  }
338
339
private:
340
  // When methods which return this class split some nodes actually, they
341
  // need to set a set of left node and right node to this class.  However,
342
  // one or both of them may be moved or removed by mutation observer.
343
  // In such case, we cannot represent the point with EditorDOMPoint since
344
  // it requires current container node.  Therefore, we need to use
345
  // nsCOMPtr<nsIContent> here instead.
346
  nsCOMPtr<nsIContent> mPreviousNode;
347
  nsCOMPtr<nsIContent> mNextNode;
348
349
  // Methods which return this class may not split any nodes actually.  Then,
350
  // they may want to return given split point as is since such behavior makes
351
  // their callers simpler.  In this case, the point may be in a text node
352
  // which cannot be represented as a node.  Therefore, we need EditorDOMPoint
353
  // for representing the point.
354
  EditorDOMPoint mGivenSplitPoint;
355
356
  nsresult mRv;
357
358
  SplitNodeResult() = delete;
359
};
360
361
/***************************************************************************
362
 * SplitRangeOffFromNodeResult class is a simple class for methods which split a
363
 * node at 2 points for making part of the node split off from the node.
364
 */
365
class MOZ_STACK_CLASS SplitRangeOffFromNodeResult final
366
{
367
public:
368
0
  bool Succeeded() const { return NS_SUCCEEDED(mRv); }
369
0
  bool Failed() const { return NS_FAILED(mRv); }
370
0
  nsresult Rv() const { return mRv; }
371
372
  /**
373
   * GetLeftContent() returns new created node before the part of quarried out.
374
   * This may return nullptr if the method didn't split at start edge of
375
   * the node.
376
   */
377
0
  nsIContent* GetLeftContent() const { return mLeftContent; }
378
  dom::Element* GetLeftContentAsElement() const
379
0
  {
380
0
    return Element::FromNodeOrNull(mLeftContent);
381
0
  }
382
383
  /**
384
   * GetMiddleContent() returns new created node between left node and right
385
   * node.  I.e., this is quarried out from the node.  This may return nullptr
386
   * if the method unwrapped the middle node.
387
   */
388
0
  nsIContent* GetMiddleContent() const { return mMiddleContent; }
389
  dom::Element* GetMiddleContentAsElement() const
390
0
  {
391
0
    return Element::FromNodeOrNull(mMiddleContent);
392
0
  }
393
394
  /**
395
   * GetRightContent() returns the right node after the part of quarried out.
396
   * This may return nullptr it the method didn't split at end edge of the
397
   * node.
398
   */
399
0
  nsIContent* GetRightContent() const { return mRightContent; }
400
  dom::Element* GetRightContentAsElement() const
401
0
  {
402
0
    return Element::FromNodeOrNull(mRightContent);
403
0
  }
404
405
  SplitRangeOffFromNodeResult(nsIContent* aLeftContent, nsIContent* aMiddleContent,
406
                   nsIContent* aRightContent)
407
    : mLeftContent(aLeftContent)
408
    , mMiddleContent(aMiddleContent)
409
    , mRightContent(aRightContent)
410
    , mRv(NS_OK)
411
0
  {
412
0
  }
413
414
  SplitRangeOffFromNodeResult(SplitNodeResult& aSplitResultAtLeftOfMiddleNode,
415
                         SplitNodeResult& aSplitResultAtRightOfMiddleNode)
416
    : mRv(NS_OK)
417
0
  {
418
0
    if (aSplitResultAtLeftOfMiddleNode.Succeeded()) {
419
0
      mLeftContent = aSplitResultAtLeftOfMiddleNode.GetPreviousNode();
420
0
    }
421
0
    if (aSplitResultAtRightOfMiddleNode.Succeeded()) {
422
0
      mRightContent = aSplitResultAtRightOfMiddleNode.GetNextNode();
423
0
      mMiddleContent = aSplitResultAtRightOfMiddleNode.GetPreviousNode();
424
0
    }
425
0
    if (!mMiddleContent && aSplitResultAtLeftOfMiddleNode.Succeeded()) {
426
0
      mMiddleContent = aSplitResultAtLeftOfMiddleNode.GetNextNode();
427
0
    }
428
0
  }
429
430
  explicit SplitRangeOffFromNodeResult(nsresult aRv)
431
    : mRv(aRv)
432
0
  {
433
0
    MOZ_DIAGNOSTIC_ASSERT(NS_FAILED(mRv));
434
0
  }
435
436
  SplitRangeOffFromNodeResult(
437
    const SplitRangeOffFromNodeResult& aOther) = delete;
438
  SplitRangeOffFromNodeResult&
439
  operator=(const SplitRangeOffFromNodeResult& aOther) = delete;
440
0
  SplitRangeOffFromNodeResult(SplitRangeOffFromNodeResult&& aOther) = default;
441
  SplitRangeOffFromNodeResult&
442
  operator=(SplitRangeOffFromNodeResult&& aOther) = default;
443
444
private:
445
  nsCOMPtr<nsIContent> mLeftContent;
446
  nsCOMPtr<nsIContent> mMiddleContent;
447
  nsCOMPtr<nsIContent> mRightContent;
448
449
  nsresult mRv;
450
451
  SplitRangeOffFromNodeResult() = delete;
452
};
453
454
/***************************************************************************
455
 * stack based helper class for calling EditorBase::EndTransaction() after
456
 * EditorBase::BeginTransaction().
457
 ***************************************************************************/
458
class MOZ_RAII AutoTransactionBatch final
459
{
460
private:
461
  OwningNonNull<EditorBase> mEditorBase;
462
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
463
464
public:
465
  explicit AutoTransactionBatch(EditorBase& aEditorBase
466
                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
467
    : mEditorBase(aEditorBase)
468
0
  {
469
0
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
470
0
    mEditorBase->BeginTransactionInternal();
471
0
  }
472
473
  ~AutoTransactionBatch()
474
0
  {
475
0
    mEditorBase->EndTransactionInternal();
476
0
  }
477
};
478
479
/***************************************************************************
480
 * stack based helper class for batching a collection of transactions inside a
481
 * placeholder transaction.
482
 */
483
class MOZ_RAII AutoPlaceholderBatch final
484
{
485
private:
486
  RefPtr<EditorBase> mEditorBase;
487
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
488
489
public:
490
  explicit AutoPlaceholderBatch(EditorBase* aEditorBase
491
                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
492
    : mEditorBase(aEditorBase)
493
0
  {
494
0
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
495
0
    BeginPlaceholderTransaction(nullptr);
496
0
  }
497
  AutoPlaceholderBatch(EditorBase* aEditorBase,
498
                       nsAtom* aTransactionName
499
                       MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
500
    : mEditorBase(aEditorBase)
501
0
  {
502
0
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
503
0
    BeginPlaceholderTransaction(aTransactionName);
504
0
  }
505
  ~AutoPlaceholderBatch()
506
0
  {
507
0
    if (mEditorBase) {
508
0
      mEditorBase->EndPlaceholderTransaction();
509
0
    }
510
0
  }
511
512
private:
513
  void BeginPlaceholderTransaction(nsAtom* aTransactionName)
514
0
  {
515
0
    if (mEditorBase) {
516
0
      mEditorBase->BeginPlaceholderTransaction(aTransactionName);
517
0
    }
518
0
  }
519
};
520
521
/***************************************************************************
522
 * stack based helper class for saving/restoring selection.  Note that this
523
 * assumes that the nodes involved are still around afterwards!
524
 */
525
class MOZ_RAII AutoSelectionRestorer final
526
{
527
private:
528
  // Ref-counted reference to the selection that we are supposed to restore.
529
  RefPtr<dom::Selection> mSelection;
530
  EditorBase* mEditorBase;  // Non-owning ref to EditorBase.
531
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
532
533
public:
534
  /**
535
   * Constructor responsible for remembering all state needed to restore
536
   * aSelection.
537
   */
538
  AutoSelectionRestorer(dom::Selection* aSelection,
539
                        EditorBase* aEditorBase
540
                        MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
541
542
  /**
543
   * Destructor restores mSelection to its former state
544
   */
545
  ~AutoSelectionRestorer();
546
547
  /**
548
   * Abort() cancels to restore the selection.
549
   */
550
  void Abort();
551
};
552
553
/***************************************************************************
554
 * AutoTopLevelEditSubActionNotifier notifies editor of start to handle
555
 * top level edit sub-action and end handling top level edit sub-action.
556
 */
557
class MOZ_RAII AutoTopLevelEditSubActionNotifier final
558
{
559
public:
560
  AutoTopLevelEditSubActionNotifier(EditorBase& aEditorBase,
561
                                    EditSubAction aEditSubAction,
562
                                    nsIEditor::EDirection aDirection
563
                                    MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
564
    : mEditorBase(aEditorBase)
565
    , mDoNothing(false)
566
0
  {
567
0
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
568
0
    // mTopLevelEditSubAction will already be set if this is nested call
569
0
    // XXX Looks like that this is not aware of unexpected nested edit action
570
0
    //     handling via selectionchange event listener or mutation event
571
0
    //     listener.
572
0
    if (!mEditorBase.mTopLevelEditSubAction) {
573
0
      mEditorBase.OnStartToHandleTopLevelEditSubAction(aEditSubAction,
574
0
                                                       aDirection);
575
0
    } else {
576
0
      mDoNothing = true; // nested calls will end up here
577
0
    }
578
0
  }
579
580
  ~AutoTopLevelEditSubActionNotifier()
581
0
  {
582
0
    if (!mDoNothing) {
583
0
      mEditorBase.OnEndHandlingTopLevelEditSubAction();
584
0
    }
585
0
  }
586
587
protected:
588
  EditorBase& mEditorBase;
589
  bool mDoNothing;
590
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
591
};
592
593
/***************************************************************************
594
 * stack based helper class for turning off active selection adjustment
595
 * by low level transactions
596
 */
597
class MOZ_RAII AutoTransactionsConserveSelection final
598
{
599
public:
600
  explicit AutoTransactionsConserveSelection(EditorBase& aEditorBase
601
                                             MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
602
    : mEditorBase(aEditorBase)
603
    , mAllowedTransactionsToChangeSelection(
604
        aEditorBase.AllowsTransactionsToChangeSelection())
605
0
  {
606
0
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
607
0
    mEditorBase.MakeThisAllowTransactionsToChangeSelection(false);
608
0
  }
609
610
  ~AutoTransactionsConserveSelection()
611
0
  {
612
0
    mEditorBase.MakeThisAllowTransactionsToChangeSelection(
613
0
                  mAllowedTransactionsToChangeSelection);
614
0
  }
615
616
protected:
617
  EditorBase& mEditorBase;
618
  bool mAllowedTransactionsToChangeSelection;
619
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
620
};
621
622
/***************************************************************************
623
 * stack based helper class for batching reflow and paint requests.
624
 */
625
class MOZ_RAII AutoUpdateViewBatch final
626
{
627
public:
628
  explicit AutoUpdateViewBatch(EditorBase* aEditorBase
629
                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
630
    : mEditorBase(aEditorBase)
631
0
  {
632
0
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
633
0
    NS_ASSERTION(mEditorBase, "null mEditorBase pointer!");
634
0
635
0
    if (mEditorBase) {
636
0
      mEditorBase->BeginUpdateViewBatch();
637
0
    }
638
0
  }
639
640
  ~AutoUpdateViewBatch()
641
0
  {
642
0
    if (mEditorBase) {
643
0
      mEditorBase->EndUpdateViewBatch();
644
0
    }
645
0
  }
646
647
protected:
648
  EditorBase* mEditorBase;
649
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
650
};
651
652
class MOZ_STACK_CLASS AutoRangeArray final
653
{
654
public:
655
  explicit AutoRangeArray(dom::Selection* aSelection)
656
0
  {
657
0
    if (!aSelection) {
658
0
      return;
659
0
    }
660
0
    uint32_t rangeCount = aSelection->RangeCount();
661
0
    for (uint32_t i = 0; i < rangeCount; i++) {
662
0
      mRanges.AppendElement(*aSelection->GetRangeAt(i));
663
0
    }
664
0
  }
665
666
  AutoTArray<mozilla::OwningNonNull<nsRange>, 8> mRanges;
667
};
668
669
/******************************************************************************
670
 * some helper classes for iterating the dom tree
671
 *****************************************************************************/
672
673
class BoolDomIterFunctor
674
{
675
public:
676
  virtual bool operator()(nsINode* aNode) const = 0;
677
};
678
679
class MOZ_RAII DOMIterator
680
{
681
public:
682
  explicit DOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
683
684
  explicit DOMIterator(nsINode& aNode MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
685
  virtual ~DOMIterator();
686
687
  nsresult Init(nsRange& aRange);
688
689
  void AppendList(
690
         const BoolDomIterFunctor& functor,
691
         nsTArray<mozilla::OwningNonNull<nsINode>>& arrayOfNodes) const;
692
693
protected:
694
  nsCOMPtr<nsIContentIterator> mIter;
695
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
696
};
697
698
class MOZ_RAII DOMSubtreeIterator final : public DOMIterator
699
{
700
public:
701
  explicit DOMSubtreeIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
702
  virtual ~DOMSubtreeIterator();
703
704
  nsresult Init(nsRange& aRange);
705
};
706
707
class TrivialFunctor final : public BoolDomIterFunctor
708
{
709
public:
710
  // Used to build list of all nodes iterator covers
711
  virtual bool operator()(nsINode* aNode) const override
712
0
  {
713
0
    return true;
714
0
  }
715
};
716
717
class EditorUtils final
718
{
719
public:
720
  /**
721
   * IsDescendantOf() checks if aNode is a child or a descendant of aParent.
722
   * aOutPoint is set to the child of aParent.
723
   *
724
   * @return            true if aNode is a child or a descendant of aParent.
725
   */
726
  static bool IsDescendantOf(const nsINode& aNode,
727
                             const nsINode& aParent,
728
                             EditorRawDOMPoint* aOutPoint = nullptr);
729
  static bool IsDescendantOf(const nsINode& aNode,
730
                             const nsINode& aParent,
731
                             EditorDOMPoint* aOutPoint);
732
};
733
734
} // namespace mozilla
735
736
#endif // #ifndef mozilla_EditorUtils_h