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/Assertions.h" // for MOZ_ASSERT, etc.
10 #include "mozilla/EditAction.h" // for EditAction and EditSubAction
11 #include "mozilla/EditorDOMPoint.h" // for EditorDOMPoint
12 #include "mozilla/EventForwards.h" // for InputEventTargetRanges
13 #include "mozilla/Maybe.h" // for Maybe
14 #include "mozilla/OwningNonNull.h" // for OwningNonNull
15 #include "mozilla/TypeInState.h" // for PropItem, StyleCache
16 #include "mozilla/RangeBoundary.h" // for RawRangeBoundary, RangeBoundary
17 #include "mozilla/SelectionState.h" // for RangeUpdater, etc.
18 #include "mozilla/StyleSheet.h" // for StyleSheet
19 #include "mozilla/TransactionManager.h" // for TransactionManager
20 #include "mozilla/WeakPtr.h" // for WeakPtr
21 #include "mozilla/dom/DataTransfer.h" // for dom::DataTransfer
22 #include "mozilla/dom/HTMLBRElement.h" // for dom::HTMLBRElement
23 #include "mozilla/dom/Selection.h"
24 #include "mozilla/dom/Text.h"
25 #include "nsAtom.h" // for nsAtom, nsStaticAtom
26 #include "nsCOMPtr.h" // for already_AddRefed, nsCOMPtr
27 #include "nsCycleCollectionParticipant.h"
28 #include "nsGkAtoms.h"
29 #include "nsIContentInlines.h" // for nsINode::IsEditable()
30 #include "nsIEditor.h" // for nsIEditor, etc.
31 #include "nsIFrame.h" // for nsBidiLevel
32 #include "nsISelectionController.h" // for nsISelectionController constants
33 #include "nsISelectionListener.h" // for nsISelectionListener
34 #include "nsISupportsImpl.h" // for EditorBase::Release, etc.
35 #include "nsIWeakReferenceUtils.h" // for nsWeakPtr
36 #include "nsLiteralString.h" // for NS_LITERAL_STRING
37 #include "nsPIDOMWindow.h" // for nsPIDOMWindowInner, etc.
38 #include "nsString.h" // for nsCString
39 #include "nsTArray.h" // for nsTArray and nsAutoTArray
40 #include "nsWeakReference.h" // for nsSupportsWeakReference
41 #include "nscore.h" // for nsresult, nsAString, etc.
43 class mozInlineSpellChecker
;
47 class nsIDocumentEncoder
;
48 class nsIDocumentStateListener
;
49 class nsIEditActionListener
;
50 class nsIEditorObserver
;
54 class nsITransferable
;
56 class nsITransactionListener
;
61 class AlignStateAtSelection
;
63 class AutoSelectionRestorer
;
64 class AutoTopLevelEditSubActionNotifier
;
65 class AutoTransactionBatch
;
66 class AutoTransactionsConserveSelection
;
67 class AutoUpdateViewBatch
;
68 class ChangeAttributeTransaction
;
69 class CompositionTransaction
;
70 class CreateElementTransaction
;
72 class DeleteNodeTransaction
;
73 class DeleteRangeTransaction
;
74 class DeleteTextTransaction
;
75 class EditActionResult
;
76 class EditAggregateTransaction
;
77 class EditorEventListener
;
78 class EditTransactionBase
;
82 class IMEContentObserver
;
83 class InsertNodeTransaction
;
84 class InsertTextTransaction
;
85 class JoinNodeTransaction
;
86 class ListElementSelectionState
;
87 class ListItemElementSelectionState
;
88 class ParagraphStateAtSelection
;
89 class PlaceholderTransaction
;
91 class ReplaceTextTransaction
;
92 class SplitNodeResult
;
93 class SplitNodeTransaction
;
94 class TextComposition
;
96 class TextInputListener
;
97 class TextServicesDocument
;
99 class WhiteSpaceVisibilityKeeper
;
101 template <typename NodeType
>
102 class CreateNodeResultBase
;
103 typedef CreateNodeResultBase
<dom::Element
> CreateElementResult
;
117 } // namespace widget
120 * Implementation of an editor object. it will be the controller/focal point
121 * for the main editor services. i.e. the GUIManager, publishing, transaction
122 * manager, event interfaces. the idea for the event interfaces is to have them
123 * delegate the actual commands to the editor independent of the XPFE
126 class EditorBase
: public nsIEditor
,
127 public nsISelectionListener
,
128 public nsSupportsWeakReference
{
130 /****************************************************************************
131 * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other
132 * classes under libeditor except EditorEventListener and
133 * HTMLEditorEventListener because each public method which may fire
134 * eEditorInput event will need to instantiate new stack class for
135 * managing input type value of eEditorInput and cache some objects
136 * for smarter handling. In other words, when you add new root
137 * method to edit the DOM tree, you can make your new method public.
138 ****************************************************************************/
140 typedef dom::Document Document
;
141 typedef dom::Element Element
;
142 typedef dom::Selection Selection
;
143 typedef dom::Text Text
;
145 enum class EditorType
{ Text
, HTML
};
147 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
148 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase
, nsIEditor
)
153 // nsISelectionListener method
154 NS_DECL_NSISELECTIONLISTENER
157 * The default constructor. This should suffice. the setting of the
158 * interfaces is done after the construction of the editor class.
163 * Init is to tell the implementation of nsIEditor to begin its services
164 * @param aDoc The dom document interface being observed
165 * @param aRoot This is the root of the editable section of this
166 * document. If it is null then we get root
167 * from document body.
168 * @param aSelCon this should be used to get the selection location
169 * (will be null for HTML editors)
170 * @param aFlags A bitmask of flags for specifying the behavior
173 MOZ_CAN_RUN_SCRIPT
virtual nsresult
Init(Document
& doc
, Element
* aRoot
,
174 nsISelectionController
* aSelCon
,
176 const nsAString
& aInitialValue
);
179 * PostCreate should be called after Init, and is the time that the editor
180 * tells its documentStateObservers that the document has been created.
182 MOZ_CAN_RUN_SCRIPT nsresult
PostCreate();
185 * PreDestroy is called before the editor goes away, and gives the editor a
186 * chance to tell its documentStateObservers that the document is going away.
187 * @param aDestroyingFrames set to true when the frames being edited
188 * are being destroyed (so there is no need to modify any nsISelections,
189 * nor is it safe to do so)
191 MOZ_CAN_RUN_SCRIPT
virtual void PreDestroy(bool aDestroyingFrames
);
193 bool IsInitialized() const { return !!mDocument
; }
194 bool Destroyed() const { return mDidPreDestroy
; }
196 Document
* GetDocument() const { return mDocument
; }
197 nsPIDOMWindowOuter
* GetWindow() const;
198 nsPIDOMWindowInner
* GetInnerWindow() const;
201 * MayHaveMutationEventListeners() returns true when the window may have
202 * mutation event listeners.
204 * @param aMutationEventType One or multiple of NS_EVENT_BITS_MUTATION_*.
205 * @return true if the editor is an HTMLEditor instance,
206 * and at least one of NS_EVENT_BITS_MUTATION_* is
207 * set to the window or in debug build.
209 bool MayHaveMutationEventListeners(
210 uint32_t aMutationEventType
= 0xFFFFFFFF) const {
211 if (IsTextEditor()) {
212 // DOM mutation event listeners cannot catch the changes of
213 // <input type="text"> nor <textarea>.
217 // On debug build, this should always return true for testing complicated
218 // path without mutation event listeners because when mutation event
219 // listeners do not touch the DOM, editor needs to run as there is no
220 // mutation event listeners.
222 #else // #ifdef DEBUG
223 nsPIDOMWindowInner
* window
= GetInnerWindow();
224 return window
? window
->HasMutationListeners(aMutationEventType
) : false;
225 #endif // #ifdef DEBUG #else
229 * MayHaveBeforeInputEventListenersForTelemetry() returns true when the
230 * window may have or have had one or more `beforeinput` event listeners.
231 * Note that this may return false even if there is a `beforeinput`.
232 * See nsPIDOMWindowInner::HasBeforeInputEventListenersForTelemetry()'s
233 * comment for the detail.
235 bool MayHaveBeforeInputEventListenersForTelemetry() const {
236 if (const nsPIDOMWindowInner
* window
= GetInnerWindow()) {
237 return window
->HasBeforeInputEventListenersForTelemetry();
243 * MutationObserverHasObservedNodeForTelemetry() returns true when a node in
244 * the window may have been observed by the web apps with a mutation observer
245 * (i.e., `MutationObserver.observe()` called by chrome script and addon's
246 * script does not make this returns true).
247 * Note that this may return false even if there is a node observed by
248 * a MutationObserver. See
249 * nsPIDOMWindowInner::MutationObserverHasObservedNodeForTelemetry()'s comment
252 bool MutationObserverHasObservedNodeForTelemetry() const {
253 if (const nsPIDOMWindowInner
* window
= GetInnerWindow()) {
254 return window
->MutationObserverHasObservedNodeForTelemetry();
259 PresShell
* GetPresShell() const;
260 nsPresContext
* GetPresContext() const;
261 already_AddRefed
<nsCaret
> GetCaret() const;
263 already_AddRefed
<nsIWidget
> GetWidget();
265 nsISelectionController
* GetSelectionController() const;
267 nsresult
GetSelection(SelectionType aSelectionType
,
268 Selection
** aSelection
) const;
270 Selection
* GetSelection(
271 SelectionType aSelectionType
= SelectionType::eNormal
) const {
272 if (aSelectionType
== SelectionType::eNormal
&&
273 IsEditActionDataAvailable()) {
274 return &SelectionRef();
276 nsISelectionController
* sc
= GetSelectionController();
280 Selection
* selection
= sc
->GetSelection(ToRawSelectionType(aSelectionType
));
285 * Fast non-refcounting editor root element accessor
287 Element
* GetRoot() const { return mRootElement
; }
290 * Likewise, but gets the text control element instead of the root for
293 Element
* GetExposedRoot() const;
296 * Set or unset TextInputListener. If setting non-nullptr when the editor
297 * already has a TextInputListener, this will crash in debug build.
299 void SetTextInputListener(TextInputListener
* aTextInputListener
);
302 * Set or unset IMEContentObserver. If setting non-nullptr when the editor
303 * already has an IMEContentObserver, this will crash in debug build.
305 void SetIMEContentObserver(IMEContentObserver
* aIMEContentObserver
);
308 * Returns current composition.
310 TextComposition
* GetComposition() const;
313 * Get preferred IME status of current widget.
315 virtual nsresult
GetPreferredIMEState(widget::IMEState
* aState
);
318 * Returns true if there is composition string and not fixed.
320 bool IsIMEComposing() const;
323 * Commit composition if there is.
324 * Note that when there is a composition, this requests to commit composition
325 * to native IME. Therefore, when there is composition, this can do anything.
326 * For example, the editor instance, the widget or the process itself may
329 nsresult
CommitComposition();
332 * ToggleTextDirection() toggles text-direction of the root element.
334 * @param aPrincipal Set subject principal if it may be called by
335 * JS. If set to nullptr, will be treated as
338 MOZ_CAN_RUN_SCRIPT nsresult
339 ToggleTextDirectionAsAction(nsIPrincipal
* aPrincipal
= nullptr);
342 * SwitchTextDirectionTo() sets the text-direction of the root element to
345 enum class TextDirection
{
349 MOZ_CAN_RUN_SCRIPT
void SwitchTextDirectionTo(TextDirection aTextDirection
);
352 * Finalizes selection and caret for the editor.
354 nsresult
FinalizeSelection();
357 * Returns true if selection is in an editable element and both the range
358 * start and the range end are editable. E.g., even if the selection range
359 * includes non-editable elements, returns true when one of common ancestors
360 * of the range start and the range end is editable. Otherwise, false.
362 bool IsSelectionEditable();
365 * Returns number of undo or redo items.
367 size_t NumberOfUndoItems() const {
368 return mTransactionManager
? mTransactionManager
->NumberOfUndoItems() : 0;
370 size_t NumberOfRedoItems() const {
371 return mTransactionManager
? mTransactionManager
->NumberOfRedoItems() : 0;
375 * Returns number of maximum undo/redo transactions.
377 int32_t NumberOfMaximumTransactions() const {
378 return mTransactionManager
379 ? mTransactionManager
->NumberOfMaximumTransactions()
384 * Returns true if this editor can store transactions for undo/redo.
386 bool IsUndoRedoEnabled() const {
387 return mTransactionManager
&&
388 mTransactionManager
->NumberOfMaximumTransactions();
392 * Return true if it's possible to undo/redo right now.
394 bool CanUndo() const {
395 return IsUndoRedoEnabled() && NumberOfUndoItems() > 0;
397 bool CanRedo() const {
398 return IsUndoRedoEnabled() && NumberOfRedoItems() > 0;
402 * Enables or disables undo/redo feature. Returns true if it succeeded,
403 * otherwise, e.g., we're undoing or redoing, returns false.
405 bool EnableUndoRedo(int32_t aMaxTransactionCount
= -1) {
406 if (!mTransactionManager
) {
407 mTransactionManager
= new TransactionManager();
409 return mTransactionManager
->EnableUndoRedo(aMaxTransactionCount
);
411 bool DisableUndoRedo() {
412 if (!mTransactionManager
) {
415 return mTransactionManager
->DisableUndoRedo();
417 bool ClearUndoRedo() {
418 if (!mTransactionManager
) {
421 return mTransactionManager
->ClearUndoRedo();
425 * See Document::AreClipboardCommandsUnconditionallyEnabled.
427 bool AreClipboardCommandsUnconditionallyEnabled() const;
430 * IsCutCommandEnabled() returns whether cut command can be enabled or
431 * disabled. This always returns true if we're in non-chrome HTML/XHTML
432 * document. Otherwise, same as the result of `IsCopyToClipboardAllowed()`.
434 MOZ_CAN_RUN_SCRIPT
bool IsCutCommandEnabled() const;
437 * IsCopyCommandEnabled() returns copy command can be enabled or disabled.
438 * This always returns true if we're in non-chrome HTML/XHTML document.
439 * Otherwise, same as the result of `IsCopyToClipboardAllowed()`.
441 MOZ_CAN_RUN_SCRIPT
bool IsCopyCommandEnabled() const;
444 * IsCopyToClipboardAllowed() returns true if the selected content can
445 * be copied into the clipboard. This returns true when:
446 * - `Selection` is not collapsed and we're not a password editor.
447 * - `Selection` is not collapsed and we're a password editor but selection
448 * range is in unmasked range.
450 bool IsCopyToClipboardAllowed() const {
451 AutoEditActionDataSetter
editActionData(*this, EditAction::eNotEditing
);
452 if (NS_WARN_IF(!editActionData
.CanHandle())) {
455 return IsCopyToClipboardAllowedInternal();
459 * Adds or removes transaction listener to or from the transaction manager.
460 * Note that TransactionManager does not check if the listener is in the
461 * array. So, caller of AddTransactionListener() needs to manage if it's
462 * already been registered to the transaction manager.
464 bool AddTransactionListener(nsITransactionListener
& aListener
) {
465 if (!mTransactionManager
) {
468 return mTransactionManager
->AddTransactionListener(aListener
);
470 bool RemoveTransactionListener(nsITransactionListener
& aListener
) {
471 if (!mTransactionManager
) {
474 return mTransactionManager
->RemoveTransactionListener(aListener
);
478 * HandleDropEvent() is called from EditorEventListener::Drop that is handler
481 MOZ_CAN_RUN_SCRIPT nsresult
HandleDropEvent(dom::DragEvent
* aDropEvent
);
483 MOZ_CAN_RUN_SCRIPT
virtual nsresult
HandleKeyPressEvent(
484 WidgetKeyboardEvent
* aKeyboardEvent
);
486 virtual dom::EventTarget
* GetDOMEventTarget() const = 0;
489 * OnCompositionStart() is called when editor receives eCompositionStart
490 * event which should be handled in this editor.
492 nsresult
OnCompositionStart(WidgetCompositionEvent
& aCompositionStartEvent
);
495 * OnCompositionChange() is called when editor receives an eCompositioChange
496 * event which should be handled in this editor.
498 * @param aCompositionChangeEvent eCompositionChange event which should
499 * be handled in this editor.
501 MOZ_CAN_RUN_SCRIPT nsresult
502 OnCompositionChange(WidgetCompositionEvent
& aCompositionChangeEvent
);
505 * OnCompositionEnd() is called when editor receives an eCompositionChange
506 * event and it's followed by eCompositionEnd event and after
507 * OnCompositionChange() is called.
509 MOZ_CAN_RUN_SCRIPT
void OnCompositionEnd(
510 WidgetCompositionEvent
& aCompositionEndEvent
);
513 * Similar to the setter for wrapWidth, but just sets the editor
514 * internal state without actually changing the content being edited
515 * to wrap at that column. This should only be used by callers who
516 * are sure that their content is already set up correctly.
518 void SetWrapColumn(int32_t aWrapColumn
) { mWrapColumn
= aWrapColumn
; }
521 * Accessor methods to flags.
523 uint32_t Flags() const { return mFlags
; }
525 MOZ_CAN_RUN_SCRIPT nsresult
AddFlags(uint32_t aFlags
) {
526 const uint32_t kOldFlags
= Flags();
527 const uint32_t kNewFlags
= (kOldFlags
| aFlags
);
528 if (kNewFlags
== kOldFlags
) {
531 return SetFlags(kNewFlags
); // virtual call and may be expensive.
533 MOZ_CAN_RUN_SCRIPT nsresult
RemoveFlags(uint32_t aFlags
) {
534 const uint32_t kOldFlags
= Flags();
535 const uint32_t kNewFlags
= (kOldFlags
& ~aFlags
);
536 if (kNewFlags
== kOldFlags
) {
539 return SetFlags(kNewFlags
); // virtual call and may be expensive.
541 MOZ_CAN_RUN_SCRIPT nsresult
AddAndRemoveFlags(uint32_t aAddingFlags
,
542 uint32_t aRemovingFlags
) {
543 MOZ_ASSERT(!(aAddingFlags
& aRemovingFlags
),
544 "Same flags are specified both adding and removing");
545 const uint32_t kOldFlags
= Flags();
546 const uint32_t kNewFlags
= ((kOldFlags
| aAddingFlags
) & ~aRemovingFlags
);
547 if (kNewFlags
== kOldFlags
) {
550 return SetFlags(kNewFlags
); // virtual call and may be expensive.
553 bool IsPlaintextEditor() const {
554 return (mFlags
& nsIEditor::eEditorPlaintextMask
) != 0;
557 bool IsSingleLineEditor() const {
558 return (mFlags
& nsIEditor::eEditorSingleLineMask
) != 0;
561 bool IsPasswordEditor() const {
562 return (mFlags
& nsIEditor::eEditorPasswordMask
) != 0;
565 // FYI: Both IsRightToLeft() and IsLeftToRight() may return false if
566 // the editor inherits the content node's direction.
567 bool IsRightToLeft() const {
568 return (mFlags
& nsIEditor::eEditorRightToLeft
) != 0;
570 bool IsLeftToRight() const {
571 return (mFlags
& nsIEditor::eEditorLeftToRight
) != 0;
574 bool IsReadonly() const {
575 return (mFlags
& nsIEditor::eEditorReadonlyMask
) != 0;
578 bool IsInputFiltered() const {
579 return (mFlags
& nsIEditor::eEditorFilterInputMask
) != 0;
582 bool IsMailEditor() const {
583 return (mFlags
& nsIEditor::eEditorMailMask
) != 0;
586 bool IsWrapHackEnabled() const {
587 return (mFlags
& nsIEditor::eEditorEnableWrapHackMask
) != 0;
590 bool IsFormWidget() const {
591 return (mFlags
& nsIEditor::eEditorWidgetMask
) != 0;
594 bool NoCSS() const { return (mFlags
& nsIEditor::eEditorNoCSSMask
) != 0; }
596 bool IsInteractionAllowed() const {
597 return (mFlags
& nsIEditor::eEditorAllowInteraction
) != 0;
600 bool ShouldSkipSpellCheck() const {
601 return (mFlags
& nsIEditor::eEditorSkipSpellCheck
) != 0;
604 bool IsTabbable() const {
605 return IsSingleLineEditor() || IsPasswordEditor() || IsFormWidget() ||
606 IsInteractionAllowed();
609 bool HasIndependentSelection() const { return !!mSelectionController
; }
611 bool IsModifiable() const { return !IsReadonly(); }
614 * IsInEditSubAction() return true while the instance is handling an edit
615 * sub-action. Otherwise, false.
617 bool IsInEditSubAction() const { return mIsInEditSubAction
; }
620 * IsEmpty() checks whether the editor is empty. If editor has only padding
621 * <br> element for empty editor, returns true. If editor's root element has
622 * non-empty text nodes or other nodes like <br>, returns false.
624 virtual bool IsEmpty() const = 0;
627 * SuppressDispatchingInputEvent() suppresses or unsuppresses dispatching
630 void SuppressDispatchingInputEvent(bool aSuppress
) {
631 mDispatchInputEvent
= !aSuppress
;
635 * IsSuppressingDispatchingInputEvent() returns true if the editor stops
636 * dispatching input event. Otherwise, false.
638 bool IsSuppressingDispatchingInputEvent() const {
639 return !mDispatchInputEvent
;
643 * Returns true if markNodeDirty() has any effect. Returns false if
644 * markNodeDirty() is a no-op.
646 bool OutputsMozDirty() const {
647 // Return true for Composer (!IsInteractionAllowed()) or mail
648 // (IsMailEditor()), but false for webpages.
649 return !IsInteractionAllowed() || IsMailEditor();
653 * Get the focused content, if we're focused. Returns null otherwise.
655 virtual nsIContent
* GetFocusedContent() const;
658 * Get the focused content for the argument of some IMEStateManager's
661 virtual nsIContent
* GetFocusedContentForIME() const;
664 * Whether the aGUIEvent should be handled by this editor or not. When this
665 * returns false, The aGUIEvent shouldn't be handled on this editor,
666 * i.e., The aGUIEvent should be handled by another inner editor or ancestor
669 virtual bool IsAcceptableInputEvent(WidgetGUIEvent
* aGUIEvent
) const;
672 * FindSelectionRoot() returns a selection root of this editor when aNode
673 * gets focus. aNode must be a content node or a document node. When the
674 * target isn't a part of this editor, returns nullptr. If this is for
675 * designMode, you should set the document node to aNode except that an
676 * element in the document has focus.
678 virtual Element
* FindSelectionRoot(nsINode
* aNode
) const;
681 * This method has to be called by EditorEventListener::Focus.
682 * All actions that have to be done when the editor is focused needs to be
685 MOZ_CAN_RUN_SCRIPT
void OnFocus(nsINode
& aFocusEventTargetNode
);
687 /** Resyncs spellchecking state (enabled/disabled). This should be called
688 * when anything that affects spellchecking state changes, such as the
689 * spellcheck attribute value.
691 void SyncRealTimeSpell();
694 * This method re-initializes the selection and caret state that are for
695 * current editor state. When editor session is destroyed, it always reset
696 * selection state even if this has no focus. So if destroying editor,
697 * we have to call this method for focused editor to set selection state.
699 MOZ_CAN_RUN_SCRIPT
void ReinitializeSelection(Element
& aElement
);
704 * @param aPrincipal If you know current context is subject
705 * principal or system principal, set it.
706 * When nullptr, this checks it automatically.
708 MOZ_CAN_RUN_SCRIPT nsresult
CutAsAction(nsIPrincipal
* aPrincipal
= nullptr);
711 * CanPaste() returns true if user can paste something at current selection.
713 virtual bool CanPaste(int32_t aClipboardType
) const = 0;
716 * Do "undo" or "redo".
718 * @param aCount How many count of transactions should be
720 * @param aPrincipal Set subject principal if it may be called by
721 * JS. If set to nullptr, will be treated as
724 MOZ_CAN_RUN_SCRIPT nsresult
UndoAsAction(uint32_t aCount
,
725 nsIPrincipal
* aPrincipal
= nullptr);
726 MOZ_CAN_RUN_SCRIPT nsresult
RedoAsAction(uint32_t aCount
,
727 nsIPrincipal
* aPrincipal
= nullptr);
730 * InsertTextAsAction() inserts aStringToInsert at selection.
731 * Although this method is implementation of nsIEditor.insertText(),
732 * this treats the input is an edit action. If you'd like to insert text
733 * as part of edit action, you probably should use InsertTextAsSubAction().
735 * @param aStringToInsert The string to insert.
736 * @param aPrincipal Set subject principal if it may be called by
737 * JS. If set to nullptr, will be treated as
740 MOZ_CAN_RUN_SCRIPT nsresult
InsertTextAsAction(
741 const nsAString
& aStringToInsert
, nsIPrincipal
* aPrincipal
= nullptr);
744 * InsertLineBreakAsAction() is called when user inputs a line break with
745 * Enter or something. If the instance is `HTMLEditor`, this is called
746 * when Shift + Enter or "insertlinebreak" command.
748 * @param aPrincipal Set subject principal if it may be called by
749 * JS. If set to nullptr, will be treated as
752 MOZ_CAN_RUN_SCRIPT
virtual nsresult
InsertLineBreakAsAction(
753 nsIPrincipal
* aPrincipal
= nullptr) = 0;
756 * CanDeleteSelection() returns true if `Selection` is not collapsed and
757 * it's allowed to be removed.
759 bool CanDeleteSelection() const {
760 AutoEditActionDataSetter
editActionData(*this, EditAction::eNotEditing
);
761 if (NS_WARN_IF(!editActionData
.CanHandle())) {
764 return IsModifiable() && !SelectionRef().IsCollapsed();
768 * DeleteSelectionAsAction() removes selection content or content around
769 * caret with transactions. This should be used for handling it as an
770 * edit action. If you'd like to remove selection for preparing to insert
771 * something, you probably should use DeleteSelectionAsSubAction().
773 * @param aDirectionAndAmount How much range should be removed.
774 * @param aStripWrappers Whether the parent blocks should be removed
775 * when they become empty.
776 * @param aPrincipal Set subject principal if it may be called by
777 * JS. If set to nullptr, will be treated as
780 MOZ_CAN_RUN_SCRIPT nsresult
781 DeleteSelectionAsAction(nsIEditor::EDirection aDirectionAndAmount
,
782 nsIEditor::EStripWrappers aStripWrappers
,
783 nsIPrincipal
* aPrincipal
= nullptr);
785 enum class AllowBeforeInputEventCancelable
{
791 * Replace text in aReplaceRange or all text in this editor with aString and
792 * treat the change as inserting the string.
794 * @param aString The string to set.
795 * @param aReplaceRange The range to be replaced.
796 * If nullptr, all contents will be replaced.
797 * NOTE: Currently, nullptr is not allowed if
798 * the editor is an HTMLEditor.
799 * @param aAllowBeforeInputEventCancelable
800 * Whether `beforeinput` event which will be
801 * dispatched for this can be cancelable or not.
802 * @param aPrincipal Set subject principal if it may be called by
803 * JS. If set to nullptr, will be treated as
806 MOZ_CAN_RUN_SCRIPT nsresult
ReplaceTextAsAction(
807 const nsAString
& aString
, nsRange
* aReplaceRange
,
808 AllowBeforeInputEventCancelable aAllowBeforeInputEventCancelable
,
809 nsIPrincipal
* aPrincipal
= nullptr);
812 * Can we paste |aTransferable| or, if |aTransferable| is null, will a call
813 * to pasteTransferable later possibly succeed if given an instance of
814 * nsITransferable then? True if the doc is modifiable, and, if
815 * |aTransfeable| is non-null, we have pasteable data in |aTransfeable|.
817 virtual bool CanPasteTransferable(nsITransferable
* aTransferable
) = 0;
820 * PasteAsAction() pastes clipboard content to Selection. This method
821 * may dispatch ePaste event first. If its defaultPrevent() is called,
822 * this does nothing but returns NS_OK.
824 * @param aClipboardType nsIClipboard::kGlobalClipboard or
825 * nsIClipboard::kSelectionClipboard.
826 * @param aDispatchPasteEvent true if this should dispatch ePaste event
827 * before pasting. Otherwise, false.
828 * @param aPrincipal Set subject principal if it may be called by
829 * JS. If set to nullptr, will be treated as
832 MOZ_CAN_RUN_SCRIPT
virtual nsresult
PasteAsAction(
833 int32_t aClipboardType
, bool aDispatchPasteEvent
,
834 nsIPrincipal
* aPrincipal
= nullptr) = 0;
837 * Paste aTransferable at Selection.
839 * @param aTransferable Must not be nullptr.
840 * @param aPrincipal Set subject principal if it may be called by
841 * JS. If set to nullptr, will be treated as
844 MOZ_CAN_RUN_SCRIPT
virtual nsresult
PasteTransferableAsAction(
845 nsITransferable
* aTransferable
, nsIPrincipal
* aPrincipal
= nullptr) = 0;
848 * PasteAsQuotationAsAction() pastes content in clipboard as quotation.
849 * If the editor is TextEditor or in plaintext mode, will paste the content
850 * with appending ">" to start of each line.
851 * if the editor is HTMLEditor and is not in plaintext mode, will patste it
852 * into newly created blockquote element.
854 * @param aClipboardType nsIClipboard::kGlobalClipboard or
855 * nsIClipboard::kSelectionClipboard.
856 * @param aDispatchPasteEvent true if this should dispatch ePaste event
857 * before pasting. Otherwise, false.
858 * @param aPrincipal Set subject principal if it may be called by
859 * JS. If set to nullptr, will be treated as
862 MOZ_CAN_RUN_SCRIPT
virtual nsresult
PasteAsQuotationAsAction(
863 int32_t aClipboardType
, bool aDispatchPasteEvent
,
864 nsIPrincipal
* aPrincipal
= nullptr) = 0;
866 protected: // May be used by friends.
867 class AutoEditActionDataSetter
;
870 * TopLevelEditSubActionData stores temporary data while we're handling
871 * top-level edit sub-action.
873 struct MOZ_STACK_CLASS TopLevelEditSubActionData final
{
874 friend class AutoEditActionDataSetter
;
876 // If we have created a new block element, set to it.
877 RefPtr
<Element
> mNewBlockElement
;
879 // Set selected range before edit. Then, RangeUpdater keep modifying
880 // the range while we're changing the DOM tree.
881 RefPtr
<RangeItem
> mSelectedRange
;
883 // Computing changed range while we're handling sub actions.
884 RefPtr
<nsRange
> mChangedRange
;
886 // XXX In strict speaking, mCachedInlineStyles isn't enough to cache inline
887 // styles because inline style can be specified with "style" attribute
888 // and/or CSS in <style> elements or CSS files. So, we need to look
889 // for better implementation about this.
890 // FYI: Initialization cost of AutoStyleCacheArray is expensive and it is
891 // not used by TextEditor so that we should construct it only when
892 // we're an HTMLEditor.
893 Maybe
<AutoStyleCacheArray
> mCachedInlineStyles
;
895 // If we tried to delete selection, set to true.
896 bool mDidDeleteSelection
;
898 // If we have explicitly set selection inter line, set to true.
899 // `AfterEdit()` or something shouldn't overwrite it in such case.
900 bool mDidExplicitlySetInterLine
;
902 // If we have deleted non-collapsed range set to true, there are only 2
904 // - non-collapsed range was selected.
905 // - selection was collapsed in a text node and a Unicode character
907 bool mDidDeleteNonCollapsedRange
;
909 // If we have deleted parent empty blocks, set to true.
910 bool mDidDeleteEmptyParentBlocks
;
912 // If we're a contenteditable editor, we temporarily increase edit count
913 // of the document between `BeforeEdit()` and `AfterEdit()`. I.e., if
914 // we increased the count in `BeforeEdit()`, we need to decrease it in
915 // `AfterEdit()`, however, the document may be changed to designMode or
916 // non-editable. Therefore, we need to store with this whether we need
918 bool mRestoreContentEditableCount
;
920 // If we explicitly normalized whitespaces around the changed range,
922 bool mDidNormalizeWhitespaces
;
925 * The following methods modifies some data of this struct and
926 * `EditSubActionData` struct. Currently, these are required only
927 * by `HTMLEditor`. Therefore, for cutting the runtime cost of
928 * `TextEditor`, these methods should be called only by `HTMLEditor`.
929 * But it's fine to use these methods in `TextEditor` if necessary.
930 * If so, you need to call `DidDeleteText()` and `DidInsertText()`
931 * from `SetTextNodeWithoutTransaction()`.
933 void DidCreateElement(EditorBase
& aEditorBase
, Element
& aNewElement
);
934 void DidInsertContent(EditorBase
& aEditorBase
, nsIContent
& aNewContent
);
935 void WillDeleteContent(EditorBase
& aEditorBase
,
936 nsIContent
& aRemovingContent
);
937 void DidSplitContent(EditorBase
& aEditorBase
,
938 nsIContent
& aExistingRightContent
,
939 nsIContent
& aNewLeftContent
);
940 void WillJoinContents(EditorBase
& aEditorBase
, nsIContent
& aLeftContent
,
941 nsIContent
& aRightContent
);
942 void DidJoinContents(EditorBase
& aEditorBase
, nsIContent
& aLeftContent
,
943 nsIContent
& aRightContent
);
944 void DidInsertText(EditorBase
& aEditorBase
,
945 const EditorRawDOMPoint
& aInsertionBegin
,
946 const EditorRawDOMPoint
& aInsertionEnd
);
947 void DidDeleteText(EditorBase
& aEditorBase
,
948 const EditorRawDOMPoint
& aStartInTextNode
);
949 void WillDeleteRange(EditorBase
& aEditorBase
,
950 const EditorRawDOMPoint
& aStart
,
951 const EditorRawDOMPoint
& aEnd
);
955 mDidExplicitlySetInterLine
= false;
956 // We don't need to clear other members which are referred only when the
957 // editor is an HTML editor anymore. Note that if `mSelectedRange` is
958 // non-nullptr, that means that we're in `HTMLEditor`.
959 if (!mSelectedRange
) {
962 mNewBlockElement
= nullptr;
963 mSelectedRange
->Clear();
964 mChangedRange
->Reset();
965 if (mCachedInlineStyles
.isSome()) {
966 mCachedInlineStyles
->Clear();
968 mDidDeleteSelection
= false;
969 mDidDeleteNonCollapsedRange
= false;
970 mDidDeleteEmptyParentBlocks
= false;
971 mRestoreContentEditableCount
= false;
972 mDidNormalizeWhitespaces
= false;
976 * Extend mChangedRange to include `aNode`.
978 nsresult
AddNodeToChangedRange(const HTMLEditor
& aHTMLEditor
,
982 * Extend mChangedRange to include `aPoint`.
984 nsresult
AddPointToChangedRange(const HTMLEditor
& aHTMLEditor
,
985 const EditorRawDOMPoint
& aPoint
);
988 * Extend mChangedRange to include `aStart` and `aEnd`.
990 nsresult
AddRangeToChangedRange(const HTMLEditor
& aHTMLEditor
,
991 const EditorRawDOMPoint
& aStart
,
992 const EditorRawDOMPoint
& aEnd
);
994 TopLevelEditSubActionData() = default;
995 TopLevelEditSubActionData(const TopLevelEditSubActionData
& aOther
) = delete;
998 struct MOZ_STACK_CLASS EditSubActionData final
{
999 uint32_t mJoinedLeftNodeLength
;
1001 // While this is set to false, TopLevelEditSubActionData::mChangedRange
1002 // shouldn't be modified since in some cases, modifying it in the setter
1003 // itself may be faster. Note that we should affect this only for current
1004 // edit sub action since mutation event listener may edit different range.
1005 bool mAdjustChangedRangeFromListener
;
1009 mJoinedLeftNodeLength
= 0;
1010 mAdjustChangedRangeFromListener
= true;
1016 protected: // AutoEditActionDataSetter, this shouldn't be accessed by friends.
1018 * SettingDataTransfer enum class is used to specify whether DataTransfer
1019 * should be initialized with or without format. For example, when user
1020 * uses Accel + Shift + V to paste text without format, DataTransfer should
1021 * have only plain/text data to make web apps treat it without format.
1023 enum class SettingDataTransfer
{
1029 * AutoEditActionDataSetter grabs some necessary objects for handling any
1030 * edit actions and store the edit action what we're handling. When this is
1031 * created, its pointer is set to the mEditActionData, and this guarantees
1032 * the lifetime of grabbing objects until it's destroyed.
1034 class MOZ_STACK_CLASS AutoEditActionDataSetter final
{
1036 // NOTE: aPrincipal will be used when we implement "beforeinput" event.
1037 // It's set only when maybe we shouldn't dispatch it because of
1038 // called by JS. I.e., if this is nullptr, we can always dispatch
1040 AutoEditActionDataSetter(const EditorBase
& aEditorBase
,
1041 EditAction aEditAction
,
1042 nsIPrincipal
* aPrincipal
= nullptr);
1043 ~AutoEditActionDataSetter();
1045 void UpdateEditAction(EditAction aEditAction
) {
1046 MOZ_ASSERT(!mHasTriedToDispatchBeforeInputEvent
,
1047 "It's too late to update EditAction since this may have "
1048 "already dispatched a beforeinput event");
1049 mEditAction
= aEditAction
;
1053 * CanHandle() or CanHandleAndHandleBeforeInput() must be called
1054 * immediately after creating the instance. If caller does not need to
1055 * handle "beforeinput" event or caller needs to set additional information
1056 * the events later, use the former. Otherwise, use the latter. If caller
1057 * uses the former, it's required to call MaybeDispatchBeforeInputEvent() by
1061 [[nodiscard
]] bool CanHandle() const {
1063 mHasCanHandleChecked
= true;
1064 #endif // #ifdefn DEBUG
1065 // Don't allow to run new edit action when an edit action caused
1066 // destroying the editor while it's being handled.
1067 if (mEditAction
!= EditAction::eInitializing
&&
1068 mEditorWasDestroyedDuringHandlingEditAction
) {
1069 NS_WARNING("Editor was destroyed during an edit action being handled");
1072 return IsDataAvailable();
1074 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1075 CanHandleAndMaybeDispatchBeforeInputEvent() {
1076 if (NS_WARN_IF(!CanHandle())) {
1077 return NS_ERROR_NOT_INITIALIZED
;
1079 return MaybeDispatchBeforeInputEvent();
1082 [[nodiscard
]] bool IsDataAvailable() const {
1083 return mSelection
&& mEditorBase
.IsInitialized();
1087 * MaybeDispatchBeforeInputEvent() considers whether this instance needs to
1088 * dispatch "beforeinput" event or not. Then,
1089 * mHasTriedToDispatchBeforeInputEvent is set to true.
1091 * @param aDeleteDirectionAndAmount
1092 * If `MayEditActionDeleteAroundCollapsedSelection(
1093 * mEditAction)` returns true, this must be set.
1094 * Otherwise, don't set explicitly.
1095 * @return If this method actually dispatches "beforeinput" event
1096 * and it's canceled, returns
1097 * NS_ERROR_EDITOR_ACTION_CANCELED.
1099 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
MaybeDispatchBeforeInputEvent(
1100 nsIEditor::EDirection aDeleteDirectionAndAmount
= nsIEditor::eNone
);
1103 * MarkAsBeforeInputHasBeenDispatched() should be called only when updating
1104 * the DOM occurs asynchronously from user input (e.g., inserting blob
1105 * object which is loaded asynchronously) and `beforeinput` has already
1106 * been dispatched (always should be so).
1108 void MarkAsBeforeInputHasBeenDispatched() {
1109 MOZ_ASSERT(!HasTriedToDispatchBeforeInputEvent());
1110 MOZ_ASSERT(mEditAction
== EditAction::ePaste
||
1111 mEditAction
== EditAction::ePasteAsQuotation
||
1112 mEditAction
== EditAction::eDrop
);
1113 mHasTriedToDispatchBeforeInputEvent
= true;
1117 * MarkAsHandled() is called before dispatching `input` event and notifying
1118 * editor observers. After this is called, any nested edit action become
1121 void MarkAsHandled() {
1122 MOZ_ASSERT(!mHandled
);
1127 * ShouldAlreadyHaveHandledBeforeInputEventDispatching() returns true if the
1128 * edit action requires to handle "beforeinput" event but not yet dispatched
1129 * it nor considered as not dispatched it and can dispatch it when this is
1132 bool ShouldAlreadyHaveHandledBeforeInputEventDispatching() const {
1133 return !HasTriedToDispatchBeforeInputEvent() &&
1134 NeedsBeforeInputEventHandling(mEditAction
) &&
1135 IsBeforeInputEventEnabled() /* &&
1136 // If we still need to dispatch a clipboard event, we should
1137 // dispatch it first, then, we need to dispatch beforeinput
1139 !NeedsToDispatchClipboardEvent()*/
1144 * HasTriedToDispatchBeforeInputEvent() returns true if the instance's
1145 * MaybeDispatchBeforeInputEvent() has already been called.
1147 bool HasTriedToDispatchBeforeInputEvent() const {
1148 return mHasTriedToDispatchBeforeInputEvent
;
1151 bool IsCanceled() const { return mBeforeInputEventCanceled
; }
1154 * Returns a `Selection` for normal selection. The lifetime is guaranteed
1155 * during alive this instance in the stack.
1157 MOZ_KNOWN_LIVE Selection
& SelectionRef() const {
1158 MOZ_ASSERT(!mSelection
||
1159 (mSelection
->GetType() == SelectionType::eNormal
));
1163 nsIPrincipal
* GetPrincipal() const { return mPrincipal
; }
1164 EditAction
GetEditAction() const { return mEditAction
; }
1166 template <typename PT
, typename CT
>
1167 void SetSpellCheckRestartPoint(const EditorDOMPointBase
<PT
, CT
>& aPoint
) {
1168 MOZ_ASSERT(aPoint
.IsSet());
1169 // We should store only container and offset because new content may
1170 // be inserted before referring child.
1171 // XXX Shouldn't we compare whether aPoint is before
1172 // mSpellCheckRestartPoint if it's set.
1173 mSpellCheckRestartPoint
=
1174 EditorDOMPoint(aPoint
.GetContainer(), aPoint
.Offset());
1176 void ClearSpellCheckRestartPoint() { mSpellCheckRestartPoint
.Clear(); }
1177 const EditorDOMPoint
& GetSpellCheckRestartPoint() const {
1178 return mSpellCheckRestartPoint
;
1181 void SetData(const nsAString
& aData
) {
1182 MOZ_ASSERT(!mHasTriedToDispatchBeforeInputEvent
,
1183 "It's too late to set data since this may have already "
1184 "dispatched a beforeinput event");
1187 const nsString
& GetData() const { return mData
; }
1189 void SetColorData(const nsAString
& aData
);
1192 * InitializeDataTransfer(DataTransfer*) sets mDataTransfer to
1193 * aDataTransfer. In this case, aDataTransfer should not be read/write
1194 * because it'll be set to InputEvent.dataTransfer and which should be
1197 void InitializeDataTransfer(dom::DataTransfer
* aDataTransfer
);
1199 * InitializeDataTransfer(nsITransferable*) creates new DataTransfer
1200 * instance, initializes it with aTransferable and sets mDataTransfer to
1203 void InitializeDataTransfer(nsITransferable
* aTransferable
);
1205 * InitializeDataTransfer(const nsAString&) creates new DataTransfer
1206 * instance, initializes it with aString and sets mDataTransfer to it.
1208 void InitializeDataTransfer(const nsAString
& aString
);
1210 * InitializeDataTransferWithClipboard() creates new DataTransfer instance,
1211 * initializes it with clipboard and sets mDataTransfer to it.
1213 void InitializeDataTransferWithClipboard(
1214 SettingDataTransfer aSettingDataTransfer
, int32_t aClipboardType
);
1215 dom::DataTransfer
* GetDataTransfer() const { return mDataTransfer
; }
1218 * AppendTargetRange() appends aTargetRange to target ranges. This should
1219 * be used only by edit action handlers which do not want to set target
1220 * ranges to selection ranges.
1222 void AppendTargetRange(dom::StaticRange
& aTargetRange
);
1225 * Make dispatching `beforeinput` forcibly non-cancelable.
1227 void MakeBeforeInputEventNonCancelable() {
1228 mMakeBeforeInputEventNonCancelable
= true;
1232 * NotifyOfDispatchingClipboardEvent() is called after dispatching
1233 * a clipboard event.
1235 void NotifyOfDispatchingClipboardEvent() {
1236 MOZ_ASSERT(NeedsToDispatchClipboardEvent());
1237 MOZ_ASSERT(!mHasTriedToDispatchClipboardEvent
);
1238 mHasTriedToDispatchClipboardEvent
= true;
1241 void Abort() { mAborted
= true; }
1242 bool IsAborted() const { return mAborted
; }
1244 void OnEditorDestroy() {
1245 if (!mHandled
&& mHasTriedToDispatchBeforeInputEvent
) {
1246 // Remember the editor was destroyed only when this edit action is being
1247 // handled because they are caused by mutation event listeners or
1248 // something other unexpected event listeners. In the cases, new child
1249 // edit action shouldn't been aborted.
1250 mEditorWasDestroyedDuringHandlingEditAction
= true;
1253 mParentData
->OnEditorDestroy();
1256 bool HasEditorDestroyedDuringHandlingEditAction() const {
1257 return mEditorWasDestroyedDuringHandlingEditAction
;
1260 void SetTopLevelEditSubAction(EditSubAction aEditSubAction
,
1261 EDirection aDirection
= eNone
) {
1262 mTopLevelEditSubAction
= aEditSubAction
;
1263 TopLevelEditSubActionDataRef().Clear();
1264 switch (mTopLevelEditSubAction
) {
1265 case EditSubAction::eInsertNode
:
1266 case EditSubAction::eCreateNode
:
1267 case EditSubAction::eSplitNode
:
1268 case EditSubAction::eInsertText
:
1269 case EditSubAction::eInsertTextComingFromIME
:
1270 case EditSubAction::eSetTextProperty
:
1271 case EditSubAction::eRemoveTextProperty
:
1272 case EditSubAction::eRemoveAllTextProperties
:
1273 case EditSubAction::eSetText
:
1274 case EditSubAction::eInsertLineBreak
:
1275 case EditSubAction::eInsertParagraphSeparator
:
1276 case EditSubAction::eCreateOrChangeList
:
1277 case EditSubAction::eIndent
:
1278 case EditSubAction::eOutdent
:
1279 case EditSubAction::eSetOrClearAlignment
:
1280 case EditSubAction::eCreateOrRemoveBlock
:
1281 case EditSubAction::eMergeBlockContents
:
1282 case EditSubAction::eRemoveList
:
1283 case EditSubAction::eCreateOrChangeDefinitionListItem
:
1284 case EditSubAction::eInsertElement
:
1285 case EditSubAction::eInsertQuotation
:
1286 case EditSubAction::eInsertQuotedText
:
1287 case EditSubAction::ePasteHTMLContent
:
1288 case EditSubAction::eInsertHTMLSource
:
1289 case EditSubAction::eSetPositionToAbsolute
:
1290 case EditSubAction::eSetPositionToStatic
:
1291 case EditSubAction::eDecreaseZIndex
:
1292 case EditSubAction::eIncreaseZIndex
:
1293 MOZ_ASSERT(aDirection
== eNext
);
1294 mDirectionOfTopLevelEditSubAction
= eNext
;
1296 case EditSubAction::eJoinNodes
:
1297 case EditSubAction::eDeleteText
:
1298 MOZ_ASSERT(aDirection
== ePrevious
);
1299 mDirectionOfTopLevelEditSubAction
= ePrevious
;
1301 case EditSubAction::eUndo
:
1302 case EditSubAction::eRedo
:
1303 case EditSubAction::eComputeTextToOutput
:
1304 case EditSubAction::eCreatePaddingBRElementForEmptyEditor
:
1305 case EditSubAction::eNone
:
1306 MOZ_ASSERT(aDirection
== eNone
);
1307 mDirectionOfTopLevelEditSubAction
= eNone
;
1309 case EditSubAction::eReplaceHeadWithHTMLSource
:
1310 // NOTE: Not used with AutoTopLevelEditSubActionNotifier.
1311 mDirectionOfTopLevelEditSubAction
= eNone
;
1313 case EditSubAction::eDeleteNode
:
1314 case EditSubAction::eDeleteSelectedContent
:
1315 // Unfortunately, eDeleteNode and eDeleteSelectedContent is used with
1316 // any direction. We might have specific sub-action for each
1317 // direction, but there are some points referencing
1318 // eDeleteSelectedContent so that we should keep storing direction
1320 mDirectionOfTopLevelEditSubAction
= aDirection
;
1324 EditSubAction
GetTopLevelEditSubAction() const {
1325 MOZ_ASSERT(IsDataAvailable());
1326 return mTopLevelEditSubAction
;
1328 EDirection
GetDirectionOfTopLevelEditSubAction() const {
1329 return mDirectionOfTopLevelEditSubAction
;
1332 const TopLevelEditSubActionData
& TopLevelEditSubActionDataRef() const {
1333 return mParentData
? mParentData
->TopLevelEditSubActionDataRef()
1334 : mTopLevelEditSubActionData
;
1336 TopLevelEditSubActionData
& TopLevelEditSubActionDataRef() {
1337 return mParentData
? mParentData
->TopLevelEditSubActionDataRef()
1338 : mTopLevelEditSubActionData
;
1341 const EditSubActionData
& EditSubActionDataRef() const {
1342 return mEditSubActionData
;
1344 EditSubActionData
& EditSubActionDataRef() { return mEditSubActionData
; }
1346 SelectionState
& SavedSelectionRef() {
1347 return mParentData
? mParentData
->SavedSelectionRef() : mSavedSelection
;
1349 const SelectionState
& SavedSelectionRef() const {
1350 return mParentData
? mParentData
->SavedSelectionRef() : mSavedSelection
;
1353 RangeUpdater
& RangeUpdaterRef() {
1354 return mParentData
? mParentData
->RangeUpdaterRef() : mRangeUpdater
;
1356 const RangeUpdater
& RangeUpdaterRef() const {
1357 return mParentData
? mParentData
->RangeUpdaterRef() : mRangeUpdater
;
1360 void UpdateSelectionCache(Selection
& aSelection
) {
1361 MOZ_ASSERT(aSelection
.GetType() == SelectionType::eNormal
);
1363 AutoEditActionDataSetter
* actionData
= this;
1364 while (actionData
) {
1365 if (actionData
->mSelection
) {
1366 actionData
->mSelection
= &aSelection
;
1368 actionData
= actionData
->mParentData
;
1373 bool IsBeforeInputEventEnabled() const;
1375 static bool NeedsBeforeInputEventHandling(EditAction aEditAction
) {
1376 MOZ_ASSERT(aEditAction
!= EditAction::eNone
);
1377 switch (aEditAction
) {
1378 case EditAction::eNone
:
1379 // If we're not handling edit action, we don't need to handle
1380 // "beforeinput" event.
1381 case EditAction::eNotEditing
:
1382 // If we're being initialized, we may need to create a padding <br>
1383 // element, but it shouldn't cause `beforeinput` event.
1384 case EditAction::eInitializing
:
1385 // If raw level transaction API is used, the API user needs to handle
1386 // both "beforeinput" event and "input" event if it's necessary.
1387 case EditAction::eUnknown
:
1388 // Hiding/showing password affects only layout so that we don't need
1389 // to handle beforeinput event for it.
1390 case EditAction::eHidePassword
:
1391 // We don't need to dispatch "beforeinput" event before
1392 // "compositionstart".
1393 case EditAction::eStartComposition
:
1394 // We don't need to let web apps know the mode change.
1395 case EditAction::eEnableOrDisableCSS
:
1396 case EditAction::eEnableOrDisableAbsolutePositionEditor
:
1397 case EditAction::eEnableOrDisableResizer
:
1398 case EditAction::eEnableOrDisableInlineTableEditingUI
:
1399 // We don't need to let contents in chrome's editor to know the size
1401 case EditAction::eSetWrapWidth
:
1402 // While resizing or moving element, we update only shadow, i.e.,
1403 // don't touch to the DOM in content. Therefore, we don't need to
1404 // dispatch "beforeinput" event.
1405 case EditAction::eResizingElement
:
1406 case EditAction::eMovingElement
:
1407 // Perhaps, we don't need to dispatch "beforeinput" event for
1408 // padding `<br>` element for empty editor because it's internal
1409 // handling and it should be occurred by another change.
1410 case EditAction::eCreatePaddingBRElementForEmptyEditor
:
1417 bool NeedsToDispatchClipboardEvent() const {
1418 if (mHasTriedToDispatchClipboardEvent
) {
1421 switch (mEditAction
) {
1422 case EditAction::ePaste
:
1423 case EditAction::ePasteAsQuotation
:
1424 case EditAction::eCut
:
1425 case EditAction::eCopy
:
1432 EditorBase
& mEditorBase
;
1433 RefPtr
<Selection
> mSelection
;
1434 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
1435 // EditAction may be nested, for example, a command may be executed
1436 // from mutation event listener which is run while editor changes
1437 // the DOM tree. In such case, we need to handle edit action separately.
1438 AutoEditActionDataSetter
* mParentData
;
1440 // Cached selection for AutoSelectionRestorer.
1441 SelectionState mSavedSelection
;
1443 // Utility class object for maintaining preserved ranges.
1444 RangeUpdater mRangeUpdater
;
1446 // The data should be set to InputEvent.data.
1449 // The dataTransfer should be set to InputEvent.dataTransfer.
1450 RefPtr
<dom::DataTransfer
> mDataTransfer
;
1452 // They are used for result of InputEvent.getTargetRanges() of beforeinput.
1453 OwningNonNullStaticRangeArray mTargetRanges
;
1455 // Start point where spell checker should check from. This is used only
1457 EditorDOMPoint mSpellCheckRestartPoint
;
1459 // Different from mTopLevelEditSubAction, its data should be stored only
1460 // in the most ancestor AutoEditActionDataSetter instance since we don't
1461 // want to pay the copying cost and sync cost.
1462 TopLevelEditSubActionData mTopLevelEditSubActionData
;
1464 // Different from mTopLevelEditSubActionData, this stores temporaly data
1465 // for current edit sub action.
1466 EditSubActionData mEditSubActionData
;
1468 EditAction mEditAction
;
1470 // Different from its data, you can refer "current" AutoEditActionDataSetter
1471 // instance's mTopLevelEditSubAction member since it's copied from the
1472 // parent instance at construction and it's always cleared before this
1473 // won't be overwritten and cleared before destruction.
1474 EditSubAction mTopLevelEditSubAction
;
1476 EDirection mDirectionOfTopLevelEditSubAction
;
1480 // Set to true when this handles "beforeinput" event dispatching. Note
1481 // that even if "beforeinput" event shouldn't be dispatched for this,
1482 // instance, this is set to true when it's considered.
1483 bool mHasTriedToDispatchBeforeInputEvent
;
1484 // Set to true if "beforeinput" event was dispatched and it's canceled.
1485 bool mBeforeInputEventCanceled
;
1486 // Set to true if `beforeinput` event must not be cancelable even if
1487 // its inputType is defined as cancelable by the standards.
1488 bool mMakeBeforeInputEventNonCancelable
;
1489 // Set to true when the edit action handler tries to dispatch a clipboard
1491 bool mHasTriedToDispatchClipboardEvent
;
1492 // The editor instance may be destroyed once temporarily if `document.write`
1493 // etc runs. In such case, we should mark this flag of being handled
1495 bool mEditorWasDestroyedDuringHandlingEditAction
;
1496 // This is set before dispatching `input` event and notifying editor
1501 mutable bool mHasCanHandleChecked
= false;
1502 #endif // #ifdef DEBUG
1504 AutoEditActionDataSetter() = delete;
1505 AutoEditActionDataSetter(const AutoEditActionDataSetter
& aOther
) = delete;
1508 void UpdateEditActionData(const nsAString
& aData
) {
1509 mEditActionData
->SetData(aData
);
1512 void NotifyOfDispatchingClipboardEvent() {
1513 MOZ_ASSERT(mEditActionData
);
1514 mEditActionData
->NotifyOfDispatchingClipboardEvent();
1517 protected: // May be called by friends.
1518 /****************************************************************************
1519 * Some friend classes are allowed to call the following protected methods.
1520 * However, those methods won't prepare caches of some objects which are
1521 * necessary for them. So, if you call them from friend classes, you need
1522 * to make sure that AutoEditActionDataSetter is created.
1523 ****************************************************************************/
1525 bool IsEditActionCanceled() const {
1526 MOZ_ASSERT(mEditActionData
);
1527 return mEditActionData
->IsCanceled();
1530 bool ShouldAlreadyHaveHandledBeforeInputEventDispatching() const {
1531 MOZ_ASSERT(mEditActionData
);
1532 return mEditActionData
1533 ->ShouldAlreadyHaveHandledBeforeInputEventDispatching();
1536 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
MaybeDispatchBeforeInputEvent() {
1537 MOZ_ASSERT(mEditActionData
);
1538 return mEditActionData
->MaybeDispatchBeforeInputEvent();
1541 void MarkAsBeforeInputHasBeenDispatched() {
1542 MOZ_ASSERT(mEditActionData
);
1543 return mEditActionData
->MarkAsBeforeInputHasBeenDispatched();
1546 bool HasTriedToDispatchBeforeInputEvent() const {
1547 return mEditActionData
&&
1548 mEditActionData
->HasTriedToDispatchBeforeInputEvent();
1551 bool IsEditActionDataAvailable() const {
1552 return mEditActionData
&& mEditActionData
->IsDataAvailable();
1555 bool IsTopLevelEditSubActionDataAvailable() const {
1556 return mEditActionData
&& !!GetTopLevelEditSubAction();
1559 bool IsEditActionAborted() const {
1560 MOZ_ASSERT(mEditActionData
);
1561 return mEditActionData
->IsAborted();
1565 * SelectionRef() returns cached normal Selection. This is pretty faster than
1566 * EditorBase::GetSelection() if available.
1567 * Note that this never crash unless public methods ignore the result of
1568 * AutoEditActionDataSetter::CanHandle() and keep handling edit action but any
1569 * methods should stop handling edit action if it returns false.
1571 MOZ_KNOWN_LIVE Selection
& SelectionRef() const {
1572 MOZ_ASSERT(mEditActionData
);
1573 MOZ_ASSERT(mEditActionData
->SelectionRef().GetType() ==
1574 SelectionType::eNormal
);
1575 return mEditActionData
->SelectionRef();
1578 nsIPrincipal
* GetEditActionPrincipal() const {
1579 MOZ_ASSERT(mEditActionData
);
1580 return mEditActionData
->GetPrincipal();
1584 * GetEditAction() returns EditAction which is being handled. If some
1585 * edit actions are nested, this returns the innermost edit action.
1587 EditAction
GetEditAction() const {
1588 return mEditActionData
? mEditActionData
->GetEditAction()
1589 : EditAction::eNone
;
1593 * GetInputEventData() returns inserting or inserted text value with
1594 * current edit action. The result is proper for InputEvent.data value.
1596 const nsString
& GetInputEventData() const {
1597 return mEditActionData
? mEditActionData
->GetData() : VoidString();
1601 * GetInputEventDataTransfer() returns inserting or inserted transferable
1602 * content with current edit action. The result is proper for
1603 * InputEvent.dataTransfer value.
1605 dom::DataTransfer
* GetInputEventDataTransfer() const {
1606 return mEditActionData
? mEditActionData
->GetDataTransfer() : nullptr;
1610 * GetTopLevelEditSubAction() returns the top level edit sub-action.
1611 * For example, if selected content is being replaced with inserted text,
1612 * while removing selected content, the top level edit sub-action may be
1613 * EditSubAction::eDeleteSelectedContent. However, while inserting new
1614 * text, the top level edit sub-action may be EditSubAction::eInsertText.
1615 * So, this result means what we are doing right now unless you're looking
1616 * for a case which the method is called via mutation event listener or
1617 * selectionchange event listener which are fired while handling the edit
1620 EditSubAction
GetTopLevelEditSubAction() const {
1621 return mEditActionData
? mEditActionData
->GetTopLevelEditSubAction()
1622 : EditSubAction::eNone
;
1626 * GetDirectionOfTopLevelEditSubAction() returns direction which user
1627 * intended for doing the edit sub-action.
1629 EDirection
GetDirectionOfTopLevelEditSubAction() const {
1630 return mEditActionData
1631 ? mEditActionData
->GetDirectionOfTopLevelEditSubAction()
1636 * SavedSelection() returns reference to saved selection which are
1637 * stored by AutoSelectionRestorer.
1639 SelectionState
& SavedSelectionRef() {
1640 MOZ_ASSERT(IsEditActionDataAvailable());
1641 return mEditActionData
->SavedSelectionRef();
1643 const SelectionState
& SavedSelectionRef() const {
1644 MOZ_ASSERT(IsEditActionDataAvailable());
1645 return mEditActionData
->SavedSelectionRef();
1648 RangeUpdater
& RangeUpdaterRef() {
1649 MOZ_ASSERT(IsEditActionDataAvailable());
1650 return mEditActionData
->RangeUpdaterRef();
1652 const RangeUpdater
& RangeUpdaterRef() const {
1653 MOZ_ASSERT(IsEditActionDataAvailable());
1654 return mEditActionData
->RangeUpdaterRef();
1657 template <typename PT
, typename CT
>
1658 void SetSpellCheckRestartPoint(const EditorDOMPointBase
<PT
, CT
>& aPoint
) {
1659 MOZ_ASSERT(IsEditActionDataAvailable());
1660 return mEditActionData
->SetSpellCheckRestartPoint(aPoint
);
1663 void ClearSpellCheckRestartPoint() {
1664 MOZ_ASSERT(IsEditActionDataAvailable());
1665 return mEditActionData
->ClearSpellCheckRestartPoint();
1668 const EditorDOMPoint
& GetSpellCheckRestartPoint() const {
1669 MOZ_ASSERT(IsEditActionDataAvailable());
1670 return mEditActionData
->GetSpellCheckRestartPoint();
1673 const TopLevelEditSubActionData
& TopLevelEditSubActionDataRef() const {
1674 MOZ_ASSERT(IsEditActionDataAvailable());
1675 return mEditActionData
->TopLevelEditSubActionDataRef();
1677 TopLevelEditSubActionData
& TopLevelEditSubActionDataRef() {
1678 MOZ_ASSERT(IsEditActionDataAvailable());
1679 return mEditActionData
->TopLevelEditSubActionDataRef();
1682 const EditSubActionData
& EditSubActionDataRef() const {
1683 MOZ_ASSERT(IsEditActionDataAvailable());
1684 return mEditActionData
->EditSubActionDataRef();
1686 EditSubActionData
& EditSubActionDataRef() {
1687 MOZ_ASSERT(IsEditActionDataAvailable());
1688 return mEditActionData
->EditSubActionDataRef();
1692 * GetCompositionStartPoint() and GetCompositionEndPoint() returns start and
1693 * end point of composition string if there is. Otherwise, returns non-set
1696 EditorRawDOMPoint
GetCompositionStartPoint() const;
1697 EditorRawDOMPoint
GetCompositionEndPoint() const;
1700 * IsSelectionRangeContainerNotContent() returns true if one of container
1701 * of selection ranges is not a content node, i.e., a Document node.
1703 bool IsSelectionRangeContainerNotContent() const;
1706 * OnInputText() is called when user inputs text with keyboard or something.
1708 * @param aStringToInsert The string to insert.
1710 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1711 OnInputText(const nsAString
& aStringToInsert
);
1714 * InsertTextAsSubAction() inserts aStringToInsert at selection. This
1715 * should be used for handling it as an edit sub-action.
1717 * @param aStringToInsert The string to insert.
1719 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1720 InsertTextAsSubAction(const nsAString
& aStringToInsert
);
1723 * InsertTextWithTransaction() inserts aStringToInsert to aPointToInsert or
1724 * better insertion point around it. If aPointToInsert isn't in a text node,
1725 * this method looks for the nearest point in a text node with
1726 * FindBetterInsertionPoint(). If there is no text node, this creates
1727 * new text node and put aStringToInsert to it.
1729 * @param aDocument The document of this editor.
1730 * @param aStringToInsert The string to insert.
1731 * @param aPointToInser The point to insert aStringToInsert.
1732 * Must be valid DOM point.
1733 * @param aPointAfterInsertedString
1734 * The point after inserted aStringToInsert.
1735 * So, when this method actually inserts string,
1736 * this is set to a point in the text node.
1737 * Otherwise, this may be set to aPointToInsert.
1738 * @return When this succeeds to insert the string or
1739 * does nothing during composition, returns NS_OK.
1740 * Otherwise, an error code.
1742 MOZ_CAN_RUN_SCRIPT
virtual nsresult
InsertTextWithTransaction(
1743 Document
& aDocument
, const nsAString
& aStringToInsert
,
1744 const EditorRawDOMPoint
& aPointToInsert
,
1745 EditorRawDOMPoint
* aPointAfterInsertedString
= nullptr);
1748 * InsertTextIntoTextNodeWithTransaction() inserts aStringToInsert into
1749 * aOffset of aTextNode with transaction.
1751 * @param aStringToInsert String to be inserted.
1752 * @param aPointToInsert The insertion point.
1753 * @param aSuppressIME true if it's not a part of IME composition.
1754 * E.g., adjusting white-spaces during composition.
1757 MOZ_CAN_RUN_SCRIPT nsresult
InsertTextIntoTextNodeWithTransaction(
1758 const nsAString
& aStringToInsert
,
1759 const EditorDOMPointInText
& aPointToInsert
, bool aSuppressIME
= false);
1762 * SetTextNodeWithoutTransaction() is optimized path to set new value to
1763 * the text node directly and without transaction. This is used when
1764 * setting `<input>.value` and `<textarea>.value`.
1766 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1767 SetTextNodeWithoutTransaction(const nsAString
& aString
, Text
& aTextNode
);
1770 * DeleteNodeWithTransaction() removes aContent from the DOM tree.
1772 * @param aContent The node which will be removed form the DOM tree.
1774 MOZ_CAN_RUN_SCRIPT nsresult
DeleteNodeWithTransaction(nsIContent
& aContent
);
1777 * InsertNodeWithTransaction() inserts aContentToInsert before the child
1778 * specified by aPointToInsert.
1780 * @param aContentToInsert The node to be inserted.
1781 * @param aPointToInsert The insertion point of aContentToInsert.
1782 * If this refers end of the container, the
1783 * transaction will append the node to the
1784 * container. Otherwise, will insert the node
1785 * before child node referred by this.
1787 MOZ_CAN_RUN_SCRIPT nsresult
InsertNodeWithTransaction(
1788 nsIContent
& aContentToInsert
, const EditorDOMPoint
& aPointToInsert
);
1791 * InsertPaddingBRElementForEmptyLastLineWithTransaction() creates a padding
1792 * <br> element with setting flags to NS_PADDING_FOR_EMPTY_LAST_LINE and
1793 * inserts it around aPointToInsert.
1795 * @param aPointToInsert The DOM point where should be <br> node inserted
1798 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT CreateElementResult
1799 InsertPaddingBRElementForEmptyLastLineWithTransaction(
1800 const EditorDOMPoint
& aPointToInsert
);
1803 * CloneAttributesWithTransaction() clones all attributes from
1804 * aSourceElement to aDestElement after removing all attributes in
1807 MOZ_CAN_RUN_SCRIPT
void CloneAttributesWithTransaction(
1808 Element
& aDestElement
, Element
& aSourceElement
);
1811 * CloneAttributeWithTransaction() copies aAttribute of aSourceElement to
1812 * aDestElement. If aSourceElement doesn't have aAttribute, this removes
1813 * aAttribute from aDestElement.
1815 * @param aAttribute Attribute name to be cloned.
1816 * @param aDestElement Element node which will be set aAttribute or
1817 * whose aAttribute will be removed.
1818 * @param aSourceElement Element node which provides the value of
1819 * aAttribute in aDestElement.
1821 MOZ_CAN_RUN_SCRIPT nsresult
CloneAttributeWithTransaction(
1822 nsAtom
& aAttribute
, Element
& aDestElement
, Element
& aSourceElement
);
1825 * RemoveAttributeWithTransaction() removes aAttribute from aElement.
1827 * @param aElement Element node which will lose aAttribute.
1828 * @param aAttribute Attribute name to be removed from aElement.
1830 MOZ_CAN_RUN_SCRIPT nsresult
1831 RemoveAttributeWithTransaction(Element
& aElement
, nsAtom
& aAttribute
);
1833 MOZ_CAN_RUN_SCRIPT
virtual nsresult
RemoveAttributeOrEquivalent(
1834 Element
* aElement
, nsAtom
* aAttribute
, bool aSuppressTransaction
) = 0;
1837 * SetAttributeWithTransaction() sets aAttribute of aElement to aValue.
1839 * @param aElement Element node which will have aAttribute.
1840 * @param aAttribute Attribute name to be set.
1841 * @param aValue Attribute value be set to aAttribute.
1843 MOZ_CAN_RUN_SCRIPT nsresult
SetAttributeWithTransaction(
1844 Element
& aElement
, nsAtom
& aAttribute
, const nsAString
& aValue
);
1846 MOZ_CAN_RUN_SCRIPT
virtual nsresult
SetAttributeOrEquivalent(
1847 Element
* aElement
, nsAtom
* aAttribute
, const nsAString
& aValue
,
1848 bool aSuppressTransaction
) = 0;
1851 * Method to replace certain CreateElementNS() calls.
1853 * @param aTag Tag you want.
1855 already_AddRefed
<Element
> CreateHTMLContent(const nsAtom
* aTag
);
1858 * Creates text node which is marked as "maybe modified frequently" and
1859 * "maybe masked" if this is a password editor.
1861 already_AddRefed
<nsTextNode
> CreateTextNode(const nsAString
& aData
);
1864 * DoInsertText(), DoDeleteText(), DoReplaceText() and DoSetText() are
1865 * wrapper of `CharacterData::InsertData()`, `CharacterData::DeleteData()`,
1866 * `CharacterData::ReplaceData()` and `CharacterData::SetData()`.
1868 MOZ_CAN_RUN_SCRIPT
void DoInsertText(dom::Text
& aText
, uint32_t aOffset
,
1869 const nsAString
& aStringToInsert
,
1871 MOZ_CAN_RUN_SCRIPT
void DoDeleteText(dom::Text
& aText
, uint32_t aOffset
,
1872 uint32_t aCount
, ErrorResult
& aRv
);
1873 MOZ_CAN_RUN_SCRIPT
void DoReplaceText(dom::Text
& aText
, uint32_t aOffset
,
1875 const nsAString
& aStringToInsert
,
1877 MOZ_CAN_RUN_SCRIPT
void DoSetText(dom::Text
& aText
,
1878 const nsAString
& aStringToSet
,
1882 * Create an element node whose name is aTag at before aPointToInsert. When
1883 * this succeed to create an element node, this sets aPointToInsert to the
1884 * new element because the relation of child and offset may be broken.
1885 * If the caller needs to collapse the selection to next to the new element
1886 * node, it should call |aPointToInsert.AdvanceOffset()| after calling this.
1888 * @param aTag The element name to create.
1889 * @param aPointToInsert The insertion point of new element. If this refers
1890 * end of the container or after, the transaction
1891 * will append the element to the container.
1892 * Otherwise, will insert the element before the
1893 * child node referred by this.
1894 * @return The created new element node or an error.
1896 MOZ_CAN_RUN_SCRIPT Result
<RefPtr
<Element
>, nsresult
>
1897 CreateNodeWithTransaction(nsAtom
& aTag
, const EditorDOMPoint
& aPointToInsert
);
1900 * DeleteTextWithTransaction() removes text in the range from aTextNode.
1902 * @param aTextNode The text node which should be modified.
1903 * @param aOffset Start offset of removing text in aTextNode.
1904 * @param aLength Length of removing text.
1906 MOZ_CAN_RUN_SCRIPT nsresult
DeleteTextWithTransaction(dom::Text
& aTextNode
,
1911 * EnsureNoPaddingBRElementForEmptyEditor() removes padding <br> element
1912 * for empty editor if there is.
1914 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1915 EnsureNoPaddingBRElementForEmptyEditor();
1918 * MaybeCreatePaddingBRElementForEmptyEditor() creates padding <br> element
1919 * for empty editor if there is no children.
1921 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1922 MaybeCreatePaddingBRElementForEmptyEditor();
1925 * MarkElementDirty() sets a special dirty attribute on the element.
1926 * Usually this will be called immediately after creating a new node.
1928 * @param aElement The element for which to insert formatting.
1930 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
MarkElementDirty(Element
& aElement
);
1932 MOZ_CAN_RUN_SCRIPT nsresult
1933 DoTransactionInternal(nsITransaction
* aTransaction
);
1936 * Returns true if aNode is our root node.
1938 bool IsRoot(const nsINode
* inNode
) const;
1939 bool IsEditorRoot(const nsINode
* aNode
) const;
1942 * Returns true if aNode is a descendant of our root node.
1944 bool IsDescendantOfRoot(const nsINode
* inNode
) const;
1945 bool IsDescendantOfEditorRoot(const nsINode
* aNode
) const;
1948 * Returns true when inserting text should be a part of current composition.
1950 bool ShouldHandleIMEComposition() const;
1952 static EditorRawDOMPoint
GetStartPoint(const Selection
& aSelection
);
1953 static EditorRawDOMPoint
GetEndPoint(const Selection
& aSelection
);
1955 static nsresult
GetEndChildNode(const Selection
& aSelection
,
1956 nsIContent
** aEndNode
);
1959 * CollapseSelectionToEnd() collapses the selection to the end of the editor.
1961 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
CollapseSelectionToEnd() const;
1964 * AllowsTransactionsToChangeSelection() returns true if editor allows any
1965 * transactions to change Selection. Otherwise, transactions shouldn't
1968 inline bool AllowsTransactionsToChangeSelection() const {
1969 return mAllowsTransactionsToChangeSelection
;
1973 * MakeThisAllowTransactionsToChangeSelection() with true makes this editor
1974 * allow transactions to change Selection. Otherwise, i.e., with false,
1975 * makes this editor not allow transactions to change Selection.
1977 inline void MakeThisAllowTransactionsToChangeSelection(bool aAllow
) {
1978 mAllowsTransactionsToChangeSelection
= aAllow
;
1981 nsresult
HandleInlineSpellCheck(
1982 const EditorDOMPoint
& aPreviouslySelectedStart
,
1983 const dom::AbstractRange
* aRange
= nullptr);
1986 * Likewise, but gets the editor's root instead, which is different for HTML
1989 virtual Element
* GetEditorRoot() const;
1992 * Whether the editor is active on the DOM window. Note that when this
1993 * returns true but GetFocusedContent() returns null, it means that this
1994 * editor was focused when the DOM window was active.
1996 virtual bool IsActiveInDOMWindow() const;
1999 * FindBetterInsertionPoint() tries to look for better insertion point which
2000 * is typically the nearest text node and offset in it.
2002 * @param aPoint Insertion point which the callers found.
2003 * @return Better insertion point if there is. If not returns
2004 * same point as aPoint.
2006 EditorRawDOMPoint
FindBetterInsertionPoint(
2007 const EditorRawDOMPoint
& aPoint
) const;
2010 * HideCaret() hides caret with nsCaret::AddForceHide() or may show carent
2011 * with nsCaret::RemoveForceHide(). This does NOT set visibility of
2012 * nsCaret. Therefore, this is stateless.
2014 void HideCaret(bool aHide
);
2016 protected: // Edit sub-action handler
2018 * AutoCaretBidiLevelManager() computes bidi level of caret, deleting
2019 * character(s) from aPointAtCaret at construction. Then, if you'll
2020 * need to extend the selection, you should calls `UpdateCaretBidiLevel()`,
2021 * then, this class may update caret bidi level for you if it's required.
2023 class MOZ_RAII AutoCaretBidiLevelManager final
{
2026 * @param aEditorBase The editor.
2027 * @param aPointAtCaret Collapsed `Selection` point.
2028 * @param aDirectionAndAmount The direction and amount to delete.
2030 template <typename PT
, typename CT
>
2031 AutoCaretBidiLevelManager(const EditorBase
& aEditorBase
,
2032 nsIEditor::EDirection aDirectionAndAmount
,
2033 const EditorDOMPointBase
<PT
, CT
>& aPointAtCaret
);
2036 * Failed() returns true if the constructor failed to handle the bidi
2039 bool Failed() const { return mFailed
; }
2042 * Canceled() returns true if when the caller should stop deleting
2043 * characters since caret position is not visually adjacent the deleting
2044 * characters and user does not wand to delete them in that case.
2046 bool Canceled() const { return mCanceled
; }
2049 * MaybeUpdateCaretBidiLevel() may update caret bidi level and schedule to
2050 * paint it if they are necessary.
2052 void MaybeUpdateCaretBidiLevel(const EditorBase
& aEditorBase
) const;
2055 Maybe
<nsBidiLevel
> mNewCaretBidiLevel
;
2056 bool mFailed
= false;
2057 bool mCanceled
= false;
2061 * UndefineCaretBidiLevel() resets bidi level of the caret.
2063 void UndefineCaretBidiLevel() const;
2066 * Flushing pending notifications if nsFrameSelection requires the latest
2067 * layout information to compute deletion range. This may destroy the
2068 * editor instance itself. When this returns false, don't keep doing
2071 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT
bool
2072 FlushPendingNotificationsIfToHandleDeletionWithFrameSelection(
2073 nsIEditor::EDirection aDirectionAndAmount
) const;
2076 * DeleteSelectionAsSubAction() removes selection content or content around
2077 * caret with transactions. This should be used for handling it as an
2080 * @param aDirectionAndAmount How much range should be removed.
2081 * @param aStripWrappers Whether the parent blocks should be removed
2082 * when they become empty. If this instance is
2083 * a TextEditor, Must be nsIEditor::eNoStrip.
2085 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2086 DeleteSelectionAsSubAction(nsIEditor::EDirection aDirectionAndAmount
,
2087 nsIEditor::EStripWrappers aStripWrappers
);
2090 * This method handles "delete selection" commands.
2091 * NOTE: Don't call this method recursively from the helper methods since
2092 * when nobody handled it without canceling and returing an error,
2093 * this falls it back to `DeleteSelectionWithTransaction()`.
2095 * @param aDirectionAndAmount Direction of the deletion.
2096 * @param aStripWrappers Must be nsIEditor::eNoStrip if this is a
2097 * TextEditor instance. Otherwise,
2098 * nsIEditor::eStrip is also valid.
2100 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT
virtual EditActionResult
2101 HandleDeleteSelection(nsIEditor::EDirection aDirectionAndAmount
,
2102 nsIEditor::EStripWrappers aStripWrappers
) = 0;
2105 * ReplaceSelectionAsSubAction() replaces selection with aString.
2107 * @param aString The string to replace.
2109 MOZ_CAN_RUN_SCRIPT nsresult
2110 ReplaceSelectionAsSubAction(const nsAString
& aString
);
2113 * HandleInsertText() handles inserting text at selection.
2115 * @param aEditSubAction Must be EditSubAction::eInsertText or
2116 * EditSubAction::eInsertTextComingFromIME.
2117 * @param aInsertionString String to be inserted at selection.
2119 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT
virtual EditActionResult
HandleInsertText(
2120 EditSubAction aEditSubAction
, const nsAString
& aInsertionString
) = 0;
2123 * InsertWithQuotationsAsSubAction() inserts aQuotedText with appending ">"
2124 * to start of every line.
2126 * @param aQuotedText String to insert. This will be quoted by ">"
2129 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT
virtual nsresult
2130 InsertWithQuotationsAsSubAction(const nsAString
& aQuotedText
) = 0;
2133 * PrepareInsertContent() is a helper method of InsertTextAt(),
2134 * HTMLEditor::HTMLWithContextInserter::Run(). They insert content coming
2135 * from clipboard or drag and drop. Before that, they may need to remove
2136 * selected contents and adjust selection. This does them instead.
2138 * @param aPointToInsert Point to insert. Must be set. Callers
2139 * shouldn't use this instance after calling this
2140 * method because this method may cause changing
2141 * the DOM tree and Selection.
2142 * @param aDoDeleteSelection true if selected content should be removed.
2144 MOZ_CAN_RUN_SCRIPT nsresult
PrepareToInsertContent(
2145 const EditorDOMPoint
& aPointToInsert
, bool aDoDeleteSelection
);
2148 * InsertTextAt() inserts aStringToInsert at aPointToInsert.
2150 * @param aStringToInsert The string which you want to insert.
2151 * @param aPointToInsert The insertion point.
2152 * @param aDoDeleteSelection true if you want this to delete selected
2153 * content. Otherwise, false.
2155 MOZ_CAN_RUN_SCRIPT nsresult
InsertTextAt(const nsAString
& aStringToInsert
,
2156 const EditorDOMPoint
& aPointToInsert
,
2157 bool aDoDeleteSelection
);
2160 * Return true if the data is safe to insert as the source and destination
2161 * principals match, or we are in a editor context where this doesn't matter.
2162 * Otherwise, the data must be sanitized first.
2164 bool IsSafeToInsertData(const Document
* aSourceDoc
) const;
2166 protected: // Called by helper classes.
2168 * OnStartToHandleTopLevelEditSubAction() is called when
2169 * GetTopLevelEditSubAction() is EditSubAction::eNone and somebody starts to
2170 * handle aEditSubAction.
2172 * @param aTopLevelEditSubAction Top level edit sub action which
2173 * will be handled soon.
2174 * @param aDirectionOfTopLevelEditSubAction Direction of aEditSubAction.
2176 MOZ_CAN_RUN_SCRIPT
virtual void OnStartToHandleTopLevelEditSubAction(
2177 EditSubAction aTopLevelEditSubAction
,
2178 nsIEditor::EDirection aDirectionOfTopLevelEditSubAction
,
2182 * OnEndHandlingTopLevelEditSubAction() is called after
2183 * SetTopLevelEditSubAction() is handled.
2185 MOZ_CAN_RUN_SCRIPT
virtual nsresult
OnEndHandlingTopLevelEditSubAction();
2188 * OnStartToHandleEditSubAction() and OnEndHandlingEditSubAction() are called
2189 * when starting to handle an edit sub action and ending handling an edit
2192 void OnStartToHandleEditSubAction() { EditSubActionDataRef().Clear(); }
2193 void OnEndHandlingEditSubAction() { EditSubActionDataRef().Clear(); }
2196 * Routines for managing the preservation of selection across
2197 * various editor actions.
2199 bool ArePreservingSelection();
2200 void PreserveSelectionAcrossActions();
2201 nsresult
RestorePreservedSelection();
2202 void StopPreservingSelection();
2205 * (Begin|End)PlaceholderTransaction() are called by AutoPlaceholderBatch.
2206 * This set of methods are similar to the (Begin|End)Transaction(), but do
2207 * not use the transaction managers batching feature. Instead we use a
2208 * placeholder transaction to wrap up any further transaction while the
2209 * batch is open. The advantage of this is that placeholder transactions
2210 * can later merge, if needed. Merging is unavailable between transaction
2213 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void BeginPlaceholderTransaction(
2214 nsStaticAtom
& aTransactionName
);
2215 enum class ScrollSelectionIntoView
{ No
, Yes
};
2216 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void EndPlaceholderTransaction(
2217 ScrollSelectionIntoView aScrollSelectionIntoView
);
2219 void BeginUpdateViewBatch();
2220 MOZ_CAN_RUN_SCRIPT
void EndUpdateViewBatch();
2223 * Used by AutoTransactionBatch. After calling BeginTransactionInternal(),
2224 * all transactions will be treated as an atomic transaction. I.e.,
2225 * two or more transactions are undid once.
2226 * XXX What's the difference with PlaceholderTransaction? Should we always
2229 MOZ_CAN_RUN_SCRIPT
void BeginTransactionInternal();
2230 MOZ_CAN_RUN_SCRIPT
void EndTransactionInternal();
2232 protected: // Shouldn't be used by friend classes
2234 * The default destructor. This should suffice. Should this be pure virtual
2235 * for someone to derive from the EditorBase later? I don't believe so.
2237 virtual ~EditorBase();
2239 MOZ_ALWAYS_INLINE EditorType
GetEditorType() const {
2240 return mIsHTMLEditorClass
? EditorType::HTML
: EditorType::Text
;
2243 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
EnsureEmptyTextFirstChild();
2246 * InitEditorContentAndSelection() may insert a padding `<br>` element for
2247 * if it's required in the anonymous `<div>` element or `<body>` element and
2248 * collapse selection at the end if there is no selection ranges.
2250 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InitEditorContentAndSelection();
2252 int32_t WrapWidth() const { return mWrapColumn
; }
2255 * ToGenericNSResult() computes proper nsresult value for the editor users.
2256 * This should be used only when public methods return result of internal
2259 static inline nsresult
ToGenericNSResult(nsresult aRv
) {
2261 // If the editor is destroyed while handling an edit action, editor needs
2262 // to stop handling it. However, editor throw exception in this case
2263 // because Chrome does not throw exception even in this case.
2264 case NS_ERROR_EDITOR_DESTROYED
:
2266 // If editor meets unexpected DOM tree due to modified by mutation event
2267 // listener, editor needs to stop handling it. However, editor shouldn't
2268 // return error for the users because Chrome does not throw exception in
2270 case NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE
:
2272 // If the editing action is canceled by event listeners, editor needs
2273 // to stop handling it. However, editor shouldn't return error for
2274 // the callers but they should be able to distinguish whether it's
2275 // canceled or not. Although it's DOM specific code, let's return
2276 // DOM_SUCCESS_DOM_NO_OPERATION here.
2277 case NS_ERROR_EDITOR_ACTION_CANCELED
:
2278 return NS_SUCCESS_DOM_NO_OPERATION
;
2279 // If there is no selection range or editable selection ranges, editor
2280 // needs to stop handling it. However, editor shouldn't return error for
2281 // the callers to avoid throwing exception. However, they may want to
2282 // check whether it works or not. Therefore, we should return
2283 // NS_SUCCESS_DOM_NO_OPERATION instead.
2284 case NS_ERROR_EDITOR_NO_EDITABLE_RANGE
:
2285 return NS_SUCCESS_DOM_NO_OPERATION
;
2292 * GetDocumentCharsetInternal() returns charset of the document.
2294 nsresult
GetDocumentCharsetInternal(nsACString
& aCharset
) const;
2297 * ComputeValueInternal() computes string value of this editor for given
2298 * format. This may be too expensive if it's in hot path.
2300 * @param aFormatType MIME type like "text/plain".
2301 * @param aDocumentEncoderFlags Flags of nsIDocumentEncoder.
2302 * @param aCharset Encoding of the document.
2304 nsresult
ComputeValueInternal(const nsAString
& aFormatType
,
2305 uint32_t aDocumentEncoderFlags
,
2306 nsAString
& aOutputString
) const;
2309 * GetAndInitDocEncoder() returns a document encoder instance for aFormatType
2310 * after initializing it. The result may be cached for saving recreation
2313 * @param aFormatType MIME type like "text/plain".
2314 * @param aDocumentEncoderFlags Flags of nsIDocumentEncoder.
2315 * @param aCharset Encoding of the document.
2317 already_AddRefed
<nsIDocumentEncoder
> GetAndInitDocEncoder(
2318 const nsAString
& aFormatType
, uint32_t aDocumentEncoderFlags
,
2319 const nsACString
& aCharset
) const;
2322 * EnsurePaddingBRElementInMultilineEditor() creates a padding `<br>` element
2323 * at end of multiline text editor.
2325 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2326 EnsurePaddingBRElementInMultilineEditor();
2329 * SelectAllInternal() should be used instead of SelectAll() in editor
2330 * because SelectAll() creates AutoEditActionSetter but we should avoid
2331 * to create it as far as possible.
2333 MOZ_CAN_RUN_SCRIPT
virtual nsresult
SelectAllInternal();
2335 nsresult
DetermineCurrentDirection();
2338 * DispatchInputEvent() dispatches an "input" event synchronously or
2339 * asynchronously if it's not safe to dispatch.
2341 MOZ_CAN_RUN_SCRIPT
void DispatchInputEvent();
2344 * Called after a transaction is done successfully.
2346 MOZ_CAN_RUN_SCRIPT
void DoAfterDoTransaction(nsITransaction
* aTransaction
);
2349 * Called after a transaction is undone successfully.
2352 MOZ_CAN_RUN_SCRIPT
void DoAfterUndoTransaction();
2355 * Called after a transaction is redone successfully.
2357 MOZ_CAN_RUN_SCRIPT
void DoAfterRedoTransaction();
2360 * Tell the doc state listeners that the doc state has changed.
2362 enum TDocumentListenerNotification
{
2364 eDocumentToBeDestroyed
,
2365 eDocumentStateChanged
2367 MOZ_CAN_RUN_SCRIPT nsresult
2368 NotifyDocumentListeners(TDocumentListenerNotification aNotificationType
);
2371 * Make the given selection span the entire document.
2373 MOZ_CAN_RUN_SCRIPT
virtual nsresult
SelectEntireDocument() = 0;
2376 * Helper method for scrolling the selection into view after
2377 * an edit operation.
2379 * Editor methods *should* call this method instead of the versions
2380 * in the various selection interfaces, since this makes sure that
2381 * the editor's sync/async settings for reflowing, painting, and scrolling
2384 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
ScrollSelectionFocusIntoView();
2386 virtual nsresult
InstallEventListeners();
2387 virtual void CreateEventListeners();
2388 virtual void RemoveEventListeners();
2391 * Called if and only if this editor is in readonly mode.
2393 void HandleKeyPressEventInReadOnlyMode(
2394 WidgetKeyboardEvent
& aKeyboardEvent
) const;
2397 * Get the input event target. This might return null.
2399 virtual already_AddRefed
<Element
> GetInputEventTargetElement() const = 0;
2402 * Return true if spellchecking should be enabled for this editor.
2404 bool GetDesiredSpellCheckState();
2406 bool CanEnableSpellCheck() {
2407 // Check for password/readonly/disabled, which are not spellchecked
2408 // regardless of DOM. Also, check to see if spell check should be skipped
2410 return !IsPasswordEditor() && !IsReadonly() && !ShouldSkipSpellCheck();
2414 * InitializeSelectionAncestorLimit() is called by InitializeSelection().
2415 * When this is called, each implementation has to call
2416 * Selection::SetAncestorLimiter() with aAnotherLimit.
2418 * @param aAncestorLimit New ancestor limit of Selection. This always
2419 * has parent node. So, it's always safe to
2420 * call SetAncestorLimit() with this node.
2422 virtual void InitializeSelectionAncestorLimit(
2423 nsIContent
& aAncestorLimit
) const;
2426 * Creates a range with just the supplied node and appends that to the
2429 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
2430 AppendNodeToSelectionAsRange(nsINode
* aNode
);
2433 * When you are using AppendNodeToSelectionAsRange(), call this first to
2434 * start a new selection.
2436 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
ClearSelection();
2439 * Initializes selection and caret for the editor. If aEventTarget isn't
2440 * a host of the editor, i.e., the editor doesn't get focus, this does
2443 MOZ_CAN_RUN_SCRIPT nsresult
InitializeSelection(nsINode
& aFocusEventTarget
);
2445 enum NotificationForEditorObservers
{
2446 eNotifyEditorObserversOfEnd
,
2447 eNotifyEditorObserversOfBefore
,
2448 eNotifyEditorObserversOfCancel
2450 MOZ_CAN_RUN_SCRIPT
void NotifyEditorObservers(
2451 NotificationForEditorObservers aNotification
);
2454 * InsertLineBreakAsSubAction() inserts a line break, i.e., \n if it's
2455 * TextEditor or <br> if it's HTMLEditor.
2457 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InsertLineBreakAsSubAction();
2460 * HowToHandleCollapsedRange indicates how collapsed range should be treated.
2462 enum class HowToHandleCollapsedRange
{
2463 // Ignore collapsed range.
2465 // Extend collapsed range for removing previous content.
2467 // Extend collapsed range for removing next content.
2471 static HowToHandleCollapsedRange
HowToHandleCollapsedRangeFor(
2472 nsIEditor::EDirection aDirectionAndAmount
) {
2473 switch (aDirectionAndAmount
) {
2474 case nsIEditor::eNone
:
2475 return HowToHandleCollapsedRange::Ignore
;
2476 case nsIEditor::ePrevious
:
2477 return HowToHandleCollapsedRange::ExtendBackward
;
2478 case nsIEditor::eNext
:
2479 return HowToHandleCollapsedRange::ExtendForward
;
2480 case nsIEditor::ePreviousWord
:
2481 case nsIEditor::eNextWord
:
2482 case nsIEditor::eToBeginningOfLine
:
2483 case nsIEditor::eToEndOfLine
:
2484 // If the amount is word or
2485 // line,`AutoRangeArray::ExtendAnchorFocusRangeFor()` must have already
2486 // been extended collapsed ranges before.
2487 return HowToHandleCollapsedRange::Ignore
;
2489 MOZ_ASSERT_UNREACHABLE("Invalid nsIEditor::EDirection value");
2490 return HowToHandleCollapsedRange::Ignore
;
2494 * InsertDroppedDataTransferAsAction() inserts all data items in aDataTransfer
2495 * at aDroppedAt unless the editor is destroyed.
2497 * @param aEditActionData The edit action data whose edit action must be
2498 * EditAction::eDrop.
2499 * @param aDataTransfer The data transfer object which is dropped.
2500 * @param aDroppedAt The DOM tree position whether aDataTransfer
2502 * @param aSrcDocument Source document which has the dragging item.
2503 * May be nullptr if it comes from another app.
2505 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT
virtual nsresult
2506 InsertDroppedDataTransferAsAction(AutoEditActionDataSetter
& aEditActionData
,
2507 dom::DataTransfer
& aDataTransfer
,
2508 const EditorDOMPoint
& aDroppedAt
,
2509 dom::Document
* aSrcDocument
) = 0;
2512 * DeleteSelectionByDragAsAction() removes selection and dispatch "input"
2513 * event whose inputType is "deleteByDrag".
2515 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2516 DeleteSelectionByDragAsAction(bool aDispatchInputEvent
);
2519 * DeleteSelectionWithTransaction() removes selected content or content
2520 * around caret with transactions and remove empty inclusive ancestor
2521 * inline elements of collapsed selection after removing the contents.
2523 * @param aDirectionAndAmount How much range should be removed.
2524 * @param aStripWrappers Whether the parent blocks should be removed
2525 * when they become empty.
2526 * Note that this must be `nsIEditor::eNoStrip`
2527 * if this is a TextEditor because anyway it'll
2530 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2531 DeleteSelectionWithTransaction(nsIEditor::EDirection aDirectionAndAmount
,
2532 nsIEditor::EStripWrappers aStripWrappers
);
2535 * DeleteRangesWithTransaction() removes content in aRangesToDelete or content
2536 * around collapsed ranges in aRangesToDelete with transactions and remove
2537 * empty inclusive ancestor inline elements of collapsed ranges after
2538 * removing the contents.
2540 * @param aDirectionAndAmount How much range should be removed.
2541 * @param aStripWrappers Whether the parent blocks should be removed
2542 * when they become empty.
2543 * Note that this must be `nsIEditor::eNoStrip`
2544 * if this is a TextEditor because anyway it'll
2546 * @param aRangesToDelete The ranges to delete content.
2548 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2549 DeleteRangesWithTransaction(nsIEditor::EDirection aDirectionAndAmount
,
2550 nsIEditor::EStripWrappers aStripWrappers
,
2551 const AutoRangeArray
& aRangesToDelete
);
2554 * Create an aggregate transaction for delete the content in aRangesToDelete.
2555 * The result may include DeleteNodeTransactions and/or DeleteTextTransactions
2558 * @param aHowToHandleCollapsedRange
2559 * How to handle collapsed ranges.
2560 * @param aRangesToDelete The ranges to delete content.
2561 * @return If it can remove the content in ranges, returns
2562 * an aggregate transaction which has some
2563 * DeleteNodeTransactions and/or
2564 * DeleteTextTransactions as its children.
2566 already_AddRefed
<EditAggregateTransaction
>
2567 CreateTransactionForDeleteSelection(
2568 HowToHandleCollapsedRange aHowToHandleCollapsedRange
,
2569 const AutoRangeArray
& aRangesToDelete
);
2572 * Create a transaction for removing the nodes and/or text around
2575 * @param aCollapsedRange The range to be removed. This must be
2577 * @param aHowToHandleCollapsedRange
2578 * How to handle aCollapsedRange. Must
2579 * be HowToHandleCollapsedRange::ExtendBackward or
2580 * HowToHandleCollapsedRange::ExtendForward.
2581 * @return The transaction to remove content around the
2582 * range. Its type is DeleteNodeTransaction or
2583 * DeleteTextTransaction.
2585 already_AddRefed
<EditTransactionBase
> CreateTransactionForCollapsedRange(
2586 const nsRange
& aCollapsedRange
,
2587 HowToHandleCollapsedRange aHowToHandleCollapsedRange
);
2590 * ComputeInsertedRange() returns actual range modified by inserting string
2591 * in a text node. If mutation event listener changed the text data, this
2592 * returns a range which covers all over the text data.
2594 Tuple
<EditorDOMPointInText
, EditorDOMPointInText
> ComputeInsertedRange(
2595 const EditorDOMPointInText
& aInsertedPoint
,
2596 const nsAString
& aInsertedString
) const;
2599 * EnsureComposition() should be called by composition event handlers. This
2600 * tries to get the composition for the event and set it to mComposition.
2601 * However, this may fail because the composition may be committed before
2602 * the event comes to the editor.
2604 * @return true if there is a composition. Otherwise, for example,
2605 * a composition event handler in web contents moved focus
2606 * for committing the composition, returns false.
2608 bool EnsureComposition(WidgetCompositionEvent
& aCompositionEvent
);
2611 * See comment of IsCopyToClipboardAllowed() for the detail.
2613 virtual bool IsCopyToClipboardAllowedInternal() const {
2614 MOZ_ASSERT(IsEditActionDataAvailable());
2615 return !SelectionRef().IsCollapsed();
2619 * Helper for Is{Cut|Copy}CommandEnabled.
2620 * Look for a listener for the given command, including up the target chain.
2622 MOZ_CAN_RUN_SCRIPT
bool CheckForClipboardCommandListener(
2623 nsAtom
* aCommand
, EventMessage aEventMessage
) const;
2626 * FireClipboardEvent() may dispatch a clipboard event.
2628 * @param aEventMessage The event message which may be set to the
2629 * dispatching event.
2630 * @param aClipboardType Working with global clipboard or selection.
2631 * @param aActionTaken [optional][out] If set to non-nullptr, will be
2632 * set to true if the action for the event is
2633 * handled or prevented default.
2634 * @return false if dispatching event is canceled.
2636 bool FireClipboardEvent(EventMessage aEventMessage
, int32_t aClipboardType
,
2637 bool* aActionTaken
= nullptr);
2640 nsCOMPtr
<nsISelectionController
> mSelectionController
;
2641 RefPtr
<Document
> mDocument
;
2643 AutoEditActionDataSetter
* mEditActionData
;
2646 * SetTextDirectionTo() sets text-direction of the root element.
2647 * Should use SwitchTextDirectionTo() or ToggleTextDirection() instead.
2648 * This is a helper class of them.
2650 nsresult
SetTextDirectionTo(TextDirection aTextDirection
);
2652 protected: // helper classes which may be used by friends
2654 * Stack based helper class for calling EditorBase::EndTransactionInternal().
2655 * NOTE: This does not suppress multiple input events. In most cases,
2656 * only one "input" event should be fired for an edit action rather
2657 * than per edit sub-action. In such case, you should use
2658 * AutoPlaceholderBatch instead.
2660 class MOZ_RAII AutoTransactionBatch final
{
2662 MOZ_CAN_RUN_SCRIPT
explicit AutoTransactionBatch(EditorBase
& aEditorBase
)
2663 : mEditorBase(aEditorBase
) {
2664 MOZ_KnownLive(mEditorBase
).BeginTransactionInternal();
2667 MOZ_CAN_RUN_SCRIPT
~AutoTransactionBatch() {
2668 MOZ_KnownLive(mEditorBase
).EndTransactionInternal();
2672 EditorBase
& mEditorBase
;
2676 * Stack based helper class for batching a collection of transactions inside
2677 * a placeholder transaction. Different from AutoTransactionBatch, this
2678 * notifies editor observers of before/end edit action handling, and
2679 * dispatches "input" event if it's necessary.
2681 class MOZ_RAII AutoPlaceholderBatch final
{
2683 AutoPlaceholderBatch(EditorBase
& aEditorBase
,
2684 ScrollSelectionIntoView aScrollSelectionIntoView
)
2685 : mEditorBase(aEditorBase
),
2686 mScrollSelectionIntoView(aScrollSelectionIntoView
) {
2687 mEditorBase
->BeginPlaceholderTransaction(*nsGkAtoms::_empty
);
2690 AutoPlaceholderBatch(EditorBase
& aEditorBase
,
2691 nsStaticAtom
& aTransactionName
,
2692 ScrollSelectionIntoView aScrollSelectionIntoView
)
2693 : mEditorBase(aEditorBase
),
2694 mScrollSelectionIntoView(aScrollSelectionIntoView
) {
2695 mEditorBase
->BeginPlaceholderTransaction(aTransactionName
);
2698 ~AutoPlaceholderBatch() {
2699 mEditorBase
->EndPlaceholderTransaction(mScrollSelectionIntoView
);
2703 OwningNonNull
<EditorBase
> mEditorBase
;
2704 ScrollSelectionIntoView mScrollSelectionIntoView
;
2708 * Stack based helper class for saving/restoring selection. Note that this
2709 * assumes that the nodes involved are still around afterwords!
2711 class MOZ_RAII AutoSelectionRestorer final
{
2714 * Constructor responsible for remembering all state needed to restore
2717 explicit AutoSelectionRestorer(EditorBase
& aEditorBase
);
2720 * Destructor restores mSelection to its former state
2722 ~AutoSelectionRestorer();
2725 * Abort() cancels to restore the selection.
2730 EditorBase
* mEditorBase
;
2734 * AutoEditSubActionNotifier notifies editor of start to handle
2735 * top level edit sub-action and end handling top level edit sub-action.
2737 class MOZ_RAII AutoEditSubActionNotifier final
{
2739 MOZ_CAN_RUN_SCRIPT
AutoEditSubActionNotifier(
2740 EditorBase
& aEditorBase
, EditSubAction aEditSubAction
,
2741 nsIEditor::EDirection aDirection
, ErrorResult
& aRv
)
2742 : mEditorBase(aEditorBase
), mIsTopLevel(true) {
2743 // The top level edit sub action has already be set if this is nested call
2744 // XXX Looks like that this is not aware of unexpected nested edit action
2745 // handling via selectionchange event listener or mutation event
2747 if (!mEditorBase
.GetTopLevelEditSubAction()) {
2748 MOZ_KnownLive(mEditorBase
)
2749 .OnStartToHandleTopLevelEditSubAction(aEditSubAction
, aDirection
,
2752 mIsTopLevel
= false;
2754 mEditorBase
.OnStartToHandleEditSubAction();
2757 MOZ_CAN_RUN_SCRIPT
~AutoEditSubActionNotifier() {
2758 mEditorBase
.OnEndHandlingEditSubAction();
2760 MOZ_KnownLive(mEditorBase
).OnEndHandlingTopLevelEditSubAction();
2765 EditorBase
& mEditorBase
;
2770 * Stack based helper class for turning off active selection adjustment
2771 * by low level transactions
2773 class MOZ_RAII AutoTransactionsConserveSelection final
{
2775 explicit AutoTransactionsConserveSelection(EditorBase
& aEditorBase
)
2776 : mEditorBase(aEditorBase
),
2777 mAllowedTransactionsToChangeSelection(
2778 aEditorBase
.AllowsTransactionsToChangeSelection()) {
2779 mEditorBase
.MakeThisAllowTransactionsToChangeSelection(false);
2782 ~AutoTransactionsConserveSelection() {
2783 mEditorBase
.MakeThisAllowTransactionsToChangeSelection(
2784 mAllowedTransactionsToChangeSelection
);
2788 EditorBase
& mEditorBase
;
2789 bool mAllowedTransactionsToChangeSelection
;
2792 /***************************************************************************
2793 * stack based helper class for batching reflow and paint requests.
2795 class MOZ_RAII AutoUpdateViewBatch final
{
2797 MOZ_CAN_RUN_SCRIPT
explicit AutoUpdateViewBatch(EditorBase
& aEditorBase
)
2798 : mEditorBase(aEditorBase
) {
2799 mEditorBase
.BeginUpdateViewBatch();
2802 MOZ_CAN_RUN_SCRIPT
~AutoUpdateViewBatch() {
2803 MOZ_KnownLive(mEditorBase
).EndUpdateViewBatch();
2807 EditorBase
& mEditorBase
;
2811 enum Tristate
{ eTriUnset
, eTriFalse
, eTriTrue
};
2813 // MIME type of the doc we are editing.
2814 nsString mContentMIMEType
;
2816 RefPtr
<mozInlineSpellChecker
> mInlineSpellChecker
;
2817 // Reference to text services document for mInlineSpellChecker.
2818 RefPtr
<TextServicesDocument
> mTextServicesDocument
;
2820 RefPtr
<TransactionManager
> mTransactionManager
;
2821 // Cached root node.
2822 RefPtr
<Element
> mRootElement
;
2824 // mPaddingBRElementForEmptyEditor should be used for placing caret
2825 // at proper position when editor is empty.
2826 RefPtr
<dom::HTMLBRElement
> mPaddingBRElementForEmptyEditor
;
2828 // The form field as an event receiver.
2829 nsCOMPtr
<dom::EventTarget
> mEventTarget
;
2830 RefPtr
<EditorEventListener
> mEventListener
;
2831 // Strong reference to placeholder for begin/end batch purposes.
2832 RefPtr
<PlaceholderTransaction
> mPlaceholderTransaction
;
2833 // Name of placeholder transaction.
2834 nsStaticAtom
* mPlaceholderName
;
2835 // Saved selection state for placeholder transaction batching.
2836 mozilla::Maybe
<SelectionState
> mSelState
;
2837 // IME composition this is not null between compositionstart and
2839 RefPtr
<TextComposition
> mComposition
;
2841 RefPtr
<TextInputListener
> mTextInputListener
;
2843 RefPtr
<IMEContentObserver
> mIMEContentObserver
;
2845 // These members cache last encoder and its type for the performance in
2846 // TextEditor::ComputeTextValue() which is the implementation of
2847 // `<input>.value` and `<textarea>.value`. See `GetAndInitDocEncoder()`.
2848 mutable nsCOMPtr
<nsIDocumentEncoder
> mCachedDocumentEncoder
;
2849 mutable nsString mCachedDocumentEncoderType
;
2851 // Listens to all low level actions on the doc.
2852 // Edit action listener is currently used by highlighter of the findbar and
2853 // the spellchecker. So, we should reserve only 2 items.
2854 typedef AutoTArray
<OwningNonNull
<nsIEditActionListener
>, 2>
2855 AutoActionListenerArray
;
2856 AutoActionListenerArray mActionListeners
;
2857 // Just notify once per high level change.
2858 // Editor observer is used only by legacy addons for Thunderbird and
2859 // BlueGriffon. So, we don't need to reserve the space for them.
2860 typedef AutoTArray
<OwningNonNull
<nsIEditorObserver
>, 0>
2861 AutoEditorObserverArray
;
2862 AutoEditorObserverArray mEditorObservers
;
2863 // Listen to overall doc state (dirty or not, just created, etc.).
2864 // Document state listener is currently used by FinderHighlighter and
2865 // BlueGriffon so that reserving only one is enough.
2866 typedef AutoTArray
<OwningNonNull
<nsIDocumentStateListener
>, 1>
2867 AutoDocumentStateListenerArray
;
2868 AutoDocumentStateListenerArray mDocStateListeners
;
2870 // Number of modifications (for undo/redo stack).
2872 // Behavior flags. See nsIEditor.idl for the flags we use.
2875 int32_t mUpdateCount
;
2877 // Nesting count for batching.
2878 int32_t mPlaceholderBatch
;
2880 int32_t mWrapColumn
;
2881 int32_t mNewlineHandling
;
2882 int32_t mCaretStyle
;
2884 // -1 = not initialized
2885 int8_t mDocDirtyState
;
2886 // A Tristate value.
2887 uint8_t mSpellcheckCheckboxState
;
2889 // If true, initialization was succeeded.
2890 bool mInitSucceeded
;
2891 // If false, transactions should not change Selection even after modifying
2893 bool mAllowsTransactionsToChangeSelection
;
2894 // Whether PreDestroy has been called.
2895 bool mDidPreDestroy
;
2896 // Whether PostCreate has been called.
2897 bool mDidPostCreate
;
2898 bool mDispatchInputEvent
;
2899 // True while the instance is handling an edit sub-action.
2900 bool mIsInEditSubAction
;
2901 // Whether caret is hidden forcibly.
2903 // Whether spellchecker dictionary is initialized after focused.
2904 bool mSpellCheckerDictionaryUpdated
;
2905 // Whether we are an HTML editor class.
2906 bool mIsHTMLEditorClass
;
2908 friend class AlignStateAtSelection
;
2909 friend class AutoRangeArray
;
2910 friend class CompositionTransaction
;
2911 friend class CreateElementTransaction
;
2912 friend class CSSEditUtils
;
2913 friend class DeleteNodeTransaction
;
2914 friend class DeleteRangeTransaction
;
2915 friend class DeleteTextTransaction
;
2916 friend class HTMLEditUtils
;
2917 friend class InsertNodeTransaction
;
2918 friend class InsertTextTransaction
;
2919 friend class JoinNodeTransaction
;
2920 friend class ListElementSelectionState
;
2921 friend class ListItemElementSelectionState
;
2922 friend class ParagraphStateAtSelection
;
2923 friend class ReplaceTextTransaction
;
2924 friend class SplitNodeTransaction
;
2925 friend class TypeInState
;
2926 friend class WhiteSpaceVisibilityKeeper
;
2927 friend class WSRunScanner
;
2928 friend class nsIEditor
;
2931 } // namespace mozilla
2933 bool nsIEditor::IsTextEditor() const {
2934 return !AsEditorBase()->mIsHTMLEditorClass
;
2937 bool nsIEditor::IsHTMLEditor() const {
2938 return AsEditorBase()->mIsHTMLEditorClass
;
2941 mozilla::EditorBase
* nsIEditor::AsEditorBase() {
2942 return static_cast<mozilla::EditorBase
*>(this);
2945 const mozilla::EditorBase
* nsIEditor::AsEditorBase() const {
2946 return static_cast<const mozilla::EditorBase
*>(this);
2949 #endif // #ifndef mozilla_EditorBase_h