Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/EditorBase.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 mozilla_EditorBase_h
7
#define mozilla_EditorBase_h
8
9
#include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc.
10
#include "mozilla/EditorDOMPoint.h"     // for EditorDOMPoint
11
#include "mozilla/Maybe.h"              // for Maybe
12
#include "mozilla/OwningNonNull.h"      // for OwningNonNull
13
#include "mozilla/PresShell.h"          // for PresShell
14
#include "mozilla/RangeBoundary.h"      // for RawRangeBoundary, RangeBoundary
15
#include "mozilla/SelectionState.h"     // for RangeUpdater, etc.
16
#include "mozilla/StyleSheet.h"         // for StyleSheet
17
#include "mozilla/TransactionManager.h" // for TransactionManager
18
#include "mozilla/WeakPtr.h"            // for WeakPtr
19
#include "mozilla/dom/Selection.h"
20
#include "mozilla/dom/Text.h"
21
#include "nsCOMPtr.h"                   // for already_AddRefed, nsCOMPtr
22
#include "nsCycleCollectionParticipant.h"
23
#include "nsGkAtoms.h"
24
#include "nsIDocument.h"                // for nsIDocument
25
#include "nsIContentInlines.h"          // for nsINode::IsEditable()
26
#include "nsIEditor.h"                  // for nsIEditor, etc.
27
#include "nsIObserver.h"                // for NS_DECL_NSIOBSERVER, etc.
28
#include "nsIPlaintextEditor.h"         // for nsIPlaintextEditor, etc.
29
#include "nsISelectionController.h"     // for nsISelectionController constants
30
#include "nsISelectionListener.h"       // for nsISelectionListener
31
#include "nsISupportsImpl.h"            // for EditorBase::Release, etc.
32
#include "nsIWeakReferenceUtils.h"      // for nsWeakPtr
33
#include "nsLiteralString.h"            // for NS_LITERAL_STRING
34
#include "nsString.h"                   // for nsCString
35
#include "nsTArray.h"                   // for nsTArray and nsAutoTArray
36
#include "nsWeakReference.h"            // for nsSupportsWeakReference
37
#include "nscore.h"                     // for nsresult, nsAString, etc.
38
39
class mozInlineSpellChecker;
40
class nsAtom;
41
class nsIContent;
42
class nsIDocumentStateListener;
43
class nsIEditActionListener;
44
class nsIEditorObserver;
45
class nsINode;
46
class nsIPresShell;
47
class nsISupports;
48
class nsITransaction;
49
class nsITransactionListener;
50
class nsIWidget;
51
class nsRange;
52
53
namespace mozilla {
54
class AutoSelectionRestorer;
55
class AutoTopLevelEditSubActionNotifier;
56
class AutoTransactionBatch;
57
class AutoTransactionsConserveSelection;
58
class AutoUpdateViewBatch;
59
class ChangeAttributeTransaction;
60
class CompositionTransaction;
61
class CreateElementTransaction;
62
class CSSEditUtils;
63
class DeleteNodeTransaction;
64
class DeleteRangeTransaction;
65
class DeleteTextTransaction;
66
class EditAggregateTransaction;
67
class EditorEventListener;
68
class EditTransactionBase;
69
class ErrorResult;
70
class HTMLEditor;
71
class HTMLEditUtils;
72
class IMEContentObserver;
73
class InsertNodeTransaction;
74
class InsertTextTransaction;
75
class JoinNodeTransaction;
76
class PlaceholderTransaction;
77
class SplitNodeResult;
78
class SplitNodeTransaction;
79
class TextComposition;
80
class TextEditor;
81
class TextEditRules;
82
class TextInputListener;
83
class TextServicesDocument;
84
class TypeInState;
85
class WSRunObject;
86
enum class EditSubAction : int32_t;
87
88
namespace dom {
89
class DataTransfer;
90
class DragEvent;
91
class Element;
92
class EventTarget;
93
class Text;
94
} // namespace dom
95
96
namespace widget {
97
struct IMEState;
98
} // namespace widget
99
100
/**
101
 * CachedWeakPtr stores a pointer to a class which inherits nsIWeakReference.
102
 * If the instance of the class has already been destroyed, this returns
103
 * nullptr.  Otherwise, returns cached pointer.
104
 * If class T inherits nsISupports a lot, specify Base explicitly for avoiding
105
 * ambiguous conversion to nsISupports.
106
 */
107
template<class T, class Base = nsISupports>
108
class CachedWeakPtr final
109
{
110
public:
111
  CachedWeakPtr<T, Base>()
112
    : mCache(nullptr)
113
  {
114
  }
115
  explicit CachedWeakPtr<T, Base>(T* aObject)
116
0
  {
117
0
    mWeakPtr = do_GetWeakReference(static_cast<Base*>(aObject));
118
0
    mCache = aObject;
119
0
  }
120
  explicit CachedWeakPtr<T, Base>(const nsCOMPtr<T>& aOther)
121
  {
122
    mWeakPtr = do_GetWeakReference(static_cast<Base*>(aOther.get()));
123
    mCache = aOther;
124
  }
125
  explicit CachedWeakPtr<T, Base>(already_AddRefed<T>& aOther)
126
  {
127
    RefPtr<T> other = aOther;
128
    mWeakPtr = do_GetWeakReference(static_cast<Base*>(other.get()));
129
    mCache = other;
130
  }
131
132
  CachedWeakPtr<T, Base>& operator=(T* aObject)
133
  {
134
    mWeakPtr = do_GetWeakReference(static_cast<Base*>(aObject));
135
    mCache = aObject;
136
    return *this;
137
  }
138
  CachedWeakPtr<T, Base>& operator=(const nsCOMPtr<T>& aOther)
139
  {
140
    mWeakPtr = do_GetWeakReference(static_cast<Base*>(aOther.get()));
141
    mCache = aOther;
142
    return *this;
143
  }
144
  CachedWeakPtr<T, Base>& operator=(already_AddRefed<T>& aOther)
145
  {
146
    RefPtr<T> other = aOther;
147
    mWeakPtr = do_GetWeakReference(static_cast<Base*>(other.get()));
148
    mCache = other;
149
    return *this;
150
  }
151
152
  bool IsAlive() const { return mWeakPtr && mWeakPtr->IsAlive(); }
153
154
  explicit operator bool() const { return mWeakPtr; }
155
  operator T*() const { return get(); }
156
  T* get() const
157
0
  {
158
0
    if (mCache && !mWeakPtr->IsAlive()) {
159
0
      const_cast<CachedWeakPtr<T, Base>*>(this)->mCache = nullptr;
160
0
    }
161
0
    return mCache;
162
0
  }
163
164
private:
165
  nsWeakPtr mWeakPtr;
166
  T* MOZ_NON_OWNING_REF mCache;
167
};
168
169
0
#define kMOZEditorBogusNodeAttrAtom nsGkAtoms::mozeditorbogusnode
170
0
#define kMOZEditorBogusNodeValue NS_LITERAL_STRING("TRUE")
171
172
/**
173
 * SplitAtEdges is for EditorBase::SplitNodeDeepWithTransaction(),
174
 * HTMLEditor::InsertNodeAtPoint()
175
 */
176
enum class SplitAtEdges
177
{
178
  // EditorBase::SplitNodeDeepWithTransaction() won't split container element
179
  // nodes at their edges.  I.e., when split point is start or end of
180
  // container, it won't be split.
181
  eDoNotCreateEmptyContainer,
182
  // EditorBase::SplitNodeDeepWithTransaction() always splits containers even
183
  // if the split point is at edge of a container.  E.g., if split point is
184
  // start of an inline element, empty inline element is created as a new left
185
  // node.
186
  eAllowToCreateEmptyContainer,
187
};
188
189
/**
190
 * Implementation of an editor object.  it will be the controller/focal point
191
 * for the main editor services. i.e. the GUIManager, publishing, transaction
192
 * manager, event interfaces. the idea for the event interfaces is to have them
193
 * delegate the actual commands to the editor independent of the XPFE
194
 * implementation.
195
 */
196
class EditorBase : public nsIEditor
197
                 , public nsISelectionListener
198
                 , public nsSupportsWeakReference
199
{
200
public:
201
  /****************************************************************************
202
   * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other
203
   *       classes under libeditor except EditorEventListener and
204
   *       HTMLEditorEventListener because each public method which may fire
205
   *       eEditorInput event will need to instantiate new stack class for
206
   *       managing input type value of eEditorInput and cache some objects
207
   *       for smarter handling.  In other words, when you add new root
208
   *       method to edit the DOM tree, you can make your new method public.
209
   ****************************************************************************/
210
211
  typedef dom::Element Element;
212
  typedef dom::Selection Selection;
213
  typedef dom::Text Text;
214
215
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
216
  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase, nsIEditor)
217
218
  // nsIEditor methods
219
  NS_DECL_NSIEDITOR
220
221
  // nsISelectionListener method
222
  NS_DECL_NSISELECTIONLISTENER
223
224
  /**
225
   * The default constructor. This should suffice. the setting of the
226
   * interfaces is done after the construction of the editor class.
227
   */
228
  EditorBase();
229
230
  /**
231
   * Init is to tell the implementation of nsIEditor to begin its services
232
   * @param aDoc          The dom document interface being observed
233
   * @param aRoot         This is the root of the editable section of this
234
   *                      document. If it is null then we get root
235
   *                      from document body.
236
   * @param aSelCon       this should be used to get the selection location
237
   *                      (will be null for HTML editors)
238
   * @param aFlags        A bitmask of flags for specifying the behavior
239
   *                      of the editor.
240
   */
241
  virtual nsresult Init(nsIDocument& doc,
242
                        Element* aRoot,
243
                        nsISelectionController* aSelCon,
244
                        uint32_t aFlags,
245
                        const nsAString& aInitialValue);
246
247
  /**
248
   * PostCreate should be called after Init, and is the time that the editor
249
   * tells its documentStateObservers that the document has been created.
250
   */
251
  nsresult PostCreate();
252
253
  /**
254
   * PreDestroy is called before the editor goes away, and gives the editor a
255
   * chance to tell its documentStateObservers that the document is going away.
256
   * @param aDestroyingFrames set to true when the frames being edited
257
   * are being destroyed (so there is no need to modify any nsISelections,
258
   * nor is it safe to do so)
259
   */
260
  virtual void PreDestroy(bool aDestroyingFrames);
261
262
0
  bool IsInitialized() const { return !!mDocument; }
263
0
  bool Destroyed() const { return mDidPreDestroy; }
264
265
0
  nsIDocument* GetDocument() const { return mDocument; }
266
267
  nsIPresShell* GetPresShell() const
268
0
  {
269
0
    return mDocument ? mDocument->GetShell() : nullptr;
270
0
  }
271
  nsPresContext* GetPresContext() const
272
0
  {
273
0
    nsIPresShell* presShell = GetPresShell();
274
0
    return presShell ? presShell->GetPresContext() : nullptr;
275
0
  }
276
277
  already_AddRefed<nsIWidget> GetWidget();
278
279
  nsISelectionController* GetSelectionController() const
280
0
  {
281
0
    if (mSelectionController) {
282
0
      return mSelectionController;
283
0
    }
284
0
    if (!mDocument) {
285
0
      return nullptr;
286
0
    }
287
0
    nsIPresShell* presShell = mDocument->GetShell();
288
0
    if (!presShell) {
289
0
      return nullptr;
290
0
    }
291
0
    nsISelectionController* sc = static_cast<PresShell*>(presShell);
292
0
    return sc;
293
0
  }
294
295
  nsresult GetSelection(SelectionType aSelectionType,
296
                        Selection** aSelection) const;
297
298
  Selection* GetSelection(SelectionType aSelectionType =
299
                                          SelectionType::eNormal) const
300
0
  {
301
0
    nsISelectionController* sc = GetSelectionController();
302
0
    if (!sc) {
303
0
      return nullptr;
304
0
    }
305
0
    Selection* selection = sc->GetSelection(ToRawSelectionType(aSelectionType));
306
0
    return selection;
307
0
  }
308
309
  /**
310
   * Fast non-refcounting editor root element accessor
311
   */
312
0
  Element* GetRoot() const { return mRootElement; }
313
314
0
  RangeUpdater& RangeUpdaterRef() { return mRangeUpdater; }
315
316
  /**
317
   * Set or unset TextInputListener.  If setting non-nullptr when the editor
318
   * already has a TextInputListener, this will crash in debug build.
319
   */
320
  void SetTextInputListener(TextInputListener* aTextInputListener);
321
322
  /**
323
   * Set or unset IMEContentObserver.  If setting non-nullptr when the editor
324
   * already has an IMEContentObserver, this will crash in debug build.
325
   */
326
  void SetIMEContentObserver(IMEContentObserver* aIMEContentObserver);
327
328
  /**
329
   * Returns current composition.
330
   */
331
  TextComposition* GetComposition() const;
332
333
  /**
334
   * Get preferred IME status of current widget.
335
   */
336
  virtual nsresult GetPreferredIMEState(widget::IMEState* aState);
337
338
  /**
339
   * Returns true if there is composition string and not fixed.
340
   */
341
  bool IsIMEComposing() const;
342
343
  /**
344
   * Commit composition if there is.
345
   * Note that when there is a composition, this requests to commit composition
346
   * to native IME.  Therefore, when there is composition, this can do anything.
347
   * For example, the editor instance, the widget or the process itself may
348
   * be destroyed.
349
   */
350
  nsresult CommitComposition();
351
352
  /**
353
   * ToggleTextDirection() toggles text-direction of the root element.
354
   */
355
  nsresult ToggleTextDirection();
356
357
  /**
358
   * SwitchTextDirectionTo() sets the text-direction of the root element to
359
   * LTR or RTL.
360
   */
361
  enum class TextDirection
362
  {
363
    eLTR,
364
    eRTL,
365
  };
366
  void SwitchTextDirectionTo(TextDirection aTextDirection);
367
368
  /**
369
   * Finalizes selection and caret for the editor.
370
   */
371
  nsresult FinalizeSelection();
372
373
  /**
374
   * Returns true if selection is in an editable element and both the range
375
   * start and the range end are editable.  E.g., even if the selection range
376
   * includes non-editable elements, returns true when one of common ancestors
377
   * of the range start and the range end is editable.  Otherwise, false.
378
   */
379
  bool IsSelectionEditable();
380
381
  /**
382
   * Returns number of undo or redo items.
383
   */
384
  size_t NumberOfUndoItems() const
385
0
  {
386
0
    return mTransactionManager ? mTransactionManager->NumberOfUndoItems() : 0;
387
0
  }
388
  size_t NumberOfRedoItems() const
389
0
  {
390
0
    return mTransactionManager ? mTransactionManager->NumberOfRedoItems() : 0;
391
0
  }
392
393
  /**
394
   * Returns number of maximum undo/redo transactions.
395
   */
396
  int32_t NumberOfMaximumTransactions() const
397
0
  {
398
0
    return mTransactionManager ?
399
0
             mTransactionManager->NumberOfMaximumTransactions() : 0;
400
0
  }
401
402
  /**
403
   * Returns true if this editor can store transactions for undo/redo.
404
   */
405
  bool IsUndoRedoEnabled() const
406
0
  {
407
0
    return mTransactionManager &&
408
0
           mTransactionManager->NumberOfMaximumTransactions();
409
0
  }
410
411
  /**
412
   * Return true if it's possible to undo/redo right now.
413
   */
414
  bool CanUndo() const
415
0
  {
416
0
    return IsUndoRedoEnabled() && NumberOfUndoItems() > 0;
417
0
  }
418
  bool CanRedo() const
419
0
  {
420
0
    return IsUndoRedoEnabled() && NumberOfRedoItems() > 0;
421
0
  }
422
423
  /**
424
   * Enables or disables undo/redo feature.  Returns true if it succeeded,
425
   * otherwise, e.g., we're undoing or redoing, returns false.
426
   */
427
  bool EnableUndoRedo(int32_t aMaxTransactionCount = -1)
428
0
  {
429
0
    if (!mTransactionManager) {
430
0
      mTransactionManager = new TransactionManager();
431
0
    }
432
0
    return mTransactionManager->EnableUndoRedo(aMaxTransactionCount);
433
0
  }
434
  bool DisableUndoRedo()
435
0
  {
436
0
    if (!mTransactionManager) {
437
0
      return true;
438
0
    }
439
0
    return mTransactionManager->DisableUndoRedo();
440
0
  }
441
  bool ClearUndoRedo()
442
0
  {
443
0
    if (!mTransactionManager) {
444
0
      return true;
445
0
    }
446
0
    return mTransactionManager->ClearUndoRedo();
447
0
  }
448
449
  /**
450
   * Adds or removes transaction listener to or from the transaction manager.
451
   * Note that TransactionManager does not check if the listener is in the
452
   * array.  So, caller of AddTransactionListener() needs to manage if it's
453
   * already been registered to the transaction manager.
454
   */
455
  bool AddTransactionListener(nsITransactionListener& aListener)
456
0
  {
457
0
    if (!mTransactionManager) {
458
0
      return false;
459
0
    }
460
0
    return mTransactionManager->AddTransactionListener(aListener);
461
0
  }
462
  bool RemoveTransactionListener(nsITransactionListener& aListener)
463
0
  {
464
0
    if (!mTransactionManager) {
465
0
      return false;
466
0
    }
467
0
    return mTransactionManager->RemoveTransactionListener(aListener);
468
0
  }
469
470
  virtual nsresult HandleKeyPressEvent(WidgetKeyboardEvent* aKeyboardEvent);
471
472
  virtual dom::EventTarget* GetDOMEventTarget() = 0;
473
474
  /**
475
   * Accessor methods to flags.
476
   */
477
0
  uint32_t Flags() const { return mFlags; }
478
479
  nsresult AddFlags(uint32_t aFlags)
480
0
  {
481
0
    const uint32_t kOldFlags = Flags();
482
0
    const uint32_t kNewFlags = (kOldFlags | aFlags);
483
0
    if (kNewFlags == kOldFlags) {
484
0
      return NS_OK;
485
0
    }
486
0
    return SetFlags(kNewFlags); // virtual call and may be expensive.
487
0
  }
488
  nsresult RemoveFlags(uint32_t aFlags)
489
0
  {
490
0
    const uint32_t kOldFlags = Flags();
491
0
    const uint32_t kNewFlags = (kOldFlags & ~aFlags);
492
0
    if (kNewFlags == kOldFlags) {
493
0
      return NS_OK;
494
0
    }
495
0
    return SetFlags(kNewFlags); // virtual call and may be expensive.
496
0
  }
497
  nsresult AddAndRemoveFlags(uint32_t aAddingFlags, uint32_t aRemovingFlags)
498
0
  {
499
0
    MOZ_ASSERT(!(aAddingFlags & aRemovingFlags),
500
0
               "Same flags are specified both adding and removing");
501
0
    const uint32_t kOldFlags = Flags();
502
0
    const uint32_t kNewFlags = ((kOldFlags | aAddingFlags) & ~aRemovingFlags);
503
0
    if (kNewFlags == kOldFlags) {
504
0
      return NS_OK;
505
0
    }
506
0
    return SetFlags(kNewFlags); // virtual call and may be expensive.
507
0
  }
508
509
  bool IsPlaintextEditor() const
510
0
  {
511
0
    return (mFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0;
512
0
  }
513
514
  bool IsSingleLineEditor() const
515
0
  {
516
0
    return (mFlags & nsIPlaintextEditor::eEditorSingleLineMask) != 0;
517
0
  }
518
519
  bool IsPasswordEditor() const
520
0
  {
521
0
    return (mFlags & nsIPlaintextEditor::eEditorPasswordMask) != 0;
522
0
  }
523
524
  // FYI: Both IsRightToLeft() and IsLeftToRight() may return false if
525
  //      the editor inherits the content node's direction.
526
  bool IsRightToLeft() const
527
0
  {
528
0
    return (mFlags & nsIPlaintextEditor::eEditorRightToLeft) != 0;
529
0
  }
530
  bool IsLeftToRight() const
531
0
  {
532
0
    return (mFlags & nsIPlaintextEditor::eEditorLeftToRight) != 0;
533
0
  }
534
535
  bool IsReadonly() const
536
0
  {
537
0
    return (mFlags & nsIPlaintextEditor::eEditorReadonlyMask) != 0;
538
0
  }
539
540
  bool IsDisabled() const
541
0
  {
542
0
    return (mFlags & nsIPlaintextEditor::eEditorDisabledMask) != 0;
543
0
  }
544
545
  bool IsInputFiltered() const
546
0
  {
547
0
    return (mFlags & nsIPlaintextEditor::eEditorFilterInputMask) != 0;
548
0
  }
549
550
  bool IsMailEditor() const
551
0
  {
552
0
    return (mFlags & nsIPlaintextEditor::eEditorMailMask) != 0;
553
0
  }
554
555
  bool IsWrapHackEnabled() const
556
0
  {
557
0
    return (mFlags & nsIPlaintextEditor::eEditorEnableWrapHackMask) != 0;
558
0
  }
559
560
  bool IsFormWidget() const
561
0
  {
562
0
    return (mFlags & nsIPlaintextEditor::eEditorWidgetMask) != 0;
563
0
  }
564
565
  bool NoCSS() const
566
0
  {
567
0
    return (mFlags & nsIPlaintextEditor::eEditorNoCSSMask) != 0;
568
0
  }
569
570
  bool IsInteractionAllowed() const
571
0
  {
572
0
    return (mFlags & nsIPlaintextEditor::eEditorAllowInteraction) != 0;
573
0
  }
574
575
  bool DontEchoPassword() const
576
0
  {
577
0
    return (mFlags & nsIPlaintextEditor::eEditorDontEchoPassword) != 0;
578
0
  }
579
580
  bool ShouldSkipSpellCheck() const
581
0
  {
582
0
    return (mFlags & nsIPlaintextEditor::eEditorSkipSpellCheck) != 0;
583
0
  }
584
585
  bool IsTabbable() const
586
0
  {
587
0
    return IsSingleLineEditor() || IsPasswordEditor() || IsFormWidget() ||
588
0
           IsInteractionAllowed();
589
0
  }
590
591
  bool HasIndependentSelection() const
592
0
  {
593
0
    return !!mSelectionController;
594
0
  }
595
596
  bool IsModifiable() const
597
0
  {
598
0
    return !IsReadonly();
599
0
  }
600
601
  /**
602
   * IsInEditSubAction() return true while the instance is handling an edit
603
   * sub-action.  Otherwise, false.
604
   */
605
0
  bool IsInEditSubAction() const { return mIsInEditSubAction; }
606
607
  /**
608
   * SuppressDispatchingInputEvent() suppresses or unsuppresses dispatching
609
   * "input" event.
610
   */
611
  void SuppressDispatchingInputEvent(bool aSuppress)
612
0
  {
613
0
    mDispatchInputEvent = !aSuppress;
614
0
  }
615
616
  /**
617
   * IsSuppressingDispatchingInputEvent() returns true if the editor stops
618
   * dispatching input event.  Otherwise, false.
619
   */
620
  bool IsSuppressingDispatchingInputEvent() const
621
0
  {
622
0
    return !mDispatchInputEvent;
623
0
  }
624
625
  /**
626
   * Returns true if markNodeDirty() has any effect.  Returns false if
627
   * markNodeDirty() is a no-op.
628
   */
629
  bool OutputsMozDirty() const
630
0
  {
631
0
    // Return true for Composer (!IsInteractionAllowed()) or mail
632
0
    // (IsMailEditor()), but false for webpages.
633
0
    return !IsInteractionAllowed() || IsMailEditor();
634
0
  }
635
636
  /**
637
   * Get the focused content, if we're focused.  Returns null otherwise.
638
   */
639
  virtual nsIContent* GetFocusedContent();
640
641
  /**
642
   * Get the focused content for the argument of some IMEStateManager's
643
   * methods.
644
   */
645
  virtual already_AddRefed<nsIContent> GetFocusedContentForIME();
646
647
  /**
648
   * Whether the aGUIEvent should be handled by this editor or not.  When this
649
   * returns false, The aGUIEvent shouldn't be handled on this editor,
650
   * i.e., The aGUIEvent should be handled by another inner editor or ancestor
651
   * elements.
652
   */
653
  virtual bool IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent);
654
655
  /**
656
   * FindSelectionRoot() returns a selection root of this editor when aNode
657
   * gets focus.  aNode must be a content node or a document node.  When the
658
   * target isn't a part of this editor, returns nullptr.  If this is for
659
   * designMode, you should set the document node to aNode except that an
660
   * element in the document has focus.
661
   */
662
  virtual already_AddRefed<nsIContent> FindSelectionRoot(nsINode* aNode);
663
664
  /**
665
   * This method has to be called by EditorEventListener::Focus.
666
   * All actions that have to be done when the editor is focused needs to be
667
   * added here.
668
   */
669
  void OnFocus(dom::EventTarget* aFocusEventTarget);
670
671
  /** Resyncs spellchecking state (enabled/disabled).  This should be called
672
    * when anything that affects spellchecking state changes, such as the
673
    * spellcheck attribute value.
674
    */
675
  void SyncRealTimeSpell();
676
677
 /**
678
   * This method re-initializes the selection and caret state that are for
679
   * current editor state. When editor session is destroyed, it always reset
680
   * selection state even if this has no focus.  So if destroying editor,
681
   * we have to call this method for focused editor to set selection state.
682
   */
683
 void ReinitializeSelection(Element& aElement);
684
685
protected: // May be called by friends.
686
  /****************************************************************************
687
   * Some classes like TextEditRules, HTMLEditRules, WSRunObject which are
688
   * part of handling edit actions are allowed to call the following protected
689
   * methods.  However, those methods won't prepare caches of some objects
690
   * which are necessary for them.  So, if you want some following methods
691
   * to do that for you, you need to create a wrapper method in public scope
692
   * and call it.
693
   ****************************************************************************/
694
695
  /**
696
   * InsertTextWithTransaction() inserts aStringToInsert to aPointToInsert or
697
   * better insertion point around it.  If aPointToInsert isn't in a text node,
698
   * this method looks for the nearest point in a text node with
699
   * FindBetterInsertionPoint().  If there is no text node, this creates
700
   * new text node and put aStringToInsert to it.
701
   *
702
   * @param aDocument       The document of this editor.
703
   * @param aStringToInsert The string to insert.
704
   * @param aPointToInser   The point to insert aStringToInsert.
705
   *                        Must be valid DOM point.
706
   * @param aPointAfterInsertedString
707
   *                        The point after inserted aStringToInsert.
708
   *                        So, when this method actually inserts string,
709
   *                        this is set to a point in the text node.
710
   *                        Otherwise, this may be set to aPointToInsert.
711
   * @return                When this succeeds to insert the string or
712
   *                        does nothing during composition, returns NS_OK.
713
   *                        Otherwise, an error code.
714
   */
715
  virtual nsresult
716
  InsertTextWithTransaction(nsIDocument& aDocument,
717
                            const nsAString& aStringToInsert,
718
                            const EditorRawDOMPoint& aPointToInsert,
719
                            EditorRawDOMPoint* aPointAfterInsertedString =
720
                              nullptr);
721
722
  /**
723
   * InsertTextIntoTextNodeWithTransaction() inserts aStringToInsert into
724
   * aOffset of aTextNode with transaction.
725
   *
726
   * @param aStringToInsert     String to be inserted.
727
   * @param aTextNode           Text node to contain aStringToInsert.
728
   * @param aOffset             Offset at insertion point in aTextNode.
729
   * @param aSuppressIME        true if it's not a part of IME composition.
730
   *                            E.g., adjusting whitespaces during composition.
731
   *                            false, otherwise.
732
   */
733
  nsresult
734
  InsertTextIntoTextNodeWithTransaction(const nsAString& aStringToInsert,
735
                                        Text& aTextNode, int32_t aOffset,
736
                                        bool aSuppressIME = false);
737
738
  nsresult SetTextImpl(Selection& aSelection,
739
                       const nsAString& aString,
740
                       Text& aTextNode);
741
742
  /**
743
   * DeleteNodeWithTransaction() removes aNode from the DOM tree.
744
   *
745
   * @param aNode       The node which will be removed form the DOM tree.
746
   */
747
  nsresult DeleteNodeWithTransaction(nsINode& aNode);
748
749
  /**
750
   * InsertNodeWithTransaction() inserts aContentToInsert before the child
751
   * specified by aPointToInsert.
752
   *
753
   * @param aContentToInsert    The node to be inserted.
754
   * @param aPointToInsert      The insertion point of aContentToInsert.
755
   *                            If this refers end of the container, the
756
   *                            transaction will append the node to the
757
   *                            container.  Otherwise, will insert the node
758
   *                            before child node referred by this.
759
   */
760
  template<typename PT, typename CT>
761
  nsresult
762
  InsertNodeWithTransaction(nsIContent& aContentToInsert,
763
                            const EditorDOMPointBase<PT, CT>& aPointToInsert);
764
765
  /**
766
   * ReplaceContainerWithTransaction() creates new element whose name is
767
   * aTagName, moves all children in aOldContainer to the new element, then,
768
   * removes aOldContainer from the DOM tree.
769
   *
770
   * @param aOldContainer       The element node which should be replaced
771
   *                            with new element.
772
   * @param aTagName            The name of new element node.
773
   */
774
  already_AddRefed<Element>
775
  ReplaceContainerWithTransaction(Element& aOldContainer,
776
                                  nsAtom& aTagName)
777
0
  {
778
0
    return ReplaceContainerWithTransactionInternal(aOldContainer, aTagName,
779
0
                                                   *nsGkAtoms::_empty,
780
0
                                                   EmptyString(), false);
781
0
  }
782
783
  /**
784
   * ReplaceContainerAndCloneAttributesWithTransaction() creates new element
785
   * whose name is aTagName, copies all attributes from aOldContainer to the
786
   * new element, moves all children in aOldContainer to the new element, then,
787
   * removes aOldContainer from the DOM tree.
788
   *
789
   * @param aOldContainer       The element node which should be replaced
790
   *                            with new element.
791
   * @param aTagName            The name of new element node.
792
   */
793
  already_AddRefed<Element>
794
  ReplaceContainerAndCloneAttributesWithTransaction(Element& aOldContainer,
795
                                                    nsAtom& aTagName)
796
0
  {
797
0
    return ReplaceContainerWithTransactionInternal(aOldContainer, aTagName,
798
0
                                                   *nsGkAtoms::_empty,
799
0
                                                   EmptyString(), true);
800
0
  }
801
802
  /**
803
   * ReplaceContainerWithTransaction() creates new element whose name is
804
   * aTagName, sets aAttributes of the new element to aAttributeValue, moves
805
   * all children in aOldContainer to the new element, then, removes
806
   * aOldContainer from the DOM tree.
807
   *
808
   * @param aOldContainer       The element node which should be replaced
809
   *                            with new element.
810
   * @param aTagName            The name of new element node.
811
   * @param aAttribute          Attribute name to be set to the new element.
812
   * @param aAttributeValue     Attribute value to be set to aAttribute.
813
   */
814
  already_AddRefed<Element>
815
  ReplaceContainerWithTransaction(Element& aOldContainer,
816
                                  nsAtom& aTagName,
817
                                  nsAtom& aAttribute,
818
                                  const nsAString& aAttributeValue)
819
0
  {
820
0
    return ReplaceContainerWithTransactionInternal(aOldContainer, aTagName,
821
0
                                                   aAttribute,
822
0
                                                   aAttributeValue, false);
823
0
  }
824
825
  /**
826
   * CloneAttributesWithTransaction() clones all attributes from
827
   * aSourceElement to aDestElement after removing all attributes in
828
   * aDestElement.
829
   */
830
  void CloneAttributesWithTransaction(Element& aDestElement,
831
                                      Element& aSourceElement);
832
833
  /**
834
   * RemoveContainerWithTransaction() removes aElement from the DOM tree and
835
   * moves all its children to the parent of aElement.
836
   *
837
   * @param aElement            The element to be removed.
838
   */
839
  nsresult RemoveContainerWithTransaction(Element& aElement);
840
841
  /**
842
   * InsertContainerWithTransaction() creates new element whose name is
843
   * aTagName, moves aContent into the new element, then, inserts the new
844
   * element into where aContent was.
845
   * Note that this method does not check if aContent is valid child of
846
   * the new element.  So, callers need to guarantee it.
847
   *
848
   * @param aContent            The content which will be wrapped with new
849
   *                            element.
850
   * @param aTagName            Element name of new element which will wrap
851
   *                            aContent and be inserted into where aContent
852
   *                            was.
853
   * @return                    The new element.
854
   */
855
  already_AddRefed<Element>
856
  InsertContainerWithTransaction(nsIContent& aContent, nsAtom& aTagName)
857
0
  {
858
0
    return InsertContainerWithTransactionInternal(aContent, aTagName,
859
0
                                                  *nsGkAtoms::_empty,
860
0
                                                  EmptyString());
861
0
  }
862
863
  /**
864
   * InsertContainerWithTransaction() creates new element whose name is
865
   * aTagName, sets its aAttribute to aAttributeValue, moves aContent into the
866
   * new element, then, inserts the new element into where aContent was.
867
   * Note that this method does not check if aContent is valid child of
868
   * the new element.  So, callers need to guarantee it.
869
   *
870
   * @param aContent            The content which will be wrapped with new
871
   *                            element.
872
   * @param aTagName            Element name of new element which will wrap
873
   *                            aContent and be inserted into where aContent
874
   *                            was.
875
   * @param aAttribute          Attribute which should be set to the new
876
   *                            element.
877
   * @param aAttributeValue     Value to be set to aAttribute.
878
   * @return                    The new element.
879
   */
880
  already_AddRefed<Element>
881
  InsertContainerWithTransaction(nsIContent& aContent, nsAtom& aTagName,
882
                                 nsAtom& aAttribute,
883
                                 const nsAString& aAttributeValue)
884
0
  {
885
0
    return InsertContainerWithTransactionInternal(aContent, aTagName,
886
0
                                                  aAttribute, aAttributeValue);
887
0
  }
888
889
  /**
890
   * SplitNodeWithTransaction() creates a transaction to create a new node
891
   * (left node) identical to an existing node (right node), and split the
892
   * contents between the same point in both nodes, then, execute the
893
   * transaction.
894
   *
895
   * @param aStartOfRightNode   The point to split.  Its container will be
896
   *                            the right node, i.e., become the new node's
897
   *                            next sibling.  And the point will be start
898
   *                            of the right node.
899
   * @param aError              If succeed, returns no error.  Otherwise, an
900
   *                            error.
901
   */
902
  template<typename PT, typename CT>
903
  already_AddRefed<nsIContent>
904
  SplitNodeWithTransaction(const EditorDOMPointBase<PT, CT>& aStartOfRightNode,
905
                           ErrorResult& aResult);
906
907
  /**
908
   * JoinNodesWithTransaction() joins aLeftNode and aRightNode.  Content of
909
   * aLeftNode will be merged into aRightNode.  Actual implemenation of this
910
   * method is JoinNodesImpl().  So, see its explanation for the detail.
911
   *
912
   * @param aLeftNode   Will be removed from the DOM tree.
913
   * @param aRightNode  The node which will be new container of the content of
914
   *                    aLeftNode.
915
   */
916
  nsresult JoinNodesWithTransaction(nsINode& aLeftNode, nsINode& aRightNode);
917
918
  /**
919
   * MoveNodeWithTransaction() moves aContent to aPointToInsert.
920
   *
921
   * @param aContent        The node to be moved.
922
   */
923
  template<typename PT, typename CT>
924
  nsresult
925
  MoveNodeWithTransaction(nsIContent& aContent,
926
                          const EditorDOMPointBase<PT, CT>& aPointToInsert);
927
928
  /**
929
   * MoveNodeToEndWithTransaction() moves aContent to end of aNewContainer.
930
   *
931
   * @param aContent        The node to be moved.
932
   * @param aNewContainer   The new container which will contain aContent as
933
   *                        its last child.
934
   */
935
  nsresult
936
  MoveNodeToEndWithTransaction(nsIContent& aContent,
937
                               nsINode& aNewContainer)
938
0
  {
939
0
    EditorRawDOMPoint pointToInsert;
940
0
    pointToInsert.SetToEndOf(&aNewContainer);
941
0
    return MoveNodeWithTransaction(aContent, pointToInsert);
942
0
  }
943
944
  /**
945
   * MoveAllChildren() moves all children of aContainer to before
946
   * aPointToInsert.GetChild().
947
   * See explanation of MoveChildren() for the detail of the behavior.
948
   *
949
   * @param aContainer          The container node whose all children should
950
   *                            be moved.
951
   * @param aPointToInsert      The insertion point.  The container must not
952
   *                            be a data node like a text node.
953
   * @param aError              The result.  If this succeeds to move children,
954
   *                            returns NS_OK.  Otherwise, an error.
955
   */
956
  void MoveAllChildren(nsINode& aContainer,
957
                       const EditorRawDOMPoint& aPointToInsert,
958
                       ErrorResult& aError);
959
960
  /**
961
   * MovePreviousSiblings() moves all siblings before aChild (i.e., aChild
962
   * won't be moved) to before aPointToInsert.GetChild().
963
   * See explanation of MoveChildren() for the detail of the behavior.
964
   *
965
   * @param aChild              The node which is next sibling of the last
966
   *                            node to be moved.
967
   * @param aPointToInsert      The insertion point.  The container must not
968
   *                            be a data node like a text node.
969
   * @param aError              The result.  If this succeeds to move children,
970
   *                            returns NS_OK.  Otherwise, an error.
971
   */
972
  void MovePreviousSiblings(nsIContent& aChild,
973
                            const EditorRawDOMPoint& aPointToInsert,
974
                            ErrorResult& aError);
975
976
  /**
977
   * MoveChildren() moves all children between aFirstChild and aLastChild to
978
   * before aPointToInsert.GetChild().
979
   * If some children are moved to different container while this method
980
   * moves other children, they are just ignored.
981
   * If the child node referred by aPointToInsert is moved to different
982
   * container while this method moves children, returns error.
983
   *
984
   * @param aFirstChild         The first child which should be moved to
985
   *                            aPointToInsert.
986
   * @param aLastChild          The last child which should be moved.  This
987
   *                            must be a sibling of aFirstChild and it should
988
   *                            be positioned after aFirstChild in the DOM tree
989
   *                            order.
990
   * @param aPointToInsert      The insertion point.  The container must not
991
   *                            be a data node like a text node.
992
   * @param aError              The result.  If this succeeds to move children,
993
   *                            returns NS_OK.  Otherwise, an error.
994
   */
995
  void MoveChildren(nsIContent& aFirstChild,
996
                    nsIContent& aLastChild,
997
                    const EditorRawDOMPoint& aPointToInsert,
998
                    ErrorResult& aError);
999
1000
  /**
1001
   * CloneAttributeWithTransaction() copies aAttribute of aSourceElement to
1002
   * aDestElement.  If aSourceElement doesn't have aAttribute, this removes
1003
   * aAttribute from aDestElement.
1004
   *
1005
   * @param aAttribute          Attribute name to be cloned.
1006
   * @param aDestElement        Element node which will be set aAttribute or
1007
   *                            whose aAttribute will be removed.
1008
   * @param aSourceElement      Element node which provides the value of
1009
   *                            aAttribute in aDestElement.
1010
   */
1011
  nsresult CloneAttributeWithTransaction(nsAtom& aAttribute,
1012
                                         Element& aDestElement,
1013
                                         Element& aSourceElement);
1014
1015
  /**
1016
   * RemoveAttributeWithTransaction() removes aAttribute from aElement.
1017
   *
1018
   * @param aElement        Element node which will lose aAttribute.
1019
   * @param aAttribute      Attribute name to be removed from aElement.
1020
   */
1021
  nsresult RemoveAttributeWithTransaction(Element& aElement,
1022
                                          nsAtom& aAttribute);
1023
1024
  virtual nsresult RemoveAttributeOrEquivalent(Element* aElement,
1025
                                               nsAtom* aAttribute,
1026
                                               bool aSuppressTransaction) = 0;
1027
1028
  /**
1029
   * SetAttributeWithTransaction() sets aAttribute of aElement to aValue.
1030
   *
1031
   * @param aElement        Element node which will have aAttribute.
1032
   * @param aAttribute      Attribute name to be set.
1033
   * @param aValue          Attribute value be set to aAttribute.
1034
   */
1035
  nsresult SetAttributeWithTransaction(Element& aElement,
1036
                                       nsAtom& aAttribute,
1037
                                       const nsAString& aValue);
1038
1039
  virtual nsresult SetAttributeOrEquivalent(Element* aElement,
1040
                                            nsAtom* aAttribute,
1041
                                            const nsAString& aValue,
1042
                                            bool aSuppressTransaction) = 0;
1043
1044
  /**
1045
   * Method to replace certain CreateElementNS() calls.
1046
   *
1047
   * @param aTag        Tag you want.
1048
   */
1049
  already_AddRefed<Element> CreateHTMLContent(const nsAtom* aTag);
1050
1051
  /**
1052
   * Creates text node which is marked as "maybe modified frequently".
1053
   */
1054
  static already_AddRefed<nsTextNode> CreateTextNode(nsIDocument& aDocument,
1055
                                                     const nsAString& aData);
1056
1057
  /**
1058
   * Create an element node whose name is aTag at before aPointToInsert.  When
1059
   * this succeed to create an element node, this sets aPointToInsert to the
1060
   * new element because the relation of child and offset may be broken.
1061
   * If the caller needs to collapse the selection to next to the new element
1062
   * node, it should call |aPointToInsert.AdvanceOffset()| after calling this.
1063
   *
1064
   * @param aTag            The element name to create.
1065
   * @param aPointToInsert  The insertion point of new element.  If this refers
1066
   *                        end of the container or after, the transaction
1067
   *                        will append the element to the container.
1068
   *                        Otherwise, will insert the element before the
1069
   *                        child node referred by this.
1070
   * @return                The created new element node.
1071
   */
1072
  template<typename PT, typename CT>
1073
  already_AddRefed<Element>
1074
  CreateNodeWithTransaction(nsAtom& aTag,
1075
                            const EditorDOMPointBase<PT, CT>& aPointToInsert);
1076
1077
  /**
1078
   * Create an aggregate transaction for delete selection.  The result may
1079
   * include DeleteNodeTransactions and/or DeleteTextTransactions as its
1080
   * children.
1081
   *
1082
   * @param aAction             The action caused removing the selection.
1083
   * @param aRemovingNode       The node to be removed.
1084
   * @param aOffset             The start offset of the range in aRemovingNode.
1085
   * @param aLength             The length of the range in aRemovingNode.
1086
   * @return                    If it can remove the selection, returns an
1087
   *                            aggregate transaction which has some
1088
   *                            DeleteNodeTransactions and/or
1089
   *                            DeleteTextTransactions as its children.
1090
   */
1091
  already_AddRefed<EditAggregateTransaction>
1092
    CreateTxnForDeleteSelection(EDirection aAction,
1093
                                nsINode** aNode,
1094
                                int32_t* aOffset,
1095
                                int32_t* aLength);
1096
1097
  /**
1098
   * Create a transaction for removing the nodes and/or text in aRange.
1099
   *
1100
   * @param aRangeToDelete      The range to be removed.
1101
   * @param aAction             The action caused removing the range.
1102
   * @param aRemovingNode       The node to be removed.
1103
   * @param aOffset             The start offset of the range in aRemovingNode.
1104
   * @param aLength             The length of the range in aRemovingNode.
1105
   * @return                    The transaction to remove the range.  Its type
1106
   *                            is DeleteNodeTransaction or
1107
   *                            DeleteTextTransaction.
1108
   */
1109
  already_AddRefed<EditTransactionBase>
1110
    CreateTxnForDeleteRange(nsRange* aRangeToDelete,
1111
                            EDirection aAction,
1112
                            nsINode** aRemovingNode,
1113
                            int32_t* aOffset,
1114
                            int32_t* aLength);
1115
1116
  /**
1117
   * DeleteTextWithTransaction() removes text in the range from aCharData.
1118
   *
1119
   * @param aCharData           The data node which should be modified.
1120
   * @param aOffset             Start offset of removing text in aCharData.
1121
   * @param aLength             Length of removing text.
1122
   */
1123
  nsresult DeleteTextWithTransaction(dom::CharacterData& aCharacterData,
1124
                                     uint32_t aOffset, uint32_t aLength);
1125
1126
  /**
1127
   * ReplaceContainerWithTransactionInternal() is implementation of
1128
   * ReplaceContainerWithTransaction() and
1129
   * ReplaceContainerAndCloneAttributesWithTransaction().
1130
   *
1131
   * @param aOldContainer       The element which will be replaced with new
1132
   *                            element.
1133
   * @param aTagName            The name of new element node.
1134
   * @param aAttribute          Attribute name which will be set to the new
1135
   *                            element.  This will be ignored if
1136
   *                            aCloneAllAttributes is set to true.
1137
   * @param aAttributeValue     Attribute value which will be set to
1138
   *                            aAttribute.
1139
   * @param aCloneAllAttributes If true, all attributes of aOldContainer will
1140
   *                            be copied to the new element.
1141
   */
1142
  already_AddRefed<Element>
1143
  ReplaceContainerWithTransactionInternal(Element& aElement,
1144
                                          nsAtom& aTagName,
1145
                                          nsAtom& aAttribute,
1146
                                          const nsAString& aAttributeValue,
1147
                                          bool aCloneAllAttributes);
1148
1149
  /**
1150
   * InsertContainerWithTransactionInternal() creates new element whose name is
1151
   * aTagName, moves aContent into the new element, then, inserts the new
1152
   * element into where aContent was.  If aAttribute is not nsGkAtoms::_empty,
1153
   * aAttribute of the new element will be set to aAttributeValue.
1154
   *
1155
   * @param aContent            The content which will be wrapped with new
1156
   *                            element.
1157
   * @param aTagName            Element name of new element which will wrap
1158
   *                            aContent and be inserted into where aContent
1159
   *                            was.
1160
   * @param aAttribute          Attribute which should be set to the new
1161
   *                            element.  If this is nsGkAtoms::_empty,
1162
   *                            this does not set any attributes to the new
1163
   *                            element.
1164
   * @param aAttributeValue     Value to be set to aAttribute.
1165
   * @return                    The new element.
1166
   */
1167
  already_AddRefed<Element>
1168
  InsertContainerWithTransactionInternal(nsIContent& aContent,
1169
                                         nsAtom& aTagName,
1170
                                         nsAtom& aAttribute,
1171
                                         const nsAString& aAttributeValue);
1172
1173
  /**
1174
   * DoSplitNode() creates a new node (left node) identical to an existing
1175
   * node (right node), and split the contents between the same point in both
1176
   * nodes.
1177
   *
1178
   * @param aStartOfRightNode   The point to split.  Its container will be
1179
   *                            the right node, i.e., become the new node's
1180
   *                            next sibling.  And the point will be start
1181
   *                            of the right node.
1182
   * @param aNewLeftNode        The new node called as left node, so, this
1183
   *                            becomes the container of aPointToSplit's
1184
   *                            previous sibling.
1185
   * @param aError              Must have not already failed.
1186
   *                            If succeed to insert aLeftNode before the
1187
   *                            right node and remove unnecessary contents
1188
   *                            (and collapse selection at end of the left
1189
   *                            node if necessary), returns no error.
1190
   *                            Otherwise, an error.
1191
   */
1192
  void DoSplitNode(const EditorDOMPoint& aStartOfRightNode,
1193
                   nsIContent& aNewLeftNode,
1194
                   ErrorResult& aError);
1195
1196
  /**
1197
   * DoJoinNodes() merges contents in aNodeToJoin to aNodeToKeep and remove
1198
   * aNodeToJoin from the DOM tree.  aNodeToJoin and aNodeToKeep must have
1199
   * same parent, aParent.  Additionally, if one of aNodeToJoin or aNodeToKeep
1200
   * is a text node, the other must be a text node.
1201
   *
1202
   * @param aNodeToKeep   The node that will remain after the join.
1203
   * @param aNodeToJoin   The node that will be joined with aNodeToKeep.
1204
   *                      There is no requirement that the two nodes be of the
1205
   *                      same type.
1206
   * @param aParent       The parent of aNodeToKeep
1207
   */
1208
  nsresult DoJoinNodes(nsINode* aNodeToKeep,
1209
                       nsINode* aNodeToJoin,
1210
                       nsINode* aParent);
1211
1212
  /**
1213
   * SplitNodeDeepWithTransaction() splits aMostAncestorToSplit deeply.
1214
   *
1215
   * @param aMostAncestorToSplit        The most ancestor node which should be
1216
   *                                    split.
1217
   * @param aStartOfDeepestRightNode    The start point of deepest right node.
1218
   *                                    This point must be descendant of
1219
   *                                    aMostAncestorToSplit.
1220
   * @param aSplitAtEdges               Whether the caller allows this to
1221
   *                                    create empty container element when
1222
   *                                    split point is start or end of an
1223
   *                                    element.
1224
   * @return                            SplitPoint() returns split point in
1225
   *                                    aMostAncestorToSplit.  The point must
1226
   *                                    be good to insert something if the
1227
   *                                    caller want to do it.
1228
   */
1229
  template<typename PT, typename CT>
1230
  SplitNodeResult
1231
  SplitNodeDeepWithTransaction(
1232
    nsIContent& aMostAncestorToSplit,
1233
    const EditorDOMPointBase<PT, CT>& aDeepestStartOfRightNode,
1234
    SplitAtEdges aSplitAtEdges);
1235
1236
  /**
1237
   * JoinNodesDeepWithTransaction() joins aLeftNode and aRightNode "deeply".
1238
   * First, they are joined simply, then, new right node is assumed as the
1239
   * child at length of the left node before joined and new left node is
1240
   * assumed as its previous sibling.  Then, they will be joined again.
1241
   * And then, these steps are repeated.
1242
   *
1243
   * @param aLeftNode   The node which will be removed form the tree.
1244
   * @param aRightNode  The node which will be inserted the contents of
1245
   *                    aLeftNode.
1246
   * @return            The point of the first child of the last right node.
1247
   */
1248
  EditorDOMPoint JoinNodesDeepWithTransaction(nsIContent& aLeftNode,
1249
                                              nsIContent& aRightNode);
1250
1251
  /**
1252
   * Note that aSelection is optional and can be nullptr.
1253
   */
1254
  nsresult DoTransaction(Selection* aSelection,
1255
                         nsITransaction* aTxn);
1256
1257
  virtual bool IsBlockNode(nsINode* aNode);
1258
1259
  /**
1260
   * Set outOffset to the offset of aChild in the parent.
1261
   * Returns the parent of aChild.
1262
   */
1263
  static nsINode* GetNodeLocation(nsINode* aChild, int32_t* aOffset);
1264
1265
  /**
1266
   * Get the previous node.
1267
   */
1268
  nsIContent* GetPreviousNode(const EditorRawDOMPoint& aPoint)
1269
0
  {
1270
0
    return GetPreviousNodeInternal(aPoint, false, true, false);
1271
0
  }
1272
  nsIContent* GetPreviousElementOrText(const EditorRawDOMPoint& aPoint)
1273
0
  {
1274
0
    return GetPreviousNodeInternal(aPoint, false, false, false);
1275
0
  }
1276
  nsIContent* GetPreviousEditableNode(const EditorRawDOMPoint& aPoint)
1277
0
  {
1278
0
    return GetPreviousNodeInternal(aPoint, true, true, false);
1279
0
  }
1280
  nsIContent* GetPreviousNodeInBlock(const EditorRawDOMPoint& aPoint)
1281
0
  {
1282
0
    return GetPreviousNodeInternal(aPoint, false, true, true);
1283
0
  }
1284
  nsIContent* GetPreviousElementOrTextInBlock(const EditorRawDOMPoint& aPoint)
1285
0
  {
1286
0
    return GetPreviousNodeInternal(aPoint, false, false, true);
1287
0
  }
1288
  nsIContent* GetPreviousEditableNodeInBlock(
1289
                const EditorRawDOMPoint& aPoint)
1290
0
  {
1291
0
    return GetPreviousNodeInternal(aPoint, true, true, true);
1292
0
  }
1293
  nsIContent* GetPreviousNode(nsINode& aNode)
1294
0
  {
1295
0
    return GetPreviousNodeInternal(aNode, false, true, false);
1296
0
  }
1297
  nsIContent* GetPreviousElementOrText(nsINode& aNode)
1298
0
  {
1299
0
    return GetPreviousNodeInternal(aNode, false, false, false);
1300
0
  }
1301
  nsIContent* GetPreviousEditableNode(nsINode& aNode)
1302
0
  {
1303
0
    return GetPreviousNodeInternal(aNode, true, true, false);
1304
0
  }
1305
  nsIContent* GetPreviousNodeInBlock(nsINode& aNode)
1306
0
  {
1307
0
    return GetPreviousNodeInternal(aNode, false, true, true);
1308
0
  }
1309
  nsIContent* GetPreviousElementOrTextInBlock(nsINode& aNode)
1310
0
  {
1311
0
    return GetPreviousNodeInternal(aNode, false, false, true);
1312
0
  }
1313
  nsIContent* GetPreviousEditableNodeInBlock(nsINode& aNode)
1314
0
  {
1315
0
    return GetPreviousNodeInternal(aNode, true, true, true);
1316
0
  }
1317
1318
  /**
1319
   * Get the next node.
1320
   *
1321
   * Note that methods taking EditorRawDOMPoint behavior includes the
1322
   * child at offset as search target.  E.g., following code causes infinite
1323
   * loop.
1324
   *
1325
   * EditorRawDOMPoint point(aEditableNode);
1326
   * while (nsIContent* content = GetNextEditableNode(point)) {
1327
   *   // Do something...
1328
   *   point.Set(content);
1329
   * }
1330
   *
1331
   * Following code must be you expected:
1332
   *
1333
   * while (nsIContent* content = GetNextEditableNode(point)) {
1334
   *   // Do something...
1335
   *   DebugOnly<bool> advanced = point.Advanced();
1336
   *   MOZ_ASSERT(advanced);
1337
   *   point.Set(point.GetChild());
1338
   * }
1339
   *
1340
   * On the other hand, the methods taking nsINode behavior must be what
1341
   * you want.  They start to search the result from next node of the given
1342
   * node.
1343
   */
1344
  template<typename PT, typename CT>
1345
  nsIContent* GetNextNode(const EditorDOMPointBase<PT, CT>& aPoint)
1346
0
  {
1347
0
    return GetNextNodeInternal(aPoint, false, true, false);
1348
0
  }
1349
  template<typename PT, typename CT>
1350
  nsIContent* GetNextElementOrText(const EditorDOMPointBase<PT, CT>& aPoint)
1351
  {
1352
    return GetNextNodeInternal(aPoint, false, false, false);
1353
  }
1354
  template<typename PT, typename CT>
1355
  nsIContent* GetNextEditableNode(const EditorDOMPointBase<PT, CT>& aPoint)
1356
0
  {
1357
0
    return GetNextNodeInternal(aPoint, true, true, false);
1358
0
  }
Unexecuted instantiation: nsIContent* mozilla::EditorBase::GetNextEditableNode<nsINode*, nsIContent*>(mozilla::EditorDOMPointBase<nsINode*, nsIContent*> const&)
Unexecuted instantiation: nsIContent* mozilla::EditorBase::GetNextEditableNode<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >(mozilla::EditorDOMPointBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> > const&)
1359
  template<typename PT, typename CT>
1360
  nsIContent* GetNextNodeInBlock(const EditorDOMPointBase<PT, CT>& aPoint)
1361
  {
1362
    return GetNextNodeInternal(aPoint, false, true, true);
1363
  }
1364
  template<typename PT, typename CT>
1365
  nsIContent* GetNextElementOrTextInBlock(
1366
                const EditorDOMPointBase<PT, CT>& aPoint)
1367
  {
1368
    return GetNextNodeInternal(aPoint, false, false, true);
1369
  }
1370
  template<typename PT, typename CT>
1371
  nsIContent* GetNextEditableNodeInBlock(
1372
                const EditorDOMPointBase<PT, CT>& aPoint)
1373
0
  {
1374
0
    return GetNextNodeInternal(aPoint, true, true, true);
1375
0
  }
Unexecuted instantiation: nsIContent* mozilla::EditorBase::GetNextEditableNodeInBlock<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >(mozilla::EditorDOMPointBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> > const&)
Unexecuted instantiation: nsIContent* mozilla::EditorBase::GetNextEditableNodeInBlock<nsINode*, nsIContent*>(mozilla::EditorDOMPointBase<nsINode*, nsIContent*> const&)
1376
  nsIContent* GetNextNode(nsINode& aNode)
1377
0
  {
1378
0
    return GetNextNodeInternal(aNode, false, true, false);
1379
0
  }
1380
  nsIContent* GetNextElementOrText(nsINode& aNode)
1381
0
  {
1382
0
    return GetNextNodeInternal(aNode, false, false, false);
1383
0
  }
1384
  nsIContent* GetNextEditableNode(nsINode& aNode)
1385
0
  {
1386
0
    return GetNextNodeInternal(aNode, true, true, false);
1387
0
  }
1388
  nsIContent* GetNextNodeInBlock(nsINode& aNode)
1389
0
  {
1390
0
    return GetNextNodeInternal(aNode, false, true, true);
1391
0
  }
1392
  nsIContent* GetNextElementOrTextInBlock(nsINode& aNode)
1393
0
  {
1394
0
    return GetNextNodeInternal(aNode, false, false, true);
1395
0
  }
1396
  nsIContent* GetNextEditableNodeInBlock(nsINode& aNode)
1397
0
  {
1398
0
    return GetNextNodeInternal(aNode, true, true, true);
1399
0
  }
1400
1401
  /**
1402
   * Get the rightmost child of aCurrentNode;
1403
   * return nullptr if aCurrentNode has no children.
1404
   */
1405
  nsIContent* GetRightmostChild(nsINode* aCurrentNode,
1406
                                bool bNoBlockCrossing = false);
1407
1408
  /**
1409
   * Get the leftmost child of aCurrentNode;
1410
   * return nullptr if aCurrentNode has no children.
1411
   */
1412
  nsIContent* GetLeftmostChild(nsINode *aCurrentNode,
1413
                               bool bNoBlockCrossing = false);
1414
1415
  /**
1416
   * Returns true if aParent can contain a child of type aTag.
1417
   */
1418
  bool CanContain(nsINode& aParent, nsIContent& aChild) const;
1419
  bool CanContainTag(nsINode& aParent, nsAtom& aTag) const;
1420
  bool TagCanContain(nsAtom& aParentTag, nsIContent& aChild) const;
1421
  virtual bool TagCanContainTag(nsAtom& aParentTag, nsAtom& aChildTag) const;
1422
1423
  /**
1424
   * Returns true if aNode is our root node.
1425
   */
1426
  bool IsRoot(nsINode* inNode) const;
1427
  bool IsEditorRoot(nsINode* aNode) const;
1428
1429
  /**
1430
   * Returns true if aNode is a descendant of our root node.
1431
   */
1432
  bool IsDescendantOfRoot(nsINode* inNode) const;
1433
  bool IsDescendantOfEditorRoot(nsINode* aNode) const;
1434
1435
  /**
1436
   * Returns true if aNode is a container.
1437
   */
1438
  virtual bool IsContainer(nsINode* aNode);
1439
1440
  /**
1441
   * returns true if aNode is an editable node.
1442
   */
1443
  bool IsEditable(nsINode* aNode)
1444
0
  {
1445
0
    if (NS_WARN_IF(!aNode)) {
1446
0
      return false;
1447
0
    }
1448
0
1449
0
    if (!aNode->IsContent() || IsMozEditorBogusNode(aNode) ||
1450
0
        !IsModifiableNode(*aNode)) {
1451
0
      return false;
1452
0
    }
1453
0
1454
0
    switch (aNode->NodeType()) {
1455
0
      case nsINode::ELEMENT_NODE:
1456
0
        // In HTML editors, if we're dealing with an element, then ask it
1457
0
        // whether it's editable.
1458
0
        return mIsHTMLEditorClass ? aNode->IsEditable() : true;
1459
0
      case nsINode::TEXT_NODE:
1460
0
        // Text nodes are considered to be editable by both typed of editors.
1461
0
        return true;
1462
0
      default:
1463
0
        return false;
1464
0
    }
1465
0
  }
1466
1467
  /**
1468
   * Returns true if aNode is a usual element node (not bogus node) or
1469
   * a text node.  In other words, returns true if aNode is a usual element
1470
   * node or visible data node.
1471
   */
1472
  bool IsElementOrText(const nsINode& aNode) const
1473
0
  {
1474
0
    if (!aNode.IsContent() || IsMozEditorBogusNode(&aNode)) {
1475
0
      return false;
1476
0
    }
1477
0
    return aNode.NodeType() == nsINode::ELEMENT_NODE ||
1478
0
           aNode.NodeType() == nsINode::TEXT_NODE;
1479
0
  }
1480
1481
  /**
1482
   * Returns true if aNode is a MozEditorBogus node.
1483
   */
1484
  bool IsMozEditorBogusNode(const nsINode* aNode) const
1485
0
  {
1486
0
    return aNode && aNode->IsElement() &&
1487
0
           aNode->AsElement()->AttrValueIs(kNameSpaceID_None,
1488
0
               kMOZEditorBogusNodeAttrAtom, kMOZEditorBogusNodeValue,
1489
0
               eCaseMatters);
1490
0
  }
1491
1492
  /**
1493
   * Counts number of editable child nodes.
1494
   */
1495
  uint32_t CountEditableChildren(nsINode* aNode);
1496
1497
  /**
1498
   * Find the deep first and last children.
1499
   */
1500
  nsINode* GetFirstEditableNode(nsINode* aRoot);
1501
1502
  /**
1503
   * Returns true when inserting text should be a part of current composition.
1504
   */
1505
  bool ShouldHandleIMEComposition() const;
1506
1507
  /**
1508
   * AreNodesSameType() returns true if aNode1 and aNode2 are same type.
1509
   * If the instance is TextEditor, only their names are checked.
1510
   * If the instance is HTMLEditor in CSS mode and both of them are <span>
1511
   * element, their styles are also checked.
1512
   */
1513
  bool AreNodesSameType(nsIContent& aNode1, nsIContent& aNode2) const;
1514
1515
  static bool IsTextNode(nsINode* aNode)
1516
0
  {
1517
0
    return aNode->NodeType() == nsINode::TEXT_NODE;
1518
0
  }
1519
1520
  /**
1521
   * IsModifiableNode() checks whether the node is editable or not.
1522
   */
1523
  bool IsModifiableNode(const nsINode& aNode) const;
1524
1525
  /**
1526
   * GetNodeAtRangeOffsetPoint() returns the node at this position in a range,
1527
   * assuming that the container is the node itself if it's a text node, or
1528
   * the node's parent otherwise.
1529
   */
1530
  static nsIContent* GetNodeAtRangeOffsetPoint(nsINode* aContainer,
1531
                                               int32_t aOffset)
1532
0
  {
1533
0
    return GetNodeAtRangeOffsetPoint(RawRangeBoundary(aContainer, aOffset));
1534
0
  }
1535
  static nsIContent* GetNodeAtRangeOffsetPoint(const RawRangeBoundary& aPoint);
1536
1537
  static EditorRawDOMPoint GetStartPoint(Selection* aSelection);
1538
  static EditorRawDOMPoint GetEndPoint(Selection* aSelection);
1539
1540
  static nsresult GetEndChildNode(Selection* aSelection,
1541
                                  nsIContent** aEndNode);
1542
1543
  /**
1544
   * CollapseSelectionToEnd() collapses the selection to the end of the editor.
1545
   */
1546
  nsresult CollapseSelectionToEnd(Selection* aSelection);
1547
1548
  /**
1549
   * Helpers to add a node to the selection.
1550
   * Used by table cell selection methods.
1551
   */
1552
  nsresult CreateRange(nsINode* aStartContainer, int32_t aStartOffset,
1553
                       nsINode* aEndContainer, int32_t aEndOffset,
1554
                       nsRange** aRange);
1555
1556
  static bool IsPreformatted(nsINode* aNode);
1557
1558
  /**
1559
   * AllowsTransactionsToChangeSelection() returns true if editor allows any
1560
   * transactions to change Selection.  Otherwise, transactions shouldn't
1561
   * change Selection.
1562
   */
1563
  inline bool AllowsTransactionsToChangeSelection() const
1564
0
  {
1565
0
    return mAllowsTransactionsToChangeSelection;
1566
0
  }
1567
1568
  /**
1569
   * MakeThisAllowTransactionsToChangeSelection() with true makes this editor
1570
   * allow transactions to change Selection.  Otherwise, i.e., with false,
1571
   * makes this editor not allow transactions to change Selection.
1572
   */
1573
  inline void MakeThisAllowTransactionsToChangeSelection(bool aAllow)
1574
0
  {
1575
0
    mAllowsTransactionsToChangeSelection = aAllow;
1576
0
  }
1577
1578
  nsresult HandleInlineSpellCheck(EditSubAction aEditSubAction,
1579
                                  Selection& aSelection,
1580
                                  nsINode* previousSelectedNode,
1581
                                  uint32_t previousSelectedOffset,
1582
                                  nsINode* aStartContainer,
1583
                                  uint32_t aStartOffset,
1584
                                  nsINode* aEndContainer,
1585
                                  uint32_t aEndOffset);
1586
1587
  /**
1588
   * Likewise, but gets the editor's root instead, which is different for HTML
1589
   * editors.
1590
   */
1591
  virtual Element* GetEditorRoot() const;
1592
1593
  /**
1594
   * Likewise, but gets the text control element instead of the root for
1595
   * plaintext editors.
1596
   */
1597
  Element* GetExposedRoot() const;
1598
1599
  /**
1600
   * Whether the editor is active on the DOM window.  Note that when this
1601
   * returns true but GetFocusedContent() returns null, it means that this editor was
1602
   * focused when the DOM window was active.
1603
   */
1604
  virtual bool IsActiveInDOMWindow();
1605
1606
  /**
1607
   * GetIMESelectionStartOffsetIn() returns the start offset of IME selection in
1608
   * the aTextNode.  If there is no IME selection, returns -1.
1609
   */
1610
  int32_t GetIMESelectionStartOffsetIn(nsINode* aTextNode);
1611
1612
  /**
1613
   * FindBetterInsertionPoint() tries to look for better insertion point which
1614
   * is typically the nearest text node and offset in it.
1615
   *
1616
   * @param aPoint      Insertion point which the callers found.
1617
   * @return            Better insertion point if there is.  If not returns
1618
   *                    same point as aPoint.
1619
   */
1620
  EditorRawDOMPoint FindBetterInsertionPoint(const EditorRawDOMPoint& aPoint);
1621
1622
  /**
1623
   * HideCaret() hides caret with nsCaret::AddForceHide() or may show carent
1624
   * with nsCaret::RemoveForceHide().  This does NOT set visibility of
1625
   * nsCaret.  Therefore, this is stateless.
1626
   */
1627
  void HideCaret(bool aHide);
1628
1629
protected: // Called by helper classes.
1630
1631
  /**
1632
   * OnStartToHandleTopLevelEditSubAction() is called when
1633
   * mTopLevelEditSubAction is EditSubAction::eNone and somebody starts to
1634
   * handle aEditSubAction.
1635
   *
1636
   * @param aEditSubAction      Top level edit sub action which will be
1637
   *                            handled soon.
1638
   * @param aDirection          Direction of aEditSubAction.
1639
   */
1640
  virtual void
1641
  OnStartToHandleTopLevelEditSubAction(EditSubAction aEditSubAction,
1642
                                       nsIEditor::EDirection aDirection);
1643
1644
  /**
1645
   * OnEndHandlingTopLevelEditSubAction() is called after
1646
   * mTopLevelEditSubAction is handled.
1647
   */
1648
  virtual void OnEndHandlingTopLevelEditSubAction();
1649
1650
  /**
1651
   * Routines for managing the preservation of selection across
1652
   * various editor actions.
1653
   */
1654
  bool ArePreservingSelection();
1655
  void PreserveSelectionAcrossActions(Selection* aSel);
1656
  nsresult RestorePreservedSelection(Selection* aSel);
1657
  void StopPreservingSelection();
1658
1659
  /**
1660
   * (Begin|End)PlaceholderTransaction() are called by AutoPlaceholderBatch.
1661
   * This set of methods are similar to the (Begin|End)Transaction(), but do
1662
   * not use the transaction managers batching feature.  Instead we use a
1663
   * placeholder transaction to wrap up any further transaction while the
1664
   * batch is open.  The advantage of this is that placeholder transactions
1665
   * can later merge, if needed.  Merging is unavailable between transaction
1666
   * manager batches.
1667
   */
1668
  void BeginPlaceholderTransaction(nsAtom* aTransactionName);
1669
  void EndPlaceholderTransaction();
1670
1671
  void BeginUpdateViewBatch();
1672
  void EndUpdateViewBatch();
1673
1674
  /**
1675
   * Used by AutoTransactionBatch.  After calling BeginTransactionInternal(),
1676
   * all transactions will be treated as an atomic transaction.  I.e.,
1677
   * two or more transactions are undid once.
1678
   * XXX What's the difference with PlaceholderTransaction? Should we always
1679
   *     use it instead?
1680
   */
1681
  void BeginTransactionInternal();
1682
  void EndTransactionInternal();
1683
1684
protected: // Shouldn't be used by friend classes
1685
  /**
1686
   * The default destructor. This should suffice. Should this be pure virtual
1687
   * for someone to derive from the EditorBase later? I don't believe so.
1688
   */
1689
  virtual ~EditorBase();
1690
1691
  /**
1692
   * GetDocumentCharsetInternal() returns charset of the document.
1693
   */
1694
  nsresult GetDocumentCharsetInternal(nsACString& aCharset) const;
1695
1696
  /**
1697
   * SelectAllInternal() should be used instead of SelectAll() in editor
1698
   * because SelectAll() creates AutoEditActionSetter but we should avoid
1699
   * to create it as far as possible.
1700
   */
1701
  virtual nsresult SelectAllInternal();
1702
1703
  nsresult DetermineCurrentDirection();
1704
  void FireInputEvent();
1705
1706
  /**
1707
   * Called after a transaction is done successfully.
1708
   */
1709
  void DoAfterDoTransaction(nsITransaction *aTxn);
1710
1711
  /**
1712
   * Called after a transaction is undone successfully.
1713
   */
1714
1715
  void DoAfterUndoTransaction();
1716
1717
  /**
1718
   * Called after a transaction is redone successfully.
1719
   */
1720
  void DoAfterRedoTransaction();
1721
1722
  /**
1723
   * Tell the doc state listeners that the doc state has changed.
1724
   */
1725
  enum TDocumentListenerNotification
1726
  {
1727
    eDocumentCreated,
1728
    eDocumentToBeDestroyed,
1729
    eDocumentStateChanged
1730
  };
1731
  nsresult NotifyDocumentListeners(
1732
             TDocumentListenerNotification aNotificationType);
1733
1734
  /**
1735
   * Make the given selection span the entire document.
1736
   */
1737
  virtual nsresult SelectEntireDocument(Selection* aSelection);
1738
1739
  /**
1740
   * Helper method for scrolling the selection into view after
1741
   * an edit operation. aScrollToAnchor should be true if you
1742
   * want to scroll to the point where the selection was started.
1743
   * If false, it attempts to scroll the end of the selection into view.
1744
   *
1745
   * Editor methods *should* call this method instead of the versions
1746
   * in the various selection interfaces, since this version makes sure
1747
   * that the editor's sync/async settings for reflowing, painting, and
1748
   * scrolling match.
1749
   */
1750
  nsresult ScrollSelectionIntoView(bool aScrollToAnchor);
1751
1752
  /**
1753
   * Helper for GetPreviousNodeInternal() and GetNextNodeInternal().
1754
   */
1755
  nsIContent* FindNextLeafNode(nsINode* aCurrentNode,
1756
                               bool aGoForward,
1757
                               bool bNoBlockCrossing);
1758
  nsIContent* FindNode(nsINode* aCurrentNode,
1759
                       bool aGoForward,
1760
                       bool aEditableNode,
1761
                       bool aFindAnyDataNode,
1762
                       bool bNoBlockCrossing);
1763
1764
  /**
1765
   * Get the node immediately previous node of aNode.
1766
   * @param atNode               The node from which we start the search.
1767
   * @param aFindEditableNode    If true, only return an editable node.
1768
   * @param aFindAnyDataNode     If true, may return invisible data node
1769
   *                             like Comment.
1770
   * @param aNoBlockCrossing     If true, don't move across "block" nodes,
1771
   *                             whatever that means.
1772
   * @return                     The node that occurs before aNode in
1773
   *                             the tree, skipping non-editable nodes if
1774
   *                             aFindEditableNode is true.  If there is no
1775
   *                             previous node, returns nullptr.
1776
   */
1777
  nsIContent* GetPreviousNodeInternal(nsINode& aNode,
1778
                                      bool aFindEditableNode,
1779
                                      bool aFindAnyDataNode,
1780
                                      bool aNoBlockCrossing);
1781
1782
  /**
1783
   * And another version that takes a point in DOM tree rather than a node.
1784
   */
1785
  nsIContent* GetPreviousNodeInternal(const EditorRawDOMPoint& aPoint,
1786
                                      bool aFindEditableNode,
1787
                                      bool aFindAnyDataNode,
1788
                                      bool aNoBlockCrossing);
1789
1790
  /**
1791
   * Get the node immediately next node of aNode.
1792
   * @param aNode                The node from which we start the search.
1793
   * @param aFindEditableNode    If true, only return an editable node.
1794
   * @param aFindAnyDataNode     If true, may return invisible data node
1795
   *                             like Comment.
1796
   * @param aNoBlockCrossing     If true, don't move across "block" nodes,
1797
   *                             whatever that means.
1798
   * @return                     The node that occurs after aNode in the
1799
   *                             tree, skipping non-editable nodes if
1800
   *                             aFindEditableNode is true.  If there is no
1801
   *                             next node, returns nullptr.
1802
   */
1803
  nsIContent* GetNextNodeInternal(nsINode& aNode,
1804
                                  bool aFindEditableNode,
1805
                                  bool aFindAnyDataNode,
1806
                                  bool bNoBlockCrossing);
1807
1808
  /**
1809
   * And another version that takes a point in DOM tree rather than a node.
1810
   */
1811
  nsIContent* GetNextNodeInternal(const EditorRawDOMPoint& aPoint,
1812
                                  bool aFindEditableNode,
1813
                                  bool aFindAnyDataNode,
1814
                                  bool aNoBlockCrossing);
1815
1816
1817
  virtual nsresult InstallEventListeners();
1818
  virtual void CreateEventListeners();
1819
  virtual void RemoveEventListeners();
1820
1821
  /**
1822
   * Get the input event target. This might return null.
1823
   */
1824
  virtual already_AddRefed<nsIContent> GetInputEventTargetContent() = 0;
1825
1826
  /**
1827
   * Return true if spellchecking should be enabled for this editor.
1828
   */
1829
  bool GetDesiredSpellCheckState();
1830
1831
  bool CanEnableSpellCheck()
1832
0
  {
1833
0
    // Check for password/readonly/disabled, which are not spellchecked
1834
0
    // regardless of DOM. Also, check to see if spell check should be skipped
1835
0
    // or not.
1836
0
    return !IsPasswordEditor() && !IsReadonly() && !IsDisabled() &&
1837
0
           !ShouldSkipSpellCheck();
1838
0
  }
1839
1840
  /**
1841
   * InitializeSelectionAncestorLimit() is called by InitializeSelection().
1842
   * When this is called, each implementation has to call
1843
   * aSelection.SetAncestorLimiter() with aAnotherLimit.
1844
   *
1845
   * @param aSelection          The selection.
1846
   * @param aAncestorLimit      New ancestor limit of aSelection.  This always
1847
   *                            has parent node.  So, it's always safe to
1848
   *                            call SetAncestorLimit() with this node.
1849
   */
1850
  virtual void InitializeSelectionAncestorLimit(Selection& aSelection,
1851
                                                nsIContent& aAncestorLimit);
1852
1853
  /**
1854
   * Return the offset of aChild in aParent.  Asserts fatally if parent or
1855
   * child is null, or parent is not child's parent.
1856
   * FYI: aChild must not be being removed from aParent.  In such case, these
1857
   *      methods may return wrong index if aChild doesn't have previous
1858
   *      sibling or next sibling.
1859
   */
1860
  static int32_t GetChildOffset(nsINode* aChild,
1861
                                nsINode* aParent);
1862
1863
  /**
1864
   * Creates a range with just the supplied node and appends that to the
1865
   * selection.
1866
   */
1867
  nsresult AppendNodeToSelectionAsRange(nsINode* aNode);
1868
1869
  /**
1870
   * When you are using AppendNodeToSelectionAsRange(), call this first to
1871
   * start a new selection.
1872
   */
1873
  nsresult ClearSelection();
1874
1875
  /**
1876
   * Initializes selection and caret for the editor.  If aEventTarget isn't
1877
   * a host of the editor, i.e., the editor doesn't get focus, this does
1878
   * nothing.
1879
   */
1880
  nsresult InitializeSelection(dom::EventTarget* aFocusEventTarget);
1881
1882
  /**
1883
   * Used to insert content from a data transfer into the editable area.
1884
   * This is called for each item in the data transfer, with the index of
1885
   * each item passed as aIndex.
1886
   */
1887
  virtual nsresult InsertFromDataTransfer(dom::DataTransfer* aDataTransfer,
1888
                                          int32_t aIndex,
1889
                                          nsIDocument* aSourceDoc,
1890
                                          nsINode* aDestinationNode,
1891
                                          int32_t aDestOffset,
1892
                                          bool aDoDeleteSelection) = 0;
1893
1894
  enum NotificationForEditorObservers
1895
  {
1896
    eNotifyEditorObserversOfEnd,
1897
    eNotifyEditorObserversOfBefore,
1898
    eNotifyEditorObserversOfCancel
1899
  };
1900
  void NotifyEditorObservers(NotificationForEditorObservers aNotification);
1901
1902
private:
1903
  nsCOMPtr<nsISelectionController> mSelectionController;
1904
  nsCOMPtr<nsIDocument> mDocument;
1905
1906
1907
  /**
1908
   * SetTextDirectionTo() sets text-direction of the root element.
1909
   * Should use SwitchTextDirectionTo() or ToggleTextDirection() instead.
1910
   * This is a helper class of them.
1911
   */
1912
  nsresult SetTextDirectionTo(TextDirection aTextDirection);
1913
protected:
1914
  enum Tristate
1915
  {
1916
    eTriUnset,
1917
    eTriFalse,
1918
    eTriTrue
1919
  };
1920
1921
  // MIME type of the doc we are editing.
1922
  nsCString mContentMIMEType;
1923
1924
  RefPtr<mozInlineSpellChecker> mInlineSpellChecker;
1925
  // Reference to text services document for mInlineSpellChecker.
1926
  RefPtr<TextServicesDocument> mTextServicesDocument;
1927
1928
  RefPtr<TransactionManager> mTransactionManager;
1929
  // Cached root node.
1930
  RefPtr<Element> mRootElement;
1931
  // The form field as an event receiver.
1932
  nsCOMPtr<dom::EventTarget> mEventTarget;
1933
  RefPtr<EditorEventListener> mEventListener;
1934
  // Strong reference to placeholder for begin/end batch purposes.
1935
  RefPtr<PlaceholderTransaction> mPlaceholderTransaction;
1936
  // Name of placeholder transaction.
1937
  nsAtom* mPlaceholderName;
1938
  // Saved selection state for placeholder transaction batching.
1939
  mozilla::Maybe<SelectionState> mSelState;
1940
  // IME composition this is not null between compositionstart and
1941
  // compositionend.
1942
  RefPtr<TextComposition> mComposition;
1943
1944
  RefPtr<TextEditRules> mRules;
1945
1946
  RefPtr<TextInputListener> mTextInputListener;
1947
1948
  RefPtr<IMEContentObserver> mIMEContentObserver;
1949
1950
  // Listens to all low level actions on the doc.
1951
  typedef AutoTArray<OwningNonNull<nsIEditActionListener>, 5>
1952
            AutoActionListenerArray;
1953
  AutoActionListenerArray mActionListeners;
1954
  // Just notify once per high level change.
1955
  typedef AutoTArray<OwningNonNull<nsIEditorObserver>, 3>
1956
            AutoEditorObserverArray;
1957
  AutoEditorObserverArray mEditorObservers;
1958
  // Listen to overall doc state (dirty or not, just created, etc.).
1959
  typedef AutoTArray<OwningNonNull<nsIDocumentStateListener>, 1>
1960
            AutoDocumentStateListenerArray;
1961
  AutoDocumentStateListenerArray mDocStateListeners;
1962
1963
  // Cached selection for AutoSelectionRestorer.
1964
  SelectionState mSavedSel;
1965
  // Utility class object for maintaining preserved ranges.
1966
  RangeUpdater mRangeUpdater;
1967
1968
  // Number of modifications (for undo/redo stack).
1969
  uint32_t mModCount;
1970
  // Behavior flags. See nsIPlaintextEditor.idl for the flags we use.
1971
  uint32_t mFlags;
1972
1973
  int32_t mUpdateCount;
1974
1975
  // Nesting count for batching.
1976
  int32_t mPlaceholderBatch;
1977
  // The top level edit sub-action.
1978
  EditSubAction mTopLevelEditSubAction;
1979
1980
  // The top level edit sub-action's direction.
1981
  EDirection mDirection;
1982
  // -1 = not initialized
1983
  int8_t mDocDirtyState;
1984
  // A Tristate value.
1985
  uint8_t mSpellcheckCheckboxState;
1986
1987
  // If false, transactions should not change Selection even after modifying
1988
  // the DOM tree.
1989
  bool mAllowsTransactionsToChangeSelection;
1990
  // Whether PreDestroy has been called.
1991
  bool mDidPreDestroy;
1992
  // Whether PostCreate has been called.
1993
  bool mDidPostCreate;
1994
  bool mDispatchInputEvent;
1995
  // True while the instance is handling an edit sub-action.
1996
  bool mIsInEditSubAction;
1997
  // Whether caret is hidden forcibly.
1998
  bool mHidingCaret;
1999
  // Whether spellchecker dictionary is initialized after focused.
2000
  bool mSpellCheckerDictionaryUpdated;
2001
  // Whether we are an HTML editor class.
2002
  bool mIsHTMLEditorClass;
2003
2004
  friend class AutoPlaceholderBatch;
2005
  friend class AutoSelectionRestorer;
2006
  friend class AutoTopLevelEditSubActionNotifier;
2007
  friend class AutoTransactionBatch;
2008
  friend class AutoTransactionsConserveSelection;
2009
  friend class AutoUpdateViewBatch;
2010
  friend class CompositionTransaction;
2011
  friend class CreateElementTransaction;
2012
  friend class CSSEditUtils;
2013
  friend class DeleteNodeTransaction;
2014
  friend class DeleteRangeTransaction;
2015
  friend class DeleteTextTransaction;
2016
  friend class HTMLEditRules;
2017
  friend class HTMLEditUtils;
2018
  friend class InsertNodeTransaction;
2019
  friend class InsertTextTransaction;
2020
  friend class JoinNodeTransaction;
2021
  friend class SplitNodeTransaction;
2022
  friend class TextEditRules;
2023
  friend class TypeInState;
2024
  friend class WSRunObject;
2025
  friend class nsIEditor;
2026
};
2027
2028
} // namespace mozilla
2029
2030
mozilla::EditorBase*
2031
nsIEditor::AsEditorBase()
2032
0
{
2033
0
  return static_cast<mozilla::EditorBase*>(this);
2034
0
}
2035
2036
const mozilla::EditorBase*
2037
nsIEditor::AsEditorBase() const
2038
0
{
2039
0
  return static_cast<const mozilla::EditorBase*>(this);
2040
0
}
2041
2042
#endif // #ifndef mozilla_EditorBase_h