Bug 1712849 [wpt PR 29110] - Keep 3D points in a quad coplanar when clamping them...
[gecko.git] / editor / libeditor / EditorBase.h
blob0be5e4dcc539bfa6db3222f9001c1df32f4a0500
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;
44 class nsAtom;
45 class nsCaret;
46 class nsIContent;
47 class nsIDocumentEncoder;
48 class nsIDocumentStateListener;
49 class nsIEditActionListener;
50 class nsIEditorObserver;
51 class nsINode;
52 class nsIPrincipal;
53 class nsISupports;
54 class nsITransferable;
55 class nsITransaction;
56 class nsITransactionListener;
57 class nsIWidget;
58 class nsRange;
60 namespace mozilla {
61 class AlignStateAtSelection;
62 class AutoRangeArray;
63 class AutoSelectionRestorer;
64 class AutoTopLevelEditSubActionNotifier;
65 class AutoTransactionBatch;
66 class AutoTransactionsConserveSelection;
67 class AutoUpdateViewBatch;
68 class ChangeAttributeTransaction;
69 class CompositionTransaction;
70 class CreateElementTransaction;
71 class CSSEditUtils;
72 class DeleteNodeTransaction;
73 class DeleteRangeTransaction;
74 class DeleteTextTransaction;
75 class EditActionResult;
76 class EditAggregateTransaction;
77 class EditorEventListener;
78 class EditTransactionBase;
79 class ErrorResult;
80 class HTMLEditor;
81 class HTMLEditUtils;
82 class IMEContentObserver;
83 class InsertNodeTransaction;
84 class InsertTextTransaction;
85 class JoinNodeTransaction;
86 class ListElementSelectionState;
87 class ListItemElementSelectionState;
88 class ParagraphStateAtSelection;
89 class PlaceholderTransaction;
90 class PresShell;
91 class ReplaceTextTransaction;
92 class SplitNodeResult;
93 class SplitNodeTransaction;
94 class TextComposition;
95 class TextEditor;
96 class TextInputListener;
97 class TextServicesDocument;
98 class TypeInState;
99 class WhiteSpaceVisibilityKeeper;
101 template <typename NodeType>
102 class CreateNodeResultBase;
103 typedef CreateNodeResultBase<dom::Element> CreateElementResult;
105 namespace dom {
106 class AbstractRange;
107 class DataTransfer;
108 class Document;
109 class DragEvent;
110 class Element;
111 class EventTarget;
112 class HTMLBRElement;
113 } // namespace dom
115 namespace widget {
116 struct IMEState;
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
124 * implementation.
126 class EditorBase : public nsIEditor,
127 public nsISelectionListener,
128 public nsSupportsWeakReference {
129 public:
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)
150 // nsIEditor methods
151 NS_DECL_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.
160 EditorBase();
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
171 * of the editor.
173 MOZ_CAN_RUN_SCRIPT virtual nsresult Init(Document& doc, Element* aRoot,
174 nsISelectionController* aSelCon,
175 uint32_t aFlags,
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>.
214 return false;
216 #ifdef DEBUG
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.
221 return true;
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();
239 return false;
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
250 * for the detail.
252 bool MutationObserverHasObservedNodeForTelemetry() const {
253 if (const nsPIDOMWindowInner* window = GetInnerWindow()) {
254 return window->MutationObserverHasObservedNodeForTelemetry();
256 return false;
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();
277 if (!sc) {
278 return nullptr;
280 Selection* selection = sc->GetSelection(ToRawSelectionType(aSelectionType));
281 return selection;
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
291 * plaintext editors.
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
327 * be destroyed.
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
336 * called by system.
338 MOZ_CAN_RUN_SCRIPT nsresult
339 ToggleTextDirectionAsAction(nsIPrincipal* aPrincipal = nullptr);
342 * SwitchTextDirectionTo() sets the text-direction of the root element to
343 * LTR or RTL.
345 enum class TextDirection {
346 eLTR,
347 eRTL,
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()
380 : 0;
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) {
413 return true;
415 return mTransactionManager->DisableUndoRedo();
417 bool ClearUndoRedo() {
418 if (!mTransactionManager) {
419 return true;
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())) {
453 return false;
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) {
466 return false;
468 return mTransactionManager->AddTransactionListener(aListener);
470 bool RemoveTransactionListener(nsITransactionListener& aListener) {
471 if (!mTransactionManager) {
472 return false;
474 return mTransactionManager->RemoveTransactionListener(aListener);
478 * HandleDropEvent() is called from EditorEventListener::Drop that is handler
479 * of drop event.
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) {
529 return NS_OK;
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) {
537 return NS_OK;
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) {
548 return NS_OK;
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
628 * "input" event.
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
659 * methods.
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
667 * elements.
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
683 * added here.
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);
702 * Do "cut".
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
719 * handled.
720 * @param aPrincipal Set subject principal if it may be called by
721 * JS. If set to nullptr, will be treated as
722 * called by system.
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
738 * called by system.
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
750 * called by system.
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())) {
762 return false;
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
778 * called by system.
780 MOZ_CAN_RUN_SCRIPT nsresult
781 DeleteSelectionAsAction(nsIEditor::EDirection aDirectionAndAmount,
782 nsIEditor::EStripWrappers aStripWrappers,
783 nsIPrincipal* aPrincipal = nullptr);
785 enum class AllowBeforeInputEventCancelable {
787 Yes,
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
804 * called by system.
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
830 * called by system.
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
842 * called by system.
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
860 * called by system.
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
903 // cases for now:
904 // - non-collapsed range was selected.
905 // - selection was collapsed in a text node and a Unicode character
906 // was removed.
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
917 // to restore it.
918 bool mRestoreContentEditableCount;
920 // If we explicitly normalized whitespaces around the changed range,
921 // set to true.
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);
953 private:
954 void Clear() {
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) {
960 return;
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,
979 nsINode& aNode);
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;
1007 private:
1008 void Clear() {
1009 mJoinedLeftNodeLength = 0;
1010 mAdjustChangedRangeFromListener = true;
1013 friend EditorBase;
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 {
1024 eWithFormat,
1025 eWithoutFormat,
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 {
1035 public:
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
1039 // it.
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
1058 * itself.
1061 [[nodiscard]] bool CanHandle() const {
1062 #ifdef DEBUG
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");
1070 return false;
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
1119 * non illegal case.
1121 void MarkAsHandled() {
1122 MOZ_ASSERT(!mHandled);
1123 mHandled = true;
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
1130 * called.
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
1138 // event later.
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));
1160 return *mSelection;
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");
1185 mData = aData;
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
1195 * read-only.
1197 void InitializeDataTransfer(dom::DataTransfer* aDataTransfer);
1199 * InitializeDataTransfer(nsITransferable*) creates new DataTransfer
1200 * instance, initializes it with aTransferable and sets mDataTransfer to
1201 * it.
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;
1252 if (mParentData) {
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;
1295 break;
1296 case EditSubAction::eJoinNodes:
1297 case EditSubAction::eDeleteText:
1298 MOZ_ASSERT(aDirection == ePrevious);
1299 mDirectionOfTopLevelEditSubAction = ePrevious;
1300 break;
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;
1308 break;
1309 case EditSubAction::eReplaceHeadWithHTMLSource:
1310 // NOTE: Not used with AutoTopLevelEditSubActionNotifier.
1311 mDirectionOfTopLevelEditSubAction = eNone;
1312 break;
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
1319 // as-is for now.
1320 mDirectionOfTopLevelEditSubAction = aDirection;
1321 break;
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;
1372 private:
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
1400 // change.
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:
1411 return false;
1412 default:
1413 return true;
1417 bool NeedsToDispatchClipboardEvent() const {
1418 if (mHasTriedToDispatchClipboardEvent) {
1419 return false;
1421 switch (mEditAction) {
1422 case EditAction::ePaste:
1423 case EditAction::ePasteAsQuotation:
1424 case EditAction::eCut:
1425 case EditAction::eCopy:
1426 return true;
1427 default:
1428 return false;
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.
1447 nsString mData;
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
1456 // by TextEditor.
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;
1478 bool mAborted;
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
1490 // event.
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
1494 // edit action.
1495 bool mEditorWasDestroyedDuringHandlingEditAction;
1496 // This is set before dispatching `input` event and notifying editor
1497 // observers.
1498 bool mHandled;
1500 #ifdef DEBUG
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
1618 * sub-action.
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()
1632 : eNone;
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
1694 * DOM point.
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.
1755 * false, otherwise.
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
1796 * before.
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
1805 * aDestElement.
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,
1870 ErrorResult& aRv);
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,
1874 uint32_t aCount,
1875 const nsAString& aStringToInsert,
1876 ErrorResult& aRv);
1877 MOZ_CAN_RUN_SCRIPT void DoSetText(dom::Text& aText,
1878 const nsAString& aStringToSet,
1879 ErrorResult& aRv);
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,
1907 uint32_t aOffset,
1908 uint32_t aLength);
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
1966 * change Selection.
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
1987 * editors.
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 {
2024 public:
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
2037 * information.
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;
2054 private:
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
2069 * anything.
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
2078 * edit sub-action.
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 ">"
2127 * automatically.
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,
2179 ErrorResult& aRv);
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
2190 * sub action.
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
2211 * manager batches.
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
2227 * use it instead?
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
2257 * methods.
2259 static inline nsresult ToGenericNSResult(nsresult aRv) {
2260 switch (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:
2265 return NS_OK;
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
2269 // this case.
2270 case NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE:
2271 return NS_OK;
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;
2286 default:
2287 return aRv;
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
2311 * cost.
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 {
2363 eDocumentCreated,
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
2382 * match.
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
2409 // or not.
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
2427 * selection.
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
2441 * nothing.
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.
2464 Ignore,
2465 // Extend collapsed range for removing previous content.
2466 ExtendBackward,
2467 // Extend collapsed range for removing next content.
2468 ExtendForward,
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
2501 * is dropped.
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
2528 * be ignored.
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
2545 * be ignored.
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
2556 * as its children.
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
2573 * aRangeToDelete.
2575 * @param aCollapsedRange The range to be removed. This must be
2576 * collapsed.
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);
2639 private:
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 {
2661 public:
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();
2671 protected:
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 {
2682 public:
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);
2702 protected:
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 {
2712 public:
2714 * Constructor responsible for remembering all state needed to restore
2715 * aSelection.
2717 explicit AutoSelectionRestorer(EditorBase& aEditorBase);
2720 * Destructor restores mSelection to its former state
2722 ~AutoSelectionRestorer();
2725 * Abort() cancels to restore the selection.
2727 void Abort();
2729 protected:
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 {
2738 public:
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
2746 // listener.
2747 if (!mEditorBase.GetTopLevelEditSubAction()) {
2748 MOZ_KnownLive(mEditorBase)
2749 .OnStartToHandleTopLevelEditSubAction(aEditSubAction, aDirection,
2750 aRv);
2751 } else {
2752 mIsTopLevel = false;
2754 mEditorBase.OnStartToHandleEditSubAction();
2757 MOZ_CAN_RUN_SCRIPT ~AutoEditSubActionNotifier() {
2758 mEditorBase.OnEndHandlingEditSubAction();
2759 if (mIsTopLevel) {
2760 MOZ_KnownLive(mEditorBase).OnEndHandlingTopLevelEditSubAction();
2764 protected:
2765 EditorBase& mEditorBase;
2766 bool mIsTopLevel;
2770 * Stack based helper class for turning off active selection adjustment
2771 * by low level transactions
2773 class MOZ_RAII AutoTransactionsConserveSelection final {
2774 public:
2775 explicit AutoTransactionsConserveSelection(EditorBase& aEditorBase)
2776 : mEditorBase(aEditorBase),
2777 mAllowedTransactionsToChangeSelection(
2778 aEditorBase.AllowsTransactionsToChangeSelection()) {
2779 mEditorBase.MakeThisAllowTransactionsToChangeSelection(false);
2782 ~AutoTransactionsConserveSelection() {
2783 mEditorBase.MakeThisAllowTransactionsToChangeSelection(
2784 mAllowedTransactionsToChangeSelection);
2787 protected:
2788 EditorBase& mEditorBase;
2789 bool mAllowedTransactionsToChangeSelection;
2792 /***************************************************************************
2793 * stack based helper class for batching reflow and paint requests.
2795 class MOZ_RAII AutoUpdateViewBatch final {
2796 public:
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();
2806 protected:
2807 EditorBase& mEditorBase;
2810 protected:
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
2838 // compositionend.
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).
2871 uint32_t mModCount;
2872 // Behavior flags. See nsIEditor.idl for the flags we use.
2873 uint32_t mFlags;
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
2892 // the DOM tree.
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.
2902 bool mHidingCaret;
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