Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / editor / libeditor / EditorBase.h
blob70f727bcbaf983203252a9488bb006adc25ff1e8
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/. */
6 #ifndef mozilla_EditorBase_h
7 #define mozilla_EditorBase_h
9 #include "mozilla/intl/BidiEmbeddingLevel.h"
10 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc.
11 #include "mozilla/EditAction.h" // for EditAction and EditSubAction
12 #include "mozilla/EditorDOMPoint.h" // for EditorDOMPoint
13 #include "mozilla/EditorForwards.h"
14 #include "mozilla/EventForwards.h" // for InputEventTargetRanges
15 #include "mozilla/Likely.h" // for MOZ_UNLIKELY, MOZ_LIKELY
16 #include "mozilla/Maybe.h" // for Maybe
17 #include "mozilla/OwningNonNull.h" // for OwningNonNull
18 #include "mozilla/PendingStyles.h" // for PendingStyle, PendingStyleCache
19 #include "mozilla/RangeBoundary.h" // for RawRangeBoundary, RangeBoundary
20 #include "mozilla/SelectionState.h" // for RangeUpdater, etc.
21 #include "mozilla/StyleSheet.h" // for StyleSheet
22 #include "mozilla/TransactionManager.h" // for TransactionManager
23 #include "mozilla/WeakPtr.h" // for WeakPtr
24 #include "mozilla/dom/DataTransfer.h" // for dom::DataTransfer
25 #include "mozilla/dom/HTMLBRElement.h" // for dom::HTMLBRElement
26 #include "mozilla/dom/Selection.h"
27 #include "mozilla/dom/Text.h"
28 #include "nsAtom.h" // for nsAtom, nsStaticAtom
29 #include "nsCOMPtr.h" // for already_AddRefed, nsCOMPtr
30 #include "nsCycleCollectionParticipant.h"
31 #include "nsGkAtoms.h"
32 #include "nsIClipboard.h" // for nsIClipboard::ClipboardType
33 #include "nsIContentInlines.h" // for nsINode::IsEditable()
34 #include "nsIEditor.h" // for nsIEditor, etc.
35 #include "nsISelectionController.h" // for nsISelectionController constants
36 #include "nsISelectionListener.h" // for nsISelectionListener
37 #include "nsISupportsImpl.h" // for EditorBase::Release, etc.
38 #include "nsIWeakReferenceUtils.h" // for nsWeakPtr
39 #include "nsLiteralString.h" // for NS_LITERAL_STRING
40 #include "nsPIDOMWindow.h" // for nsPIDOMWindowInner, etc.
41 #include "nsString.h" // for nsCString
42 #include "nsTArray.h" // for nsTArray and AutoTArray
43 #include "nsWeakReference.h" // for nsSupportsWeakReference
44 #include "nscore.h" // for nsresult, nsAString, etc.
46 #include <tuple> // for std::tuple
48 class mozInlineSpellChecker;
49 class nsAtom;
50 class nsCaret;
51 class nsIContent;
52 class nsIDocumentEncoder;
53 class nsIDocumentStateListener;
54 class nsIEditActionListener;
55 class nsINode;
56 class nsIPrincipal;
57 class nsISupports;
58 class nsITransferable;
59 class nsITransaction;
60 class nsIWidget;
61 class nsRange;
63 namespace mozilla {
64 class AlignStateAtSelection;
65 class AutoTransactionsConserveSelection;
66 class AutoUpdateViewBatch;
67 class ErrorResult;
68 class IMEContentObserver;
69 class ListElementSelectionState;
70 class ListItemElementSelectionState;
71 class ParagraphStateAtSelection;
72 class PresShell;
73 class TextComposition;
74 class TextInputListener;
75 class TextServicesDocument;
76 namespace dom {
77 class AbstractRange;
78 class DataTransfer;
79 class Document;
80 class DragEvent;
81 class Element;
82 class EventTarget;
83 class HTMLBRElement;
84 } // namespace dom
86 namespace widget {
87 struct IMEState;
88 } // namespace widget
90 /**
91 * Implementation of an editor object. it will be the controller/focal point
92 * for the main editor services. i.e. the GUIManager, publishing, transaction
93 * manager, event interfaces. the idea for the event interfaces is to have them
94 * delegate the actual commands to the editor independent of the XPFE
95 * implementation.
97 class EditorBase : public nsIEditor,
98 public nsISelectionListener,
99 public nsSupportsWeakReference {
100 public:
101 /****************************************************************************
102 * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other
103 * classes under libeditor except EditorEventListener and
104 * HTMLEditorEventListener because each public method which may fire
105 * eEditorInput event will need to instantiate new stack class for
106 * managing input type value of eEditorInput and cache some objects
107 * for smarter handling. In other words, when you add new root
108 * method to edit the DOM tree, you can make your new method public.
109 ****************************************************************************/
111 using DataTransfer = dom::DataTransfer;
112 using Document = dom::Document;
113 using Element = dom::Element;
114 using InterlinePosition = dom::Selection::InterlinePosition;
115 using Selection = dom::Selection;
116 using Text = dom::Text;
118 enum class EditorType { Text, HTML };
120 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
121 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase, nsIEditor)
123 // nsIEditor methods
124 NS_DECL_NSIEDITOR
126 // nsISelectionListener method
127 NS_DECL_NSISELECTIONLISTENER
130 * The default constructor. This should suffice. the setting of the
131 * interfaces is done after the construction of the editor class.
133 explicit EditorBase(EditorType aEditorType);
135 [[nodiscard]] bool IsInitialized() const {
136 return mDocument && mDidPostCreate;
138 [[nodiscard]] bool IsBeingInitialized() const {
139 return mDocument && !mDidPostCreate;
141 [[nodiscard]] bool Destroyed() const { return mDidPreDestroy; }
143 Document* GetDocument() const { return mDocument; }
144 nsPIDOMWindowOuter* GetWindow() const;
145 nsPIDOMWindowInner* GetInnerWindow() const;
148 * MayHaveMutationEventListeners() returns true when the window may have
149 * mutation event listeners.
151 * @param aMutationEventType One or multiple of NS_EVENT_BITS_MUTATION_*.
152 * @return true if the editor is an HTMLEditor instance,
153 * and at least one of NS_EVENT_BITS_MUTATION_* is
154 * set to the window or in debug build.
156 bool MayHaveMutationEventListeners(
157 uint32_t aMutationEventType = 0xFFFFFFFF) const {
158 if (IsTextEditor()) {
159 // DOM mutation event listeners cannot catch the changes of
160 // <input type="text"> nor <textarea>.
161 return false;
163 #ifdef DEBUG
164 // On debug build, this should always return true for testing complicated
165 // path without mutation event listeners because when mutation event
166 // listeners do not touch the DOM, editor needs to run as there is no
167 // mutation event listeners.
168 return true;
169 #else // #ifdef DEBUG
170 nsPIDOMWindowInner* window = GetInnerWindow();
171 return window ? window->HasMutationListeners(aMutationEventType) : false;
172 #endif // #ifdef DEBUG #else
176 * MayHaveBeforeInputEventListenersForTelemetry() returns true when the
177 * window may have or have had one or more `beforeinput` event listeners.
178 * Note that this may return false even if there is a `beforeinput`.
179 * See nsPIDOMWindowInner::HasBeforeInputEventListenersForTelemetry()'s
180 * comment for the detail.
182 bool MayHaveBeforeInputEventListenersForTelemetry() const {
183 if (const nsPIDOMWindowInner* window = GetInnerWindow()) {
184 return window->HasBeforeInputEventListenersForTelemetry();
186 return false;
190 * MutationObserverHasObservedNodeForTelemetry() returns true when a node in
191 * the window may have been observed by the web apps with a mutation observer
192 * (i.e., `MutationObserver.observe()` called by chrome script and addon's
193 * script does not make this returns true).
194 * Note that this may return false even if there is a node observed by
195 * a MutationObserver. See
196 * nsPIDOMWindowInner::MutationObserverHasObservedNodeForTelemetry()'s comment
197 * for the detail.
199 bool MutationObserverHasObservedNodeForTelemetry() const {
200 if (const nsPIDOMWindowInner* window = GetInnerWindow()) {
201 return window->MutationObserverHasObservedNodeForTelemetry();
203 return false;
207 * This checks whether the call with aPrincipal should or should not be
208 * treated as user input.
210 [[nodiscard]] static bool TreatAsUserInput(nsIPrincipal* aPrincipal);
212 PresShell* GetPresShell() const;
213 nsPresContext* GetPresContext() const;
214 already_AddRefed<nsCaret> GetCaret() const;
216 already_AddRefed<nsIWidget> GetWidget() const;
218 nsISelectionController* GetSelectionController() const;
220 nsresult GetSelection(SelectionType aSelectionType,
221 Selection** aSelection) const;
223 Selection* GetSelection(
224 SelectionType aSelectionType = SelectionType::eNormal) const {
225 if (aSelectionType == SelectionType::eNormal &&
226 IsEditActionDataAvailable()) {
227 return &SelectionRef();
229 nsISelectionController* sc = GetSelectionController();
230 if (!sc) {
231 return nullptr;
233 Selection* selection = sc->GetSelection(ToRawSelectionType(aSelectionType));
234 return selection;
238 * @return Ancestor limiter of normal selection
240 [[nodiscard]] nsIContent* GetSelectionAncestorLimiter() const {
241 Selection* selection = GetSelection(SelectionType::eNormal);
242 return selection ? selection->GetAncestorLimiter() : nullptr;
246 * Create a DataTransfer object that can be shared between the paste event
247 * and pasting into a DOM element.
249 already_AddRefed<DataTransfer> CreateDataTransferForPaste(
250 EventMessage aEventMessage,
251 nsIClipboard::ClipboardType aClipboardType) const;
254 * Fast non-refcounting editor root element accessor
256 Element* GetRoot() const { return mRootElement; }
259 * Likewise, but gets the text control element instead of the root for
260 * plaintext editors.
262 Element* GetExposedRoot() const;
265 * Set or unset TextInputListener. If setting non-nullptr when the editor
266 * already has a TextInputListener, this will crash in debug build.
268 void SetTextInputListener(TextInputListener* aTextInputListener);
271 * Set or unset IMEContentObserver. If setting non-nullptr when the editor
272 * already has an IMEContentObserver, this will crash in debug build.
274 void SetIMEContentObserver(IMEContentObserver* aIMEContentObserver);
277 * Returns current composition.
279 TextComposition* GetComposition() const;
282 * Get preferred IME status of current widget.
284 virtual nsresult GetPreferredIMEState(widget::IMEState* aState);
287 * Returns true if there is composition string and not fixed.
289 bool IsIMEComposing() const;
292 * Commit composition if there is.
293 * Note that when there is a composition, this requests to commit composition
294 * to native IME. Therefore, when there is composition, this can do anything.
295 * For example, the editor instance, the widget or the process itself may
296 * be destroyed.
298 nsresult CommitComposition();
301 * ToggleTextDirection() toggles text-direction of the root element.
303 * @param aPrincipal Set subject principal if it may be called by
304 * JS. If set to nullptr, will be treated as
305 * called by system.
307 MOZ_CAN_RUN_SCRIPT nsresult
308 ToggleTextDirectionAsAction(nsIPrincipal* aPrincipal = nullptr);
311 * SwitchTextDirectionTo() sets the text-direction of the root element to
312 * LTR or RTL.
314 enum class TextDirection {
315 eLTR,
316 eRTL,
318 MOZ_CAN_RUN_SCRIPT void SwitchTextDirectionTo(TextDirection aTextDirection);
321 * Finalizes selection and caret for the editor.
323 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult FinalizeSelection();
326 * Returns true if selection is in an editable element and both the range
327 * start and the range end are editable. E.g., even if the selection range
328 * includes non-editable elements, returns true when one of common ancestors
329 * of the range start and the range end is editable. Otherwise, false.
331 bool IsSelectionEditable();
334 * Returns number of undo or redo items.
336 size_t NumberOfUndoItems() const {
337 return mTransactionManager ? mTransactionManager->NumberOfUndoItems() : 0;
339 size_t NumberOfRedoItems() const {
340 return mTransactionManager ? mTransactionManager->NumberOfRedoItems() : 0;
344 * Returns number of maximum undo/redo transactions.
346 int32_t NumberOfMaximumTransactions() const {
347 return mTransactionManager
348 ? mTransactionManager->NumberOfMaximumTransactions()
349 : 0;
353 * Returns true if this editor can store transactions for undo/redo.
355 bool IsUndoRedoEnabled() const {
356 return mTransactionManager &&
357 mTransactionManager->NumberOfMaximumTransactions();
361 * Return true if it's possible to undo/redo right now.
363 bool CanUndo() const {
364 return IsUndoRedoEnabled() && NumberOfUndoItems() > 0;
366 bool CanRedo() const {
367 return IsUndoRedoEnabled() && NumberOfRedoItems() > 0;
371 * Enables or disables undo/redo feature. Returns true if it succeeded,
372 * otherwise, e.g., we're undoing or redoing, returns false.
374 bool EnableUndoRedo(int32_t aMaxTransactionCount = -1) {
375 if (!mTransactionManager) {
376 mTransactionManager = new TransactionManager();
378 return mTransactionManager->EnableUndoRedo(aMaxTransactionCount);
380 bool DisableUndoRedo() {
381 if (!mTransactionManager) {
382 return true;
384 return mTransactionManager->DisableUndoRedo();
386 bool ClearUndoRedo() {
387 if (!mTransactionManager) {
388 return true;
390 return mTransactionManager->ClearUndoRedo();
394 * See Document::AreClipboardCommandsUnconditionallyEnabled.
396 bool AreClipboardCommandsUnconditionallyEnabled() const;
399 * IsCutCommandEnabled() returns whether cut command can be enabled or
400 * disabled. This always returns true if we're in non-chrome HTML/XHTML
401 * document. Otherwise, same as the result of `IsCopyToClipboardAllowed()`.
403 MOZ_CAN_RUN_SCRIPT bool IsCutCommandEnabled() const;
406 * IsCopyCommandEnabled() returns copy command can be enabled or disabled.
407 * This always returns true if we're in non-chrome HTML/XHTML document.
408 * Otherwise, same as the result of `IsCopyToClipboardAllowed()`.
410 MOZ_CAN_RUN_SCRIPT bool IsCopyCommandEnabled() const;
413 * IsCopyToClipboardAllowed() returns true if the selected content can
414 * be copied into the clipboard. This returns true when:
415 * - `Selection` is not collapsed and we're not a password editor.
416 * - `Selection` is not collapsed and we're a password editor but selection
417 * range is in unmasked range.
419 bool IsCopyToClipboardAllowed() const {
420 AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
421 if (NS_WARN_IF(!editActionData.CanHandle())) {
422 return false;
424 return IsCopyToClipboardAllowedInternal();
428 * HandleDropEvent() is called from EditorEventListener::Drop that is handler
429 * of drop event.
431 MOZ_CAN_RUN_SCRIPT nsresult HandleDropEvent(dom::DragEvent* aDropEvent);
433 MOZ_CAN_RUN_SCRIPT virtual nsresult HandleKeyPressEvent(
434 WidgetKeyboardEvent* aKeyboardEvent);
436 virtual dom::EventTarget* GetDOMEventTarget() const = 0;
439 * OnCompositionStart() is called when editor receives eCompositionStart
440 * event which should be handled in this editor.
442 nsresult OnCompositionStart(WidgetCompositionEvent& aCompositionStartEvent);
445 * OnCompositionChange() is called when editor receives an eCompositioChange
446 * event which should be handled in this editor.
448 * @param aCompositionChangeEvent eCompositionChange event which should
449 * be handled in this editor.
451 MOZ_CAN_RUN_SCRIPT nsresult
452 OnCompositionChange(WidgetCompositionEvent& aCompositionChangeEvent);
455 * OnCompositionEnd() is called when editor receives an eCompositionChange
456 * event and it's followed by eCompositionEnd event and after
457 * OnCompositionChange() is called.
459 MOZ_CAN_RUN_SCRIPT void OnCompositionEnd(
460 WidgetCompositionEvent& aCompositionEndEvent);
463 * Accessor methods to flags.
465 uint32_t Flags() const { return mFlags; }
467 MOZ_CAN_RUN_SCRIPT nsresult AddFlags(uint32_t aFlags) {
468 const uint32_t kOldFlags = Flags();
469 const uint32_t kNewFlags = (kOldFlags | aFlags);
470 if (kNewFlags == kOldFlags) {
471 return NS_OK;
473 return SetFlags(kNewFlags); // virtual call and may be expensive.
475 MOZ_CAN_RUN_SCRIPT nsresult RemoveFlags(uint32_t aFlags) {
476 const uint32_t kOldFlags = Flags();
477 const uint32_t kNewFlags = (kOldFlags & ~aFlags);
478 if (kNewFlags == kOldFlags) {
479 return NS_OK;
481 return SetFlags(kNewFlags); // virtual call and may be expensive.
483 MOZ_CAN_RUN_SCRIPT nsresult AddAndRemoveFlags(uint32_t aAddingFlags,
484 uint32_t aRemovingFlags) {
485 MOZ_ASSERT(!(aAddingFlags & aRemovingFlags),
486 "Same flags are specified both adding and removing");
487 const uint32_t kOldFlags = Flags();
488 const uint32_t kNewFlags = ((kOldFlags | aAddingFlags) & ~aRemovingFlags);
489 if (kNewFlags == kOldFlags) {
490 return NS_OK;
492 return SetFlags(kNewFlags); // virtual call and may be expensive.
495 bool IsSingleLineEditor() const {
496 const bool isSingleLineEditor =
497 (mFlags & nsIEditor::eEditorSingleLineMask) != 0;
498 MOZ_ASSERT_IF(isSingleLineEditor, IsTextEditor());
499 return isSingleLineEditor;
502 bool IsPasswordEditor() const {
503 const bool isPasswordEditor =
504 (mFlags & nsIEditor::eEditorPasswordMask) != 0;
505 MOZ_ASSERT_IF(isPasswordEditor, IsTextEditor());
506 return isPasswordEditor;
509 // FYI: Both IsRightToLeft() and IsLeftToRight() may return false if
510 // the editor inherits the content node's direction.
511 bool IsRightToLeft() const {
512 return (mFlags & nsIEditor::eEditorRightToLeft) != 0;
514 bool IsLeftToRight() const {
515 return (mFlags & nsIEditor::eEditorLeftToRight) != 0;
518 bool IsReadonly() const {
519 return (mFlags & nsIEditor::eEditorReadonlyMask) != 0;
522 bool IsMailEditor() const {
523 return (mFlags & nsIEditor::eEditorMailMask) != 0;
526 bool IsInteractionAllowed() const {
527 const bool isInteractionAllowed =
528 (mFlags & nsIEditor::eEditorAllowInteraction) != 0;
529 MOZ_ASSERT_IF(isInteractionAllowed, IsHTMLEditor());
530 return isInteractionAllowed;
533 bool ShouldSkipSpellCheck() const {
534 return (mFlags & nsIEditor::eEditorSkipSpellCheck) != 0;
537 bool HasIndependentSelection() const {
538 MOZ_ASSERT_IF(mSelectionController, IsTextEditor());
539 return !!mSelectionController;
542 bool IsModifiable() const { return !IsReadonly(); }
545 * IsInEditSubAction() return true while the instance is handling an edit
546 * sub-action. Otherwise, false.
548 bool IsInEditSubAction() const { return mIsInEditSubAction; }
551 * IsEmpty() checks whether the editor is empty. If editor has only padding
552 * <br> element for empty editor, returns true. If editor's root element has
553 * non-empty text nodes or other nodes like <br>, returns false.
555 virtual bool IsEmpty() const = 0;
558 * SuppressDispatchingInputEvent() suppresses or unsuppresses dispatching
559 * "input" event.
561 void SuppressDispatchingInputEvent(bool aSuppress) {
562 mDispatchInputEvent = !aSuppress;
566 * IsSuppressingDispatchingInputEvent() returns true if the editor stops
567 * dispatching input event. Otherwise, false.
569 bool IsSuppressingDispatchingInputEvent() const {
570 return !mDispatchInputEvent;
574 * Returns true if markNodeDirty() has any effect. Returns false if
575 * markNodeDirty() is a no-op.
577 bool OutputsMozDirty() const {
578 // Return true for Composer (!IsInteractionAllowed()) or mail
579 // (IsMailEditor()), but false for webpages.
580 return !IsInteractionAllowed() || IsMailEditor();
584 * Get the focused element, if we're focused. Returns null otherwise.
586 virtual Element* GetFocusedElement() const;
589 * Whether the aGUIEvent should be handled by this editor or not. When this
590 * returns false, The aGUIEvent shouldn't be handled on this editor,
591 * i.e., The aGUIEvent should be handled by another inner editor or ancestor
592 * elements.
594 virtual bool IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent) const;
597 * FindSelectionRoot() returns a selection root of this editor when aNode
598 * gets focus. aNode must be a content node or a document node. When the
599 * target isn't a part of this editor, returns nullptr. If this is for
600 * designMode, you should set the document node to aNode except that an
601 * element in the document has focus.
603 [[nodiscard]] virtual Element* FindSelectionRoot(const nsINode& aNode) const;
606 * OnFocus() is called when we get a focus event.
608 * @param aOriginalEventTargetNode The original event target node of the
609 * focus event.
611 MOZ_CAN_RUN_SCRIPT virtual nsresult OnFocus(
612 const nsINode& aOriginalEventTargetNode);
615 * OnBlur() is called when we're blurred.
617 * @param aEventTarget The event target of the blur event.
619 virtual nsresult OnBlur(const dom::EventTarget* aEventTarget) = 0;
621 /** Resyncs spellchecking state (enabled/disabled). This should be called
622 * when anything that affects spellchecking state changes, such as the
623 * spellcheck attribute value.
625 void SyncRealTimeSpell();
628 * Do "cut".
630 * @param aPrincipal If you know current context is subject
631 * principal or system principal, set it.
632 * When nullptr, this checks it automatically.
634 MOZ_CAN_RUN_SCRIPT nsresult CutAsAction(nsIPrincipal* aPrincipal = nullptr);
637 * CanPaste() returns true if user can paste something at current selection.
639 virtual bool CanPaste(nsIClipboard::ClipboardType aClipboardType) const = 0;
642 * Do "undo" or "redo".
644 * @param aCount How many count of transactions should be
645 * handled.
646 * @param aPrincipal Set subject principal if it may be called by
647 * JS. If set to nullptr, will be treated as
648 * called by system.
650 MOZ_CAN_RUN_SCRIPT nsresult UndoAsAction(uint32_t aCount,
651 nsIPrincipal* aPrincipal = nullptr);
652 MOZ_CAN_RUN_SCRIPT nsresult RedoAsAction(uint32_t aCount,
653 nsIPrincipal* aPrincipal = nullptr);
656 * InsertTextAsAction() inserts aStringToInsert at selection.
657 * Although this method is implementation of nsIEditor.insertText(),
658 * this treats the input is an edit action. If you'd like to insert text
659 * as part of edit action, you probably should use InsertTextAsSubAction().
661 * @param aStringToInsert The string to insert.
662 * @param aPrincipal Set subject principal if it may be called by
663 * JS. If set to nullptr, will be treated as
664 * called by system.
666 MOZ_CAN_RUN_SCRIPT nsresult InsertTextAsAction(
667 const nsAString& aStringToInsert, nsIPrincipal* aPrincipal = nullptr);
670 * InsertLineBreakAsAction() is called when user inputs a line break with
671 * Enter or something. If the instance is `HTMLEditor`, this is called
672 * when Shift + Enter or "insertlinebreak" command.
674 * @param aPrincipal Set subject principal if it may be called by
675 * JS. If set to nullptr, will be treated as
676 * called by system.
678 MOZ_CAN_RUN_SCRIPT virtual nsresult InsertLineBreakAsAction(
679 nsIPrincipal* aPrincipal = nullptr) = 0;
682 * CanDeleteSelection() returns true if `Selection` is not collapsed and
683 * it's allowed to be removed.
685 bool CanDeleteSelection() const {
686 AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
687 if (NS_WARN_IF(!editActionData.CanHandle())) {
688 return false;
690 return IsModifiable() && !SelectionRef().IsCollapsed();
694 * DeleteSelectionAsAction() removes selection content or content around
695 * caret with transactions. This should be used for handling it as an
696 * edit action. If you'd like to remove selection for preparing to insert
697 * something, you probably should use DeleteSelectionAsSubAction().
699 * @param aDirectionAndAmount How much range should be removed.
700 * @param aStripWrappers Whether the parent blocks should be removed
701 * when they become empty.
702 * @param aPrincipal Set subject principal if it may be called by
703 * JS. If set to nullptr, will be treated as
704 * called by system.
706 MOZ_CAN_RUN_SCRIPT nsresult
707 DeleteSelectionAsAction(nsIEditor::EDirection aDirectionAndAmount,
708 nsIEditor::EStripWrappers aStripWrappers,
709 nsIPrincipal* aPrincipal = nullptr);
711 enum class AllowBeforeInputEventCancelable {
713 Yes,
716 enum class PreventSetSelection {
718 Yes,
722 * Replace text in aReplaceRange or all text in this editor with aString and
723 * treat the change as inserting the string.
725 * @param aString The string to set.
726 * @param aReplaceRange The range to be replaced.
727 * If nullptr, all contents will be replaced.
728 * NOTE: Currently, nullptr is not allowed if
729 * the editor is an HTMLEditor.
730 * @param aAllowBeforeInputEventCancelable
731 * Whether `beforeinput` event which will be
732 * dispatched for this can be cancelable or not.
733 * @param aPreventSetSelection
734 * Whether setting selection after replacing text.
735 * If No, selection is the tail of replaced text.
736 * If Yes, selection isn't changed.
737 * @param aPrincipal Set subject principal if it may be called by
738 * JS. If set to nullptr, will be treated as
739 * called by system.
741 MOZ_CAN_RUN_SCRIPT nsresult ReplaceTextAsAction(
742 const nsAString& aString, nsRange* aReplaceRange,
743 AllowBeforeInputEventCancelable aAllowBeforeInputEventCancelable,
744 PreventSetSelection aPreventSetSelection = PreventSetSelection::No,
745 nsIPrincipal* aPrincipal = nullptr);
748 * Can we paste |aTransferable| or, if |aTransferable| is null, will a call
749 * to pasteTransferable later possibly succeed if given an instance of
750 * nsITransferable then? True if the doc is modifiable, and, if
751 * |aTransfeable| is non-null, we have pasteable data in |aTransfeable|.
753 virtual bool CanPasteTransferable(nsITransferable* aTransferable) = 0;
756 * PasteAsAction() pastes clipboard content to Selection. This method
757 * may dispatch ePaste event first. If its defaultPrevent() is called,
758 * this does nothing but returns NS_OK.
760 * @param aClipboardType nsIClipboard::kGlobalClipboard or
761 * nsIClipboard::kSelectionClipboard.
762 * @param aDispatchPasteEvent Yes if this should dispatch ePaste event
763 * before pasting. Otherwise, No.
764 * @param aDataTransfer The object containing the data to use for the
765 * paste operation. May be nullptr, in which case
766 * this will just get the data from the clipboard.
767 * @param aPrincipal Set subject principal if it may be called by
768 * JS. If set to nullptr, will be treated as
769 * called by system.
771 enum class DispatchPasteEvent { No, Yes };
772 MOZ_CAN_RUN_SCRIPT nsresult
773 PasteAsAction(nsIClipboard::ClipboardType aClipboardType,
774 DispatchPasteEvent aDispatchPasteEvent,
775 DataTransfer* aDataTransfer = nullptr,
776 nsIPrincipal* aPrincipal = nullptr);
779 * Paste aTransferable at Selection.
781 * @param aTransferable Must not be nullptr.
782 * @param aDispatchPasteEvent Yes if this should dispatch ePaste event
783 * before pasting. Otherwise, No.
784 * @param aPrincipal Set subject principal if it may be called by
785 * JS. If set to nullptr, will be treated as
786 * called by system.
788 MOZ_CAN_RUN_SCRIPT nsresult PasteTransferableAsAction(
789 nsITransferable* aTransferable, DispatchPasteEvent aDispatchPasteEvent,
790 nsIPrincipal* aPrincipal = nullptr);
793 * PasteAsQuotationAsAction() pastes content in clipboard as quotation.
794 * If the editor is TextEditor or in plaintext mode, will paste the content
795 * with appending ">" to start of each line.
796 * if the editor is HTMLEditor and is not in plaintext mode, will patste it
797 * into newly created blockquote element.
799 * @param aClipboardType nsIClipboard::kGlobalClipboard or
800 * nsIClipboard::kSelectionClipboard.
801 * @param aDispatchPasteEvent Yes if this should dispatch ePaste event
802 * before pasting. Otherwise, No.
803 * @param aDataTransfer The object containing the data to use for the
804 * paste operation. May be nullptr, in which case
805 * this will just get the data from the clipboard.
806 * @param aPrincipal Set subject principal if it may be called by
807 * JS. If set to nullptr, will be treated as
808 * called by system.
810 MOZ_CAN_RUN_SCRIPT nsresult
811 PasteAsQuotationAsAction(nsIClipboard::ClipboardType aClipboardType,
812 DispatchPasteEvent aDispatchPasteEvent,
813 DataTransfer* aDataTransfer = nullptr,
814 nsIPrincipal* aPrincipal = nullptr);
817 * Return true if `beforeinput` or `input` event is being dispatched.
819 [[nodiscard]] bool IsDispatchingInputEvent() const {
820 return mEditActionData && mEditActionData->IsDispatchingInputEvent();
823 protected: // May be used by friends.
824 class AutoEditActionDataSetter;
827 * TopLevelEditSubActionData stores temporary data while we're handling
828 * top-level edit sub-action.
830 struct MOZ_STACK_CLASS TopLevelEditSubActionData final {
831 friend class AutoEditActionDataSetter;
833 // Set selected range before edit. Then, RangeUpdater keep modifying
834 // the range while we're changing the DOM tree.
835 RefPtr<RangeItem> mSelectedRange;
837 // Computing changed range while we're handling sub actions.
838 RefPtr<nsRange> mChangedRange;
840 // XXX In strict speaking, mCachedPendingStyles isn't enough to cache
841 // inline styles because inline style can be specified with "style"
842 // attribute and/or CSS in <style> elements or CSS files. So, we need
843 // to look for better implementation about this.
844 // FYI: Initialization cost of AutoPendingStyleCacheArray is expensive and
845 // it is not used by TextEditor so that we should construct it only
846 // when we're an HTMLEditor.
847 Maybe<AutoPendingStyleCacheArray> mCachedPendingStyles;
849 // If we tried to delete selection, set to true.
850 bool mDidDeleteSelection;
852 // If we have explicitly set selection inter line, set to true.
853 // `AfterEdit()` or something shouldn't overwrite it in such case.
854 bool mDidExplicitlySetInterLine;
856 // If we have deleted non-collapsed range set to true, there are only 2
857 // cases for now:
858 // - non-collapsed range was selected.
859 // - selection was collapsed in a text node and a Unicode character
860 // was removed.
861 bool mDidDeleteNonCollapsedRange;
863 // If we have deleted parent empty blocks, set to true.
864 bool mDidDeleteEmptyParentBlocks;
866 // If we're a contenteditable editor, we temporarily increase edit count
867 // of the document between `BeforeEdit()` and `AfterEdit()`. I.e., if
868 // we increased the count in `BeforeEdit()`, we need to decrease it in
869 // `AfterEdit()`, however, the document may be changed to designMode or
870 // non-editable. Therefore, we need to store with this whether we need
871 // to restore it.
872 bool mRestoreContentEditableCount;
874 // If we explicitly normalized whitespaces around the changed range,
875 // set to true.
876 bool mDidNormalizeWhitespaces;
878 // Set to true by default. If somebody inserts an HTML fragment
879 // intentionally, any empty elements shouldn't be cleaned up later. In the
880 // case this is set to false.
881 // TODO: We should not do this by default. If it's necessary, each edit
882 // action handler do it by itself instead. Then, we can avoid such
883 // unnecessary DOM tree scan.
884 bool mNeedsToCleanUpEmptyElements;
887 * The following methods modifies some data of this struct and
888 * `EditSubActionData` struct. Currently, these are required only
889 * by `HTMLEditor`. Therefore, for cutting the runtime cost of
890 * `TextEditor`, these methods should be called only by `HTMLEditor`.
891 * But it's fine to use these methods in `TextEditor` if necessary.
892 * If so, you need to call `DidDeleteText()` and `DidInsertText()`
893 * from `SetTextNodeWithoutTransaction()`.
895 void DidCreateElement(EditorBase& aEditorBase, Element& aNewElement);
896 void DidInsertContent(EditorBase& aEditorBase, nsIContent& aNewContent);
897 void WillDeleteContent(EditorBase& aEditorBase,
898 nsIContent& aRemovingContent);
899 void DidSplitContent(EditorBase& aEditorBase, nsIContent& aSplitContent,
900 nsIContent& aNewContent);
901 void DidJoinContents(EditorBase& aEditorBase,
902 const EditorRawDOMPoint& aJoinedPoint);
903 void DidInsertText(EditorBase& aEditorBase,
904 const EditorRawDOMPoint& aInsertionBegin,
905 const EditorRawDOMPoint& aInsertionEnd);
906 void DidDeleteText(EditorBase& aEditorBase,
907 const EditorRawDOMPoint& aStartInTextNode);
908 void WillDeleteRange(EditorBase& aEditorBase,
909 const EditorRawDOMPoint& aStart,
910 const EditorRawDOMPoint& aEnd);
912 private:
913 void Clear() {
914 mDidExplicitlySetInterLine = false;
915 // We don't need to clear other members which are referred only when the
916 // editor is an HTML editor anymore. Note that if `mSelectedRange` is
917 // non-nullptr, that means that we're in `HTMLEditor`.
918 if (!mSelectedRange) {
919 return;
921 mSelectedRange->Clear();
922 mChangedRange->Reset();
923 if (mCachedPendingStyles.isSome()) {
924 mCachedPendingStyles->Clear();
926 mDidDeleteSelection = false;
927 mDidDeleteNonCollapsedRange = false;
928 mDidDeleteEmptyParentBlocks = false;
929 mRestoreContentEditableCount = false;
930 mDidNormalizeWhitespaces = false;
931 mNeedsToCleanUpEmptyElements = true;
935 * Extend mChangedRange to include `aNode`.
937 nsresult AddNodeToChangedRange(const HTMLEditor& aHTMLEditor,
938 nsINode& aNode);
941 * Extend mChangedRange to include `aPoint`.
943 nsresult AddPointToChangedRange(const HTMLEditor& aHTMLEditor,
944 const EditorRawDOMPoint& aPoint);
947 * Extend mChangedRange to include `aStart` and `aEnd`.
949 nsresult AddRangeToChangedRange(const HTMLEditor& aHTMLEditor,
950 const EditorRawDOMPoint& aStart,
951 const EditorRawDOMPoint& aEnd);
953 TopLevelEditSubActionData() = default;
954 TopLevelEditSubActionData(const TopLevelEditSubActionData& aOther) = delete;
957 struct MOZ_STACK_CLASS EditSubActionData final {
958 // While this is set to false, TopLevelEditSubActionData::mChangedRange
959 // shouldn't be modified since in some cases, modifying it in the setter
960 // itself may be faster. Note that we should affect this only for current
961 // edit sub action since mutation event listener may edit different range.
962 bool mAdjustChangedRangeFromListener;
964 private:
965 void Clear() { mAdjustChangedRangeFromListener = true; }
967 friend EditorBase;
970 protected: // AutoEditActionDataSetter, this shouldn't be accessed by friends.
972 * SettingDataTransfer enum class is used to specify whether DataTransfer
973 * should be initialized with or without format. For example, when user
974 * uses Accel + Shift + V to paste text without format, DataTransfer should
975 * have only plain/text data to make web apps treat it without format.
977 enum class SettingDataTransfer {
978 eWithFormat,
979 eWithoutFormat,
983 * AutoEditActionDataSetter grabs some necessary objects for handling any
984 * edit actions and store the edit action what we're handling. When this is
985 * created, its pointer is set to the mEditActionData, and this guarantees
986 * the lifetime of grabbing objects until it's destroyed.
988 class MOZ_STACK_CLASS AutoEditActionDataSetter final {
989 public:
990 // NOTE: aPrincipal will be used when we implement "beforeinput" event.
991 // It's set only when maybe we shouldn't dispatch it because of
992 // called by JS. I.e., if this is nullptr, we can always dispatch
993 // it.
994 AutoEditActionDataSetter(const EditorBase& aEditorBase,
995 EditAction aEditAction,
996 nsIPrincipal* aPrincipal = nullptr);
997 ~AutoEditActionDataSetter();
999 void SetSelectionCreatedByDoubleclick(bool aSelectionCreatedByDoubleclick) {
1000 mSelectionCreatedByDoubleclick = aSelectionCreatedByDoubleclick;
1003 [[nodiscard]] bool SelectionCreatedByDoubleclick() const {
1004 return mSelectionCreatedByDoubleclick;
1007 void UpdateEditAction(EditAction aEditAction) {
1008 MOZ_ASSERT(!mHasTriedToDispatchBeforeInputEvent,
1009 "It's too late to update EditAction since this may have "
1010 "already dispatched a beforeinput event");
1011 mEditAction = aEditAction;
1015 * CanHandle() or CanHandleAndHandleBeforeInput() must be called
1016 * immediately after creating the instance. If caller does not need to
1017 * handle "beforeinput" event or caller needs to set additional information
1018 * the events later, use the former. Otherwise, use the latter. If caller
1019 * uses the former, it's required to call MaybeDispatchBeforeInputEvent() by
1020 * itself.
1023 [[nodiscard]] bool CanHandle() const {
1024 #ifdef DEBUG
1025 mHasCanHandleChecked = true;
1026 #endif // #ifdefn DEBUG
1027 // Don't allow to run new edit action when an edit action caused
1028 // destroying the editor while it's being handled.
1029 if (mEditAction != EditAction::eInitializing &&
1030 mEditorWasDestroyedDuringHandlingEditAction) {
1031 NS_WARNING("Editor was destroyed during an edit action being handled");
1032 return false;
1034 return IsDataAvailable();
1036 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1037 CanHandleAndMaybeDispatchBeforeInputEvent() {
1038 if (MOZ_UNLIKELY(NS_WARN_IF(!CanHandle()))) {
1039 return NS_ERROR_NOT_INITIALIZED;
1041 nsresult rv = MaybeFlushPendingNotifications();
1042 if (MOZ_UNLIKELY(NS_FAILED(rv))) {
1043 return rv;
1045 return MaybeDispatchBeforeInputEvent();
1047 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1048 CanHandleAndFlushPendingNotifications() {
1049 if (MOZ_UNLIKELY(NS_WARN_IF(!CanHandle()))) {
1050 return NS_ERROR_NOT_INITIALIZED;
1052 MOZ_ASSERT(MayEditActionRequireLayout(mRawEditAction));
1053 return MaybeFlushPendingNotifications();
1056 [[nodiscard]] bool IsDataAvailable() const {
1057 return mSelection && mEditorBase.mDocument;
1061 * MaybeDispatchBeforeInputEvent() considers whether this instance needs to
1062 * dispatch "beforeinput" event or not. Then,
1063 * mHasTriedToDispatchBeforeInputEvent is set to true.
1065 * @param aDeleteDirectionAndAmount
1066 * If `MayEditActionDeleteAroundCollapsedSelection(
1067 * mEditAction)` returns true, this must be set.
1068 * Otherwise, don't set explicitly.
1069 * @return If this method actually dispatches "beforeinput" event
1070 * and it's canceled, returns
1071 * NS_ERROR_EDITOR_ACTION_CANCELED.
1073 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult MaybeDispatchBeforeInputEvent(
1074 nsIEditor::EDirection aDeleteDirectionAndAmount = nsIEditor::eNone);
1077 * MarkAsBeforeInputHasBeenDispatched() should be called only when updating
1078 * the DOM occurs asynchronously from user input (e.g., inserting blob
1079 * object which is loaded asynchronously) and `beforeinput` has already
1080 * been dispatched (always should be so).
1082 void MarkAsBeforeInputHasBeenDispatched() {
1083 MOZ_ASSERT(!HasTriedToDispatchBeforeInputEvent());
1084 MOZ_ASSERT(mEditAction == EditAction::ePaste ||
1085 mEditAction == EditAction::ePasteAsQuotation ||
1086 mEditAction == EditAction::eDrop);
1087 mHasTriedToDispatchBeforeInputEvent = true;
1091 * MarkAsHandled() is called before dispatching `input` event and notifying
1092 * editor observers. After this is called, any nested edit action become
1093 * non illegal case.
1095 void MarkAsHandled() {
1096 MOZ_ASSERT(!mHandled);
1097 mHandled = true;
1101 * ShouldAlreadyHaveHandledBeforeInputEventDispatching() returns true if the
1102 * edit action requires to handle "beforeinput" event but not yet dispatched
1103 * it nor considered as not dispatched it and can dispatch it when this is
1104 * called.
1106 bool ShouldAlreadyHaveHandledBeforeInputEventDispatching() const {
1107 return !HasTriedToDispatchBeforeInputEvent() &&
1108 NeedsBeforeInputEventHandling(mEditAction) &&
1109 IsBeforeInputEventEnabled() /* &&
1110 // If we still need to dispatch a clipboard event, we should
1111 // dispatch it first, then, we need to dispatch beforeinput
1112 // event later.
1113 !NeedsToDispatchClipboardEvent()*/
1118 * HasTriedToDispatchBeforeInputEvent() returns true if the instance's
1119 * MaybeDispatchBeforeInputEvent() has already been called.
1121 bool HasTriedToDispatchBeforeInputEvent() const {
1122 return mHasTriedToDispatchBeforeInputEvent;
1125 bool IsCanceled() const { return mBeforeInputEventCanceled; }
1128 * Returns a `Selection` for normal selection. The lifetime is guaranteed
1129 * during alive this instance in the stack.
1131 MOZ_KNOWN_LIVE Selection& SelectionRef() const {
1132 MOZ_ASSERT(!mSelection ||
1133 (mSelection->GetType() == SelectionType::eNormal));
1134 return *mSelection;
1137 nsIPrincipal* GetPrincipal() const { return mPrincipal; }
1138 EditAction GetEditAction() const { return mEditAction; }
1140 template <typename PT, typename CT>
1141 void SetSpellCheckRestartPoint(const EditorDOMPointBase<PT, CT>& aPoint) {
1142 MOZ_ASSERT(aPoint.IsSet());
1143 // We should store only container and offset because new content may
1144 // be inserted before referring child.
1145 // XXX Shouldn't we compare whether aPoint is before
1146 // mSpellCheckRestartPoint if it's set.
1147 mSpellCheckRestartPoint =
1148 EditorDOMPoint(aPoint.GetContainer(), aPoint.Offset());
1150 void ClearSpellCheckRestartPoint() { mSpellCheckRestartPoint.Clear(); }
1151 const EditorDOMPoint& GetSpellCheckRestartPoint() const {
1152 return mSpellCheckRestartPoint;
1155 void SetData(const nsAString& aData) {
1156 MOZ_ASSERT(!mHasTriedToDispatchBeforeInputEvent,
1157 "It's too late to set data since this may have already "
1158 "dispatched a beforeinput event");
1159 mData = aData;
1161 const nsString& GetData() const { return mData; }
1163 void SetColorData(const nsAString& aData);
1166 * InitializeDataTransfer(DataTransfer*) sets mDataTransfer to
1167 * aDataTransfer. In this case, aDataTransfer should not be read/write
1168 * because it'll be set to InputEvent.dataTransfer and which should be
1169 * read-only.
1171 void InitializeDataTransfer(DataTransfer* aDataTransfer);
1173 * InitializeDataTransfer(nsITransferable*) creates new DataTransfer
1174 * instance, initializes it with aTransferable and sets mDataTransfer to
1175 * it.
1177 void InitializeDataTransfer(nsITransferable* aTransferable);
1179 * InitializeDataTransfer(const nsAString&) creates new DataTransfer
1180 * instance, initializes it with aString and sets mDataTransfer to it.
1182 void InitializeDataTransfer(const nsAString& aString);
1184 * InitializeDataTransferWithClipboard() creates new DataTransfer instance,
1185 * initializes it with clipboard and sets mDataTransfer to it.
1187 void InitializeDataTransferWithClipboard(
1188 SettingDataTransfer aSettingDataTransfer, DataTransfer* aDataTransfer,
1189 nsIClipboard::ClipboardType aClipboardType);
1190 DataTransfer* GetDataTransfer() const { return mDataTransfer; }
1193 * AppendTargetRange() appends aTargetRange to target ranges. This should
1194 * be used only by edit action handlers which do not want to set target
1195 * ranges to selection ranges.
1197 void AppendTargetRange(dom::StaticRange& aTargetRange);
1200 * Make dispatching `beforeinput` forcibly non-cancelable.
1202 void MakeBeforeInputEventNonCancelable() {
1203 mMakeBeforeInputEventNonCancelable = true;
1207 * NotifyOfDispatchingClipboardEvent() is called after dispatching
1208 * a clipboard event.
1210 void NotifyOfDispatchingClipboardEvent() {
1211 MOZ_ASSERT(NeedsToDispatchClipboardEvent());
1212 MOZ_ASSERT(!mHasTriedToDispatchClipboardEvent);
1213 mHasTriedToDispatchClipboardEvent = true;
1216 void Abort() { mAborted = true; }
1217 bool IsAborted() const { return mAborted; }
1219 void OnEditorDestroy() {
1220 if (!mHandled && mHasTriedToDispatchBeforeInputEvent) {
1221 // Remember the editor was destroyed only when this edit action is being
1222 // handled because they are caused by mutation event listeners or
1223 // something other unexpected event listeners. In the cases, new child
1224 // edit action shouldn't been aborted.
1225 mEditorWasDestroyedDuringHandlingEditAction = true;
1227 if (mParentData) {
1228 mParentData->OnEditorDestroy();
1231 bool HasEditorDestroyedDuringHandlingEditAction() const {
1232 return mEditorWasDestroyedDuringHandlingEditAction;
1235 void SetTopLevelEditSubAction(EditSubAction aEditSubAction,
1236 EDirection aDirection = eNone) {
1237 mTopLevelEditSubAction = aEditSubAction;
1238 TopLevelEditSubActionDataRef().Clear();
1239 switch (mTopLevelEditSubAction) {
1240 case EditSubAction::eInsertNode:
1241 case EditSubAction::eMoveNode:
1242 case EditSubAction::eCreateNode:
1243 case EditSubAction::eSplitNode:
1244 case EditSubAction::eInsertText:
1245 case EditSubAction::eInsertTextComingFromIME:
1246 case EditSubAction::eSetTextProperty:
1247 case EditSubAction::eRemoveTextProperty:
1248 case EditSubAction::eRemoveAllTextProperties:
1249 case EditSubAction::eSetText:
1250 case EditSubAction::eInsertLineBreak:
1251 case EditSubAction::eInsertParagraphSeparator:
1252 case EditSubAction::eCreateOrChangeList:
1253 case EditSubAction::eIndent:
1254 case EditSubAction::eOutdent:
1255 case EditSubAction::eSetOrClearAlignment:
1256 case EditSubAction::eCreateOrRemoveBlock:
1257 case EditSubAction::eFormatBlockForHTMLCommand:
1258 case EditSubAction::eMergeBlockContents:
1259 case EditSubAction::eRemoveList:
1260 case EditSubAction::eCreateOrChangeDefinitionListItem:
1261 case EditSubAction::eInsertElement:
1262 case EditSubAction::eInsertQuotation:
1263 case EditSubAction::eInsertQuotedText:
1264 case EditSubAction::ePasteHTMLContent:
1265 case EditSubAction::eInsertHTMLSource:
1266 case EditSubAction::eSetPositionToAbsolute:
1267 case EditSubAction::eSetPositionToStatic:
1268 case EditSubAction::eDecreaseZIndex:
1269 case EditSubAction::eIncreaseZIndex:
1270 MOZ_ASSERT(aDirection == eNext);
1271 mDirectionOfTopLevelEditSubAction = eNext;
1272 break;
1273 case EditSubAction::eJoinNodes:
1274 case EditSubAction::eDeleteText:
1275 MOZ_ASSERT(aDirection == ePrevious);
1276 mDirectionOfTopLevelEditSubAction = ePrevious;
1277 break;
1278 case EditSubAction::eUndo:
1279 case EditSubAction::eRedo:
1280 case EditSubAction::eComputeTextToOutput:
1281 case EditSubAction::eCreatePaddingBRElementForEmptyEditor:
1282 case EditSubAction::eMaintainWhiteSpaceVisibility:
1283 case EditSubAction::eNone:
1284 case EditSubAction::eReplaceHeadWithHTMLSource:
1285 MOZ_ASSERT(aDirection == eNone);
1286 mDirectionOfTopLevelEditSubAction = eNone;
1287 break;
1288 case EditSubAction::eDeleteNode:
1289 case EditSubAction::eDeleteSelectedContent:
1290 // Unfortunately, eDeleteNode and eDeleteSelectedContent is used with
1291 // any direction. We might have specific sub-action for each
1292 // direction, but there are some points referencing
1293 // eDeleteSelectedContent so that we should keep storing direction
1294 // as-is for now.
1295 mDirectionOfTopLevelEditSubAction = aDirection;
1296 break;
1299 EditSubAction GetTopLevelEditSubAction() const {
1300 MOZ_ASSERT(IsDataAvailable());
1301 return mTopLevelEditSubAction;
1303 EDirection GetDirectionOfTopLevelEditSubAction() const {
1304 return mDirectionOfTopLevelEditSubAction;
1307 const TopLevelEditSubActionData& TopLevelEditSubActionDataRef() const {
1308 return mParentData ? mParentData->TopLevelEditSubActionDataRef()
1309 : mTopLevelEditSubActionData;
1311 TopLevelEditSubActionData& TopLevelEditSubActionDataRef() {
1312 return mParentData ? mParentData->TopLevelEditSubActionDataRef()
1313 : mTopLevelEditSubActionData;
1316 const EditSubActionData& EditSubActionDataRef() const {
1317 return mEditSubActionData;
1319 EditSubActionData& EditSubActionDataRef() { return mEditSubActionData; }
1321 SelectionState& SavedSelectionRef() {
1322 return mParentData ? mParentData->SavedSelectionRef() : mSavedSelection;
1324 const SelectionState& SavedSelectionRef() const {
1325 return mParentData ? mParentData->SavedSelectionRef() : mSavedSelection;
1328 RangeUpdater& RangeUpdaterRef() {
1329 return mParentData ? mParentData->RangeUpdaterRef() : mRangeUpdater;
1331 const RangeUpdater& RangeUpdaterRef() const {
1332 return mParentData ? mParentData->RangeUpdaterRef() : mRangeUpdater;
1335 void UpdateSelectionCache(Selection& aSelection);
1337 bool IsDispatchingInputEvent() const {
1338 return mDispatchingInputEvent ||
1339 (mParentData && mParentData->IsDispatchingInputEvent());
1341 void WillDispatchInputEvent() {
1342 MOZ_ASSERT(!mDispatchingInputEvent);
1343 mDispatchingInputEvent = true;
1345 void DidDispatchInputEvent() {
1346 MOZ_ASSERT(mDispatchingInputEvent);
1347 mDispatchingInputEvent = false;
1350 private:
1351 bool IsBeforeInputEventEnabled() const;
1353 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1354 MaybeFlushPendingNotifications() const;
1356 static bool NeedsBeforeInputEventHandling(EditAction aEditAction) {
1357 MOZ_ASSERT(aEditAction != EditAction::eNone);
1358 switch (aEditAction) {
1359 case EditAction::eNone:
1360 // If we're not handling edit action, we don't need to handle
1361 // "beforeinput" event.
1362 case EditAction::eNotEditing:
1363 // If we're being initialized, we may need to create a padding <br>
1364 // element, but it shouldn't cause `beforeinput` event.
1365 case EditAction::eInitializing:
1366 // If we're just selecting or getting table cells, we shouldn't
1367 // dispatch `beforeinput` event.
1368 case NS_EDIT_ACTION_CASES_ACCESSING_TABLE_DATA_WITHOUT_EDITING:
1369 // If raw level transaction API is used, the API user needs to handle
1370 // both "beforeinput" event and "input" event if it's necessary.
1371 case EditAction::eUnknown:
1372 // Hiding/showing password affects only layout so that we don't need
1373 // to handle beforeinput event for it.
1374 case EditAction::eHidePassword:
1375 // We don't need to dispatch "beforeinput" event before
1376 // "compositionstart".
1377 case EditAction::eStartComposition:
1378 // We don't need to let web apps know the mode change.
1379 case EditAction::eEnableOrDisableCSS:
1380 case EditAction::eEnableOrDisableAbsolutePositionEditor:
1381 case EditAction::eEnableOrDisableResizer:
1382 case EditAction::eEnableOrDisableInlineTableEditingUI:
1383 // We don't need to let contents in chrome's editor to know the size
1384 // change.
1385 case EditAction::eSetWrapWidth:
1386 // While resizing or moving element, we update only shadow, i.e.,
1387 // don't touch to the DOM in content. Therefore, we don't need to
1388 // dispatch "beforeinput" event.
1389 case EditAction::eResizingElement:
1390 case EditAction::eMovingElement:
1391 // Perhaps, we don't need to dispatch "beforeinput" event for
1392 // padding `<br>` element for empty editor because it's internal
1393 // handling and it should be occurred by another change.
1394 case EditAction::eCreatePaddingBRElementForEmptyEditor:
1395 return false;
1396 default:
1397 return true;
1401 bool NeedsToDispatchClipboardEvent() const {
1402 if (mHasTriedToDispatchClipboardEvent) {
1403 return false;
1405 switch (mEditAction) {
1406 case EditAction::ePaste:
1407 case EditAction::ePasteAsQuotation:
1408 case EditAction::eCut:
1409 case EditAction::eCopy:
1410 return true;
1411 default:
1412 return false;
1416 void MarkEditActionCanceled();
1418 EditorBase& mEditorBase;
1419 RefPtr<Selection> mSelection;
1420 nsTArray<OwningNonNull<Selection>> mRetiredSelections;
1422 // True if the selection was created by doubleclicking a word.
1423 bool mSelectionCreatedByDoubleclick{false};
1425 nsCOMPtr<nsIPrincipal> mPrincipal;
1426 // EditAction may be nested, for example, a command may be executed
1427 // from mutation event listener which is run while editor changes
1428 // the DOM tree. In such case, we need to handle edit action separately.
1429 AutoEditActionDataSetter* mParentData;
1431 // Cached selection for AutoSelectionRestorer.
1432 SelectionState mSavedSelection;
1434 // Utility class object for maintaining preserved ranges.
1435 RangeUpdater mRangeUpdater;
1437 // The data should be set to InputEvent.data.
1438 nsString mData;
1440 // The dataTransfer should be set to InputEvent.dataTransfer.
1441 RefPtr<DataTransfer> mDataTransfer;
1443 // They are used for result of InputEvent.getTargetRanges() of beforeinput.
1444 OwningNonNullStaticRangeArray mTargetRanges;
1446 // Start point where spell checker should check from. This is used only
1447 // by TextEditor.
1448 EditorDOMPoint mSpellCheckRestartPoint;
1450 // Different from mTopLevelEditSubAction, its data should be stored only
1451 // in the most ancestor AutoEditActionDataSetter instance since we don't
1452 // want to pay the copying cost and sync cost.
1453 TopLevelEditSubActionData mTopLevelEditSubActionData;
1455 // Different from mTopLevelEditSubActionData, this stores temporaly data
1456 // for current edit sub action.
1457 EditSubActionData mEditSubActionData;
1459 // mEditAction and mRawEditActions stores edit action. The difference of
1460 // them is, if and only if edit actions are nested and parent edit action
1461 // is one of trying to edit something, but nested one is not so, it's
1462 // overwritten by the parent edit action.
1463 EditAction mEditAction;
1464 EditAction mRawEditAction;
1466 // Different from its data, you can refer "current" AutoEditActionDataSetter
1467 // instance's mTopLevelEditSubAction member since it's copied from the
1468 // parent instance at construction and it's always cleared before this
1469 // won't be overwritten and cleared before destruction.
1470 EditSubAction mTopLevelEditSubAction;
1472 EDirection mDirectionOfTopLevelEditSubAction;
1474 bool mAborted;
1476 // Set to true when this handles "beforeinput" event dispatching. Note
1477 // that even if "beforeinput" event shouldn't be dispatched for this,
1478 // instance, this is set to true when it's considered.
1479 bool mHasTriedToDispatchBeforeInputEvent;
1480 // Set to true if "beforeinput" event was dispatched and it's canceled.
1481 bool mBeforeInputEventCanceled;
1482 // Set to true if `beforeinput` event must not be cancelable even if
1483 // its inputType is defined as cancelable by the standards.
1484 bool mMakeBeforeInputEventNonCancelable;
1485 // Set to true when the edit action handler tries to dispatch a clipboard
1486 // event.
1487 bool mHasTriedToDispatchClipboardEvent;
1488 // The editor instance may be destroyed once temporarily if `document.write`
1489 // etc runs. In such case, we should mark this flag of being handled
1490 // edit action.
1491 bool mEditorWasDestroyedDuringHandlingEditAction;
1492 // This is set before dispatching `input` event and notifying editor
1493 // observers.
1494 bool mHandled;
1495 // Whether the editor is dispatching a `beforeinput` or `input` event.
1496 bool mDispatchingInputEvent = false;
1498 #ifdef DEBUG
1499 mutable bool mHasCanHandleChecked = false;
1500 #endif // #ifdef DEBUG
1502 AutoEditActionDataSetter() = delete;
1503 AutoEditActionDataSetter(const AutoEditActionDataSetter& aOther) = delete;
1506 void UpdateEditActionData(const nsAString& aData) {
1507 mEditActionData->SetData(aData);
1510 void NotifyOfDispatchingClipboardEvent() {
1511 MOZ_ASSERT(mEditActionData);
1512 mEditActionData->NotifyOfDispatchingClipboardEvent();
1515 protected: // May be called by friends.
1516 /****************************************************************************
1517 * Some friend classes are allowed to call the following protected methods.
1518 * However, those methods won't prepare caches of some objects which are
1519 * necessary for them. So, if you call them from friend classes, you need
1520 * to make sure that AutoEditActionDataSetter is created.
1521 ****************************************************************************/
1523 bool IsEditActionCanceled() const {
1524 MOZ_ASSERT(mEditActionData);
1525 return mEditActionData->IsCanceled();
1528 bool ShouldAlreadyHaveHandledBeforeInputEventDispatching() const {
1529 MOZ_ASSERT(mEditActionData);
1530 return mEditActionData
1531 ->ShouldAlreadyHaveHandledBeforeInputEventDispatching();
1534 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult MaybeDispatchBeforeInputEvent() {
1535 MOZ_ASSERT(mEditActionData);
1536 return mEditActionData->MaybeDispatchBeforeInputEvent();
1539 void MarkAsBeforeInputHasBeenDispatched() {
1540 MOZ_ASSERT(mEditActionData);
1541 return mEditActionData->MarkAsBeforeInputHasBeenDispatched();
1544 bool HasTriedToDispatchBeforeInputEvent() const {
1545 return mEditActionData &&
1546 mEditActionData->HasTriedToDispatchBeforeInputEvent();
1549 bool IsEditActionDataAvailable() const {
1550 return mEditActionData && mEditActionData->IsDataAvailable();
1553 bool IsTopLevelEditSubActionDataAvailable() const {
1554 return mEditActionData && !!GetTopLevelEditSubAction();
1557 bool IsEditActionAborted() const {
1558 MOZ_ASSERT(mEditActionData);
1559 return mEditActionData->IsAborted();
1562 nsresult GetDataFromDataTransferOrClipboard(
1563 DataTransfer* aDataTransfer, nsITransferable* aTransferable,
1564 nsIClipboard::ClipboardType aClipboardType) const;
1567 * SelectionRef() returns cached normal Selection. This is pretty faster than
1568 * EditorBase::GetSelection() if available.
1569 * Note that this never crash unless public methods ignore the result of
1570 * AutoEditActionDataSetter::CanHandle() and keep handling edit action but any
1571 * methods should stop handling edit action if it returns false.
1573 MOZ_KNOWN_LIVE Selection& SelectionRef() const {
1574 MOZ_ASSERT(mEditActionData);
1575 MOZ_ASSERT(mEditActionData->SelectionRef().GetType() ==
1576 SelectionType::eNormal);
1577 return mEditActionData->SelectionRef();
1580 nsIPrincipal* GetEditActionPrincipal() const {
1581 MOZ_ASSERT(mEditActionData);
1582 return mEditActionData->GetPrincipal();
1586 * GetEditAction() returns EditAction which is being handled. If some
1587 * edit actions are nested, this returns the innermost edit action.
1589 EditAction GetEditAction() const {
1590 return mEditActionData ? mEditActionData->GetEditAction()
1591 : EditAction::eNone;
1595 * GetInputEventData() returns inserting or inserted text value with
1596 * current edit action. The result is proper for InputEvent.data value.
1598 const nsString& GetInputEventData() const {
1599 return mEditActionData ? mEditActionData->GetData() : VoidString();
1603 * GetInputEventDataTransfer() returns inserting or inserted transferable
1604 * content with current edit action. The result is proper for
1605 * InputEvent.dataTransfer value.
1607 DataTransfer* GetInputEventDataTransfer() const {
1608 return mEditActionData ? mEditActionData->GetDataTransfer() : nullptr;
1612 * GetTopLevelEditSubAction() returns the top level edit sub-action.
1613 * For example, if selected content is being replaced with inserted text,
1614 * while removing selected content, the top level edit sub-action may be
1615 * EditSubAction::eDeleteSelectedContent. However, while inserting new
1616 * text, the top level edit sub-action may be EditSubAction::eInsertText.
1617 * So, this result means what we are doing right now unless you're looking
1618 * for a case which the method is called via mutation event listener or
1619 * selectionchange event listener which are fired while handling the edit
1620 * sub-action.
1622 EditSubAction GetTopLevelEditSubAction() const {
1623 return mEditActionData ? mEditActionData->GetTopLevelEditSubAction()
1624 : EditSubAction::eNone;
1628 * GetDirectionOfTopLevelEditSubAction() returns direction which user
1629 * intended for doing the edit sub-action.
1631 EDirection GetDirectionOfTopLevelEditSubAction() const {
1632 return mEditActionData
1633 ? mEditActionData->GetDirectionOfTopLevelEditSubAction()
1634 : eNone;
1638 * SavedSelection() returns reference to saved selection which are
1639 * stored by AutoSelectionRestorer.
1641 SelectionState& SavedSelectionRef() {
1642 MOZ_ASSERT(IsEditActionDataAvailable());
1643 return mEditActionData->SavedSelectionRef();
1645 const SelectionState& SavedSelectionRef() const {
1646 MOZ_ASSERT(IsEditActionDataAvailable());
1647 return mEditActionData->SavedSelectionRef();
1650 RangeUpdater& RangeUpdaterRef() {
1651 MOZ_ASSERT(IsEditActionDataAvailable());
1652 return mEditActionData->RangeUpdaterRef();
1654 const RangeUpdater& RangeUpdaterRef() const {
1655 MOZ_ASSERT(IsEditActionDataAvailable());
1656 return mEditActionData->RangeUpdaterRef();
1659 template <typename PT, typename CT>
1660 void SetSpellCheckRestartPoint(const EditorDOMPointBase<PT, CT>& aPoint) {
1661 MOZ_ASSERT(IsEditActionDataAvailable());
1662 return mEditActionData->SetSpellCheckRestartPoint(aPoint);
1665 void ClearSpellCheckRestartPoint() {
1666 MOZ_ASSERT(IsEditActionDataAvailable());
1667 return mEditActionData->ClearSpellCheckRestartPoint();
1670 const EditorDOMPoint& GetSpellCheckRestartPoint() const {
1671 MOZ_ASSERT(IsEditActionDataAvailable());
1672 return mEditActionData->GetSpellCheckRestartPoint();
1675 const TopLevelEditSubActionData& TopLevelEditSubActionDataRef() const {
1676 MOZ_ASSERT(IsEditActionDataAvailable());
1677 return mEditActionData->TopLevelEditSubActionDataRef();
1679 TopLevelEditSubActionData& TopLevelEditSubActionDataRef() {
1680 MOZ_ASSERT(IsEditActionDataAvailable());
1681 return mEditActionData->TopLevelEditSubActionDataRef();
1684 const EditSubActionData& EditSubActionDataRef() const {
1685 MOZ_ASSERT(IsEditActionDataAvailable());
1686 return mEditActionData->EditSubActionDataRef();
1688 EditSubActionData& EditSubActionDataRef() {
1689 MOZ_ASSERT(IsEditActionDataAvailable());
1690 return mEditActionData->EditSubActionDataRef();
1694 * GetFirstIMESelectionStartPoint() and GetLastIMESelectionEndPoint() returns
1695 * start of first IME selection range or end of last IME selection range if
1696 * there is. Otherwise, returns non-set DOM point.
1698 template <typename EditorDOMPointType>
1699 EditorDOMPointType GetFirstIMESelectionStartPoint() const;
1700 template <typename EditorDOMPointType>
1701 EditorDOMPointType GetLastIMESelectionEndPoint() const;
1704 * IsSelectionRangeContainerNotContent() returns true if one of container
1705 * of selection ranges is not a content node, i.e., a Document node.
1707 bool IsSelectionRangeContainerNotContent() const;
1710 * OnInputText() is called when user inputs text with keyboard or something.
1712 * @param aStringToInsert The string to insert.
1714 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1715 OnInputText(const nsAString& aStringToInsert);
1718 * InsertTextAsSubAction() inserts aStringToInsert at selection. This
1719 * should be used for handling it as an edit sub-action.
1721 * @param aStringToInsert The string to insert.
1722 * @param aSelectionHandling Specify whether selected content should be
1723 * deleted or ignored.
1725 enum class SelectionHandling { Ignore, Delete };
1726 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertTextAsSubAction(
1727 const nsAString& aStringToInsert, SelectionHandling aSelectionHandling);
1730 * Insert aStringToInsert to aPointToInsert or better insertion point around
1731 * it. If aPointToInsert isn't in a text node, this method looks for the
1732 * nearest point in a text node with TextEditor::FindBetterInsertionPoint()
1733 * or EditorDOMPoint::GetPointInTextNodeIfPointingAroundTextNode().
1734 * If there is no text node, this creates new text node and put
1735 * aStringToInsert to it.
1737 * @param aDocument The document of this editor.
1738 * @param aStringToInsert The string to insert.
1739 * @param aPointToInsert The point to insert aStringToInsert.
1740 * Must be valid DOM point.
1741 * @param aInsertTextTo Whether forcibly creates a new `Text` node in
1742 * specific condition or use existing `Text` if
1743 * available.
1745 enum class InsertTextTo {
1746 ExistingTextNodeIfAvailable,
1747 ExistingTextNodeIfAvailableAndNotStart,
1748 AlwaysCreateNewTextNode
1750 [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual Result<InsertTextResult, nsresult>
1751 InsertTextWithTransaction(Document& aDocument,
1752 const nsAString& aStringToInsert,
1753 const EditorDOMPoint& aPointToInsert,
1754 InsertTextTo aInsertTextTo);
1757 * Insert aStringToInsert to aPointToInsert.
1759 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<InsertTextResult, nsresult>
1760 InsertTextIntoTextNodeWithTransaction(
1761 const nsAString& aStringToInsert,
1762 const EditorDOMPointInText& aPointToInsert);
1765 * SetTextNodeWithoutTransaction() is optimized path to set new value to
1766 * the text node directly and without transaction. This is used when
1767 * setting `<input>.value` and `<textarea>.value`.
1769 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1770 SetTextNodeWithoutTransaction(const nsAString& aString, Text& aTextNode);
1773 * DeleteNodeWithTransaction() removes aContent from the DOM tree.
1775 * @param aContent The node which will be removed form the DOM tree.
1777 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1778 DeleteNodeWithTransaction(nsIContent& aContent);
1781 * InsertNodeWithTransaction() inserts aContentToInsert before the child
1782 * specified by aPointToInsert.
1784 * @param aContentToInsert The node to be inserted.
1785 * @param aPointToInsert The insertion point of aContentToInsert.
1786 * If this refers end of the container, the
1787 * transaction will append the node to the
1788 * container. Otherwise, will insert the node
1789 * before child node referred by this.
1790 * @return If succeeded, returns the new content node and
1791 * point to put caret.
1793 template <typename ContentNodeType>
1794 [[nodiscard]] MOZ_CAN_RUN_SCRIPT
1795 Result<CreateNodeResultBase<ContentNodeType>, nsresult>
1796 InsertNodeWithTransaction(ContentNodeType& aContentToInsert,
1797 const EditorDOMPoint& aPointToInsert);
1800 * InsertPaddingBRElementForEmptyLastLineWithTransaction() creates a padding
1801 * <br> element with setting flags to NS_PADDING_FOR_EMPTY_LAST_LINE and
1802 * inserts it around aPointToInsert.
1804 * @param aPointToInsert The DOM point where should be <br> node inserted
1805 * before.
1806 * @return If succeeded, returns the new <br> element and
1807 * point to put caret around it.
1809 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1810 InsertPaddingBRElementForEmptyLastLineWithTransaction(
1811 const EditorDOMPoint& aPointToInsert);
1813 enum class BRElementType {
1814 Normal,
1815 PaddingForEmptyEditor,
1816 PaddingForEmptyLastLine
1819 * Updates the type of aBRElement. If it will be hidden or shown from
1820 * IMEContentObserver and ContentEventHandler points of view, this temporarily
1821 * removes the node and reconnect to the same position.
1823 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1824 UpdateBRElementType(dom::HTMLBRElement& aBRElement, BRElementType aNewType);
1827 * Create and insert a line break to aPointToInsert.
1829 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1830 InsertBRElement(WithTransaction aWithTransaction,
1831 BRElementType aBRElementType,
1832 const EditorDOMPoint& aPointToInsert);
1835 * CloneAttributesWithTransaction() clones all attributes from
1836 * aSourceElement to aDestElement after removing all attributes in
1837 * aDestElement.
1839 MOZ_CAN_RUN_SCRIPT void CloneAttributesWithTransaction(
1840 Element& aDestElement, Element& aSourceElement);
1843 * CloneAttributeWithTransaction() copies aAttribute of aSourceElement to
1844 * aDestElement. If aSourceElement doesn't have aAttribute, this removes
1845 * aAttribute from aDestElement.
1847 * @param aAttribute Attribute name to be cloned.
1848 * @param aDestElement Element node which will be set aAttribute or
1849 * whose aAttribute will be removed.
1850 * @param aSourceElement Element node which provides the value of
1851 * aAttribute in aDestElement.
1853 MOZ_CAN_RUN_SCRIPT nsresult CloneAttributeWithTransaction(
1854 nsAtom& aAttribute, Element& aDestElement, Element& aSourceElement);
1857 * RemoveAttributeWithTransaction() removes aAttribute from aElement.
1859 * @param aElement Element node which will lose aAttribute.
1860 * @param aAttribute Attribute name to be removed from aElement.
1862 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1863 RemoveAttributeWithTransaction(Element& aElement, nsAtom& aAttribute);
1865 MOZ_CAN_RUN_SCRIPT virtual nsresult RemoveAttributeOrEquivalent(
1866 Element* aElement, nsAtom* aAttribute, bool aSuppressTransaction) = 0;
1869 * SetAttributeWithTransaction() sets aAttribute of aElement to aValue.
1871 * @param aElement Element node which will have aAttribute.
1872 * @param aAttribute Attribute name to be set.
1873 * @param aValue Attribute value be set to aAttribute.
1875 MOZ_CAN_RUN_SCRIPT nsresult SetAttributeWithTransaction(
1876 Element& aElement, nsAtom& aAttribute, const nsAString& aValue);
1878 MOZ_CAN_RUN_SCRIPT virtual nsresult SetAttributeOrEquivalent(
1879 Element* aElement, nsAtom* aAttribute, const nsAString& aValue,
1880 bool aSuppressTransaction) = 0;
1883 * Method to replace certain CreateElementNS() calls.
1885 * @param aTag Tag you want.
1887 already_AddRefed<Element> CreateHTMLContent(const nsAtom* aTag) const;
1890 * Creates text node which is marked as "maybe modified frequently" and
1891 * "maybe masked" if this is a password editor.
1893 already_AddRefed<nsTextNode> CreateTextNode(const nsAString& aData) const;
1896 * DoInsertText(), DoDeleteText(), DoReplaceText() and DoSetText() are
1897 * wrapper of `CharacterData::InsertData()`, `CharacterData::DeleteData()`,
1898 * `CharacterData::ReplaceData()` and `CharacterData::SetData()`.
1900 MOZ_CAN_RUN_SCRIPT void DoInsertText(dom::Text& aText, uint32_t aOffset,
1901 const nsAString& aStringToInsert,
1902 ErrorResult& aRv);
1903 MOZ_CAN_RUN_SCRIPT void DoDeleteText(dom::Text& aText, uint32_t aOffset,
1904 uint32_t aCount, ErrorResult& aRv);
1905 MOZ_CAN_RUN_SCRIPT void DoReplaceText(dom::Text& aText, uint32_t aOffset,
1906 uint32_t aCount,
1907 const nsAString& aStringToInsert,
1908 ErrorResult& aRv);
1909 MOZ_CAN_RUN_SCRIPT void DoSetText(dom::Text& aText,
1910 const nsAString& aStringToSet,
1911 ErrorResult& aRv);
1914 * Delete text in the range in aTextNode. Use
1915 * `HTMLEditor::ReplaceTextWithTransaction` if you'll insert text there (and
1916 * if you want to use it in `TextEditor`, move it into `EditorBase`).
1918 * @param aTextNode The text node which should be modified.
1919 * @param aOffset Start offset of removing text in aTextNode.
1920 * @param aLength Length of removing text.
1922 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
1923 DeleteTextWithTransaction(dom::Text& aTextNode, uint32_t aOffset,
1924 uint32_t aLength);
1927 * MarkElementDirty() sets a special dirty attribute on the element.
1928 * Usually this will be called immediately after creating a new node.
1930 * @param aElement The element for which to insert formatting.
1932 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1933 MarkElementDirty(Element& aElement) const;
1935 MOZ_CAN_RUN_SCRIPT nsresult
1936 DoTransactionInternal(nsITransaction* aTransaction);
1939 * Returns true if aNode is our root node. The root is:
1940 * If TextEditor, the anonymous <div> element.
1941 * If HTMLEditor, a <body> element or the document element which may not be
1942 * editable if it's not in the design mode.
1944 bool IsRoot(const nsINode* inNode) const;
1947 * Returns true if aNode is a descendant of our root node.
1948 * See the comment for IsRoot() for what the root node means.
1950 bool IsDescendantOfRoot(const nsINode* inNode) const;
1953 * Returns true when inserting text should be a part of current composition.
1955 bool ShouldHandleIMEComposition() const;
1957 template <typename EditorDOMPointType>
1958 EditorDOMPointType GetFirstSelectionStartPoint() const;
1959 template <typename EditorDOMPointType>
1960 EditorDOMPointType GetFirstSelectionEndPoint() const;
1962 static nsresult GetEndChildNode(const Selection& aSelection,
1963 nsIContent** aEndNode);
1965 template <typename PT, typename CT>
1966 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1967 CollapseSelectionTo(const EditorDOMPointBase<PT, CT>& aPoint) const {
1968 // We don't need to throw exception directly for a failure of updating
1969 // selection. Therefore, let's use IgnoredErrorResult for the performance.
1970 IgnoredErrorResult error;
1971 CollapseSelectionTo(aPoint, error);
1972 return error.StealNSResult();
1975 template <typename PT, typename CT>
1976 MOZ_CAN_RUN_SCRIPT void CollapseSelectionTo(
1977 const EditorDOMPointBase<PT, CT>& aPoint, ErrorResult& aRv) const {
1978 MOZ_ASSERT(IsEditActionDataAvailable());
1979 MOZ_ASSERT(!aRv.Failed());
1981 if (aPoint.GetInterlinePosition() != InterlinePosition::Undefined) {
1982 if (MOZ_UNLIKELY(NS_FAILED(SelectionRef().SetInterlinePosition(
1983 aPoint.GetInterlinePosition())))) {
1984 NS_WARNING("Selection::SetInterlinePosition() failed");
1985 aRv.Throw(NS_ERROR_FAILURE);
1986 return;
1990 SelectionRef().CollapseInLimiter(aPoint, aRv);
1991 if (MOZ_UNLIKELY(Destroyed())) {
1992 NS_WARNING("Selection::CollapseInLimiter() caused destroying the editor");
1993 aRv.Throw(NS_ERROR_EDITOR_DESTROYED);
1994 return;
1996 NS_WARNING_ASSERTION(!aRv.Failed(),
1997 "Selection::CollapseInLimiter() failed");
2000 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2001 CollapseSelectionToStartOf(nsINode& aNode) const {
2002 return CollapseSelectionTo(EditorRawDOMPoint(&aNode, 0u));
2005 MOZ_CAN_RUN_SCRIPT void CollapseSelectionToStartOf(nsINode& aNode,
2006 ErrorResult& aRv) const {
2007 CollapseSelectionTo(EditorRawDOMPoint(&aNode, 0u), aRv);
2010 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2011 CollapseSelectionToEndOf(nsINode& aNode) const {
2012 return CollapseSelectionTo(EditorRawDOMPoint::AtEndOf(aNode));
2015 MOZ_CAN_RUN_SCRIPT void CollapseSelectionToEndOf(nsINode& aNode,
2016 ErrorResult& aRv) const {
2017 CollapseSelectionTo(EditorRawDOMPoint::AtEndOf(aNode), aRv);
2021 * AllowsTransactionsToChangeSelection() returns true if editor allows any
2022 * transactions to change Selection. Otherwise, transactions shouldn't
2023 * change Selection.
2025 inline bool AllowsTransactionsToChangeSelection() const {
2026 return mAllowsTransactionsToChangeSelection;
2030 * MakeThisAllowTransactionsToChangeSelection() with true makes this editor
2031 * allow transactions to change Selection. Otherwise, i.e., with false,
2032 * makes this editor not allow transactions to change Selection.
2034 inline void MakeThisAllowTransactionsToChangeSelection(bool aAllow) {
2035 mAllowsTransactionsToChangeSelection = aAllow;
2038 nsresult HandleInlineSpellCheck(
2039 const EditorDOMPoint& aPreviouslySelectedStart,
2040 const dom::AbstractRange* aRange = nullptr);
2043 * Whether the editor is active on the DOM window. Note that when this
2044 * returns true but GetFocusedElement() returns null, it means that this
2045 * editor was focused when the DOM window was active.
2047 virtual bool IsActiveInDOMWindow() const;
2050 * HideCaret() hides caret with nsCaret::AddForceHide() or may show carent
2051 * with nsCaret::RemoveForceHide(). This does NOT set visibility of
2052 * nsCaret. Therefore, this is stateless.
2054 void HideCaret(bool aHide);
2056 protected: // Edit sub-action handler
2058 * AutoCaretBidiLevelManager() computes bidi level of caret, deleting
2059 * character(s) from aPointAtCaret at construction. Then, if you'll
2060 * need to extend the selection, you should calls `UpdateCaretBidiLevel()`,
2061 * then, this class may update caret bidi level for you if it's required.
2063 class MOZ_RAII AutoCaretBidiLevelManager final {
2064 public:
2066 * @param aEditorBase The editor.
2067 * @param aPointAtCaret Collapsed `Selection` point.
2068 * @param aDirectionAndAmount The direction and amount to delete.
2070 template <typename PT, typename CT>
2071 AutoCaretBidiLevelManager(const EditorBase& aEditorBase,
2072 nsIEditor::EDirection aDirectionAndAmount,
2073 const EditorDOMPointBase<PT, CT>& aPointAtCaret);
2076 * Failed() returns true if the constructor failed to handle the bidi
2077 * information.
2079 bool Failed() const { return mFailed; }
2082 * Canceled() returns true if when the caller should stop deleting
2083 * characters since caret position is not visually adjacent the deleting
2084 * characters and user does not wand to delete them in that case.
2086 bool Canceled() const { return mCanceled; }
2089 * MaybeUpdateCaretBidiLevel() may update caret bidi level and schedule to
2090 * paint it if they are necessary.
2092 void MaybeUpdateCaretBidiLevel(const EditorBase& aEditorBase) const;
2094 private:
2095 Maybe<mozilla::intl::BidiEmbeddingLevel> mNewCaretBidiLevel;
2096 bool mFailed = false;
2097 bool mCanceled = false;
2101 * UndefineCaretBidiLevel() resets bidi level of the caret.
2103 void UndefineCaretBidiLevel() const;
2106 * Flushing pending notifications if nsFrameSelection requires the latest
2107 * layout information to compute deletion range. This may destroy the
2108 * editor instance itself. When this returns false, don't keep doing
2109 * anything.
2111 [[nodiscard]] MOZ_CAN_RUN_SCRIPT bool
2112 FlushPendingNotificationsIfToHandleDeletionWithFrameSelection(
2113 nsIEditor::EDirection aDirectionAndAmount) const;
2116 * DeleteSelectionAsSubAction() removes selection content or content around
2117 * caret with transactions. This should be used for handling it as an
2118 * edit sub-action.
2120 * @param aDirectionAndAmount How much range should be removed.
2121 * @param aStripWrappers Whether the parent blocks should be removed
2122 * when they become empty. If this instance is
2123 * a TextEditor, Must be nsIEditor::eNoStrip.
2125 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2126 DeleteSelectionAsSubAction(nsIEditor::EDirection aDirectionAndAmount,
2127 nsIEditor::EStripWrappers aStripWrappers);
2130 * This method handles "delete selection" commands.
2131 * NOTE: Don't call this method recursively from the helper methods since
2132 * when nobody handled it without canceling and returing an error,
2133 * this falls it back to `DeleteSelectionWithTransaction()`.
2135 * @param aDirectionAndAmount Direction of the deletion.
2136 * @param aStripWrappers Must be nsIEditor::eNoStrip if this is a
2137 * TextEditor instance. Otherwise,
2138 * nsIEditor::eStrip is also valid.
2140 [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual Result<EditActionResult, nsresult>
2141 HandleDeleteSelection(nsIEditor::EDirection aDirectionAndAmount,
2142 nsIEditor::EStripWrappers aStripWrappers) = 0;
2145 * ReplaceSelectionAsSubAction() replaces selection with aString.
2147 * @param aString The string to replace.
2149 MOZ_CAN_RUN_SCRIPT nsresult
2150 ReplaceSelectionAsSubAction(const nsAString& aString);
2153 * HandleInsertText() handles inserting text at selection.
2155 * @param aEditSubAction Must be EditSubAction::eInsertText or
2156 * EditSubAction::eInsertTextComingFromIME.
2157 * @param aInsertionString String to be inserted at selection.
2158 * @param aSelectionHandling Specify whether selected content should be
2159 * deleted or ignored.
2161 [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual Result<EditActionResult, nsresult>
2162 HandleInsertText(EditSubAction aEditSubAction,
2163 const nsAString& aInsertionString,
2164 SelectionHandling aSelectionHandling) = 0;
2167 * InsertWithQuotationsAsSubAction() inserts aQuotedText with appending ">"
2168 * to start of every line.
2170 * @param aQuotedText String to insert. This will be quoted by ">"
2171 * automatically.
2173 [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult
2174 InsertWithQuotationsAsSubAction(const nsAString& aQuotedText) = 0;
2177 * PrepareInsertContent() is a helper method of InsertTextAt(),
2178 * HTMLEditor::HTMLWithContextInserter::Run(). They insert content coming
2179 * from clipboard or drag and drop. Before that, they may need to remove
2180 * selected contents and adjust selection. This does them instead.
2182 * @param aPointToInsert Point to insert. Must be set. Callers
2183 * shouldn't use this instance after calling this
2184 * method because this method may cause changing
2185 * the DOM tree and Selection.
2187 enum class DeleteSelectedContent : bool {
2188 No, // Don't delete selection
2189 Yes, // Delete selected content
2191 MOZ_CAN_RUN_SCRIPT nsresult
2192 PrepareToInsertContent(const EditorDOMPoint& aPointToInsert,
2193 DeleteSelectedContent aDeleteSelectedContent);
2196 * InsertTextAt() inserts aStringToInsert at aPointToInsert.
2198 * @param aStringToInsert The string which you want to insert.
2199 * @param aPointToInsert The insertion point.
2201 MOZ_CAN_RUN_SCRIPT nsresult InsertTextAt(
2202 const nsAString& aStringToInsert, const EditorDOMPoint& aPointToInsert,
2203 DeleteSelectedContent aDeleteSelectedContent);
2206 * Return whether the data is safe to insert as the source and destination
2207 * principals match, or we are in a editor context where this doesn't matter.
2208 * Otherwise, the data must be sanitized first.
2210 enum class SafeToInsertData : bool { No, Yes };
2211 SafeToInsertData IsSafeToInsertData(nsIPrincipal* aSourcePrincipal) const;
2214 * Routines for managing the preservation of selection across
2215 * various editor actions.
2217 bool ArePreservingSelection() const;
2218 void PreserveSelectionAcrossActions();
2219 MOZ_CAN_RUN_SCRIPT nsresult RestorePreservedSelection();
2220 void StopPreservingSelection();
2222 protected: // Called by helper classes.
2224 * OnStartToHandleTopLevelEditSubAction() is called when
2225 * GetTopLevelEditSubAction() is EditSubAction::eNone and somebody starts to
2226 * handle aEditSubAction.
2228 * @param aTopLevelEditSubAction Top level edit sub action which
2229 * will be handled soon.
2230 * @param aDirectionOfTopLevelEditSubAction Direction of aEditSubAction.
2232 MOZ_CAN_RUN_SCRIPT virtual void OnStartToHandleTopLevelEditSubAction(
2233 EditSubAction aTopLevelEditSubAction,
2234 nsIEditor::EDirection aDirectionOfTopLevelEditSubAction,
2235 ErrorResult& aRv);
2238 * OnEndHandlingTopLevelEditSubAction() is called after
2239 * SetTopLevelEditSubAction() is handled.
2241 MOZ_CAN_RUN_SCRIPT virtual nsresult OnEndHandlingTopLevelEditSubAction();
2244 * OnStartToHandleEditSubAction() and OnEndHandlingEditSubAction() are called
2245 * when starting to handle an edit sub action and ending handling an edit
2246 * sub action.
2248 void OnStartToHandleEditSubAction() { EditSubActionDataRef().Clear(); }
2249 void OnEndHandlingEditSubAction() { EditSubActionDataRef().Clear(); }
2252 * (Begin|End)PlaceholderTransaction() are called by AutoPlaceholderBatch.
2253 * This set of methods are similar to the (Begin|End)Transaction(), but do
2254 * not use the transaction managers batching feature. Instead we use a
2255 * placeholder transaction to wrap up any further transaction while the
2256 * batch is open. The advantage of this is that placeholder transactions
2257 * can later merge, if needed. Merging is unavailable between transaction
2258 * manager batches.
2260 MOZ_CAN_RUN_SCRIPT_BOUNDARY void BeginPlaceholderTransaction(
2261 nsStaticAtom& aTransactionName, const char* aRequesterFuncName);
2262 enum class ScrollSelectionIntoView { No, Yes };
2263 MOZ_CAN_RUN_SCRIPT_BOUNDARY void EndPlaceholderTransaction(
2264 ScrollSelectionIntoView aScrollSelectionIntoView,
2265 const char* aRequesterFuncName);
2267 void BeginUpdateViewBatch(const char* aRequesterFuncName);
2268 MOZ_CAN_RUN_SCRIPT void EndUpdateViewBatch(const char* aRequesterFuncName);
2271 * Used by HTMLEditor::AutoTransactionBatch, nsIEditor::BeginTransaction
2272 * and nsIEditor::EndTransation. After calling BeginTransactionInternal(),
2273 * all transactions will be treated as an atomic transaction. I.e., two or
2274 * more transactions are undid once.
2275 * XXX What's the difference with PlaceholderTransaction? Should we always
2276 * use it instead?
2278 MOZ_CAN_RUN_SCRIPT void BeginTransactionInternal(
2279 const char* aRequesterFuncName);
2280 MOZ_CAN_RUN_SCRIPT void EndTransactionInternal(
2281 const char* aRequesterFuncName);
2283 protected: // Shouldn't be used by friend classes
2285 * The default destructor. This should suffice. Should this be pure virtual
2286 * for someone to derive from the EditorBase later? I don't believe so.
2288 virtual ~EditorBase();
2291 * @param aDocument The dom document interface being observed
2292 * @param aRootElement
2293 * This is the root of the editable section of this
2294 * document. If it is null then we get root from document
2295 * body.
2296 * @param aSelectionController
2297 * The selection controller of selections which will be
2298 * used in this editor.
2299 * @param aFlags Some of nsIEditor::eEditor*Mask flags.
2301 MOZ_CAN_RUN_SCRIPT nsresult
2302 InitInternal(Document& aDocument, Element* aRootElement,
2303 nsISelectionController& aSelectionController, uint32_t aFlags);
2306 * PostCreateInternal() should be called after InitInternal(), and is the time
2307 * that the editor tells its documentStateObservers that the document has been
2308 * created.
2310 MOZ_CAN_RUN_SCRIPT nsresult PostCreateInternal();
2313 * PreDestroyInternal() is called before the editor goes away, and gives the
2314 * editor a chance to tell its documentStateObservers that the document is
2315 * going away.
2317 MOZ_CAN_RUN_SCRIPT virtual void PreDestroyInternal();
2319 MOZ_ALWAYS_INLINE EditorType GetEditorType() const {
2320 return mIsHTMLEditorClass ? EditorType::HTML : EditorType::Text;
2324 * Check whether the caller can keep handling focus event.
2326 * @param aOriginalEventTargetNode The original event target of the focus
2327 * event.
2329 [[nodiscard]] bool CanKeepHandlingFocusEvent(
2330 const nsINode& aOriginalEventTargetNode) const;
2333 * If this editor has skipped spell checking and not yet flushed, this runs
2334 * the spell checker.
2336 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult FlushPendingSpellCheck();
2338 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult EnsureEmptyTextFirstChild();
2340 int32_t WrapWidth() const { return mWrapColumn; }
2343 * ToGenericNSResult() computes proper nsresult value for the editor users.
2344 * This should be used only when public methods return result of internal
2345 * methods.
2347 static inline nsresult ToGenericNSResult(nsresult aRv) {
2348 switch (aRv) {
2349 // If the editor is destroyed while handling an edit action, editor needs
2350 // to stop handling it. However, editor throw exception in this case
2351 // because Chrome does not throw exception even in this case.
2352 case NS_ERROR_EDITOR_DESTROYED:
2353 return NS_OK;
2354 // If editor meets unexpected DOM tree due to modified by mutation event
2355 // listener, editor needs to stop handling it. However, editor shouldn't
2356 // return error for the users because Chrome does not throw exception in
2357 // this case.
2358 case NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE:
2359 return NS_OK;
2360 // If the editing action is canceled by event listeners, editor needs
2361 // to stop handling it. However, editor shouldn't return error for
2362 // the callers but they should be able to distinguish whether it's
2363 // canceled or not. Although it's DOM specific code, let's return
2364 // DOM_SUCCESS_DOM_NO_OPERATION here.
2365 case NS_ERROR_EDITOR_ACTION_CANCELED:
2366 return NS_SUCCESS_DOM_NO_OPERATION;
2367 // If there is no selection range or editable selection ranges, editor
2368 // needs to stop handling it. However, editor shouldn't return error for
2369 // the callers to avoid throwing exception. However, they may want to
2370 // check whether it works or not. Therefore, we should return
2371 // NS_SUCCESS_DOM_NO_OPERATION instead.
2372 case NS_ERROR_EDITOR_NO_EDITABLE_RANGE:
2373 return NS_SUCCESS_DOM_NO_OPERATION;
2374 // If CreateNodeResultBase::SuggestCaretPointTo etc is called with
2375 // SuggestCaret::AndIgnoreTrivialErrors and CollapseSelectionTo returns
2376 // non-critical error e.g., not NS_ERROR_EDITOR_DESTROYED, it returns
2377 // this success code instead of actual error code for making the caller
2378 // handle the case easier. Therefore, this should be mapped to NS_OK
2379 // for the users of editor.
2380 case NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR:
2381 return NS_OK;
2382 default:
2383 return aRv;
2388 * GetDocumentCharsetInternal() returns charset of the document.
2390 nsresult GetDocumentCharsetInternal(nsACString& aCharset) const;
2393 * ComputeValueInternal() computes string value of this editor for given
2394 * format. This may be too expensive if it's in hot path.
2396 * @param aFormatType MIME type like "text/plain".
2397 * @param aDocumentEncoderFlags Flags of nsIDocumentEncoder.
2398 * @param aCharset Encoding of the document.
2400 nsresult ComputeValueInternal(const nsAString& aFormatType,
2401 uint32_t aDocumentEncoderFlags,
2402 nsAString& aOutputString) const;
2405 * GetAndInitDocEncoder() returns a document encoder instance for aFormatType
2406 * after initializing it. The result may be cached for saving recreation
2407 * cost.
2409 * @param aFormatType MIME type like "text/plain".
2410 * @param aDocumentEncoderFlags Flags of nsIDocumentEncoder.
2411 * @param aCharset Encoding of the document.
2413 already_AddRefed<nsIDocumentEncoder> GetAndInitDocEncoder(
2414 const nsAString& aFormatType, uint32_t aDocumentEncoderFlags,
2415 const nsACString& aCharset) const;
2418 * EnsurePaddingBRElementInMultilineEditor() creates a padding `<br>` element
2419 * at end of multiline text editor.
2421 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2422 EnsurePaddingBRElementInMultilineEditor();
2425 * SelectAllInternal() should be used instead of SelectAll() in editor
2426 * because SelectAll() creates AutoEditActionSetter but we should avoid
2427 * to create it as far as possible.
2429 MOZ_CAN_RUN_SCRIPT virtual nsresult SelectAllInternal();
2431 nsresult DetermineCurrentDirection();
2434 * DispatchInputEvent() dispatches an "input" event synchronously or
2435 * asynchronously if it's not safe to dispatch.
2437 MOZ_CAN_RUN_SCRIPT void DispatchInputEvent();
2440 * Called after a transaction is done successfully.
2442 MOZ_CAN_RUN_SCRIPT void DoAfterDoTransaction(nsITransaction* aTransaction);
2445 * Called after a transaction is undone successfully.
2448 MOZ_CAN_RUN_SCRIPT void DoAfterUndoTransaction();
2451 * Called after a transaction is redone successfully.
2453 MOZ_CAN_RUN_SCRIPT void DoAfterRedoTransaction();
2456 * Tell the doc state listeners that the doc state has changed.
2458 enum TDocumentListenerNotification {
2459 eDocumentCreated,
2460 eDocumentToBeDestroyed,
2461 eDocumentStateChanged
2463 MOZ_CAN_RUN_SCRIPT nsresult
2464 NotifyDocumentListeners(TDocumentListenerNotification aNotificationType);
2467 * Make the given selection span the entire document.
2469 MOZ_CAN_RUN_SCRIPT virtual nsresult SelectEntireDocument() = 0;
2472 * Helper method for scrolling the selection into view after
2473 * an edit operation.
2475 * Editor methods *should* call this method instead of the versions
2476 * in the various selection interfaces, since this makes sure that
2477 * the editor's sync/async settings for reflowing, painting, and scrolling
2478 * match.
2480 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2481 ScrollSelectionFocusIntoView() const;
2483 virtual nsresult InstallEventListeners();
2484 virtual void CreateEventListeners();
2485 void RemoveEventListeners();
2486 [[nodiscard]] bool IsListeningToEvents() const;
2489 * Called if and only if this editor is in readonly mode.
2491 void HandleKeyPressEventInReadOnlyMode(
2492 WidgetKeyboardEvent& aKeyboardEvent) const;
2495 * Get the input event target. This might return null.
2497 virtual already_AddRefed<Element> GetInputEventTargetElement() const = 0;
2500 * Return true if spellchecking should be enabled for this editor.
2502 [[nodiscard]] bool GetDesiredSpellCheckState();
2504 [[nodiscard]] bool CanEnableSpellCheck() const {
2505 // Check for password/readonly/disabled, which are not spellchecked
2506 // regardless of DOM. Also, check to see if spell check should be skipped
2507 // or not.
2508 return !IsPasswordEditor() && !IsReadonly() && !ShouldSkipSpellCheck();
2512 * InitializeSelectionAncestorLimit() is called by InitializeSelection().
2513 * When this is called, each implementation has to call
2514 * Selection::SetAncestorLimiter() with aAnotherLimit.
2516 * @param aAncestorLimit New ancestor limit of Selection. This always
2517 * has parent node. So, it's always safe to
2518 * call SetAncestorLimit() with this node.
2520 virtual void InitializeSelectionAncestorLimit(Element& aAncestorLimit) const;
2523 * Initializes selection and caret for the editor at getting focus. If
2524 * aOriginalEventTargetNode isn't a host of the editor, i.e., the editor
2525 * doesn't get focus, this does nothing.
2527 * @param aOriginalEventTargetNode The original event target node of the
2528 * focus event.
2530 MOZ_CAN_RUN_SCRIPT nsresult
2531 InitializeSelection(const nsINode& aOriginalEventTargetNode);
2533 enum NotificationForEditorObservers {
2534 eNotifyEditorObserversOfEnd,
2535 eNotifyEditorObserversOfBefore,
2536 eNotifyEditorObserversOfCancel
2538 MOZ_CAN_RUN_SCRIPT void NotifyEditorObservers(
2539 NotificationForEditorObservers aNotification);
2542 * HowToHandleCollapsedRange indicates how collapsed range should be treated.
2544 enum class HowToHandleCollapsedRange {
2545 // Ignore collapsed range.
2546 Ignore,
2547 // Extend collapsed range for removing previous content.
2548 ExtendBackward,
2549 // Extend collapsed range for removing next content.
2550 ExtendForward,
2553 static HowToHandleCollapsedRange HowToHandleCollapsedRangeFor(
2554 nsIEditor::EDirection aDirectionAndAmount) {
2555 switch (aDirectionAndAmount) {
2556 case nsIEditor::eNone:
2557 return HowToHandleCollapsedRange::Ignore;
2558 case nsIEditor::ePrevious:
2559 return HowToHandleCollapsedRange::ExtendBackward;
2560 case nsIEditor::eNext:
2561 return HowToHandleCollapsedRange::ExtendForward;
2562 case nsIEditor::ePreviousWord:
2563 case nsIEditor::eNextWord:
2564 case nsIEditor::eToBeginningOfLine:
2565 case nsIEditor::eToEndOfLine:
2566 // If the amount is word or
2567 // line,`AutoClonedSelectionRangeArray::ExtendAnchorFocusRangeFor()`
2568 // must have already been extended collapsed ranges before.
2569 return HowToHandleCollapsedRange::Ignore;
2571 MOZ_ASSERT_UNREACHABLE("Invalid nsIEditor::EDirection value");
2572 return HowToHandleCollapsedRange::Ignore;
2576 * InsertDroppedDataTransferAsAction() inserts all data items in aDataTransfer
2577 * at aDroppedAt unless the editor is destroyed.
2579 * @param aEditActionData The edit action data whose edit action must be
2580 * EditAction::eDrop.
2581 * @param aDataTransfer The data transfer object which is dropped.
2582 * @param aDroppedAt The DOM tree position whether aDataTransfer
2583 * is dropped.
2584 * @param aSourcePrincipal Principal of the source of the drag.
2585 * May be nullptr if it comes from another app
2586 * or process.
2588 [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult
2589 InsertDroppedDataTransferAsAction(AutoEditActionDataSetter& aEditActionData,
2590 DataTransfer& aDataTransfer,
2591 const EditorDOMPoint& aDroppedAt,
2592 nsIPrincipal* aSourcePrincipal) = 0;
2595 * DeleteSelectionByDragAsAction() removes selection and dispatch "input"
2596 * event whose inputType is "deleteByDrag".
2598 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2599 DeleteSelectionByDragAsAction(bool aDispatchInputEvent);
2602 * DeleteSelectionWithTransaction() removes selected content or content
2603 * around caret with transactions and remove empty inclusive ancestor
2604 * inline elements of collapsed selection after removing the contents.
2606 * @param aDirectionAndAmount How much range should be removed.
2607 * @param aStripWrappers Whether the parent blocks should be removed
2608 * when they become empty.
2609 * Note that this must be `nsIEditor::eNoStrip`
2610 * if this is a TextEditor because anyway it'll
2611 * be ignored.
2613 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2614 DeleteSelectionWithTransaction(nsIEditor::EDirection aDirectionAndAmount,
2615 nsIEditor::EStripWrappers aStripWrappers);
2618 * DeleteRangeWithTransaction() removes content in aRangeToDelete or content
2619 * around collapsed aRangeToDelete with transactions and remove empty
2620 * inclusive ancestor inline elements of the collapsed range after removing
2621 * the contents.
2623 * @param aDirectionAndAmount How much range should be removed.
2624 * @param aStripWrappers Whether the parent blocks should be removed
2625 * when they become empty.
2626 * Note that this must be `nsIEditor::eNoStrip`
2627 * if this is a TextEditor because anyway it'll
2628 * be ignored.
2629 * @param aRangeToDelete The range to delete content.
2631 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
2632 DeleteRangeWithTransaction(nsIEditor::EDirection aDirectionAndAmount,
2633 nsIEditor::EStripWrappers aStripWrappers,
2634 nsRange& aRangeToDelete);
2637 * DeleteRangesWithTransaction() removes content in aRangesToDelete or content
2638 * around collapsed ranges in aRangesToDelete with transactions and remove
2639 * empty inclusive ancestor inline elements of collapsed ranges after
2640 * removing the contents.
2642 * @param aDirectionAndAmount How much range should be removed.
2643 * @param aStripWrappers Whether the parent blocks should be removed
2644 * when they become empty.
2645 * Note that this must be `nsIEditor::eNoStrip`
2646 * if this is a TextEditor because anyway it'll
2647 * be ignored.
2648 * @param aRangesToDelete The ranges to delete content.
2650 [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual Result<CaretPoint, nsresult>
2651 DeleteRangesWithTransaction(nsIEditor::EDirection aDirectionAndAmount,
2652 nsIEditor::EStripWrappers aStripWrappers,
2653 const AutoClonedRangeArray& aRangesToDelete);
2656 * Create a transaction for delete the content in aRangesToDelete.
2657 * The result may include DeleteRangeTransaction (for deleting non-collapsed
2658 * range), DeleteNodeTransactions and DeleteTextTransactions (for deleting
2659 * collapsed range) as its children.
2661 * @param aHowToHandleCollapsedRange
2662 * How to handle collapsed ranges.
2663 * @param aRangesToDelete The ranges to delete content.
2665 already_AddRefed<DeleteMultipleRangesTransaction>
2666 CreateTransactionForDeleteSelection(
2667 HowToHandleCollapsedRange aHowToHandleCollapsedRange,
2668 const AutoClonedRangeArray& aRangesToDelete);
2671 * Create a DeleteNodeTransaction or DeleteTextTransaction for removing a
2672 * nodes or some text around aRangeToDelete.
2674 * @param aCollapsedRange The range to be removed. This must be
2675 * collapsed.
2676 * @param aHowToHandleCollapsedRange
2677 * How to handle aCollapsedRange. Must
2678 * be HowToHandleCollapsedRange::ExtendBackward or
2679 * HowToHandleCollapsedRange::ExtendForward.
2681 already_AddRefed<DeleteContentTransactionBase>
2682 CreateTransactionForCollapsedRange(
2683 const nsRange& aCollapsedRange,
2684 HowToHandleCollapsedRange aHowToHandleCollapsedRange);
2687 * ComputeInsertedRange() returns actual range modified by inserting string
2688 * in a text node. If mutation event listener changed the text data, this
2689 * returns a range which covers all over the text data.
2691 std::tuple<EditorDOMPointInText, EditorDOMPointInText> ComputeInsertedRange(
2692 const EditorDOMPointInText& aInsertedPoint,
2693 const nsAString& aInsertedString) const;
2696 * EnsureComposition() should be called by composition event handlers. This
2697 * tries to get the composition for the event and set it to mComposition.
2698 * However, this may fail because the composition may be committed before
2699 * the event comes to the editor.
2701 * @return true if there is a composition. Otherwise, for example,
2702 * a composition event handler in web contents moved focus
2703 * for committing the composition, returns false.
2705 bool EnsureComposition(WidgetCompositionEvent& aCompositionEvent);
2708 * See comment of IsCopyToClipboardAllowed() for the detail.
2710 virtual bool IsCopyToClipboardAllowedInternal() const {
2711 MOZ_ASSERT(IsEditActionDataAvailable());
2712 return !SelectionRef().IsCollapsed();
2716 * Helper for Is{Cut|Copy}CommandEnabled.
2717 * Look for a listener for the given command, including up the target chain.
2719 MOZ_CAN_RUN_SCRIPT bool CheckForClipboardCommandListener(
2720 nsAtom* aCommand, EventMessage aEventMessage) const;
2723 * DispatchClipboardEventAndUpdateClipboard() may dispatch a clipboard event
2724 * and update clipboard if aEventMessage is eCopy or eCut.
2726 * @param aEventMessage The event message which may be set to the
2727 * dispatching event.
2728 * @param aClipboardType Working with global clipboard or selection.
2730 enum class ClipboardEventResult {
2731 // We have met an error in nsCopySupport::FireClipboardEvent,
2732 // or, default of dispatched event is NOT prevented, the event is "cut"
2733 // and the event target is not editable.
2734 IgnoredOrError,
2735 // A "paste" event is dispatched and prevented its default.
2736 DefaultPreventedOfPaste,
2737 // Default of a "copy" or "cut" event is prevented but the clipboard is
2738 // updated unless the dataTransfer of the event is cleared by the listener.
2739 // Or, default of the event is NOT prevented but selection is collapsed
2740 // when the event target is editable or the event is "copy".
2741 CopyOrCutHandled,
2742 // A clipboard event is maybe dispatched and not canceled by the web app.
2743 // In this case, the clipboard has been updated if aEventMessage is eCopy
2744 // or eCut.
2745 DoDefault,
2747 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<ClipboardEventResult, nsresult>
2748 DispatchClipboardEventAndUpdateClipboard(
2749 EventMessage aEventMessage,
2750 mozilla::Maybe<nsIClipboard::ClipboardType> aClipboardType,
2751 DataTransfer* aDataTransfer = nullptr);
2754 * Called after PasteAsAction() dispatches "paste" event and it's not
2755 * canceled.
2757 [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult HandlePaste(
2758 AutoEditActionDataSetter& aEditActionData,
2759 nsIClipboard::ClipboardType aClipboardType,
2760 DataTransfer* aDataTransfer) = 0;
2763 * Called after PasteAsQuotationAsAction() dispatches "paste" event and it's
2764 * not canceled.
2766 [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult HandlePasteAsQuotation(
2767 AutoEditActionDataSetter& aEditActionData,
2768 nsIClipboard::ClipboardType aClipboardType,
2769 DataTransfer* aDataTransfer) = 0;
2772 * Called after PasteTransferableAsAction() dispatches "paste" event and
2773 * it's not canceled.
2775 [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult HandlePasteTransferable(
2776 AutoEditActionDataSetter& aEditActionData,
2777 nsITransferable& aTransferable) = 0;
2779 private:
2780 nsCOMPtr<nsISelectionController> mSelectionController;
2781 RefPtr<Document> mDocument;
2783 AutoEditActionDataSetter* mEditActionData;
2786 * SetTextDirectionTo() sets text-direction of the root element.
2787 * Should use SwitchTextDirectionTo() or ToggleTextDirection() instead.
2788 * This is a helper class of them.
2790 nsresult SetTextDirectionTo(TextDirection aTextDirection);
2792 protected: // helper classes which may be used by friends
2794 * Stack based helper class for batching a collection of transactions
2795 * inside a placeholder transaction. Different from AutoTransactionBatch,
2796 * this notifies editor observers of before/end edit action handling, and
2797 * dispatches "input" event if it's necessary.
2799 class MOZ_RAII AutoPlaceholderBatch final {
2800 public:
2802 * @param aRequesterFuncName function name which wants to end the batch.
2803 * This won't be stored nor exposed to selection listeners etc, used
2804 * only for logging. This MUST be alive when the destructor runs.
2806 AutoPlaceholderBatch(EditorBase& aEditorBase,
2807 ScrollSelectionIntoView aScrollSelectionIntoView,
2808 const char* aRequesterFuncName)
2809 : mEditorBase(aEditorBase),
2810 mScrollSelectionIntoView(aScrollSelectionIntoView),
2811 mRequesterFuncName(aRequesterFuncName) {
2812 mEditorBase->BeginPlaceholderTransaction(*nsGkAtoms::_empty,
2813 mRequesterFuncName);
2816 AutoPlaceholderBatch(EditorBase& aEditorBase,
2817 nsStaticAtom& aTransactionName,
2818 ScrollSelectionIntoView aScrollSelectionIntoView,
2819 const char* aRequesterFuncName)
2820 : mEditorBase(aEditorBase),
2821 mScrollSelectionIntoView(aScrollSelectionIntoView),
2822 mRequesterFuncName(aRequesterFuncName) {
2823 mEditorBase->BeginPlaceholderTransaction(aTransactionName,
2824 mRequesterFuncName);
2827 ~AutoPlaceholderBatch() {
2828 mEditorBase->EndPlaceholderTransaction(mScrollSelectionIntoView,
2829 mRequesterFuncName);
2832 protected:
2833 const OwningNonNull<EditorBase> mEditorBase;
2834 const ScrollSelectionIntoView mScrollSelectionIntoView;
2835 const char* const mRequesterFuncName;
2839 * AutoEditSubActionNotifier notifies editor of start to handle
2840 * top level edit sub-action and end handling top level edit sub-action.
2842 class MOZ_RAII AutoEditSubActionNotifier final {
2843 public:
2844 MOZ_CAN_RUN_SCRIPT AutoEditSubActionNotifier(
2845 EditorBase& aEditorBase, EditSubAction aEditSubAction,
2846 nsIEditor::EDirection aDirection, ErrorResult& aRv)
2847 : mEditorBase(aEditorBase), mIsTopLevel(true) {
2848 // The top level edit sub action has already be set if this is nested
2849 // call
2850 // XXX Looks like that this is not aware of unexpected nested edit
2851 // action
2852 // handling via selectionchange event listener or mutation event
2853 // listener.
2854 if (!mEditorBase.GetTopLevelEditSubAction()) {
2855 MOZ_KnownLive(mEditorBase)
2856 .OnStartToHandleTopLevelEditSubAction(aEditSubAction, aDirection,
2857 aRv);
2858 } else {
2859 mIsTopLevel = false;
2861 mEditorBase.OnStartToHandleEditSubAction();
2864 MOZ_CAN_RUN_SCRIPT ~AutoEditSubActionNotifier() {
2865 mEditorBase.OnEndHandlingEditSubAction();
2866 if (mIsTopLevel) {
2867 MOZ_KnownLive(mEditorBase).OnEndHandlingTopLevelEditSubAction();
2871 protected:
2872 EditorBase& mEditorBase;
2873 bool mIsTopLevel;
2877 * Stack based helper class for turning off active selection adjustment
2878 * by low level transactions
2880 class MOZ_RAII AutoTransactionsConserveSelection final {
2881 public:
2882 explicit AutoTransactionsConserveSelection(EditorBase& aEditorBase)
2883 : mEditorBase(aEditorBase),
2884 mAllowedTransactionsToChangeSelection(
2885 aEditorBase.AllowsTransactionsToChangeSelection()) {
2886 mEditorBase.MakeThisAllowTransactionsToChangeSelection(false);
2889 ~AutoTransactionsConserveSelection() {
2890 mEditorBase.MakeThisAllowTransactionsToChangeSelection(
2891 mAllowedTransactionsToChangeSelection);
2894 protected:
2895 EditorBase& mEditorBase;
2896 bool mAllowedTransactionsToChangeSelection;
2899 /***************************************************************************
2900 * stack based helper class for batching reflow and paint requests.
2902 class MOZ_RAII AutoUpdateViewBatch final {
2903 public:
2905 * @param aRequesterFuncName function name which wants to end the batch.
2906 * This won't be stored nor exposed to selection listeners etc, used
2907 * only for logging. This MUST be alive when the destructor runs.
2909 MOZ_CAN_RUN_SCRIPT explicit AutoUpdateViewBatch(
2910 EditorBase& aEditorBase, const char* aRequesterFuncName)
2911 : mEditorBase(aEditorBase), mRequesterFuncName(aRequesterFuncName) {
2912 mEditorBase.BeginUpdateViewBatch(mRequesterFuncName);
2915 MOZ_CAN_RUN_SCRIPT ~AutoUpdateViewBatch() {
2916 MOZ_KnownLive(mEditorBase).EndUpdateViewBatch(mRequesterFuncName);
2919 protected:
2920 EditorBase& mEditorBase;
2921 const char* const mRequesterFuncName;
2924 protected:
2925 enum Tristate { eTriUnset, eTriFalse, eTriTrue };
2927 // MIME type of the doc we are editing.
2928 nsString mContentMIMEType;
2930 RefPtr<mozInlineSpellChecker> mInlineSpellChecker;
2931 // Reference to text services document for mInlineSpellChecker.
2932 RefPtr<TextServicesDocument> mTextServicesDocument;
2934 RefPtr<TransactionManager> mTransactionManager;
2935 // Cached root node.
2936 RefPtr<Element> mRootElement;
2938 // The form field as an event receiver.
2939 nsCOMPtr<dom::EventTarget> mEventTarget;
2940 RefPtr<EditorEventListener> mEventListener;
2941 // Strong reference to placeholder for begin/end batch purposes.
2942 RefPtr<PlaceholderTransaction> mPlaceholderTransaction;
2943 // Name of placeholder transaction.
2944 nsStaticAtom* mPlaceholderName;
2945 // Saved selection state for placeholder transaction batching.
2946 mozilla::Maybe<SelectionState> mSelState;
2947 // IME composition this is not null between compositionstart and
2948 // compositionend.
2949 RefPtr<TextComposition> mComposition;
2951 RefPtr<TextInputListener> mTextInputListener;
2953 RefPtr<IMEContentObserver> mIMEContentObserver;
2955 // These members cache last encoder and its type for the performance in
2956 // TextEditor::ComputeTextValue() which is the implementation of
2957 // `<input>.value` and `<textarea>.value`. See `GetAndInitDocEncoder()`.
2958 mutable nsCOMPtr<nsIDocumentEncoder> mCachedDocumentEncoder;
2959 mutable nsString mCachedDocumentEncoderType;
2961 // Listens to all low level actions on the doc.
2962 // Edit action listener is currently used by highlighter of the findbar
2963 // and the spellchecker. So, we should reserve only 2 items.
2964 using AutoActionListenerArray =
2965 AutoTArray<OwningNonNull<nsIEditActionListener>, 2>;
2966 AutoActionListenerArray mActionListeners;
2967 // Listen to overall doc state (dirty or not, just created, etc.).
2968 // Document state listener is currently used by FinderHighlighter and
2969 // BlueGriffon so that reserving only one is enough.
2970 using AutoDocumentStateListenerArray =
2971 AutoTArray<OwningNonNull<nsIDocumentStateListener>, 1>;
2972 AutoDocumentStateListenerArray mDocStateListeners;
2974 // Number of modifications (for undo/redo stack).
2975 uint32_t mModCount;
2976 // Behavior flags. See nsIEditor.idl for the flags we use.
2977 uint32_t mFlags;
2979 int32_t mUpdateCount;
2981 // Nesting count for batching.
2982 int32_t mPlaceholderBatch;
2984 int32_t mWrapColumn = 0;
2985 int32_t mNewlineHandling;
2986 int32_t mCaretStyle;
2988 // -1 = not initialized
2989 int8_t mDocDirtyState;
2990 // A Tristate value.
2991 uint8_t mSpellcheckCheckboxState;
2993 // If true, initialization was succeeded.
2994 bool mInitSucceeded;
2995 // If false, transactions should not change Selection even after modifying
2996 // the DOM tree.
2997 bool mAllowsTransactionsToChangeSelection;
2998 // Whether PreDestroy has been called.
2999 bool mDidPreDestroy;
3000 // Whether PostCreate has been called.
3001 bool mDidPostCreate;
3002 bool mDispatchInputEvent;
3003 // True while the instance is handling an edit sub-action.
3004 bool mIsInEditSubAction;
3005 // Whether caret is hidden forcibly.
3006 bool mHidingCaret;
3007 // Whether spellchecker dictionary is initialized after focused.
3008 bool mSpellCheckerDictionaryUpdated;
3009 // Whether we are an HTML editor class.
3010 bool mIsHTMLEditorClass;
3012 friend class AlignStateAtSelection; // AutoEditActionDataSetter,
3013 // ToGenericNSResult
3014 friend class AutoClonedRangeArray; // IsSEditActionDataAvailable,
3015 // RangeUpdaterRef
3016 friend class AutoClonedSelectionRangeArray; // RangeUpdaterRef, SelectionRef
3017 friend class AutoSelectionRestorer; // RangeUpdaterRef, SavedSelectionRef
3018 friend class CaretPoint; // AllowsTransactionsToChangeSelection,
3019 // CollapseSelectionTo
3020 friend class CompositionTransaction; // CollapseSelectionTo,
3021 // DoDeleteText, DoInsertText,
3022 // DoReplaceText, HideCaret,
3023 // RangeUpdaterRef
3024 friend class DeleteNodeTransaction; // RangeUpdaterRef
3025 friend class DeleteRangeTransaction; // AllowsTransactionsToChangeSelection,
3026 // CollapseSelectionTo
3027 friend class DeleteTextTransaction; // AllowsTransactionsToChangeSelection,
3028 // DoDeleteText, DoInsertText,
3029 // RangeUpdaterRef
3030 friend class InsertNodeTransaction; // AllowsTransactionsToChangeSelection,
3031 // CollapseSelectionTo,
3032 // MarkElementDirty, ToGenericNSResult
3033 friend class InsertTextTransaction; // AllowsTransactionsToChangeSelection,
3034 // CollapseSelectionTo, DoDeleteText,
3035 // DoInsertText, RangeUpdaterRef
3036 friend class ListElementSelectionState; // AutoEditActionDataSetter,
3037 // ToGenericNSResult
3038 friend class ListItemElementSelectionState; // AutoEditActionDataSetter,
3039 // ToGenericNSResult
3040 friend class MoveNodeTransaction; // ToGenericNSResult
3041 friend class ParagraphStateAtSelection; // AutoEditActionDataSetter,
3042 // ToGenericNSResult
3043 friend class PendingStyles; // GetEditAction,
3044 // GetFirstSelectionStartPoint,
3045 // SelectionRef
3046 friend class ReplaceTextTransaction; // AllowsTransactionsToChangeSelection,
3047 // CollapseSelectionTo, DoReplaceText,
3048 // RangeUpdaterRef
3049 friend class SplitNodeTransaction; // ToGenericNSResult
3050 friend class WhiteSpaceVisibilityKeeper; // AutoTransactionsConserveSelection
3051 friend class nsIEditor; // mIsHTMLEditorClass
3054 } // namespace mozilla
3056 bool nsIEditor::IsTextEditor() const {
3057 return !AsEditorBase()->mIsHTMLEditorClass;
3060 bool nsIEditor::IsHTMLEditor() const {
3061 return AsEditorBase()->mIsHTMLEditorClass;
3064 mozilla::EditorBase* nsIEditor::AsEditorBase() {
3065 return static_cast<mozilla::EditorBase*>(this);
3068 const mozilla::EditorBase* nsIEditor::AsEditorBase() const {
3069 return static_cast<const mozilla::EditorBase*>(this);
3072 #endif // #ifndef mozilla_EditorBase_h