Bug 1883912: Enable Intl.ListFormat test for "unit" style. r=spidermonkey-reviewers...
[gecko.git] / editor / libeditor / HTMLEditor.h
blob2a31ead29d21f3bb1d0e38341a0d0b9a52934373
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_HTMLEditor_h
7 #define mozilla_HTMLEditor_h
9 #include "mozilla/Attributes.h"
10 #include "mozilla/ComposerCommandsUpdater.h"
11 #include "mozilla/EditorBase.h"
12 #include "mozilla/EditorForwards.h"
13 #include "mozilla/ErrorResult.h"
14 #include "mozilla/ManualNAC.h"
15 #include "mozilla/Result.h"
16 #include "mozilla/dom/BlobImpl.h"
17 #include "mozilla/dom/Element.h"
18 #include "mozilla/dom/File.h"
20 #include "nsAttrName.h"
21 #include "nsCOMPtr.h"
22 #include "nsIDocumentObserver.h"
23 #include "nsIDOMEventListener.h"
24 #include "nsIEditorMailSupport.h"
25 #include "nsIHTMLAbsPosEditor.h"
26 #include "nsIHTMLEditor.h"
27 #include "nsIHTMLInlineTableEditor.h"
28 #include "nsIHTMLObjectResizer.h"
29 #include "nsIPrincipal.h"
30 #include "nsITableEditor.h"
31 #include "nsPoint.h"
32 #include "nsStubMutationObserver.h"
34 #include <functional>
36 class nsDocumentFragment;
37 class nsFrameSelection;
38 class nsHTMLDocument;
39 class nsITransferable;
40 class nsIClipboard;
41 class nsRange;
42 class nsStaticAtom;
43 class nsStyledElement;
44 class nsTableCellFrame;
45 class nsTableWrapperFrame;
46 template <class E>
47 class nsTArray;
49 namespace mozilla {
50 class AlignStateAtSelection;
51 class AutoSelectionSetterAfterTableEdit;
52 class AutoSetTemporaryAncestorLimiter;
53 class EmptyEditableFunctor;
54 class ListElementSelectionState;
55 class ListItemElementSelectionState;
56 class ParagraphStateAtSelection;
57 class ResizerSelectionListener;
58 class Runnable;
59 template <class T>
60 class OwningNonNull;
61 namespace dom {
62 class AbstractRange;
63 class Blob;
64 class DocumentFragment;
65 class Event;
66 class HTMLBRElement;
67 class MouseEvent;
68 class StaticRange;
69 } // namespace dom
70 namespace widget {
71 struct IMEState;
72 } // namespace widget
74 enum class ParagraphSeparator { div, p, br };
76 /**
77 * The HTML editor implementation.<br>
78 * Use to edit HTML document represented as a DOM tree.
80 class HTMLEditor final : public EditorBase,
81 public nsIHTMLEditor,
82 public nsIHTMLObjectResizer,
83 public nsIHTMLAbsPosEditor,
84 public nsITableEditor,
85 public nsIHTMLInlineTableEditor,
86 public nsStubMutationObserver,
87 public nsIEditorMailSupport {
88 public:
89 /****************************************************************************
90 * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other
91 * classes under libeditor except EditorEventListener and
92 * HTMLEditorEventListener because each public method which may fire
93 * eEditorInput event will need to instantiate new stack class for
94 * managing input type value of eEditorInput and cache some objects
95 * for smarter handling. In other words, when you add new root
96 * method to edit the DOM tree, you can make your new method public.
97 ****************************************************************************/
99 NS_DECL_ISUPPORTS_INHERITED
100 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLEditor, EditorBase)
102 // nsStubMutationObserver overrides
103 NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
104 NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
105 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
106 NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
108 // nsIHTMLEditor methods
109 NS_DECL_NSIHTMLEDITOR
111 // nsIHTMLObjectResizer methods (implemented in HTMLObjectResizer.cpp)
112 NS_DECL_NSIHTMLOBJECTRESIZER
114 // nsIHTMLAbsPosEditor methods (implemented in HTMLAbsPositionEditor.cpp)
115 NS_DECL_NSIHTMLABSPOSEDITOR
117 // nsIHTMLInlineTableEditor methods (implemented in HTMLInlineTableEditor.cpp)
118 NS_DECL_NSIHTMLINLINETABLEEDITOR
120 // nsIEditorMailSupport methods
121 NS_DECL_NSIEDITORMAILSUPPORT
123 // nsITableEditor methods
124 NS_DECL_NSITABLEEDITOR
126 // nsISelectionListener overrides
127 NS_DECL_NSISELECTIONLISTENER
130 * @param aDocument The document whose content will be editable.
132 explicit HTMLEditor(const Document& aDocument);
135 * @param aDocument The document whose content will be editable.
136 * @param aComposerCommandsUpdater The composer command updater.
137 * @param aFlags Some of nsIEditor::eEditor*Mask flags.
139 MOZ_CAN_RUN_SCRIPT nsresult
140 Init(Document& aDocument, ComposerCommandsUpdater& aComposerCommandsUpdater,
141 uint32_t aFlags);
144 * PostCreate() should be called after Init, and is the time that the editor
145 * tells its documentStateObservers that the document has been created.
147 MOZ_CAN_RUN_SCRIPT nsresult PostCreate();
150 * PreDestroy() is called before the editor goes away, and gives the editor a
151 * chance to tell its documentStateObservers that the document is going away.
153 MOZ_CAN_RUN_SCRIPT void PreDestroy();
155 static HTMLEditor* GetFrom(nsIEditor* aEditor) {
156 return aEditor ? aEditor->GetAsHTMLEditor() : nullptr;
158 static const HTMLEditor* GetFrom(const nsIEditor* aEditor) {
159 return aEditor ? aEditor->GetAsHTMLEditor() : nullptr;
162 [[nodiscard]] bool GetReturnInParagraphCreatesNewParagraph() const;
164 // EditorBase overrides
165 MOZ_CAN_RUN_SCRIPT NS_IMETHOD BeginningOfDocument() final;
166 MOZ_CAN_RUN_SCRIPT NS_IMETHOD EndOfDocument() final;
168 NS_IMETHOD GetDocumentCharacterSet(nsACString& aCharacterSet) final;
169 MOZ_CAN_RUN_SCRIPT NS_IMETHOD
170 SetDocumentCharacterSet(const nsACString& aCharacterSet) final;
172 bool IsEmpty() const final;
174 bool CanPaste(int32_t aClipboardType) const final;
175 using EditorBase::CanPaste;
177 MOZ_CAN_RUN_SCRIPT NS_IMETHOD DeleteNode(nsINode* aNode,
178 bool aPreseveSelection,
179 uint8_t aOptionalArgCount) final;
181 MOZ_CAN_RUN_SCRIPT NS_IMETHOD InsertLineBreak() final;
184 * PreHandleMouseDown() and PreHandleMouseUp() are called before
185 * HTMLEditorEventListener handles them. The coming event may be
186 * non-acceptable event.
188 void PreHandleMouseDown(const dom::MouseEvent& aMouseDownEvent);
189 void PreHandleMouseUp(const dom::MouseEvent& aMouseUpEvent);
192 * PreHandleSelectionChangeCommand() and PostHandleSelectionChangeCommand()
193 * are called before or after handling a command which may change selection
194 * and/or scroll position.
196 void PreHandleSelectionChangeCommand(Command aCommand);
197 void PostHandleSelectionChangeCommand(Command aCommand);
199 MOZ_CAN_RUN_SCRIPT nsresult
200 HandleKeyPressEvent(WidgetKeyboardEvent* aKeyboardEvent) final;
201 Element* GetFocusedElement() const final;
202 bool IsActiveInDOMWindow() const final;
203 dom::EventTarget* GetDOMEventTarget() const final;
204 [[nodiscard]] Element* FindSelectionRoot(const nsINode& aNode) const final;
205 bool IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent) const final;
206 nsresult GetPreferredIMEState(widget::IMEState* aState) final;
207 MOZ_CAN_RUN_SCRIPT nsresult
208 OnFocus(const nsINode& aOriginalEventTargetNode) final;
209 nsresult OnBlur(const dom::EventTarget* aEventTarget) final;
212 * Called when aDocument or aElement becomes editable without focus change.
213 * E.g., when the design mode is enabled or the contenteditable attribute
214 * is set to the focused element.
216 MOZ_CAN_RUN_SCRIPT nsresult FocusedElementOrDocumentBecomesEditable(
217 Document& aDocument, Element* aElement);
220 * Called when aDocument or aElement becomes not editable without focus
221 * change. E.g., when the design mode ends or the contenteditable attribute is
222 * removed or set to "false".
224 MOZ_CAN_RUN_SCRIPT static nsresult FocusedElementOrDocumentBecomesNotEditable(
225 HTMLEditor* aHTMLEditor, Document& aDocument, Element* aElement);
228 * GetBackgroundColorState() returns what the background color of the
229 * selection.
231 * @param aMixed true if there is more than one font color
232 * @param aOutColor Color string. "" is returned for none.
234 MOZ_CAN_RUN_SCRIPT nsresult GetBackgroundColorState(bool* aMixed,
235 nsAString& aOutColor);
238 * PasteNoFormattingAsAction() pastes content in clipboard without any style
239 * information.
241 * @param aClipboardType nsIClipboard::kGlobalClipboard or
242 * nsIClipboard::kSelectionClipboard.
243 * @param aDispatchPasteEvent Yes if this should dispatch ePaste event
244 * before pasting. Otherwise, No.
245 * @param aPrincipal Set subject principal if it may be called by
246 * JS. If set to nullptr, will be treated as
247 * called by system.
249 MOZ_CAN_RUN_SCRIPT nsresult PasteNoFormattingAsAction(
250 int32_t aClipboardType, DispatchPasteEvent aDispatchPasteEvent,
251 nsIPrincipal* aPrincipal = nullptr);
253 bool CanPasteTransferable(nsITransferable* aTransferable) final;
255 MOZ_CAN_RUN_SCRIPT nsresult
256 InsertLineBreakAsAction(nsIPrincipal* aPrincipal = nullptr) final;
259 * InsertParagraphSeparatorAsAction() is called when user tries to separate
260 * current paragraph with Enter key press in HTMLEditor or something.
262 * @param aPrincipal Set subject principal if it may be called by
263 * JS. If set to nullptr, will be treated as
264 * called by system.
266 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
267 InsertParagraphSeparatorAsAction(nsIPrincipal* aPrincipal = nullptr);
269 MOZ_CAN_RUN_SCRIPT nsresult
270 InsertElementAtSelectionAsAction(Element* aElement, bool aDeleteSelection,
271 nsIPrincipal* aPrincipal = nullptr);
273 MOZ_CAN_RUN_SCRIPT nsresult InsertLinkAroundSelectionAsAction(
274 Element* aAnchorElement, nsIPrincipal* aPrincipal = nullptr);
277 * CreateElementWithDefaults() creates new element whose name is
278 * aTagName with some default attributes are set. Note that this is a
279 * public utility method. I.e., just creates element, not insert it
280 * into the DOM tree.
281 * NOTE: This is available for internal use too since this does not change
282 * the DOM tree nor undo transactions, and does not refer Selection,
283 * etc.
285 * @param aTagName The new element's tag name. If the name is
286 * one of "href", "anchor" or "namedanchor",
287 * this creates an <a> element.
288 * @return Newly created element.
290 MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> CreateElementWithDefaults(
291 const nsAtom& aTagName);
294 * Indent or outdent content around Selection.
296 * @param aPrincipal Set subject principal if it may be called by
297 * JS. If set to nullptr, will be treated as
298 * called by system.
300 MOZ_CAN_RUN_SCRIPT nsresult
301 IndentAsAction(nsIPrincipal* aPrincipal = nullptr);
302 MOZ_CAN_RUN_SCRIPT nsresult
303 OutdentAsAction(nsIPrincipal* aPrincipal = nullptr);
306 * The Document.execCommand("formatBlock") handler.
308 * @param aParagraphFormat Must not be an empty string, and the value must
309 * be one of address, article, aside, blockquote,
310 * div, footer, h1, h2, h3, h4, h5, h6, header,
311 * hgroup, main, nav, p, pre, selection, dt or dd.
313 MOZ_CAN_RUN_SCRIPT nsresult FormatBlockAsAction(
314 const nsAString& aParagraphFormat, nsIPrincipal* aPrincipal = nullptr);
317 * The cmd_paragraphState command handler.
319 * @param aParagraphFormat Can be empty string. If this is empty string,
320 * this removes ancestor format elements.
321 * Otherwise, the value must be one of p, pre,
322 * h1, h2, h3, h4, h5, h6, address, dt or dl.
324 MOZ_CAN_RUN_SCRIPT nsresult SetParagraphStateAsAction(
325 const nsAString& aParagraphFormat, nsIPrincipal* aPrincipal = nullptr);
327 MOZ_CAN_RUN_SCRIPT nsresult AlignAsAction(const nsAString& aAlignType,
328 nsIPrincipal* aPrincipal = nullptr);
330 MOZ_CAN_RUN_SCRIPT nsresult RemoveListAsAction(
331 const nsAString& aListType, nsIPrincipal* aPrincipal = nullptr);
334 * MakeOrChangeListAsAction() makes selected hard lines list element(s).
336 * @param aListElementTagName The new list element tag name. Must be
337 * nsGkAtoms::ul, nsGkAtoms::ol or
338 * nsGkAtoms::dl.
339 * @param aBulletType If this is not empty string, it's set
340 * to `type` attribute of new list item
341 * elements. Otherwise, existing `type`
342 * attributes will be removed.
343 * @param aSelectAllOfCurrentList Yes if this should treat all of
344 * ancestor list element at selection.
346 enum class SelectAllOfCurrentList { Yes, No };
347 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult MakeOrChangeListAsAction(
348 const nsStaticAtom& aListElementTagName, const nsAString& aBulletType,
349 SelectAllOfCurrentList aSelectAllOfCurrentList,
350 nsIPrincipal* aPrincipal = nullptr);
353 * If aTargetElement is a resizer, start to drag the resizer. Otherwise, if
354 * aTargetElement is the grabber, start to handle drag gester on it.
356 * @param aMouseDownEvent A `mousedown` event fired on aTargetElement.
357 * @param aEventTargetElement The target element being pressed. This must
358 * be same as explicit original event target of
359 * aMouseDownEvent.
361 MOZ_CAN_RUN_SCRIPT nsresult StartToDragResizerOrHandleDragGestureOnGrabber(
362 dom::MouseEvent& aMouseDownEvent, Element& aEventTargetElement);
365 * If the editor is handling dragging a resizer, handling drag gesture on
366 * the grabber or dragging the grabber, this finalize it. Otherwise,
367 * does nothing.
369 * @param aClientPoint The final point of the drag.
371 MOZ_CAN_RUN_SCRIPT nsresult
372 StopDraggingResizerOrGrabberAt(const CSSIntPoint& aClientPoint);
375 * If the editor is handling dragging a resizer, handling drag gesture to
376 * start dragging the grabber or dragging the grabber, this method updates
377 * it's position.
379 * @param aClientPoint The new point of the drag.
381 MOZ_CAN_RUN_SCRIPT nsresult
382 UpdateResizerOrGrabberPositionTo(const CSSIntPoint& aClientPoint);
385 * IsCSSEnabled() returns true if this editor treats styles with style
386 * attribute of HTML elements. Otherwise, if this editor treats all styles
387 * with "font style elements" like <b>, <i>, etc, and <blockquote> to indent,
388 * align attribute to align contents, returns false.
390 bool IsCSSEnabled() const { return mIsCSSPrefChecked; }
393 * Enable/disable object resizers for <img> elements, <table> elements,
394 * absolute positioned elements (required absolute position editor enabled).
396 MOZ_CAN_RUN_SCRIPT void EnableObjectResizer(bool aEnable) {
397 if (mIsObjectResizingEnabled == aEnable) {
398 return;
401 AutoEditActionDataSetter editActionData(
402 *this, EditAction::eEnableOrDisableResizer);
403 if (NS_WARN_IF(!editActionData.CanHandle())) {
404 return;
407 mIsObjectResizingEnabled = aEnable;
408 RefreshEditingUI();
410 bool IsObjectResizerEnabled() const { return mIsObjectResizingEnabled; }
412 Element* GetResizerTarget() const { return mResizedObject; }
415 * Enable/disable inline table editor, e.g., adding new row or column,
416 * removing existing row or column.
418 MOZ_CAN_RUN_SCRIPT void EnableInlineTableEditor(bool aEnable) {
419 if (mIsInlineTableEditingEnabled == aEnable) {
420 return;
423 AutoEditActionDataSetter editActionData(
424 *this, EditAction::eEnableOrDisableInlineTableEditingUI);
425 if (NS_WARN_IF(!editActionData.CanHandle())) {
426 return;
429 mIsInlineTableEditingEnabled = aEnable;
430 RefreshEditingUI();
432 bool IsInlineTableEditorEnabled() const {
433 return mIsInlineTableEditingEnabled;
437 * Enable/disable absolute position editor, resizing absolute positioned
438 * elements (required object resizers enabled) or positioning them with
439 * dragging grabber.
441 MOZ_CAN_RUN_SCRIPT void EnableAbsolutePositionEditor(bool aEnable) {
442 if (mIsAbsolutelyPositioningEnabled == aEnable) {
443 return;
446 AutoEditActionDataSetter editActionData(
447 *this, EditAction::eEnableOrDisableAbsolutePositionEditor);
448 if (NS_WARN_IF(!editActionData.CanHandle())) {
449 return;
452 mIsAbsolutelyPositioningEnabled = aEnable;
453 RefreshEditingUI();
455 bool IsAbsolutePositionEditorEnabled() const {
456 return mIsAbsolutelyPositioningEnabled;
460 * returns the deepest absolutely positioned container of the selection
461 * if it exists or null.
463 MOZ_CAN_RUN_SCRIPT already_AddRefed<Element>
464 GetAbsolutelyPositionedSelectionContainer() const;
466 Element* GetPositionedElement() const { return mAbsolutelyPositionedObject; }
469 * extracts the selection from the normal flow of the document and
470 * positions it.
472 * @param aEnabled [IN] true to absolutely position the selection,
473 * false to put it back in the normal flow
474 * @param aPrincipal Set subject principal if it may be called by
475 * JS. If set to nullptr, will be treated as
476 * called by system.
478 MOZ_CAN_RUN_SCRIPT nsresult SetSelectionToAbsoluteOrStaticAsAction(
479 bool aEnabled, nsIPrincipal* aPrincipal = nullptr);
482 * returns the absolute z-index of a positioned element. Never returns 'auto'
483 * @return the z-index of the element
484 * @param aElement [IN] the element.
486 MOZ_CAN_RUN_SCRIPT int32_t GetZIndex(Element& aElement);
489 * adds aChange to the z-index of the currently positioned element.
491 * @param aChange [IN] relative change to apply to current z-index
492 * @param aPrincipal Set subject principal if it may be called by
493 * JS. If set to nullptr, will be treated as
494 * called by system.
496 MOZ_CAN_RUN_SCRIPT nsresult
497 AddZIndexAsAction(int32_t aChange, nsIPrincipal* aPrincipal = nullptr);
499 MOZ_CAN_RUN_SCRIPT nsresult SetBackgroundColorAsAction(
500 const nsAString& aColor, nsIPrincipal* aPrincipal = nullptr);
503 * SetInlinePropertyAsAction() sets a property which changes inline style of
504 * text. E.g., bold, italic, super and sub.
505 * This automatically removes exclusive style, however, treats all changes
506 * as a transaction.
508 * @param aPrincipal Set subject principal if it may be called by
509 * JS. If set to nullptr, will be treated as
510 * called by system.
512 MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertyAsAction(
513 nsStaticAtom& aProperty, nsStaticAtom* aAttribute,
514 const nsAString& aValue, nsIPrincipal* aPrincipal = nullptr);
517 * GetInlineProperty() gets aggregate properties of the current selection.
518 * All object in the current selection are scanned and their attributes are
519 * represented in a list of Property object.
520 * TODO: Make this return Result<Something> instead of bool out arguments.
522 * @param aHTMLProperty the property to get on the selection
523 * @param aAttribute the attribute of the property, if applicable.
524 * May be null.
525 * Example: aHTMLProperty=nsGkAtoms::font,
526 * aAttribute=nsGkAtoms::color
527 * @param aValue if aAttribute is not null, the value of the
528 * attribute. May be null.
529 * Example: aHTMLProperty=nsGkAtoms::font,
530 * aAttribute=nsGkAtoms::color,
531 * aValue="0x00FFFF"
532 * @param aFirst [OUT] true if the first text node in the
533 * selection has the property
534 * @param aAny [OUT] true if any of the text nodes in the
535 * selection have the property
536 * @param aAll [OUT] true if all of the text nodes in the
537 * selection have the property
539 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlineProperty(
540 nsStaticAtom& aHTMLProperty, nsAtom* aAttribute, const nsAString& aValue,
541 bool* aFirst, bool* aAny, bool* aAll) const;
543 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlinePropertyWithAttrValue(
544 nsStaticAtom& aHTMLProperty, nsAtom* aAttribute, const nsAString& aValue,
545 bool* aFirst, bool* aAny, bool* aAll, nsAString& outValue);
548 * RemoveInlinePropertyAsAction() removes a property which changes inline
549 * style of text. E.g., bold, italic, super and sub.
551 * @param aHTMLProperty Tag name whcih represents the inline style you want
552 * to remove. E.g., nsGkAtoms::strong, nsGkAtoms::b,
553 * etc. If nsGkAtoms::href, <a> element which has
554 * href attribute will be removed.
555 * If nsGkAtoms::name, <a> element which has non-empty
556 * name attribute will be removed.
557 * @param aAttribute If aHTMLProperty is nsGkAtoms::font, aAttribute should
558 * be nsGkAtoms::fase, nsGkAtoms::size, nsGkAtoms::color
559 * or nsGkAtoms::bgcolor. Otherwise, set nullptr.
560 * Must not use nsGkAtoms::_empty here.
561 * @param aPrincipal Set subject principal if it may be called by JS. If
562 * set to nullptr, will be treated as called by system.
564 MOZ_CAN_RUN_SCRIPT nsresult RemoveInlinePropertyAsAction(
565 nsStaticAtom& aHTMLProperty, nsStaticAtom* aAttribute,
566 nsIPrincipal* aPrincipal = nullptr);
568 MOZ_CAN_RUN_SCRIPT nsresult
569 RemoveAllInlinePropertiesAsAction(nsIPrincipal* aPrincipal = nullptr);
571 MOZ_CAN_RUN_SCRIPT nsresult
572 IncreaseFontSizeAsAction(nsIPrincipal* aPrincipal = nullptr);
574 MOZ_CAN_RUN_SCRIPT nsresult
575 DecreaseFontSizeAsAction(nsIPrincipal* aPrincipal = nullptr);
578 * GetFontColorState() returns foreground color information in first
579 * range of Selection.
580 * If first range of Selection is collapsed and there is a cache of style for
581 * new text, aIsMixed is set to false and aColor is set to the cached color.
582 * If first range of Selection is collapsed and there is no cached color,
583 * this returns the color of the node, aIsMixed is set to false and aColor is
584 * set to the color.
585 * If first range of Selection is not collapsed, this collects colors of
586 * each node in the range. If there are two or more colors, aIsMixed is set
587 * to true and aColor is truncated. If only one color is set to all of the
588 * range, aIsMixed is set to false and aColor is set to the color.
589 * If there is no Selection ranges, aIsMixed is set to false and aColor is
590 * truncated.
592 * @param aIsMixed Must not be nullptr. This is set to true
593 * if there is two or more colors in first
594 * range of Selection.
595 * @param aColor Returns the color if only one color is set to
596 * all of first range in Selection. Otherwise,
597 * returns empty string.
598 * @return Returns error only when illegal cases, e.g.,
599 * Selection instance has gone, first range
600 * Selection is broken.
602 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
603 GetFontColorState(bool* aIsMixed, nsAString& aColor);
606 * Detach aComposerCommandsUpdater from this.
608 void Detach(const ComposerCommandsUpdater& aComposerCommandsUpdater);
610 nsStaticAtom& DefaultParagraphSeparatorTagName() const {
611 return HTMLEditor::ToParagraphSeparatorTagName(mDefaultParagraphSeparator);
613 ParagraphSeparator GetDefaultParagraphSeparator() const {
614 return mDefaultParagraphSeparator;
616 void SetDefaultParagraphSeparator(ParagraphSeparator aSep) {
617 mDefaultParagraphSeparator = aSep;
619 static nsStaticAtom& ToParagraphSeparatorTagName(
620 ParagraphSeparator aSeparator) {
621 switch (aSeparator) {
622 case ParagraphSeparator::div:
623 return *nsGkAtoms::div;
624 case ParagraphSeparator::p:
625 return *nsGkAtoms::p;
626 case ParagraphSeparator::br:
627 return *nsGkAtoms::br;
628 default:
629 MOZ_ASSERT_UNREACHABLE("New paragraph separator isn't handled here");
630 return *nsGkAtoms::div;
635 * Modifies the table containing the selection according to the
636 * activation of an inline table editing UI element
637 * @param aUIAnonymousElement [IN] the inline table editing UI element
639 MOZ_CAN_RUN_SCRIPT nsresult
640 DoInlineTableEditingAction(const Element& aUIAnonymousElement);
643 * GetInclusiveAncestorByTagName() looks for an element node whose name
644 * matches aTagName from aNode or anchor node of Selection to <body> element.
646 * @param aTagName The tag name which you want to look for.
647 * Must not be nsGkAtoms::_empty.
648 * If nsGkAtoms::list, the result may be <ul>, <ol> or
649 * <dl> element.
650 * If nsGkAtoms::td, the result may be <td> or <th>.
651 * If nsGkAtoms::href, the result may be <a> element
652 * which has "href" attribute with non-empty value.
653 * If nsGkAtoms::anchor, the result may be <a> which
654 * has "name" attribute with non-empty value.
655 * @param aContent Start node to look for the result.
656 * @return If an element which matches aTagName, returns
657 * an Element. Otherwise, nullptr.
659 Element* GetInclusiveAncestorByTagName(const nsStaticAtom& aTagName,
660 nsIContent& aContent) const;
663 * Compute editing host for aContent. If this editor isn't active in the DOM
664 * window, this returns nullptr.
666 enum class LimitInBodyElement { No, Yes };
667 [[nodiscard]] Element* ComputeEditingHost(
668 const nsIContent& aContent,
669 LimitInBodyElement aLimitInBodyElement = LimitInBodyElement::Yes) const {
670 return ComputeEditingHostInternal(&aContent, aLimitInBodyElement);
674 * Compute editing host for the focus node of the Selection. If this editor
675 * isn't active in the DOM window, this returns nullptr.
677 [[nodiscard]] Element* ComputeEditingHost(
678 LimitInBodyElement aLimitInBodyElement = LimitInBodyElement::Yes) const {
679 return ComputeEditingHostInternal(nullptr, aLimitInBodyElement);
683 * Return true if we're in designMode.
685 bool IsInDesignMode() const;
688 * Return true if entire the document is editable (although the document
689 * may have non-editable nodes, e.g.,
690 * <body contenteditable><div contenteditable="false"></div></body>
692 bool EntireDocumentIsEditable() const;
695 * Basically, this always returns true if we're for `contenteditable` or
696 * `designMode` editor in web apps. However, e.g., Composer of SeaMonkey
697 * can make the editor not tabbable.
699 bool IsTabbable() const { return IsInteractionAllowed(); }
702 * NotifyEditingHostMaybeChanged() is called when new element becomes
703 * contenteditable when the document already had contenteditable elements.
705 void NotifyEditingHostMaybeChanged();
707 /** Insert a string as quoted text
708 * (whose representation is dependant on the editor type),
709 * replacing the selected text (if any).
711 * @param aQuotedText The actual text to be quoted
712 * @parem aNodeInserted Return the node which was inserted.
714 MOZ_CAN_RUN_SCRIPT // USED_BY_COMM_CENTRAL
715 nsresult
716 InsertAsQuotation(const nsAString& aQuotedText, nsINode** aNodeInserted);
718 MOZ_CAN_RUN_SCRIPT nsresult InsertHTMLAsAction(
719 const nsAString& aInString, nsIPrincipal* aPrincipal = nullptr);
722 * Refresh positions of resizers. If you change size of target of resizers,
723 * you need to refresh position of resizers with calling this.
725 MOZ_CAN_RUN_SCRIPT nsresult RefreshResizers();
727 bool IsWrapHackEnabled() const {
728 return (mFlags & nsIEditor::eEditorEnableWrapHackMask) != 0;
732 * Return true if this is in the plaintext mail composer mode of
733 * Thunderbird or something.
734 * NOTE: This is different from contenteditable="plaintext-only"
736 bool IsPlaintextMailComposer() const {
737 const bool isPlaintextMode =
738 (mFlags & nsIEditor::eEditorPlaintextMask) != 0;
739 MOZ_ASSERT_IF(IsTextEditor(), isPlaintextMode);
740 return isPlaintextMode;
743 protected: // May be called by friends.
744 /****************************************************************************
745 * Some friend classes are allowed to call the following protected methods.
746 * However, those methods won't prepare caches of some objects which are
747 * necessary for them. So, if you call them from friend classes, you need
748 * to make sure that AutoEditActionDataSetter is created.
749 ****************************************************************************/
752 * InsertBRElement() creates a <br> element and inserts it before
753 * aPointToInsert.
755 * @param aWithTransaction Whether the inserting is new element is undoable
756 * or not. WithTransaction::No is useful only when
757 * the new element is inserted into a new element
758 * which has not been connected yet.
759 * @param aPointToInsert The DOM point where should be <br> node inserted
760 * before.
761 * @param aSelect If eNone, returns a point to put caret which is
762 * suggested by InsertNodeTransaction.
763 * If eNext, returns a point after the new <br>
764 * element.
765 * If ePrevious, returns a point at the new <br>
766 * element.
767 * @return The new <br> node and suggesting point to put
768 * caret which respects aSelect.
770 MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult> InsertBRElement(
771 WithTransaction aWithTransaction, const EditorDOMPoint& aPointToInsert,
772 EDirection aSelect = eNone);
775 * Delete text in the range in aTextNode. If aTextNode is not editable, this
776 * does nothing.
778 * @param aTextNode The text node which should be modified.
779 * @param aOffset Start offset of removing text in aTextNode.
780 * @param aLength Length of removing text.
782 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
783 DeleteTextWithTransaction(dom::Text& aTextNode, uint32_t aOffset,
784 uint32_t aLength);
787 * Replace text in the range with aStringToInsert. If there is a DOM range
788 * exactly same as the replacing range, it'll be collapsed to
789 * {aTextNode, aOffset} because of the order of deletion and insertion.
790 * Therefore, the callers may need to handle `Selection` even when callers
791 * do not want to update `Selection`.
793 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<InsertTextResult, nsresult>
794 ReplaceTextWithTransaction(dom::Text& aTextNode, uint32_t aOffset,
795 uint32_t aLength,
796 const nsAString& aStringToInsert);
799 * Insert aStringToInsert to aPointToInsert. If the point is not editable,
800 * this returns error.
802 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<InsertTextResult, nsresult>
803 InsertTextWithTransaction(Document& aDocument,
804 const nsAString& aStringToInsert,
805 const EditorDOMPoint& aPointToInsert) final;
808 * CopyLastEditableChildStyles() clones inline container elements into
809 * aPreviousBlock to aNewBlock to keep using same style in it.
811 * @param aPreviousBlock The previous block element. All inline
812 * elements which are last sibling of each level
813 * are cloned to aNewBlock.
814 * @param aNewBlock New block container element. All children of
815 * this is deleted first.
816 * @param aEditingHost The editing host.
817 * @return If succeeded, returns a suggesting point to put
818 * caret.
820 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
821 CopyLastEditableChildStylesWithTransaction(Element& aPreviousBlock,
822 Element& aNewBlock,
823 const Element& aEditingHost);
826 * RemoveBlockContainerWithTransaction() removes aElement from the DOM tree
827 * but moves its all children to its parent node and if its parent needs <br>
828 * element to have at least one line-height, this inserts <br> element
829 * automatically.
831 * @param aElement Block element to be removed.
832 * @return If succeeded, returns a suggesting point to put
833 * caret.
835 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
836 RemoveBlockContainerWithTransaction(Element& aElement);
838 MOZ_CAN_RUN_SCRIPT nsresult RemoveAttributeOrEquivalent(
839 Element* aElement, nsAtom* aAttribute, bool aSuppressTransaction) final;
840 MOZ_CAN_RUN_SCRIPT nsresult SetAttributeOrEquivalent(
841 Element* aElement, nsAtom* aAttribute, const nsAString& aValue,
842 bool aSuppressTransaction) final;
843 using EditorBase::RemoveAttributeOrEquivalent;
844 using EditorBase::SetAttributeOrEquivalent;
847 * Returns container element of ranges in Selection. If Selection is
848 * collapsed, returns focus container node (or its parent element).
849 * If Selection selects only one element node, returns the element node.
850 * If Selection is only one range, returns common ancestor of the range.
851 * XXX If there are two or more Selection ranges, this returns parent node
852 * of start container of a range which starts with different node from
853 * start container of the first range.
855 Element* GetSelectionContainerElement() const;
858 * DeleteTableCellContentsWithTransaction() removes any contents in cell
859 * elements. If two or more cell elements are selected, this removes
860 * all selected cells' contents. Otherwise, this removes contents of
861 * a cell which contains first selection range. This does not return
862 * error even if selection is not in cell element, just does nothing.
864 MOZ_CAN_RUN_SCRIPT nsresult DeleteTableCellContentsWithTransaction();
867 * extracts an element from the normal flow of the document and
868 * positions it, and puts it back in the normal flow.
869 * @param aElement [IN] the element
870 * @param aEnabled [IN] true to absolutely position the element,
871 * false to put it back in the normal flow
873 MOZ_CAN_RUN_SCRIPT nsresult SetPositionToAbsoluteOrStatic(Element& aElement,
874 bool aEnabled);
877 * adds aChange to the z-index of an arbitrary element.
878 * @param aElement [IN] the element
879 * @param aChange [IN] relative change to apply to current z-index of
880 * the element
881 * @return The new z-index of the element
883 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<int32_t, nsresult>
884 AddZIndexWithTransaction(nsStyledElement& aStyledElement, int32_t aChange);
887 * Join together any adjacent editable text nodes in the range.
889 MOZ_CAN_RUN_SCRIPT nsresult CollapseAdjacentTextNodes(nsRange& aRange);
891 static dom::Element* GetLinkElement(nsINode* aNode);
894 * Helper routines for font size changing.
896 enum class FontSize { incr, decr };
897 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
898 SetFontSizeOnTextNode(Text& aTextNode, uint32_t aStartOffset,
899 uint32_t aEndOffset, FontSize aIncrementOrDecrement);
901 enum class SplitAtEdges {
902 // SplitNodeDeepWithTransaction() won't split container element
903 // nodes at their edges. I.e., when split point is start or end of
904 // container, it won't be split.
905 eDoNotCreateEmptyContainer,
906 // SplitNodeDeepWithTransaction() always splits containers even
907 // if the split point is at edge of a container. E.g., if split point is
908 // start of an inline element, empty inline element is created as a new left
909 // node.
910 eAllowToCreateEmptyContainer,
914 * SplitAncestorStyledInlineElementsAtRangeEdges() splits all ancestor inline
915 * elements in the block at aRange if given style matches with some of them.
917 * @param aRange Ancestor inline elements of the start and end
918 * boundaries will be split.
919 * @param aStyle The style which you want to split.
920 * RemoveAllStyles instance is allowed to split any
921 * inline elements.
922 * @param aSplitAtEdges Whether this should split elements at start or
923 * end of inline elements or not.
925 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffResult, nsresult>
926 SplitAncestorStyledInlineElementsAtRangeEdges(const EditorDOMRange& aRange,
927 const EditorInlineStyle& aStyle,
928 SplitAtEdges aSplitAtEdges);
931 * SplitAncestorStyledInlineElementsAt() splits ancestor inline elements at
932 * aPointToSplit if specified style matches with them.
934 * @param aPointToSplit The point to split style at.
935 * @param aStyle The style which you want to split.
936 * RemoveAllStyles instance is allowed to split any
937 * inline elements.
938 * @param aSplitAtEdges Whether this should split elements at start or
939 * end of inline elements or not.
940 * @return The result of SplitNodeDeepWithTransaction()
941 * with topmost split element. If this didn't
942 * find inline elements to be split, Handled()
943 * returns false.
945 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
946 SplitAncestorStyledInlineElementsAt(const EditorDOMPoint& aPointToSplit,
947 const EditorInlineStyle& aStyle,
948 SplitAtEdges aSplitAtEdges);
950 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlinePropertyBase(
951 const EditorInlineStyle& aStyle, const nsAString* aValue, bool* aFirst,
952 bool* aAny, bool* aAll, nsAString* outValue) const;
955 * ClearStyleAt() splits parent elements to remove the specified style.
956 * If this splits some parent elements at near their start or end, such
957 * empty elements will be removed. Then, remove the specified style
958 * from the point and returns DOM point to put caret.
960 * @param aPoint The point to clear style at.
961 * @param aStyleToRemove The style which you want to clear.
962 * @param aSpecifiedStyle Whether the class and style attributes should
963 * be preserved or discarded.
964 * @return A candidate position to put caret. If there is
965 * AutoTransactionsConserveSelection instances, this stops
966 * suggesting caret point only in some cases.
968 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
969 ClearStyleAt(const EditorDOMPoint& aPoint,
970 const EditorInlineStyle& aStyleToRemove,
971 SpecifiedStyle aSpecifiedStyle);
973 MOZ_CAN_RUN_SCRIPT nsresult SetPositionToAbsolute(Element& aElement);
974 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
975 SetPositionToStatic(Element& aElement);
978 * OnModifyDocument() is called when the editor is changed. This should
979 * be called only by runnable in HTMLEditor::OnDocumentModified() to call
980 * HTMLEditor::OnModifyDocument() with AutoEditActionDataSetter instance.
982 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult OnModifyDocument();
985 * DoSplitNode() inserts aNewNode and moves all content before or after
986 * aStartOfRightNode to aNewNode.
988 * @param aStartOfRightNode The point to split. The container will keep
989 * having following or previous content of this.
990 * @param aNewNode The new node called. The previous or following
991 * content of aStartOfRightNode will be moved into
992 * this node.
994 MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult> DoSplitNode(
995 const EditorDOMPoint& aStartOfRightNode, nsIContent& aNewNode);
998 * DoJoinNodes() merges contents in aContentToRemove to aContentToKeep and
999 * remove aContentToRemove from the DOM tree. aContentToRemove and
1000 * aContentToKeep must have same parent. Additionally, if one of
1001 * aContentToRemove or aContentToKeep is a text node, the other must be a
1002 * text node.
1004 * @param aContentToKeep The node that will remain after the join.
1005 * @param aContentToRemove The node that will be joined with aContentToKeep.
1006 * There is no requirement that the two nodes be of
1007 * the same type.
1009 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1010 DoJoinNodes(nsIContent& aContentToKeep, nsIContent& aContentToRemove);
1013 * Routines for managing the preservation of selection across
1014 * various editor actions.
1016 bool ArePreservingSelection() const;
1017 void PreserveSelectionAcrossActions();
1018 MOZ_CAN_RUN_SCRIPT nsresult RestorePreservedSelection();
1019 void StopPreservingSelection();
1022 * Called when JoinNodesTransaction::DoTransaction() did its transaction.
1023 * Note that this is not called when undoing nor redoing.
1025 * @param aTransaction The transaction which did join nodes.
1026 * @param aDoJoinNodesResult Result of the doing join nodes.
1028 MOZ_CAN_RUN_SCRIPT void DidJoinNodesTransaction(
1029 const JoinNodesTransaction& aTransaction, nsresult aDoJoinNodesResult);
1031 protected: // edit sub-action handler
1033 * CanHandleHTMLEditSubAction() checks whether there is at least one
1034 * selection range or not, and whether the first range is editable.
1035 * If it's not editable, `Canceled()` of the result returns true.
1036 * If `Selection` is in odd situation, returns an error.
1038 * XXX I think that `IsSelectionEditable()` is better name, but it's already
1039 * in `EditorBase`...
1041 enum class CheckSelectionInReplacedElement { Yes, OnlyWhenNotInSameNode };
1042 Result<EditActionResult, nsresult> CanHandleHTMLEditSubAction(
1043 CheckSelectionInReplacedElement aCheckSelectionInReplacedElement =
1044 CheckSelectionInReplacedElement::Yes) const;
1047 * EnsureCaretNotAfterInvisibleBRElement() makes sure that caret is NOT after
1048 * padding `<br>` element for preventing insertion after padding `<br>`
1049 * element at empty last line.
1050 * NOTE: This method should be called only when `Selection` is collapsed
1051 * because `Selection` is a pain to work with when not collapsed.
1052 * (no good way to extend start or end of selection), so we need to
1053 * ignore those types of selections.
1055 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1056 EnsureCaretNotAfterInvisibleBRElement();
1059 * MaybeCreatePaddingBRElementForEmptyEditor() creates padding <br> element
1060 * for empty editor if there is no children.
1062 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1063 MaybeCreatePaddingBRElementForEmptyEditor();
1066 * EnsureNoPaddingBRElementForEmptyEditor() removes padding <br> element
1067 * for empty editor if there is.
1069 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1070 EnsureNoPaddingBRElementForEmptyEditor();
1073 * ReflectPaddingBRElementForEmptyEditor() scans the tree from the root
1074 * element and sets mPaddingBRElementForEmptyEditor if exists, or otherwise
1075 * nullptr. Can be used to manage undo/redo.
1077 [[nodiscard]] nsresult ReflectPaddingBRElementForEmptyEditor();
1080 * PrepareInlineStylesForCaret() consider inline styles from top level edit
1081 * sub-action and setting it to `mPendingStylesToApplyToNewContent` and clear
1082 * inline style cache if necessary.
1083 * NOTE: This method should be called only when `Selection` is collapsed.
1085 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult PrepareInlineStylesForCaret();
1087 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
1088 HandleInsertText(EditSubAction aEditSubAction,
1089 const nsAString& aInsertionString,
1090 SelectionHandling aSelectionHandling) final;
1092 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertDroppedDataTransferAsAction(
1093 AutoEditActionDataSetter& aEditActionData,
1094 dom::DataTransfer& aDataTransfer, const EditorDOMPoint& aDroppedAt,
1095 nsIPrincipal* aSourcePrincipal) final;
1098 * GetInlineStyles() retrieves the style of aElement and modifies each item of
1099 * aPendingStyleCacheArray. This might cause flushing layout at retrieving
1100 * computed values of CSS properties.
1102 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlineStyles(
1103 Element& aElement, AutoPendingStyleCacheArray& aPendingStyleCacheArray);
1106 * CacheInlineStyles() caches style of aElement into mCachedPendingStyles of
1107 * TopLevelEditSubAction. This may cause flushing layout at retrieving
1108 * computed value of CSS properties.
1110 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1111 CacheInlineStyles(Element& aElement);
1114 * ReapplyCachedStyles() restores some styles which are disappeared during
1115 * handling edit action and it should be restored. This may cause flushing
1116 * layout at retrieving computed value of CSS properties.
1118 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult ReapplyCachedStyles();
1121 * CreateStyleForInsertText() sets CSS properties which are stored in
1122 * PendingStyles to proper element node.
1124 * @param aPointToInsertText The point to insert text.
1125 * @param aEditingHost The editing host.
1126 * @return A suggest point to put caret or unset point.
1128 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1129 CreateStyleForInsertText(const EditorDOMPoint& aPointToInsertText,
1130 const Element& aEditingHost);
1133 * GetMostDistantAncestorMailCiteElement() returns most-ancestor mail cite
1134 * element. "mail cite element" is <pre> element when it's in plaintext editor
1135 * mode or an element with which calling HTMLEditUtils::IsMailCite() returns
1136 * true.
1138 * @param aNode The start node to look for parent mail cite elements.
1140 Element* GetMostDistantAncestorMailCiteElement(const nsINode& aNode) const;
1143 * HandleInsertParagraphInMailCiteElement() splits aMailCiteElement at
1144 * aPointToSplit.
1146 * @param aMailCiteElement The mail-cite element which should be split.
1147 * @param aPointToSplit The point to split.
1148 * @param aEditingHost The editing host.
1149 * @return Candidate caret position where is at inserted
1150 * <br> element into the split point.
1152 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1153 HandleInsertParagraphInMailCiteElement(Element& aMailCiteElement,
1154 const EditorDOMPoint& aPointToSplit,
1155 const Element& aEditingHost);
1158 * HandleInsertBRElement() inserts a <br> element into aPointToBreak.
1159 * This may split container elements at the point and/or may move following
1160 * <br> element to immediately after the new <br> element if necessary.
1162 * @param aPointToBreak The point where new <br> element will be
1163 * inserted before.
1164 * @param aEditingHost Current active editing host.
1165 * @return If succeeded, returns new <br> element and
1166 * candidate caret point.
1168 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1169 HandleInsertBRElement(const EditorDOMPoint& aPointToBreak,
1170 const Element& aEditingHost);
1173 * HandleInsertLinefeed() inserts a linefeed character into aInsertToBreak.
1175 * @param aInsertToBreak The point where new linefeed character will be
1176 * inserted before.
1177 * @param aEditingHost Current active editing host.
1178 * @return A suggest point to put caret.
1180 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1181 HandleInsertLinefeed(const EditorDOMPoint& aInsertToBreak,
1182 const Element& aEditingHost);
1185 * Splits inclusive inline ancestors at both start and end of aRangeItem. If
1186 * this splits at every point, this modifies aRangeItem to point each split
1187 * point (typically, at right node).
1189 * @param aRangeItem [in/out] One or two DOM points where should be
1190 * split. Will be modified to split point if
1191 * they're split.
1192 * @param aBlockInlineCheck [in] Whether this method considers block vs.
1193 * inline with computed style or the default style.
1194 * @param aEditingHost [in] The editing host.
1195 * @param aAncestorLimiter [in/optional] If specified, this stops splitting
1196 * ancestors when meets this node.
1197 * @return A suggest point to put caret if succeeded, but
1198 * it may be unset.
1200 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1201 SplitInlineAncestorsAtRangeBoundaries(
1202 RangeItem& aRangeItem, BlockInlineCheck aBlockInlineCheck,
1203 const Element& aEditingHost,
1204 const nsIContent* aAncestorLimiter = nullptr);
1207 * SplitElementsAtEveryBRElement() splits before all <br> elements in
1208 * aMostAncestorToBeSplit. All <br> nodes will be moved before right node
1209 * at splitting its parent. Finally, this returns left node, first <br>
1210 * element, next left node, second <br> element... and right-most node.
1212 * @param aMostAncestorToBeSplit Most-ancestor element which should
1213 * be split.
1214 * @param aOutArrayOfNodes First left node, first <br> element,
1215 * Second left node, second <br> element,
1216 * ...right-most node. So, all nodes
1217 * in this list should be siblings (may be
1218 * broken the relation by mutation event
1219 * listener though). If first <br> element
1220 * is first leaf node of
1221 * aMostAncestorToBeSplit, starting from
1222 * the first <br> element.
1223 * @return A suggest point to put caret if
1224 * succeeded, but it may unset.
1226 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1227 SplitElementsAtEveryBRElement(
1228 nsIContent& aMostAncestorToBeSplit,
1229 nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents);
1232 * MaybeSplitElementsAtEveryBRElement() calls SplitElementsAtEveryBRElement()
1233 * for each given node when this needs to do that for aEditSubAction.
1234 * If split a node, it in aArrayOfContents is replaced with split nodes and
1235 * <br> elements.
1237 * @return A suggest point to put caret if
1238 * succeeded, but it may unset.
1240 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1241 MaybeSplitElementsAtEveryBRElement(
1242 nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
1243 EditSubAction aEditSubAction);
1246 * CreateRangeIncludingAdjuscentWhiteSpaces() creates an nsRange instance
1247 * which may be expanded from the given range to include adjuscent
1248 * white-spaces. If this fails handling something, returns nullptr.
1250 template <typename EditorDOMRangeType>
1251 already_AddRefed<nsRange> CreateRangeIncludingAdjuscentWhiteSpaces(
1252 const EditorDOMRangeType& aRange);
1253 template <typename EditorDOMPointType1, typename EditorDOMPointType2>
1254 already_AddRefed<nsRange> CreateRangeIncludingAdjuscentWhiteSpaces(
1255 const EditorDOMPointType1& aStartPoint,
1256 const EditorDOMPointType2& aEndPoint);
1259 * GetRangeExtendedToHardLineEdgesForBlockEditAction() returns an extended
1260 * range if aRange should be extended before handling a block level editing.
1261 * If aRange start and/or end point <br> or something non-editable point, they
1262 * should be moved to nearest text node or something where the other methods
1263 * easier to handle edit action.
1265 [[nodiscard]] Result<EditorRawDOMRange, nsresult>
1266 GetRangeExtendedToHardLineEdgesForBlockEditAction(
1267 const nsRange* aRange, const Element& aEditingHost) const;
1270 * InitializeInsertingElement is a callback type of methods which inserts
1271 * an element into the DOM tree. This is called immediately before inserting
1272 * aNewElement into the DOM tree.
1274 * @param aHTMLEditor The HTML editor which modifies the DOM tree.
1275 * @param aNewElement The new element which will be or was inserted into
1276 * the DOM tree.
1277 * @param aPointToInsert The position aNewElement will be or was inserted.
1279 using InitializeInsertingElement =
1280 std::function<nsresult(HTMLEditor& aHTMLEditor, Element& aNewElement,
1281 const EditorDOMPoint& aPointToInsert)>;
1282 static InitializeInsertingElement DoNothingForNewElement;
1283 static InitializeInsertingElement InsertNewBRElement;
1286 * Helper methods to implement InitializeInsertingElement.
1288 MOZ_CAN_RUN_SCRIPT static Result<CreateElementResult, nsresult>
1289 AppendNewElementToInsertingElement(
1290 HTMLEditor& aHTMLEditor, const nsStaticAtom& aTagName,
1291 Element& aNewElement,
1292 const InitializeInsertingElement& aInitializer = DoNothingForNewElement);
1293 MOZ_CAN_RUN_SCRIPT static Result<CreateElementResult, nsresult>
1294 AppendNewElementWithBRToInsertingElement(HTMLEditor& aHTMLEditor,
1295 const nsStaticAtom& aTagName,
1296 Element& aNewElement);
1299 * Create an element node whose name is aTag at before aPointToInsert. When
1300 * this succeed to create an element node, this inserts the element to
1301 * aPointToInsert.
1303 * @param aWithTransaction Whether the inserting is new element is undoable
1304 * or not. WithTransaction::No is useful only when
1305 * the new element is inserted into a new element
1306 * which has not been connected yet.
1307 * @param aTagName The element name to create.
1308 * @param aPointToInsert The insertion point of new element.
1309 * If this refers end of the container or after,
1310 * the transaction will append the element to the
1311 * container.
1312 * Otherwise, will insert the element before the
1313 * child node referred by this.
1314 * Note that this point will be invalid once this
1315 * method inserts the new element.
1316 * @param aInitializer A function to initialize the new element before
1317 * connecting the element into the DOM tree. Note
1318 * that this should not touch outside given element
1319 * because doing it would break range updater's
1320 * result.
1321 * @return The created new element node and candidate caret
1322 * position.
1324 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1325 CreateAndInsertElement(
1326 WithTransaction aWithTransaction, const nsAtom& aTagName,
1327 const EditorDOMPoint& aPointToInsert,
1328 const InitializeInsertingElement& aInitializer = DoNothingForNewElement);
1331 * Callback of CopyAttributes().
1333 * @param aHTMLEditor The HTML editor.
1334 * @param aSrcElement The element which have the attribute.
1335 * @param aDestElement The element which will have the attribute.
1336 * @param aAttr [in] The attribute which will be copied.
1337 * @param aValue [in/out] The attribute value which will be copied.
1338 * Once updated, the new value is used.
1339 * @return true if the attribute should be copied, otherwise,
1340 * false.
1342 using AttributeFilter = std::function<bool(
1343 HTMLEditor& aHTMLEditor, Element& aSrcElement, Element& aDestElement,
1344 const dom::Attr& aAttr, nsString& aValue)>;
1345 static AttributeFilter CopyAllAttributes;
1346 static AttributeFilter CopyAllAttributesExceptId;
1347 static AttributeFilter CopyAllAttributesExceptDir;
1348 static AttributeFilter CopyAllAttributesExceptIdAndDir;
1351 * Copy all attributes of aSrcElement to aDestElement as-is. Different from
1352 * EditorBase::CloneAttributesWithTransaction(), this does not use
1353 * SetAttributeOrEquivalent() nor does not clear existing attributes of
1354 * aDestElement.
1356 * @param aWithTransaction Whether recoding with transactions or not.
1357 * @param aDestElement The element will have attributes.
1358 * @param aSrcElement The element whose attributes will be copied.
1360 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult CopyAttributes(
1361 WithTransaction aWithTransaction, Element& aDestElement,
1362 Element& aSrcElement, const AttributeFilter& = CopyAllAttributes);
1365 * MaybeSplitAncestorsForInsertWithTransaction() does nothing if container of
1366 * aStartOfDeepestRightNode can have an element whose tag name is aTag.
1367 * Otherwise, looks for an ancestor node which is or is in active editing
1368 * host and can have an element whose name is aTag. If there is such
1369 * ancestor, its descendants are split.
1371 * Note that this may create empty elements while splitting ancestors.
1373 * @param aTag The name of element to be inserted
1374 * after calling this method.
1375 * @param aStartOfDeepestRightNode The start point of deepest right node.
1376 * This point must be in aEditingHost.
1377 * @param aEditingHost The editing host.
1378 * @return When succeeded, SplitPoint() returns
1379 * the point to insert the element.
1381 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
1382 MaybeSplitAncestorsForInsertWithTransaction(
1383 const nsAtom& aTag, const EditorDOMPoint& aStartOfDeepestRightNode,
1384 const Element& aEditingHost);
1387 * InsertElementWithSplittingAncestorsWithTransaction() is a wrapper of
1388 * MaybeSplitAncestorsForInsertWithTransaction() and CreateAndInsertElement().
1389 * I.e., will create an element whose tag name is aTagName and split ancestors
1390 * if it's necessary, then, insert it.
1392 * @param aTagName The tag name which you want to insert new
1393 * element at aPointToInsert.
1394 * @param aPointToInsert The insertion point. New element will be
1395 * inserted before here.
1396 * @param aBRElementNextToSplitPoint
1397 * Whether <br> element should be deleted or
1398 * kept if and only if a <br> element follows
1399 * split point.
1400 * @param aEditingHost The editing host with which we're handling it.
1401 * @param aInitializer A function to initialize the new element before
1402 * connecting the element into the DOM tree. Note
1403 * that this should not touch outside given element
1404 * because doing it would break range updater's
1405 * result.
1406 * @return If succeeded, returns the new element node and
1407 * suggesting point to put caret.
1409 enum class BRElementNextToSplitPoint { Keep, Delete };
1410 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1411 InsertElementWithSplittingAncestorsWithTransaction(
1412 const nsAtom& aTagName, const EditorDOMPoint& aPointToInsert,
1413 BRElementNextToSplitPoint aBRElementNextToSplitPoint,
1414 const Element& aEditingHost,
1415 const InitializeInsertingElement& aInitializer = DoNothingForNewElement);
1418 * Split aElementToSplit at two points, before aStartOfMiddleElement and after
1419 * aEndOfMiddleElement. If they are very start or very end of aBlockElement,
1420 * this won't create empty block.
1422 * @param aElementToSplit An element which will be split.
1423 * @param aStartOfMiddleElement Start node of middle block element.
1424 * @param aEndOfMiddleElement End node of middle block element.
1426 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffFromNodeResult, nsresult>
1427 SplitRangeOffFromElement(Element& aElementToSplit,
1428 nsIContent& aStartOfMiddleElement,
1429 nsIContent& aEndOfMiddleElement);
1432 * RemoveBlockContainerElementWithTransactionBetween() splits the nodes
1433 * at aStartOfRange and aEndOfRange, then, removes the middle element which
1434 * was split off from aBlockContainerElement and moves the ex-children to
1435 * where the middle element was. I.e., all nodes between aStartOfRange and
1436 * aEndOfRange (including themselves) will be unwrapped from
1437 * aBlockContainerElement.
1439 * @param aBlockContainerElement The node which will be split.
1440 * @param aStartOfRange The first node which will be unwrapped
1441 * from aBlockContainerElement.
1442 * @param aEndOfRange The last node which will be unwrapped from
1443 * aBlockContainerElement.
1444 * @param aBlockInlineCheck Whether this method considers block vs.
1445 * inline with computed style or the default
1446 * style.
1447 * @return The left content is new created left
1448 * element of aBlockContainerElement.
1449 * The right content is split element,
1450 * i.e., must be aBlockContainerElement.
1451 * The middle content is nullptr since
1452 * removing it is the job of this method.
1454 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffFromNodeResult, nsresult>
1455 RemoveBlockContainerElementWithTransactionBetween(
1456 Element& aBlockContainerElement, nsIContent& aStartOfRange,
1457 nsIContent& aEndOfRange, BlockInlineCheck aBlockInlineCheck);
1460 * WrapContentsInBlockquoteElementsWithTransaction() inserts at least one
1461 * <blockquote> element and moves nodes in aArrayOfContents into new
1462 * <blockquote> elements. If aArrayOfContents includes a table related element
1463 * except <table>, this calls itself recursively to insert <blockquote> into
1464 * the cell.
1466 * @param aArrayOfContents Nodes which will be moved into created
1467 * <blockquote> elements.
1468 * @param aEditingHost The editing host.
1469 * @return A blockquote element which is created at last
1470 * and a suggest of caret position if succeeded.
1471 * The caret suggestion may be unset if there is
1472 * no suggestion.
1474 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1475 WrapContentsInBlockquoteElementsWithTransaction(
1476 const nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
1477 const Element& aEditingHost);
1480 * Our traditional formatBlock was same as XUL cmd_paragraphState command.
1481 * However, the behavior is pretty different from the others and aligning
1482 * the XUL command behavior may break Thunderbird a lot because it handles
1483 * <blockquote> in a special path and <div> (generic block element) is not
1484 * treated as a format node and these things may be used for designing
1485 * current roles of the elements in the email composer of Thunderbird.
1486 * Therefore, we create a new mode for HTMLFormatBlockCommand to align
1487 * the behavior to the others but does not harm Thunderbird.
1489 enum class FormatBlockMode {
1490 // Document.execCommand("formatBlock"). Cannot set new format to "normal"
1491 // nor "". So, the paths to handle these ones are not used in this mode.
1492 HTMLFormatBlockCommand,
1493 // cmd_paragraphState. Can set new format to "normal" or "" to remove
1494 // ancestor format blocks.
1495 XULParagraphStateCommand,
1499 * RemoveBlockContainerElementsWithTransaction() removes all format blocks,
1500 * table related element, etc in aArrayOfContents from the DOM tree. If
1501 * aArrayOfContents has a format node, it will be removed and its contents
1502 * will be moved to where it was.
1503 * If aArrayOfContents has a table related element, <li>, <blockquote> or
1504 * <div>, it will be removed and its contents will be moved to where it was.
1506 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
1507 * paragraphState command.
1509 * @return A suggest point to put caret if succeeded, but it may be
1510 * unset if there is no suggestion.
1512 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1513 RemoveBlockContainerElementsWithTransaction(
1514 const nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
1515 FormatBlockMode aFormatBlockMode, BlockInlineCheck aBlockInlineCheck);
1518 * CreateOrChangeFormatContainerElement() formats all nodes in
1519 * aArrayOfContents with block elements whose name is aNewFormatTagName.
1521 * If aArrayOfContents has an inline element, a block element is created and
1522 * the inline element and following inline elements are moved into the new
1523 * block element.
1524 * If aArrayOfContents has <br> elements, they'll be removed from the DOM tree
1525 * and new block element will be created when there are some remaining inline
1526 * elements.
1527 * If aArrayOfContents has a block element, this calls itself with children of
1528 * the block element. Then, new block element will be created when there are
1529 * some remaining inline elements.
1531 * @param aArrayOfContents Must be descendants of a node.
1532 * @param aNewFormatTagName The element name of new block elements.
1533 * @param aFormatBlockMode The replacing block element target type is for
1534 * whether HTML formatBLock command or XUL
1535 * paragraphState command.
1536 * @param aEditingHost The editing host.
1537 * @return The latest created new block element and a
1538 * suggest point to put caret.
1540 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1541 CreateOrChangeFormatContainerElement(
1542 nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
1543 const nsStaticAtom& aNewFormatTagName, FormatBlockMode aFormatBlockMode,
1544 const Element& aEditingHost);
1547 * FormatBlockContainerWithTransaction() is implementation of "formatBlock"
1548 * command of `Document.execCommand()`. This applies block style or removes
1549 * it.
1551 * @param aSelectionRanges The ranges which are cloned by selection or
1552 * updated from it with doing something before
1553 * calling this.
1554 * @param aNewFormatTagName New block tag name.
1555 * If nsGkAtoms::normal or nsGkAtoms::_empty,
1556 * RemoveBlockContainerElementsWithTransaction()
1557 * will be called.
1558 * If nsGkAtoms::blockquote,
1559 * WrapContentsInBlockquoteElementsWithTransaction()
1560 * will be called.
1561 * Otherwise, CreateOrChangeBlockContainerElement()
1562 * will be called.
1563 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
1564 * paragraphState command.
1565 * @param aEditingHost The editing host.
1566 * @return If selection should be finally collapsed in a
1567 * created block element, this returns the element.
1569 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<RefPtr<Element>, nsresult>
1570 FormatBlockContainerWithTransaction(AutoRangeArray& aSelectionRanges,
1571 const nsStaticAtom& aNewFormatTagName,
1572 FormatBlockMode aFormatBlockMode,
1573 const Element& aEditingHost);
1576 * Determine if aPointToInsert is start of a hard line and end of the line
1577 * (i.e, in an empty line) and the line ends with block boundary, inserts a
1578 * `<br>` element.
1580 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
1581 InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary(
1582 const EditorDOMPoint& aPointToInsert);
1585 * Insert padding `<br>` element for empty last line into aElement if
1586 * aElement is a block element and empty.
1588 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1589 InsertPaddingBRElementForEmptyLastLineIfNeeded(Element& aElement);
1592 * This method inserts a padding `<br>` element for empty last line if
1593 * selection is collapsed and container of the range needs it.
1595 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1596 MaybeInsertPaddingBRElementForEmptyLastLineAtSelection();
1599 * SplitParagraphWithTransaction() splits the parent block, aParentDivOrP, at
1600 * aStartOfRightNode.
1602 * @param aParentDivOrP The parent block to be split. This must be <p>
1603 * or <div> element.
1604 * @param aStartOfRightNode The point to be start of right node after
1605 * split. This must be descendant of
1606 * aParentDivOrP.
1607 * @param aMayBecomeVisibleBRElement
1608 * Next <br> element of the split point if there
1609 * is. Otherwise, nullptr. If this is not nullptr,
1610 * the <br> element may be removed if it becomes
1611 * visible.
1613 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
1614 SplitParagraphWithTransaction(Element& aParentDivOrP,
1615 const EditorDOMPoint& aStartOfRightNode,
1616 dom::HTMLBRElement* aMayBecomeVisibleBRElement);
1619 * HandleInsertParagraphInParagraph() does the right thing for Enter key
1620 * press or 'insertParagraph' command in aParentDivOrP. aParentDivOrP will
1621 * be split **around** aCandidatePointToSplit. If this thinks that it should
1622 * be handled to insert a <br> instead, this returns "not handled".
1624 * @param aParentDivOrP The parent block. This must be <p> or <div>
1625 * element.
1626 * @param aCandidatePointToSplit
1627 * The point where the caller want to split
1628 * aParentDivOrP. However, in some cases, this is not
1629 * used as-is. E.g., this method avoids to create new
1630 * empty <a href> in the right paragraph. So this may
1631 * be adjusted to proper position around it.
1632 * @param aEditingHost The editing host.
1633 * @return If the caller should default to inserting <br>
1634 * element, returns "not handled".
1636 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
1637 HandleInsertParagraphInParagraph(Element& aParentDivOrP,
1638 const EditorDOMPoint& aCandidatePointToSplit,
1639 const Element& aEditingHost);
1642 * HandleInsertParagraphInHeadingElement() handles insertParagraph command
1643 * (i.e., handling Enter key press) in a heading element. This splits
1644 * aHeadingElement element at aPointToSplit. Then, if right heading element
1645 * is empty, it'll be removed and new paragraph is created (its type is
1646 * decided with default paragraph separator).
1648 * @param aHeadingElement The heading element to be split.
1649 * @param aPointToSplit The point to split aHeadingElement.
1650 * @return New paragraph element, meaning right heading
1651 * element if aHeadingElement is split, or newly
1652 * created or existing paragraph element.
1654 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<InsertParagraphResult, nsresult>
1655 HandleInsertParagraphInHeadingElement(Element& aHeadingElement,
1656 const EditorDOMPoint& aPointToSplit);
1659 * HandleInsertParagraphInListItemElement() handles insertParagraph command
1660 * (i.e., handling Enter key press) in a list item element.
1662 * @param aListItemElement The list item which has the following point.
1663 * @param aPointToSplit The point to split aListItemElement.
1664 * @param aEditingHost The editing host.
1665 * @return New paragraph element, meaning right list item
1666 * element if aListItemElement is split, or newly
1667 * created paragraph element.
1669 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<InsertParagraphResult, nsresult>
1670 HandleInsertParagraphInListItemElement(Element& aListItemElement,
1671 const EditorDOMPoint& aPointToSplit,
1672 const Element& aEditingHost);
1675 * InsertParagraphSeparatorAsSubAction() handles insertPargraph commad
1676 * (i.e., handling Enter key press) with the above helper methods.
1678 * @param aEditingHost The editing host.
1680 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
1681 InsertParagraphSeparatorAsSubAction(const Element& aEditingHost);
1684 * InsertLineBreakAsSubAction() inserts a new <br> element or a linefeed
1685 * character at selection. If there is non-collapsed selection ranges, the
1686 * selected ranges is deleted first.
1688 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertLineBreakAsSubAction();
1691 * ChangeListElementType() replaces child list items of aListElement with
1692 * new list item element whose tag name is aNewListItemTag.
1693 * Note that if there are other list elements as children of aListElement,
1694 * this calls itself recursively even though it's invalid structure.
1696 * @param aListElement The list element whose list items will be
1697 * replaced.
1698 * @param aNewListTag New list tag name.
1699 * @param aNewListItemTag New list item tag name.
1700 * @return New list element or an error code if it fails.
1701 * New list element may be aListElement if its
1702 * tag name is same as aNewListTag.
1704 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1705 ChangeListElementType(Element& aListElement, nsAtom& aListType,
1706 nsAtom& aItemType);
1708 class AutoListElementCreator;
1710 [[nodiscard]] static bool IsFormatElement(FormatBlockMode aFormatBlockMode,
1711 const nsIContent& aContent);
1714 * MakeOrChangeListAndListItemAsSubAction() handles create list commands with
1715 * current selection. If
1717 * @param aListElementOrListItemElementTagName
1718 * The new list element tag name or
1719 * new list item tag name.
1720 * If the former, list item tag name will
1721 * be computed automatically. Otherwise,
1722 * list tag name will be computed.
1723 * @param aBulletType If this is not empty string, it's set
1724 * to `type` attribute of new list item
1725 * elements. Otherwise, existing `type`
1726 * attributes will be removed.
1727 * @param aSelectAllOfCurrentList Yes if this should treat all of
1728 * ancestor list element at selection.
1730 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
1731 MakeOrChangeListAndListItemAsSubAction(
1732 const nsStaticAtom& aListElementOrListItemElementTagName,
1733 const nsAString& aBulletType,
1734 SelectAllOfCurrentList aSelectAllOfCurrentList);
1737 * DeleteTextAndTextNodesWithTransaction() removes text or text nodes in
1738 * the given range.
1740 enum class TreatEmptyTextNodes {
1741 // KeepIfContainerOfRangeBoundaries:
1742 // Will remove empty text nodes middle of the range, but keep empty
1743 // text nodes which are containers of range boundaries.
1744 KeepIfContainerOfRangeBoundaries,
1745 // Remove:
1746 // Will remove all empty text nodes.
1747 Remove,
1748 // RemoveAllEmptyInlineAncestors:
1749 // Will remove all empty text nodes and its inline ancestors which
1750 // become empty due to removing empty text nodes.
1751 RemoveAllEmptyInlineAncestors,
1753 template <typename EditorDOMPointType>
1754 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
1755 DeleteTextAndTextNodesWithTransaction(
1756 const EditorDOMPointType& aStartPoint,
1757 const EditorDOMPointType& aEndPoint,
1758 TreatEmptyTextNodes aTreatEmptyTextNodes);
1761 * JoinNodesWithTransaction() joins aLeftContent and aRightContent. Content
1762 * of aLeftContent will be merged into aRightContent. Actual implemenation of
1763 * this method is JoinNodesImpl(). So, see its explanation for the detail.
1765 * @param aLeftContent Will be removed from the DOM tree.
1766 * @param aRightContent The node which will be new container of the content
1767 * of aLeftContent.
1769 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<JoinNodesResult, nsresult>
1770 JoinNodesWithTransaction(nsIContent& aLeftContent, nsIContent& aRightContent);
1773 * JoinNearestEditableNodesWithTransaction() joins two editable nodes which
1774 * are themselves or the nearest editable node of aLeftNode and aRightNode.
1775 * XXX This method's behavior is odd. For example, if user types Backspace
1776 * key at the second editable paragraph in this case:
1777 * <div contenteditable>
1778 * <p>first editable paragraph</p>
1779 * <p contenteditable="false">non-editable paragraph</p>
1780 * <p>second editable paragraph</p>
1781 * </div>
1782 * The first editable paragraph's content will be moved into the second
1783 * editable paragraph and the non-editable paragraph becomes the first
1784 * paragraph of the editor. I don't think that it's expected behavior of
1785 * any users...
1787 * @param aLeftNode The node which will be removed.
1788 * @param aRightNode The node which will be inserted the content of
1789 * aLeftNode.
1790 * @param aNewFirstChildOfRightNode
1791 * [out] The point at the first child of aRightNode.
1793 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1794 JoinNearestEditableNodesWithTransaction(
1795 nsIContent& aLeftNode, nsIContent& aRightNode,
1796 EditorDOMPoint* aNewFirstChildOfRightNode);
1799 * ReplaceContainerAndCloneAttributesWithTransaction() creates new element
1800 * whose name is aTagName, copies all attributes from aOldContainer to the
1801 * new element, moves all children in aOldContainer to the new element, then,
1802 * removes aOldContainer from the DOM tree.
1804 * @param aOldContainer The element node which should be replaced
1805 * with new element.
1806 * @param aTagName The name of new element node.
1808 [[nodiscard]] inline MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1809 ReplaceContainerAndCloneAttributesWithTransaction(Element& aOldContainer,
1810 const nsAtom& aTagName);
1813 * ReplaceContainerWithTransaction() creates new element whose name is
1814 * aTagName, sets aAttributes of the new element to aAttributeValue, moves
1815 * all children in aOldContainer to the new element, then, removes
1816 * aOldContainer from the DOM tree.
1818 * @param aOldContainer The element node which should be replaced
1819 * with new element.
1820 * @param aTagName The name of new element node.
1821 * @param aAttribute Attribute name to be set to the new element.
1822 * @param aAttributeValue Attribute value to be set to aAttribute.
1824 [[nodiscard]] inline MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1825 ReplaceContainerWithTransaction(Element& aOldContainer,
1826 const nsAtom& aTagName,
1827 const nsAtom& aAttribute,
1828 const nsAString& aAttributeValue);
1831 * ReplaceContainerWithTransaction() creates new element whose name is
1832 * aTagName, moves all children in aOldContainer to the new element, then,
1833 * removes aOldContainer from the DOM tree.
1835 * @param aOldContainer The element node which should be replaced
1836 * with new element.
1837 * @param aTagName The name of new element node.
1839 [[nodiscard]] inline MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1840 ReplaceContainerWithTransaction(Element& aOldContainer,
1841 const nsAtom& aTagName);
1844 * RemoveContainerWithTransaction() removes aElement from the DOM tree and
1845 * moves all its children to the parent of aElement.
1847 * @param aElement The element to be removed.
1848 * @return A suggestion point to put caret.
1850 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1851 RemoveContainerWithTransaction(Element& aElement);
1854 * InsertContainerWithTransaction() creates new element whose name is
1855 * aWrapperTagName, moves aContentToBeWrapped into the new element, then,
1856 * inserts the new element into where aContentToBeWrapped was.
1857 * NOTE: This method does not check if aContentToBeWrapped is valid child
1858 * of the new element. So, callers need to guarantee it.
1860 * @param aContentToBeWrapped The content which will be wrapped with new
1861 * element.
1862 * @param aWrapperTagName Element name of new element which will wrap
1863 * aContent and be inserted into where aContent
1864 * was.
1865 * @param aInitializer A callback to initialize new element before
1866 * inserting to the DOM tree.
1868 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1869 InsertContainerWithTransaction(
1870 nsIContent& aContentToBeWrapped, const nsAtom& aWrapperTagName,
1871 const InitializeInsertingElement& aInitializer = DoNothingForNewElement);
1874 * MoveNodeWithTransaction() moves aContentToMove to aPointToInsert.
1876 * @param aContentToMove The node to be moved.
1877 * @param aPointToInsert The point where aContentToMove will be inserted.
1879 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<MoveNodeResult, nsresult>
1880 MoveNodeWithTransaction(nsIContent& aContentToMove,
1881 const EditorDOMPoint& aPointToInsert);
1884 * MoveNodeToEndWithTransaction() moves aContentToMove to end of
1885 * aNewContainer.
1887 * @param aContentToMove The node to be moved.
1888 * @param aNewContainer The new container which will contain aContentToMove
1889 * as its last child.
1891 [[nodiscard]] inline MOZ_CAN_RUN_SCRIPT Result<MoveNodeResult, nsresult>
1892 MoveNodeToEndWithTransaction(nsIContent& aContentToMove,
1893 nsINode& aNewContainer);
1896 * MoveNodeOrChildrenWithTransaction() moves aContent to aPointToInsert. If
1897 * cannot insert aContent due to invalid relation, moves only its children
1898 * recursively and removes aContent from the DOM tree.
1900 * @param aContent Content which should be moved.
1901 * @param aPointToInsert The point to be inserted aContent or its
1902 * descendants.
1903 * @param aPreserveWhiteSpaceStyle
1904 * If yes and if it's possible to keep white-space
1905 * style, this method will set `style` attribute to
1906 * moving node or creating new <span> element.
1907 * @param aRemoveIfCommentNode
1908 * If yes, this removes a comment node instead of
1909 * moving it to the destination. Note that this
1910 * does not remove comment nodes in moving nodes
1911 * because it requires additional scan.
1913 enum class PreserveWhiteSpaceStyle { No, Yes };
1914 friend std::ostream& operator<<(
1915 std::ostream& aStream,
1916 const PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle);
1917 enum class RemoveIfCommentNode { No, Yes };
1918 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<MoveNodeResult, nsresult>
1919 MoveNodeOrChildrenWithTransaction(
1920 nsIContent& aContentToMove, const EditorDOMPoint& aPointToInsert,
1921 PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle,
1922 RemoveIfCommentNode aRemoveIfCommentNode);
1925 * CanMoveNodeOrChildren() returns true if
1926 * `MoveNodeOrChildrenWithTransaction()` can move or delete at least a
1927 * descendant of aElement into aNewContainer. I.e., when this returns true,
1928 * `MoveNodeOrChildrenWithTransaction()` must return "handled".
1930 Result<bool, nsresult> CanMoveNodeOrChildren(
1931 const nsIContent& aContent, const nsINode& aNewContainer) const;
1934 * MoveChildrenWithTransaction() moves the children of aElement to
1935 * aPointToInsert. If cannot insert some children due to invalid relation,
1936 * calls MoveNodeOrChildrenWithTransaction() to remove the children but keep
1937 * moving its children.
1939 * @param aElement Container element whose children should be
1940 * moved.
1941 * @param aPointToInsert The point to be inserted children of aElement
1942 * or its descendants.
1943 * @param aPreserveWhiteSpaceStyle
1944 * If yes and if it's possible to keep white-space
1945 * style, this method will set `style` attribute to
1946 * moving node or creating new <span> element.
1947 * @param aRemoveIfCommentNode
1948 * If yes, this removes a comment node instead of
1949 * moving it to the destination. Note that this
1950 * does not remove comment nodes in moving nodes
1951 * because it requires additional scan.
1953 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<MoveNodeResult, nsresult>
1954 MoveChildrenWithTransaction(Element& aElement,
1955 const EditorDOMPoint& aPointToInsert,
1956 PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle,
1957 RemoveIfCommentNode aRemoveIfCommentNode);
1960 * CanMoveChildren() returns true if `MoveChildrenWithTransaction()` can move
1961 * at least a descendant of aElement into aNewContainer. I.e., when this
1962 * returns true, `MoveChildrenWithTransaction()` return "handled".
1964 Result<bool, nsresult> CanMoveChildren(const Element& aElement,
1965 const nsINode& aNewContainer) const;
1968 * MoveAllChildren() moves all children of aContainer to before
1969 * aPointToInsert.GetChild().
1970 * See explanation of MoveChildrenBetween() for the detail of the behavior.
1972 * @param aContainer The container node whose all children should
1973 * be moved.
1974 * @param aPointToInsert The insertion point. The container must not
1975 * be a data node like a text node.
1977 [[nodiscard]] nsresult MoveAllChildren(
1978 nsINode& aContainer, const EditorRawDOMPoint& aPointToInsert);
1981 * MoveChildrenBetween() moves all children between aFirstChild and aLastChild
1982 * to before aPointToInsert.GetChild(). If some children are moved to
1983 * different container while this method moves other children, they are just
1984 * ignored. If the child node referred by aPointToInsert is moved to different
1985 * container while this method moves children, returns error.
1987 * @param aFirstChild The first child which should be moved to
1988 * aPointToInsert.
1989 * @param aLastChild The last child which should be moved. This
1990 * must be a sibling of aFirstChild and it should
1991 * be positioned after aFirstChild in the DOM tree
1992 * order.
1993 * @param aPointToInsert The insertion point. The container must not
1994 * be a data node like a text node.
1996 [[nodiscard]] nsresult MoveChildrenBetween(
1997 nsIContent& aFirstChild, nsIContent& aLastChild,
1998 const EditorRawDOMPoint& aPointToInsert);
2001 * MovePreviousSiblings() moves all siblings before aChild (i.e., aChild
2002 * won't be moved) to before aPointToInsert.GetChild().
2003 * See explanation of MoveChildrenBetween() for the detail of the behavior.
2005 * @param aChild The node which is next sibling of the last
2006 * node to be moved.
2007 * @param aPointToInsert The insertion point. The container must not
2008 * be a data node like a text node.
2010 [[nodiscard]] nsresult MovePreviousSiblings(
2011 nsIContent& aChild, const EditorRawDOMPoint& aPointToInsert);
2014 * MoveInclusiveNextSiblings() moves aChild and all siblings after it to
2015 * before aPointToInsert.GetChild().
2016 * See explanation of MoveChildrenBetween() for the detail of the behavior.
2018 * @param aChild The node which is first node to be moved.
2019 * @param aPointToInsert The insertion point. The container must not
2020 * be a data node like a text node.
2022 [[nodiscard]] nsresult MoveInclusiveNextSiblings(
2023 nsIContent& aChild, const EditorRawDOMPoint& aPointToInsert);
2026 * SplitNodeWithTransaction() creates a transaction to create a new node
2027 * (left node) identical to an existing node (right node), and split the
2028 * contents between the same point in both nodes, then, execute the
2029 * transaction.
2031 * @param aStartOfRightNode The point to split. Its container will be
2032 * the right node, i.e., become the new node's
2033 * next sibling. And the point will be start
2034 * of the right node.
2036 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
2037 SplitNodeWithTransaction(const EditorDOMPoint& aStartOfRightNode);
2040 * SplitNodeDeepWithTransaction() splits aMostAncestorToSplit deeply.
2042 * @param aMostAncestorToSplit The most ancestor node which should be
2043 * split.
2044 * @param aStartOfDeepestRightNode The start point of deepest right node.
2045 * This point must be descendant of
2046 * aMostAncestorToSplit.
2047 * @param aSplitAtEdges Whether the caller allows this to
2048 * create empty container element when
2049 * split point is start or end of an
2050 * element.
2051 * @return SplitPoint() returns split point in
2052 * aMostAncestorToSplit. The point must
2053 * be good to insert something if the
2054 * caller want to do it.
2056 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
2057 SplitNodeDeepWithTransaction(nsIContent& aMostAncestorToSplit,
2058 const EditorDOMPoint& aDeepestStartOfRightNode,
2059 SplitAtEdges aSplitAtEdges);
2062 * RemoveEmptyInclusiveAncestorInlineElements() removes empty inclusive
2063 * ancestor inline elements in inclusive ancestor block element of aContent.
2065 * @param aContent Must be an empty content.
2067 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2068 RemoveEmptyInclusiveAncestorInlineElements(nsIContent& aContent);
2071 * DeleteTextAndNormalizeSurroundingWhiteSpaces() deletes text between
2072 * aStartToDelete and immediately before aEndToDelete and return new caret
2073 * position. If surrounding characters are white-spaces, this normalize them
2074 * too. Finally, inserts `<br>` element if it's required.
2075 * Note that if you wants only normalizing white-spaces, you can set same
2076 * point to both aStartToDelete and aEndToDelete. Then, this tries to
2077 * normalize white-space sequence containing previous character of
2078 * aStartToDelete.
2080 enum class DeleteDirection {
2081 Forward,
2082 Backward,
2084 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
2085 DeleteTextAndNormalizeSurroundingWhiteSpaces(
2086 const EditorDOMPointInText& aStartToDelete,
2087 const EditorDOMPointInText& aEndToDelete,
2088 TreatEmptyTextNodes aTreatEmptyTextNodes,
2089 DeleteDirection aDeleteDirection);
2092 * ExtendRangeToDeleteWithNormalizingWhiteSpaces() is a helper method of
2093 * DeleteTextAndNormalizeSurroundingWhiteSpaces(). This expands
2094 * aStartToDelete and/or aEndToDelete if there are white-spaces which need
2095 * normalizing.
2097 * @param aStartToDelete [In/Out] Start to delete. If this point
2098 * follows white-spaces, this may be modified.
2099 * @param aEndToDelete [In/Out] Next point of last content to be
2100 * deleted. If this point is a white-space,
2101 * this may be modified.
2102 * @param aNormalizedWhiteSpacesInStartNode
2103 * [Out] If container text node of aStartToDelete
2104 * should be modified, this offers new string
2105 * in the range in the text node.
2106 * @param aNormalizedWhiteSpacesInEndNode
2107 * [Out] If container text node of aEndToDelete
2108 * is different from the container of
2109 * aStartToDelete and it should be modified, this
2110 * offers new string in the range in the text node.
2112 void ExtendRangeToDeleteWithNormalizingWhiteSpaces(
2113 EditorDOMPointInText& aStartToDelete, EditorDOMPointInText& aEndToDelete,
2114 nsAString& aNormalizedWhiteSpacesInStartNode,
2115 nsAString& aNormalizedWhiteSpacesInEndNode) const;
2118 * CharPointType let the following helper methods of
2119 * ExtendRangeToDeleteWithNormalizingWhiteSpaces() know what type of
2120 * character will be previous or next char point after deletion.
2122 enum class CharPointType {
2123 TextEnd, // Start or end of the text (hardline break or replaced inline
2124 // element)
2125 ASCIIWhiteSpace, // One of ASCII white-spaces (collapsible white-space)
2126 NoBreakingSpace, // NBSP
2127 VisibleChar, // Non-white-space characters
2128 PreformattedChar, // Any character except a linefeed in a preformatted
2129 // node.
2130 PreformattedLineBreak, // Preformatted linebreak
2134 * GetPreviousCharPointType() and GetCharPointType() get type of
2135 * previous/current char point from current DOM tree. In other words, if the
2136 * point will be deleted, you cannot use these methods.
2138 template <typename EditorDOMPointType>
2139 static CharPointType GetPreviousCharPointType(
2140 const EditorDOMPointType& aPoint);
2141 template <typename EditorDOMPointType>
2142 static CharPointType GetCharPointType(const EditorDOMPointType& aPoint);
2145 * CharPointData let the following helper methods of
2146 * ExtendRangeToDeleteWithNormalizingWhiteSpaces() know what type of
2147 * character will be previous or next char point and the point is
2148 * in same or different text node after deletion.
2150 class MOZ_STACK_CLASS CharPointData final {
2151 public:
2152 static CharPointData InDifferentTextNode(CharPointType aCharPointType) {
2153 CharPointData result;
2154 result.mIsInDifferentTextNode = true;
2155 result.mType = aCharPointType;
2156 return result;
2158 static CharPointData InSameTextNode(CharPointType aCharPointType) {
2159 CharPointData result;
2160 // Let's mark this as in different text node if given one indicates
2161 // that there is end of text because it means that adjacent content
2162 // from point of text node view is another element.
2163 result.mIsInDifferentTextNode = aCharPointType == CharPointType::TextEnd;
2164 result.mType = aCharPointType;
2165 return result;
2168 bool AcrossTextNodeBoundary() const { return mIsInDifferentTextNode; }
2169 bool IsCollapsibleWhiteSpace() const {
2170 return mType == CharPointType::ASCIIWhiteSpace ||
2171 mType == CharPointType::NoBreakingSpace;
2173 CharPointType Type() const { return mType; }
2175 private:
2176 CharPointData() = default;
2178 CharPointType mType;
2179 bool mIsInDifferentTextNode;
2183 * GetPreviousCharPointDataForNormalizingWhiteSpaces() and
2184 * GetInclusiveNextCharPointDataForNormalizingWhiteSpaces() is helper methods
2185 * of ExtendRangeToDeleteWithNormalizingWhiteSpaces(). This retrieves
2186 * previous or inclusive next editable char point and returns its data.
2188 CharPointData GetPreviousCharPointDataForNormalizingWhiteSpaces(
2189 const EditorDOMPointInText& aPoint) const;
2190 CharPointData GetInclusiveNextCharPointDataForNormalizingWhiteSpaces(
2191 const EditorDOMPointInText& aPoint) const;
2194 * GenerateWhiteSpaceSequence() generates white-space sequence which won't
2195 * be collapsed.
2197 * @param aResult [out] White space sequence which won't be
2198 * collapsed, but wrapable.
2199 * @param aLength Length of generating white-space sequence.
2200 * Must be 1 or larger.
2201 * @param aPreviousCharPointData
2202 * Specify the previous char point where it'll be
2203 * inserted. Currently, for keepin this method
2204 * simple, does not support to generate a part
2205 * of white-space sequence in a text node. So,
2206 * if the type is white-space, it must indicate
2207 * different text nodes white-space.
2208 * @param aNextCharPointData Specify the next char point where it'll be
2209 * inserted. Same as aPreviousCharPointData,
2210 * this must node indidate white-space in same
2211 * text node.
2213 static void GenerateWhiteSpaceSequence(
2214 nsAString& aResult, uint32_t aLength,
2215 const CharPointData& aPreviousCharPointData,
2216 const CharPointData& aNextCharPointData);
2219 * ComputeTargetRanges() computes actual delete ranges which will be deleted
2220 * unless the following `beforeinput` event is canceled.
2222 * @param aDirectionAndAmount The direction and amount of deletion.
2223 * @param aRangesToDelete [In/Out] The ranges to be deleted,
2224 * typically, initialized with the
2225 * selection ranges. This may be modified
2226 * if selection ranges should be extened.
2228 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2229 ComputeTargetRanges(nsIEditor::EDirection aDirectionAndAmount,
2230 AutoRangeArray& aRangesToDelete) const;
2233 * This method handles "delete selection" commands.
2235 * @param aDirectionAndAmount Direction of the deletion.
2236 * @param aStripWrappers Must be eStrip or eNoStrip.
2238 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2239 HandleDeleteSelection(nsIEditor::EDirection aDirectionAndAmount,
2240 nsIEditor::EStripWrappers aStripWrappers) final;
2242 class AutoDeleteRangesHandler;
2243 class AutoMoveOneLineHandler;
2246 * DeleteMostAncestorMailCiteElementIfEmpty() deletes most ancestor
2247 * mail cite element (`<blockquote type="cite">` or
2248 * `<span _moz_quote="true">`, the former can be created with middle click
2249 * paste with `Control` or `Command` even in the web) of aContent if it
2250 * becomes empty.
2252 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2253 DeleteMostAncestorMailCiteElementIfEmpty(nsIContent& aContent);
2256 * LiftUpListItemElement() moves aListItemElement outside its parent.
2257 * If it's in a middle of a list element, the parent list element is split
2258 * before aListItemElement. Then, moves aListItemElement to before its
2259 * parent list element. I.e., moves aListItemElement between the 2 list
2260 * elements if original parent was split. Then, if new parent becomes not a
2261 * list element, the list item element is removed and its contents are moved
2262 * to where the list item element was. If aListItemElement becomse not a
2263 * child of list element, its contents are unwrapped from aListItemElement.
2265 * @param aListItemElement Must be a <li>, <dt> or <dd> element.
2266 * @param aLiftUpFromAllParentListElements
2267 * If Yes, this method calls itself recursively
2268 * to unwrap the contents in aListItemElement
2269 * from any ancestor list elements.
2270 * XXX This checks only direct parent of list
2271 * elements. Therefore, if a parent list
2272 * element in a list item element, the
2273 * list item element and its list element
2274 * won't be unwrapped.
2276 enum class LiftUpFromAllParentListElements { Yes, No };
2277 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult LiftUpListItemElement(
2278 dom::Element& aListItemElement,
2279 LiftUpFromAllParentListElements aLiftUpFromAllParentListElements);
2282 * DestroyListStructureRecursively() destroys the list structure of
2283 * aListElement recursively.
2284 * If aListElement has <li>, <dl> or <dt> as a child, the element is removed
2285 * but its descendants are moved to where the list item element was.
2286 * If aListElement has another <ul>, <ol> or <dl> as a child, this method is
2287 * called recursively.
2288 * If aListElement has other nodes as its child, they are just removed.
2289 * Finally, aListElement is removed. and its all children are moved to
2290 * where the aListElement was.
2292 * @param aListElement A <ul>, <ol> or <dl> element.
2294 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2295 DestroyListStructureRecursively(Element& aListElement);
2298 * RemoveListAtSelectionAsSubAction() removes list elements and list item
2299 * elements at Selection. And move contents in them where the removed list
2300 * was.
2302 * @param aEditingHost The editing host.
2304 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2305 RemoveListAtSelectionAsSubAction(const Element& aEditingHost);
2308 * ChangeMarginStart() changes margin of aElement to indent or outdent.
2309 * If it's rtl text, margin-right will be changed. Otherwise, margin-left.
2310 * XXX This is not aware of vertical writing-mode.
2312 * @param aElement The element whose start margin should be
2313 * changed.
2314 * @param aChangeMargin Whether increase or decrease the margin.
2315 * @param aEditingHost The editing host.
2316 * @return May suggest a suggest point to put caret.
2318 enum class ChangeMargin { Increase, Decrease };
2319 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
2320 ChangeMarginStart(Element& aElement, ChangeMargin aChangeMargin,
2321 const Element& aEditingHost);
2324 * HandleCSSIndentAroundRanges() indents around aRanges with CSS.
2326 * @param aRanges The ranges where the content should be indented.
2327 * @param aEditingHost The editing host.
2329 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult HandleCSSIndentAroundRanges(
2330 AutoRangeArray& aRanges, const Element& aEditingHost);
2333 * HandleCSSIndentAroundRanges() indents around aRanges with HTML.
2335 * @param aRanges The ranges where the content should be indented.
2336 * @param aEditingHost The editing host.
2338 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult HandleHTMLIndentAroundRanges(
2339 AutoRangeArray& aRanges, const Element& aEditingHost);
2342 * HandleIndentAtSelection() indents around Selection with HTML or CSS.
2344 * @param aEditingHost The editing host.
2346 // TODO: Make this take AutoRangeArray instead of retrieving `Selection`
2347 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2348 HandleIndentAtSelection(const Element& aEditingHost);
2351 * OutdentPartOfBlock() outdents the nodes between aStartOfOutdent and
2352 * aEndOfOutdent. This splits the range off from aBlockElement first.
2353 * Then, removes the middle element if aIsBlockIndentedWithCSS is false.
2354 * Otherwise, decreases the margin of the middle element.
2356 * @param aBlockElement A block element which includes both
2357 * aStartOfOutdent and aEndOfOutdent.
2358 * @param aStartOfOutdent First node which is descendant of
2359 * aBlockElement will be outdented.
2360 * @param aEndOfOutdent Last node which is descandant of
2361 * aBlockElement will be outdented.
2362 * @param aBlockIndentedWith `CSS` if aBlockElement is indented with
2363 * CSS margin property.
2364 * `HTML` if aBlockElement is `<blockquote>`
2365 * or something.
2366 * @param aEditingHost The editing host.
2367 * @return The left content is new created element
2368 * splitting before aStartOfOutdent.
2369 * The right content is existing element.
2370 * The middle content is outdented element
2371 * if aBlockIndentedWith is `CSS`.
2372 * Otherwise, nullptr.
2374 enum class BlockIndentedWith { CSS, HTML };
2375 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffFromNodeResult, nsresult>
2376 OutdentPartOfBlock(Element& aBlockElement, nsIContent& aStartOfOutdent,
2377 nsIContent& aEndOfOutdent,
2378 BlockIndentedWith aBlockIndentedWith,
2379 const Element& aEditingHost);
2382 * HandleOutdentAtSelectionInternal() outdents contents around Selection.
2383 * This method creates AutoSelectionRestorer. Therefore, each caller
2384 * needs to check if the editor is still available even if this returns
2385 * NS_OK.
2386 * NOTE: Call `HandleOutdentAtSelection()` instead.
2388 * @param aEditingHost The editing host.
2389 * @return The left content is left content of last
2390 * outdented element.
2391 * The right content is right content of last
2392 * outdented element.
2393 * The middle content is middle content of last
2394 * outdented element.
2396 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffFromNodeResult, nsresult>
2397 HandleOutdentAtSelectionInternal(const Element& aEditingHost);
2400 * HandleOutdentAtSelection() outdents contents around Selection.
2402 * @param aEditingHost The editing host.
2404 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2405 HandleOutdentAtSelection(const Element& aEditingHost);
2408 * AlignBlockContentsWithDivElement() sets align attribute of <div> element
2409 * which is only child of aBlockElement to aAlignType. If aBlockElement
2410 * has 2 or more children or does not have a `<div>` element, inserts a
2411 * new `<div>` element into aBlockElement and move all children of
2412 * aBlockElement into the new `<div>` element.
2414 * @param aBlockElement The element node whose contents should be
2415 * aligned to aAlignType. This should be
2416 * an element which can have `<div>` element
2417 * as its child.
2418 * @param aAlignType New value of align attribute of `<div>`
2419 * element.
2420 * @return A candidate position to put caret.
2422 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
2423 AlignBlockContentsWithDivElement(Element& aBlockElement,
2424 const nsAString& aAlignType);
2427 * AlignContentsInAllTableCellsAndListItems() calls
2428 * AlignBlockContentsWithDivElement() for aligning contents in every list
2429 * item element and table cell element in aElement.
2431 * @param aElement The node which is or whose descendants should
2432 * be aligned to aAlignType.
2433 * @param aAlignType New value of `align` attribute of `<div>`.
2434 * @return A candidate position to put caret.
2436 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
2437 AlignContentsInAllTableCellsAndListItems(dom::Element& aElement,
2438 const nsAString& aAlignType);
2441 * MakeTransitionList() detects all the transitions in the array, where a
2442 * transition means that adjacent nodes in the array don't have the same
2443 * parent.
2445 static void MakeTransitionList(
2446 const nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
2447 nsTArray<bool>& aTransitionArray);
2450 * EnsureHardLineBeginsWithFirstChildOf() inserts `<br>` element before
2451 * first child of aRemovingContainerElement if it will not be start of a
2452 * hard line after removing aRemovingContainerElement.
2454 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
2455 EnsureHardLineBeginsWithFirstChildOf(Element& aRemovingContainerElement);
2458 * EnsureHardLineEndsWithLastChildOf() inserts `<br>` element after last
2459 * child of aRemovingContainerElement if it will not be end of a hard line
2460 * after removing aRemovingContainerElement.
2462 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
2463 EnsureHardLineEndsWithLastChildOf(Element& aRemovingContainerElement);
2466 * RemoveAlignFromDescendants() removes align attributes, text-align
2467 * properties and <center> elements in aElement.
2469 * @param aElement Alignment information of the node and/or its
2470 * descendants will be removed.
2471 * NOTE: aElement must not be a `<table>` element.
2472 * @param aAlignType New align value to be set only when it's in
2473 * CSS mode and this method meets <table> or <hr>.
2474 * XXX This is odd and not clear when you see caller of
2475 * this method. Do you have better idea?
2476 * @param aEditTarget If `OnlyDescendantsExceptTable`, modifies only
2477 * descendants of aElement.
2478 * If `NodeAndDescendantsExceptTable`, modifies `aElement`
2479 * and its descendants.
2480 * @return A candidate point to put caret.
2482 enum class EditTarget {
2483 OnlyDescendantsExceptTable,
2484 NodeAndDescendantsExceptTable
2486 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
2487 RemoveAlignFromDescendants(Element& aElement, const nsAString& aAlignType,
2488 EditTarget aEditTarget);
2491 * SetBlockElementAlign() resets `align` attribute, `text-align` property
2492 * of descendants of aBlockOrHRElement except `<table>` element descendants.
2493 * Then, set `align` attribute or `text-align` property of aBlockOrHRElement.
2495 * @param aBlockOrHRElement The element whose contents will be aligned.
2496 * This must be a block element or `<hr>` element.
2497 * If we're not in CSS mode, this element has
2498 * to support `align` attribute (i.e.,
2499 * `HTMLEditUtils::SupportsAlignAttr()` must
2500 * return true).
2501 * @param aAlignType Boundary or "center" which contents should be
2502 * aligned on.
2503 * @param aEditTarget If `OnlyDescendantsExceptTable`, modifies only
2504 * descendants of aBlockOrHRElement.
2505 * If `NodeAndDescendantsExceptTable`, modifies
2506 * aBlockOrHRElement and its descendants.
2507 * @return A candidate point to put caret.
2509 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
2510 SetBlockElementAlign(Element& aBlockOrHRElement, const nsAString& aAlignType,
2511 EditTarget aEditTarget);
2514 * InsertDivElementToAlignContents() inserts a new <div> element (which has
2515 * only a padding <br> element) to aPointToInsert for a placeholder whose
2516 * contents will be aligned.
2518 * @param aPointToInsert A point to insert new empty <div>.
2519 * @param aAlignType New align attribute value where the contents
2520 * should be aligned to.
2521 * @param aEditingHost The editing host.
2522 * @return New <div> element which has only a padding <br>
2523 * element and is styled to align contents.
2525 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
2526 InsertDivElementToAlignContents(const EditorDOMPoint& aPointToInsert,
2527 const nsAString& aAlignType,
2528 const Element& aEditingHost);
2531 * AlignNodesAndDescendants() make contents of nodes in aArrayOfContents and
2532 * their descendants aligned to aAlignType.
2534 * @param aAlignType New align attribute value where the contents
2535 * should be aligned to.
2536 * @param aEditingHost The editing host.
2537 * @return Last created <div> element which should contain
2538 * caret and candidate position which may be
2539 * outside the <div> element.
2541 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
2542 AlignNodesAndDescendants(
2543 nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
2544 const nsAString& aAlignType, const Element& aEditingHost);
2547 * AlignContentsAtRanges() aligns contents around aRanges to aAlignType.
2549 * @param aRanges The ranges where should be aligned.
2550 * @param aAlignType New align attribute value where the contents
2551 * should be aligned to.
2552 * @param aEditingHost The editing host.
2554 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2555 AlignContentsAtRanges(AutoRangeArray& aRanges, const nsAString& aAlignType,
2556 const Element& aEditingHost);
2559 * AlignAsSubAction() handles "align" command with `Selection`.
2561 * @param aAlignType New align attribute value where the contents
2562 * should be aligned to.
2563 * @param aEditingHost The editing host.
2565 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2566 AlignAsSubAction(const nsAString& aAlignType, const Element& aEditingHost);
2569 * AdjustCaretPositionAndEnsurePaddingBRElement() may adjust caret
2570 * position to nearest editable content and if padding `<br>` element is
2571 * necessary at caret position, this creates it.
2573 * @param aDirectionAndAmount Direction of the edit action.
2575 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2576 AdjustCaretPositionAndEnsurePaddingBRElement(
2577 nsIEditor::EDirection aDirectionAndAmount);
2580 * EnsureSelectionInBodyOrDocumentElement() collapse `Selection` to the
2581 * primary `<body>` element or document element when `Selection` crosses
2582 * `<body>` element's boundary.
2584 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2585 EnsureSelectionInBodyOrDocumentElement();
2588 * InsertBRElementToEmptyListItemsAndTableCellsInRange() inserts
2589 * `<br>` element into empty list item or table cell elements between
2590 * aStartRef and aEndRef.
2592 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2593 InsertBRElementToEmptyListItemsAndTableCellsInRange(
2594 const RawRangeBoundary& aStartRef, const RawRangeBoundary& aEndRef);
2597 * RemoveEmptyNodesIn() removes all empty nodes in aRange. However, if
2598 * mail-cite node has only a `<br>` element, the node will be removed
2599 * but <br> element is moved to where the mail-cite node was.
2600 * XXX This method is expensive if aRange is too wide and may remove
2601 * unexpected empty element, e.g., it was created by JS, but we haven't
2602 * touched it. Cannot we remove this method and make guarantee that
2603 * empty nodes won't be created?
2605 * @param aRange Must be positioned.
2607 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2608 RemoveEmptyNodesIn(const EditorDOMRange& aRange);
2611 * SetSelectionInterlinePosition() may set interline position if caret is
2612 * positioned around `<br>` or block boundary. Don't call this when
2613 * `Selection` is not collapsed.
2615 void SetSelectionInterlinePosition();
2618 * Called by `HTMLEditor::OnEndHandlingTopLevelEditSubAction()`. This may
2619 * adjust Selection, remove unnecessary empty nodes, create `<br>` elements
2620 * if needed, etc.
2622 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2623 OnEndHandlingTopLevelEditSubActionInternal();
2626 * MoveSelectedContentsToDivElementToMakeItAbsolutePosition() looks for
2627 * a `<div>` element in selection first. If not, creates new `<div>`
2628 * element. Then, move all selected contents into the target `<div>`
2629 * element.
2630 * Note that this creates AutoSelectionRestorer. Therefore, callers need
2631 * to check whether we have been destroyed even when this returns NS_OK.
2633 * @param aTargetElement Returns target `<div>` element which should be
2634 * changed to absolute positioned.
2635 * @param aEditingHost The editing host.
2637 // TODO: Rewrite this with `Result<RefPtr<Element>, nsresult>`.
2638 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2639 MoveSelectedContentsToDivElementToMakeItAbsolutePosition(
2640 RefPtr<Element>* aTargetElement, const Element& aEditingHost);
2643 * SetSelectionToAbsoluteAsSubAction() move selected contents to first
2644 * selected `<div>` element or newly created `<div>` element and make
2645 * the `<div>` element positioned absolutely.
2647 * @param aEditingHost The editing host.
2649 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2650 SetSelectionToAbsoluteAsSubAction(const Element& aEditingHost);
2653 * SetSelectionToStaticAsSubAction() sets the `position` property of a
2654 * selection parent's block whose `position` is `absolute` to `static`.
2656 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2657 SetSelectionToStaticAsSubAction();
2660 * AddZIndexAsSubAction() adds aChange to `z-index` of nearest parent
2661 * absolute-positioned element from current selection.
2663 * @param aChange Amount to change `z-index`.
2665 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2666 AddZIndexAsSubAction(int32_t aChange);
2669 * OnDocumentModified() is called when editor content is changed.
2671 MOZ_CAN_RUN_SCRIPT nsresult OnDocumentModified();
2673 protected: // Called by helper classes.
2674 MOZ_CAN_RUN_SCRIPT void OnStartToHandleTopLevelEditSubAction(
2675 EditSubAction aTopLevelEditSubAction,
2676 nsIEditor::EDirection aDirectionOfTopLevelEditSubAction,
2677 ErrorResult& aRv) final;
2678 MOZ_CAN_RUN_SCRIPT nsresult OnEndHandlingTopLevelEditSubAction() final;
2680 protected: // Shouldn't be used by friend classes
2681 virtual ~HTMLEditor();
2684 * InitEditorContentAndSelection() may insert `<br>` elements and padding
2685 * `<br>` elements if they are required for `<body>` or document element.
2686 * And collapse selection at the end if there is no selection ranges.
2688 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InitEditorContentAndSelection();
2691 * Collapse `Selection` to the last leaf content of the <body> or the document
2692 * element.
2694 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2695 CollapseSelectionToEndOfLastLeafNodeOfDocument() const;
2697 MOZ_CAN_RUN_SCRIPT nsresult SelectAllInternal() final;
2699 [[nodiscard]] Element* ComputeEditingHostInternal(
2700 const nsIContent* aContent, LimitInBodyElement aLimitInBodyElement) const;
2703 * Creates a range with just the supplied node and appends that to the
2704 * selection.
2706 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2707 AppendContentToSelectionAsRange(nsIContent& aContent);
2710 * When you are using AppendContentToSelectionAsRange(), call this first to
2711 * start a new selection.
2713 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult ClearSelection();
2716 * SelectContentInternal() sets Selection to aContentToSelect to
2717 * aContentToSelect + 1 in parent of aContentToSelect.
2719 * @param aContentToSelect The content which should be selected.
2721 MOZ_CAN_RUN_SCRIPT nsresult
2722 SelectContentInternal(nsIContent& aContentToSelect);
2725 * GetInclusiveAncestorByTagNameAtSelection() looks for an element node whose
2726 * name matches aTagName from anchor node of Selection to <body> element.
2728 * @param aTagName The tag name which you want to look for.
2729 * Must not be nsGkAtoms::_empty.
2730 * If nsGkAtoms::list, the result may be <ul>, <ol> or
2731 * <dl> element.
2732 * If nsGkAtoms::td, the result may be <td> or <th>.
2733 * If nsGkAtoms::href, the result may be <a> element
2734 * which has "href" attribute with non-empty value.
2735 * If nsGkAtoms::anchor, the result may be <a> which
2736 * has "name" attribute with non-empty value.
2737 * @return If an element which matches aTagName, returns
2738 * an Element. Otherwise, nullptr.
2740 Element* GetInclusiveAncestorByTagNameAtSelection(
2741 const nsStaticAtom& aTagName) const;
2744 * GetInclusiveAncestorByTagNameInternal() looks for an element node whose
2745 * name matches aTagName from aNode to <body> element.
2747 * @param aTagName The tag name which you want to look for.
2748 * Must not be nsGkAtoms::_empty.
2749 * If nsGkAtoms::list, the result may be <ul>, <ol> or
2750 * <dl> element.
2751 * If nsGkAtoms::td, the result may be <td> or <th>.
2752 * If nsGkAtoms::href, the result may be <a> element
2753 * which has "href" attribute with non-empty value.
2754 * If nsGkAtoms::anchor, the result may be <a> which
2755 * has "name" attribute with non-empty value.
2756 * @param aContent Start node to look for the element. This should
2757 * not be an orphan node.
2758 * @return If an element which matches aTagName, returns
2759 * an Element. Otherwise, nullptr.
2761 Element* GetInclusiveAncestorByTagNameInternal(
2762 const nsStaticAtom& aTagName, const nsIContent& aContent) const;
2765 * GetSelectedElement() returns a "selected" element node. "selected" means:
2766 * - there is only one selection range
2767 * - the range starts from an element node or in an element
2768 * - the range ends at immediately after same element
2769 * - and the range does not include any other element nodes.
2770 * Additionally, only when aTagName is nsGkAtoms::href, this thinks that an
2771 * <a> element which has non-empty "href" attribute includes the range, the
2772 * <a> element is selected.
2774 * NOTE: This method is implementation of nsIHTMLEditor.getSelectedElement()
2775 * and comm-central depends on this behavior. Therefore, if you need to use
2776 * this method internally but you need to change, perhaps, you should create
2777 * another method for avoiding breakage of comm-central apps.
2779 * @param aTagName The atom of tag name in lower case. Set this to
2780 * result of EditorUtils::GetTagNameAtom() if you have a
2781 * tag name with nsString.
2782 * If nullptr, this returns any element node or nullptr.
2783 * If nsGkAtoms::href, this returns an <a> element which
2784 * has non-empty "href" attribute or nullptr.
2785 * If nsGkAtoms::anchor, this returns an <a> element which
2786 * has non-empty "name" attribute or nullptr.
2787 * Otherwise, returns an element node whose name is
2788 * same as aTagName or nullptr.
2789 * @param aRv Returns error code.
2790 * @return A "selected" element.
2792 already_AddRefed<Element> GetSelectedElement(const nsAtom* aTagName,
2793 ErrorResult& aRv);
2796 * GetFirstTableRowElement() returns the first <tr> element in the most
2797 * nearest ancestor of aTableOrElementInTable or itself.
2798 * When aTableOrElementInTable is neither <table> nor in a <table> element,
2799 * returns NS_ERROR_FAILURE. However, if <table> does not have <tr> element,
2800 * returns nullptr.
2802 * @param aTableOrElementInTable <table> element or another element.
2803 * If this is a <table> element, returns
2804 * first <tr> element in it. Otherwise,
2805 * returns first <tr> element in nearest
2806 * ancestor <table> element.
2808 Result<RefPtr<Element>, nsresult> GetFirstTableRowElement(
2809 const Element& aTableOrElementInTable) const;
2812 * GetNextTableRowElement() returns next <tr> element of aTableRowElement.
2813 * This won't cross <table> element boundary but may cross table section
2814 * elements like <tbody>.
2815 * Note that if given element is <tr> but there is no next <tr> element, this
2816 * returns nullptr but does not return error.
2818 * @param aTableRowElement A <tr> element.
2820 Result<RefPtr<Element>, nsresult> GetNextTableRowElement(
2821 const Element& aTableRowElement) const;
2823 struct CellData;
2826 * CellIndexes store both row index and column index of a table cell.
2828 struct MOZ_STACK_CLASS CellIndexes final {
2829 int32_t mRow;
2830 int32_t mColumn;
2833 * This constructor initializes mRowIndex and mColumnIndex with indexes of
2834 * aCellElement.
2836 * @param aCellElement An <td> or <th> element.
2838 MOZ_CAN_RUN_SCRIPT CellIndexes(Element& aCellElement, PresShell* aPresShell)
2839 : mRow(-1), mColumn(-1) {
2840 Update(aCellElement, aPresShell);
2844 * Update mRowIndex and mColumnIndex with indexes of aCellElement.
2846 * @param See above.
2848 MOZ_CAN_RUN_SCRIPT void Update(Element& aCellElement,
2849 PresShell* aPresShell);
2852 * This constructor initializes mRowIndex and mColumnIndex with indexes of
2853 * cell element which contains anchor of Selection.
2855 * @param aHTMLEditor The editor which creates the instance.
2856 * @param aSelection The Selection for the editor.
2858 MOZ_CAN_RUN_SCRIPT CellIndexes(HTMLEditor& aHTMLEditor,
2859 Selection& aSelection)
2860 : mRow(-1), mColumn(-1) {
2861 Update(aHTMLEditor, aSelection);
2865 * Update mRowIndex and mColumnIndex with indexes of cell element which
2866 * contains anchor of Selection.
2868 * @param See above.
2870 MOZ_CAN_RUN_SCRIPT void Update(HTMLEditor& aHTMLEditor,
2871 Selection& aSelection);
2873 bool operator==(const CellIndexes& aOther) const {
2874 return mRow == aOther.mRow && mColumn == aOther.mColumn;
2876 bool operator!=(const CellIndexes& aOther) const {
2877 return mRow != aOther.mRow || mColumn != aOther.mColumn;
2880 [[nodiscard]] bool isErr() const { return mRow < 0 || mColumn < 0; }
2882 private:
2883 CellIndexes() : mRow(-1), mColumn(-1) {}
2884 CellIndexes(int32_t aRowIndex, int32_t aColumnIndex)
2885 : mRow(aRowIndex), mColumn(aColumnIndex) {}
2887 friend struct CellData;
2890 struct MOZ_STACK_CLASS CellData final {
2891 MOZ_KNOWN_LIVE RefPtr<Element> mElement;
2892 // Current indexes which this is initialized with.
2893 CellIndexes mCurrent;
2894 // First column/row indexes of the cell. When current position is spanned
2895 // from other column/row, this value becomes different from mCurrent.
2896 CellIndexes mFirst;
2897 // Computed rowspan/colspan values which are specified to the cell.
2898 // Note that if the cell has larger rowspan/colspan value than actual
2899 // table size, these values are the larger values.
2900 int32_t mRowSpan = -1;
2901 int32_t mColSpan = -1;
2902 // Effective rowspan/colspan value at the index. For example, if first
2903 // cell element in first row has rowspan="3", then, if this is initialized
2904 // with 0-0 indexes, effective rowspan is 3. However, if this is
2905 // initialized with 1-0 indexes, effective rowspan is 2.
2906 int32_t mEffectiveRowSpan = -1;
2907 int32_t mEffectiveColSpan = -1;
2908 // mIsSelected is set to true if mElement itself or its parent <tr> or
2909 // <table> is selected. Otherwise, e.g., the cell just contains selection
2910 // range, this is set to false.
2911 bool mIsSelected = false;
2913 CellData() = delete;
2916 * This returns an instance which is initialized with a <table> element and
2917 * both row and column index to specify a cell element.
2919 [[nodiscard]] static CellData AtIndexInTableElement(
2920 const HTMLEditor& aHTMLEditor, const Element& aTableElement,
2921 int32_t aRowIndex, int32_t aColumnIndex);
2922 [[nodiscard]] static CellData AtIndexInTableElement(
2923 const HTMLEditor& aHTMLEditor, const Element& aTableElement,
2924 const CellIndexes& aIndexes) {
2925 MOZ_ASSERT(!aIndexes.isErr());
2926 return AtIndexInTableElement(aHTMLEditor, aTableElement, aIndexes.mRow,
2927 aIndexes.mColumn);
2931 * Treated as error if fails to compute current index or first index of the
2932 * cell. Note that even if the cell is not found due to no corresponding
2933 * frame at current index, it's not an error situation.
2935 [[nodiscard]] bool isOk() const { return !isErr(); }
2936 [[nodiscard]] bool isErr() const { return mFirst.isErr(); }
2939 * FailedOrNotFound() returns true if this failed to initialize/update
2940 * or succeeded but found no cell element.
2942 [[nodiscard]] bool FailedOrNotFound() const { return isErr() || !mElement; }
2945 * IsSpannedFromOtherRowOrColumn(), IsSpannedFromOtherColumn and
2946 * IsSpannedFromOtherRow() return true if there is no cell element
2947 * at the index because of spanning from other row and/or column.
2949 [[nodiscard]] bool IsSpannedFromOtherRowOrColumn() const {
2950 return mElement && mCurrent != mFirst;
2952 [[nodiscard]] bool IsSpannedFromOtherColumn() const {
2953 return mElement && mCurrent.mColumn != mFirst.mColumn;
2955 [[nodiscard]] bool IsSpannedFromOtherRow() const {
2956 return mElement && mCurrent.mRow != mFirst.mRow;
2958 [[nodiscard]] bool IsNextColumnSpannedFromOtherColumn() const {
2959 return mElement && mCurrent.mColumn + 1 < NextColumnIndex();
2963 * NextColumnIndex() and NextRowIndex() return column/row index of
2964 * next cell. Note that this does not check whether there is next
2965 * cell or not actually.
2967 [[nodiscard]] int32_t NextColumnIndex() const {
2968 if (NS_WARN_IF(FailedOrNotFound())) {
2969 return -1;
2971 return mCurrent.mColumn + mEffectiveColSpan;
2973 [[nodiscard]] int32_t NextRowIndex() const {
2974 if (NS_WARN_IF(FailedOrNotFound())) {
2975 return -1;
2977 return mCurrent.mRow + mEffectiveRowSpan;
2981 * LastColumnIndex() and LastRowIndex() return column/row index of
2982 * column/row which is spanned by the cell.
2984 [[nodiscard]] int32_t LastColumnIndex() const {
2985 if (NS_WARN_IF(FailedOrNotFound())) {
2986 return -1;
2988 return NextColumnIndex() - 1;
2990 [[nodiscard]] int32_t LastRowIndex() const {
2991 if (NS_WARN_IF(FailedOrNotFound())) {
2992 return -1;
2994 return NextRowIndex() - 1;
2998 * NumberOfPrecedingColmuns() and NumberOfPrecedingRows() return number of
2999 * preceding columns/rows if current index is spanned from other column/row.
3000 * Otherwise, i.e., current point is not spanned form other column/row,
3001 * returns 0.
3003 [[nodiscard]] int32_t NumberOfPrecedingColmuns() const {
3004 if (NS_WARN_IF(FailedOrNotFound())) {
3005 return -1;
3007 return mCurrent.mColumn - mFirst.mColumn;
3009 [[nodiscard]] int32_t NumberOfPrecedingRows() const {
3010 if (NS_WARN_IF(FailedOrNotFound())) {
3011 return -1;
3013 return mCurrent.mRow - mFirst.mRow;
3017 * NumberOfFollowingColumns() and NumberOfFollowingRows() return
3018 * number of remaining columns/rows if the cell spans to other
3019 * column/row.
3021 [[nodiscard]] int32_t NumberOfFollowingColumns() const {
3022 if (NS_WARN_IF(FailedOrNotFound())) {
3023 return -1;
3025 return mEffectiveColSpan - 1;
3027 [[nodiscard]] int32_t NumberOfFollowingRows() const {
3028 if (NS_WARN_IF(FailedOrNotFound())) {
3029 return -1;
3031 return mEffectiveRowSpan - 1;
3034 private:
3035 explicit CellData(int32_t aCurrentRowIndex, int32_t aCurrentColumnIndex,
3036 int32_t aFirstRowIndex, int32_t aFirstColumnIndex)
3037 : mCurrent(aCurrentRowIndex, aCurrentColumnIndex),
3038 mFirst(aFirstRowIndex, aFirstColumnIndex) {}
3039 explicit CellData(Element& aElement, int32_t aRowIndex,
3040 int32_t aColumnIndex, nsTableCellFrame& aTableCellFrame,
3041 nsTableWrapperFrame& aTableWrapperFrame);
3043 [[nodiscard]] static CellData Error(int32_t aRowIndex,
3044 int32_t aColumnIndex) {
3045 return CellData(aRowIndex, aColumnIndex, -1, -1);
3047 [[nodiscard]] static CellData NotFound(int32_t aRowIndex,
3048 int32_t aColumnIndex) {
3049 return CellData(aRowIndex, aColumnIndex, aRowIndex, aColumnIndex);
3054 * TableSize stores and computes number of rows and columns of a <table>
3055 * element.
3057 struct MOZ_STACK_CLASS TableSize final {
3058 int32_t mRowCount;
3059 int32_t mColumnCount;
3061 TableSize() = delete;
3064 * @param aHTMLEditor The editor which creates the instance.
3065 * @param aTableOrElementInTable If a <table> element, computes number
3066 * of rows and columns of it.
3067 * If another element in a <table> element,
3068 * computes number of rows and columns
3069 * of nearest ancestor <table> element.
3070 * Otherwise, i.e., non-<table> element
3071 * not in <table>, returns error.
3073 [[nodiscard]] static Result<TableSize, nsresult> Create(
3074 HTMLEditor& aHTMLEditor, Element& aTableOrElementInTable);
3076 [[nodiscard]] bool IsEmpty() const { return !mRowCount || !mColumnCount; }
3078 private:
3079 TableSize(int32_t aRowCount, int32_t aColumCount)
3080 : mRowCount(aRowCount), mColumnCount(aColumCount) {}
3084 * GetTableCellElementAt() returns a <td> or <th> element of aTableElement
3085 * if there is a cell at the indexes.
3087 * @param aTableElement Must be a <table> element.
3088 * @param aCellIndexes Indexes of cell which you want.
3089 * If rowspan and/or colspan is specified 2 or
3090 * larger, any indexes are allowed to retrieve
3091 * the cell in the area.
3092 * @return The cell element if there is in the <table>.
3093 * Returns nullptr without error if the indexes
3094 * are out of bounds.
3096 [[nodiscard]] inline Element* GetTableCellElementAt(
3097 Element& aTableElement, const CellIndexes& aCellIndexes) const;
3098 [[nodiscard]] Element* GetTableCellElementAt(Element& aTableElement,
3099 int32_t aRowIndex,
3100 int32_t aColumnIndex) const;
3103 * GetSelectedOrParentTableElement() returns <td>, <th>, <tr> or <table>
3104 * element:
3105 * #1 if the first selection range selects a cell, returns it.
3106 * #2 if the first selection range does not select a cell and
3107 * the selection anchor refers a <table>, returns it.
3108 * #3 if the first selection range does not select a cell and
3109 * the selection anchor refers a <tr>, returns it.
3110 * #4 if the first selection range does not select a cell and
3111 * the selection anchor refers a <td>, returns it.
3112 * #5 otherwise, nearest ancestor <td> or <th> element of the
3113 * selection anchor if there is.
3114 * In #1 and #4, *aIsCellSelected will be set to true (i.e,, when
3115 * a selection range selects a cell element).
3117 Result<RefPtr<Element>, nsresult> GetSelectedOrParentTableElement(
3118 bool* aIsCellSelected = nullptr) const;
3121 * GetFirstSelectedCellElementInTable() returns <td> or <th> element at
3122 * first selection (using GetSelectedOrParentTableElement). If found cell
3123 * element is not in <table> or <tr> element, this returns nullptr.
3125 Result<RefPtr<Element>, nsresult> GetFirstSelectedCellElementInTable() const;
3127 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult HandlePaste(
3128 AutoEditActionDataSetter& aEditActionData, int32_t aClipboardType) final;
3129 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult HandlePasteAsQuotation(
3130 AutoEditActionDataSetter& aEditActionData, int32_t aClipboardType) final;
3131 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3132 HandlePasteTransferable(AutoEditActionDataSetter& aEditActionData,
3133 nsITransferable& aTransferable) final;
3136 * PasteInternal() pasts text with replacing selected content.
3137 * This tries to dispatch ePaste event first. If its defaultPrevent() is
3138 * called, this does nothing but returns NS_OK.
3140 * @param aClipboardType nsIClipboard::kGlobalClipboard or
3141 * nsIClipboard::kSelectionClipboard.
3143 MOZ_CAN_RUN_SCRIPT nsresult PasteInternal(int32_t aClipboardType);
3145 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3146 InsertWithQuotationsAsSubAction(const nsAString& aQuotedText) final;
3149 * InsertAsCitedQuotationInternal() inserts a <blockquote> element whose
3150 * cite attribute is aCitation and whose content is aQuotedText.
3151 * Note that this shouldn't be called when IsPlaintextMailComposer() is true.
3153 * @param aQuotedText HTML source if aInsertHTML is true. Otherwise,
3154 * plain text. This is inserted into new <blockquote>
3155 * element.
3156 * @param aCitation cite attribute value of new <blockquote> element.
3157 * @param aInsertHTML true if aQuotedText should be treated as HTML
3158 * source.
3159 * false if aQuotedText should be treated as plain
3160 * text.
3161 * @param aNodeInserted [OUT] The new <blockquote> element.
3163 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertAsCitedQuotationInternal(
3164 const nsAString& aQuotedText, const nsAString& aCitation,
3165 bool aInsertHTML, nsINode** aNodeInserted);
3168 * InsertNodeIntoProperAncestorWithTransaction() attempts to insert aNode
3169 * into the document, at aPointToInsert. Checks with strict dtd to see if
3170 * containment is allowed. If not allowed, will attempt to find a parent
3171 * in the parent hierarchy of aPointToInsert.GetContainer() that will accept
3172 * aNode as a child. If such a parent is found, will split the document
3173 * tree from aPointToInsert up to parent, and then insert aNode.
3174 * aPointToInsert is then adjusted to point to the actual location that
3175 * aNode was inserted at. aSplitAtEdges specifies if the splitting process
3176 * is allowed to result in empty nodes.
3178 * @param aContent The content node to insert.
3179 * @param aPointToInsert Insertion point.
3180 * @param aSplitAtEdges Splitting can result in empty nodes?
3182 template <typename NodeType>
3183 [[nodiscard]] MOZ_CAN_RUN_SCRIPT
3184 Result<CreateNodeResultBase<NodeType>, nsresult>
3185 InsertNodeIntoProperAncestorWithTransaction(
3186 NodeType& aContent, const EditorDOMPoint& aPointToInsert,
3187 SplitAtEdges aSplitAtEdges);
3190 * InsertTextWithQuotationsInternal() replaces selection with new content.
3191 * First, this method splits aStringToInsert to multiple chunks which start
3192 * with non-linebreaker except first chunk and end with a linebreaker except
3193 * last chunk. Then, each chunk starting with ">" is inserted after wrapping
3194 * with <span _moz_quote="true">, and each chunk not starting with ">" is
3195 * inserted as normal text.
3197 MOZ_CAN_RUN_SCRIPT nsresult
3198 InsertTextWithQuotationsInternal(const nsAString& aStringToInsert);
3201 * ReplaceContainerWithTransactionInternal() is implementation of
3202 * ReplaceContainerWithTransaction() and
3203 * ReplaceContainerAndCloneAttributesWithTransaction().
3205 * @param aOldContainer The element which will be replaced with new
3206 * element.
3207 * @param aTagName The name of new element node.
3208 * @param aAttribute Attribute name which will be set to the new
3209 * element. This will be ignored if
3210 * aCloneAllAttributes is set to true.
3211 * @param aAttributeValue Attribute value which will be set to
3212 * aAttribute.
3213 * @param aCloneAllAttributes If true, all attributes of aOldContainer will
3214 * be copied to the new element.
3216 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
3217 ReplaceContainerWithTransactionInternal(Element& aOldContainer,
3218 const nsAtom& aTagName,
3219 const nsAtom& aAttribute,
3220 const nsAString& aAttributeValue,
3221 bool aCloneAllAttributes);
3224 * DeleteSelectionAndCreateElement() creates a element whose name is aTag.
3225 * And insert it into the DOM tree after removing the selected content.
3227 * @param aTag The element name to be created.
3228 * @param aInitializer A function to initialize the new element before
3229 * or after (depends on the pref) connecting the
3230 * element into the DOM tree. Note that this should
3231 * not touch outside given element because doing it
3232 * would break range updater's result.
3234 MOZ_CAN_RUN_SCRIPT Result<RefPtr<Element>, nsresult>
3235 DeleteSelectionAndCreateElement(
3236 nsAtom& aTag,
3237 const InitializeInsertingElement& aInitializer = DoNothingForNewElement);
3240 * This method first deletes the selection, if it's not collapsed. Then if
3241 * the selection lies in a CharacterData node, it splits it. If the
3242 * selection is at this point collapsed in a CharacterData node, it's
3243 * adjusted to be collapsed right before or after the node instead (which is
3244 * always possible, since the node was split).
3246 MOZ_CAN_RUN_SCRIPT nsresult DeleteSelectionAndPrepareToCreateNode();
3249 * PrepareToInsertBRElement() returns a point where new <br> element should
3250 * be inserted. If aPointToInsert points middle of a text node, this method
3251 * splits the text node and returns the point before right node.
3253 * @param aPointToInsert Candidate point to insert new <br> element.
3254 * @return Computed point to insert new <br> element.
3255 * If something failed, this return error.
3257 MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult> PrepareToInsertBRElement(
3258 const EditorDOMPoint& aPointToInsert);
3261 * IndentAsSubAction() indents the content around Selection.
3263 * @param aEditingHost The editing host.
3265 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
3266 IndentAsSubAction(const Element& aEditingHost);
3269 * OutdentAsSubAction() outdents the content around Selection.
3271 * @param aEditingHost The editing host.
3273 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
3274 OutdentAsSubAction(const Element& aEditingHost);
3276 MOZ_CAN_RUN_SCRIPT nsresult LoadHTML(const nsAString& aInputString);
3279 * UpdateMetaCharsetWithTransaction() scans all <meta> elements in the
3280 * document and if and only if there is a <meta> element having `httpEquiv`
3281 * attribute and whose value includes `content-type`, updates its `content`
3282 * attribute value to aCharacterSet.
3284 MOZ_CAN_RUN_SCRIPT bool UpdateMetaCharsetWithTransaction(
3285 Document& aDocument, const nsACString& aCharacterSet);
3288 * SetInlinePropertiesAsSubAction() stores new styles with
3289 * mPendingStylesToApplyToNewContent if `Selection` is collapsed. Otherwise,
3290 * applying the styles to all selected contents.
3292 * @param aStylesToSet The styles which should be applied to the
3293 * selected content.
3295 template <size_t N>
3296 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertiesAsSubAction(
3297 const AutoTArray<EditorInlineStyleAndValue, N>& aStylesToSet);
3300 * SetInlinePropertiesAroundRanges() applying the styles to the ranges even if
3301 * the ranges are collapsed.
3303 template <size_t N>
3304 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertiesAroundRanges(
3305 AutoRangeArray& aRanges,
3306 const AutoTArray<EditorInlineStyleAndValue, N>& aStylesToSet,
3307 const Element& aEditingHost);
3310 * RemoveInlinePropertiesAsSubAction() removes specified styles from
3311 * mPendingStylesToApplyToNewContent if `Selection` is collapsed. Otherwise,
3312 * removing the style.
3314 * @param aStylesToRemove Styles to remove from the selected contents.
3316 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveInlinePropertiesAsSubAction(
3317 const nsTArray<EditorInlineStyle>& aStylesToRemove);
3320 * Helper method to call RemoveInlinePropertiesAsSubAction(). If you want to
3321 * remove other elements to remove the style completely, this will append
3322 * related elements of aStyleToRemove and aStyleToRemove itself to the array.
3323 * E.g., nsGkAtoms::strong and nsGkAtoms::b will be appended if aStyleToRemove
3324 * is nsGkAtoms::b.
3326 void AppendInlineStyleAndRelatedStyle(
3327 const EditorInlineStyle& aStyleToRemove,
3328 nsTArray<EditorInlineStyle>& aStylesToRemove) const;
3331 * ReplaceHeadContentsWithSourceWithTransaction() replaces all children of
3332 * <head> element with given source code. This is undoable.
3334 * @param aSourceToInsert HTML source fragment to replace the children
3335 * of <head> element.
3337 MOZ_CAN_RUN_SCRIPT nsresult ReplaceHeadContentsWithSourceWithTransaction(
3338 const nsAString& aSourceToInsert);
3340 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetCSSBackgroundColorState(
3341 bool* aMixed, nsAString& aOutColor, bool aBlockLevel);
3342 nsresult GetHTMLBackgroundColorState(bool* aMixed, nsAString& outColor);
3345 * This sets background on the appropriate container element (table, cell,)
3346 * or calls to set the page background.
3348 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3349 SetBlockBackgroundColorWithCSSAsSubAction(const nsAString& aColor);
3350 MOZ_CAN_RUN_SCRIPT nsresult
3351 SetHTMLBackgroundColorWithTransaction(const nsAString& aColor);
3353 MOZ_CAN_RUN_SCRIPT_BOUNDARY void InitializeSelectionAncestorLimit(
3354 nsIContent& aAncestorLimit) const final;
3357 * Make the given selection span the entire document.
3359 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SelectEntireDocument() final;
3362 * Use this to assure that selection is set after attribute nodes when
3363 * trying to collapse selection at begining of a block node
3364 * e.g., when setting at beginning of a table cell
3365 * This will stop at a table, however, since we don't want to
3366 * "drill down" into nested tables.
3368 MOZ_CAN_RUN_SCRIPT void CollapseSelectionToDeepestNonTableFirstChild(
3369 nsINode* aNode);
3371 * MaybeCollapseSelectionAtFirstEditableNode() may collapse selection at
3372 * proper position to staring to edit. If there is a non-editable node
3373 * before any editable text nodes or inline elements which can have text
3374 * nodes as their children, collapse selection at start of the editing
3375 * host. If there is an editable text node which is not collapsed, collapses
3376 * selection at the start of the text node. If there is an editable inline
3377 * element which cannot have text nodes as its child, collapses selection at
3378 * before the element node. Otherwise, collapses selection at start of the
3379 * editing host.
3381 * @param aIgnoreIfSelectionInEditingHost
3382 * This method does nothing if selection is in the
3383 * editing host except if it's collapsed at start of
3384 * the editing host.
3385 * Note that if selection ranges were outside of
3386 * current selection limiter, selection was collapsed
3387 * at the start of the editing host therefore, if
3388 * you call this with setting this to true, you can
3389 * keep selection ranges if user has already been
3390 * changed.
3392 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3393 MaybeCollapseSelectionAtFirstEditableNode(
3394 bool aIgnoreIfSelectionInEditingHost) const;
3396 class BlobReader final {
3397 using AutoEditActionDataSetter = EditorBase::AutoEditActionDataSetter;
3399 public:
3400 MOZ_CAN_RUN_SCRIPT BlobReader(dom::BlobImpl* aBlob, HTMLEditor* aHTMLEditor,
3401 SafeToInsertData aSafeToInsertData,
3402 const EditorDOMPoint& aPointToInsert,
3403 DeleteSelectedContent aDeleteSelectedContent);
3405 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BlobReader)
3406 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(BlobReader)
3408 MOZ_CAN_RUN_SCRIPT nsresult OnResult(const nsACString& aResult);
3409 nsresult OnError(const nsAString& aErrorName);
3411 private:
3412 ~BlobReader() = default;
3414 RefPtr<dom::BlobImpl> mBlob;
3415 RefPtr<HTMLEditor> mHTMLEditor;
3416 RefPtr<dom::DataTransfer> mDataTransfer;
3417 EditorDOMPoint mPointToInsert;
3418 EditAction mEditAction;
3419 SafeToInsertData mSafeToInsertData;
3420 DeleteSelectedContent mDeleteSelectedContent;
3421 bool mNeedsToDispatchBeforeInputEvent;
3424 void CreateEventListeners() final;
3425 nsresult InstallEventListeners() final;
3427 bool ShouldReplaceRootElement() const;
3428 MOZ_CAN_RUN_SCRIPT void NotifyRootChanged();
3429 Element* GetBodyElement() const;
3432 * Get the focused node of this editor.
3433 * @return If the editor has focus, this returns the focused node.
3434 * Otherwise, returns null.
3436 nsINode* GetFocusedNode() const;
3438 already_AddRefed<Element> GetInputEventTargetElement() const final;
3441 * Return TRUE if aElement is a table-related elemet and caret was set.
3443 MOZ_CAN_RUN_SCRIPT bool SetCaretInTableCell(dom::Element* aElement);
3446 * HandleTabKeyPressInTable() handles "Tab" key press in table if selection
3447 * is in a `<table>` element.
3449 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
3450 HandleTabKeyPressInTable(WidgetKeyboardEvent* aKeyboardEvent);
3453 * InsertPosition is an enum to indicate where the method should insert to.
3455 enum class InsertPosition {
3456 // Before selected cell or a cell containing first selection range.
3457 eBeforeSelectedCell,
3458 // After selected cell or a cell containing first selection range.
3459 eAfterSelectedCell,
3463 * InsertTableCellsWithTransaction() inserts <td> elements at aPointToInsert.
3464 * Note that this simply inserts <td> elements, i.e., colspan and rowspan
3465 * around the cell containing selection are not modified. So, for example,
3466 * adding a cell to rectangular table changes non-rectangular table.
3467 * And if the cell containing selection is at left of row-spanning cell,
3468 * it may be moved to right side of the row-spanning cell after inserting
3469 * some cell elements before it. Similarly, colspan won't be adjusted
3470 * for keeping table rectangle.
3471 * Finally, puts caret into previous cell of the insertion point or the
3472 * first inserted cell if aPointToInsert is start of the row.
3474 * @param aPointToInsert The place to insert one or more cell
3475 * elements. The container must be a
3476 * <tr> element.
3477 * @param aNumberOfCellsToInsert Number of cells to insert.
3478 * @return The first inserted cell element and
3479 * start of the last inserted cell element
3480 * as a point to put caret.
3482 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
3483 InsertTableCellsWithTransaction(const EditorDOMPoint& aPointToInsert,
3484 int32_t aNumberOfCellsToInsert);
3487 * InsertTableColumnsWithTransaction() inserts cell elements to every rows
3488 * at same column index as the cell specified by aPointToInsert.
3490 * @param aNumberOfColumnsToInsert Number of columns to insert.
3492 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertTableColumnsWithTransaction(
3493 const EditorDOMPoint& aPointToInsert, int32_t aNumberOfColumnsToInsert);
3496 * InsertTableRowsWithTransaction() inserts <tr> elements before or after
3497 * aCellElement. When aCellElement spans rows and aInsertPosition is
3498 * eAfterSelectedCell, new rows will be inserted after the most-bottom row
3499 * which contains the cell.
3501 * @param aCellElement The cell element pinting where this will
3502 * insert a row before or after.
3503 * @param aNumberOfRowsToInsert Number of rows to insert.
3504 * @param aInsertPosition Before or after the target cell which
3505 * contains first selection range.
3507 MOZ_CAN_RUN_SCRIPT nsresult InsertTableRowsWithTransaction(
3508 Element& aCellElement, int32_t aNumberOfRowsToInsert,
3509 InsertPosition aInsertPosition);
3512 * Insert a new cell after or before supplied aCell.
3513 * Optional: If aNewCell supplied, returns the newly-created cell (addref'd,
3514 * of course)
3515 * This doesn't change or use the current selection.
3517 MOZ_CAN_RUN_SCRIPT nsresult InsertCell(Element* aCell, int32_t aRowSpan,
3518 int32_t aColSpan, bool aAfter,
3519 bool aIsHeader, Element** aNewCell);
3522 * DeleteSelectedTableColumnsWithTransaction() removes cell elements which
3523 * belong to same columns of selected cell elements.
3524 * If only one cell element is selected or first selection range is
3525 * in a cell, removes cell elements which belong to same column.
3526 * If 2 or more cell elements are selected, removes cell elements which
3527 * belong to any of all selected columns. In this case,
3528 * aNumberOfColumnsToDelete is ignored.
3529 * If there is no selection ranges, returns error.
3530 * If selection is not in a cell element, this does not return error,
3531 * just does nothing.
3532 * WARNING: This does not remove <col> nor <colgroup> elements.
3534 * @param aNumberOfColumnsToDelete Number of columns to remove. This is
3535 * ignored if 2 ore more cells are
3536 * selected.
3538 MOZ_CAN_RUN_SCRIPT nsresult
3539 DeleteSelectedTableColumnsWithTransaction(int32_t aNumberOfColumnsToDelete);
3542 * DeleteTableColumnWithTransaction() removes cell elements which belong
3543 * to the specified column.
3544 * This method adjusts colspan attribute value if cells spanning the
3545 * column to delete.
3546 * WARNING: This does not remove <col> nor <colgroup> elements.
3548 * @param aTableElement The <table> element which contains the
3549 * column which you want to remove.
3550 * @param aRowIndex Index of the column which you want to remove.
3551 * 0 is the first column.
3553 MOZ_CAN_RUN_SCRIPT nsresult DeleteTableColumnWithTransaction(
3554 Element& aTableElement, int32_t aColumnIndex);
3557 * DeleteSelectedTableRowsWithTransaction() removes <tr> elements.
3558 * If only one cell element is selected or first selection range is
3559 * in a cell, removes <tr> elements starting from a <tr> element
3560 * containing the selected cell or first selection range.
3561 * If 2 or more cell elements are selected, all <tr> elements
3562 * which contains selected cell(s). In this case, aNumberOfRowsToDelete
3563 * is ignored.
3564 * If there is no selection ranges, returns error.
3565 * If selection is not in a cell element, this does not return error,
3566 * just does nothing.
3568 * @param aNumberOfRowsToDelete Number of rows to remove. This is ignored
3569 * if 2 or more cells are selected.
3571 MOZ_CAN_RUN_SCRIPT nsresult
3572 DeleteSelectedTableRowsWithTransaction(int32_t aNumberOfRowsToDelete);
3575 * DeleteTableRowWithTransaction() removes a <tr> element whose index in
3576 * the <table> is aRowIndex.
3577 * This method adjusts rowspan attribute value if the <tr> element contains
3578 * cells which spans rows.
3580 * @param aTableElement The <table> element which contains the
3581 * <tr> element which you want to remove.
3582 * @param aRowIndex Index of the <tr> element which you want to
3583 * remove. 0 is the first row.
3585 MOZ_CAN_RUN_SCRIPT nsresult
3586 DeleteTableRowWithTransaction(Element& aTableElement, int32_t aRowIndex);
3589 * DeleteTableCellWithTransaction() removes table cell elements. If two or
3590 * more cell elements are selected, this removes all selected cell elements.
3591 * Otherwise, this removes some cell elements starting from selected cell
3592 * element or a cell containing first selection range. When this removes
3593 * last cell element in <tr> or <table>, this removes the <tr> or the
3594 * <table> too. Note that when removing a cell causes number of its row
3595 * becomes less than the others, this method does NOT fill the place with
3596 * rowspan nor colspan. This does not return error even if selection is not
3597 * in cell element, just does nothing.
3599 * @param aNumberOfCellsToDelete Number of cells to remove. This is ignored
3600 * if 2 or more cells are selected.
3602 MOZ_CAN_RUN_SCRIPT nsresult
3603 DeleteTableCellWithTransaction(int32_t aNumberOfCellsToDelete);
3606 * DeleteAllChildrenWithTransaction() removes all children of aElement from
3607 * the tree.
3609 * @param aElement The element whose children you want to remove.
3611 MOZ_CAN_RUN_SCRIPT nsresult
3612 DeleteAllChildrenWithTransaction(Element& aElement);
3615 * Move all contents from aCellToMerge into aTargetCell (append at end).
3617 MOZ_CAN_RUN_SCRIPT nsresult MergeCells(RefPtr<Element> aTargetCell,
3618 RefPtr<Element> aCellToMerge,
3619 bool aDeleteCellToMerge);
3622 * DeleteTableElementAndChildren() removes aTableElement (and its children)
3623 * from the DOM tree with transaction.
3625 * @param aTableElement The <table> element which you want to remove.
3627 MOZ_CAN_RUN_SCRIPT nsresult
3628 DeleteTableElementAndChildrenWithTransaction(Element& aTableElement);
3630 MOZ_CAN_RUN_SCRIPT nsresult SetColSpan(Element* aCell, int32_t aColSpan);
3631 MOZ_CAN_RUN_SCRIPT nsresult SetRowSpan(Element* aCell, int32_t aRowSpan);
3634 * Helper used to get nsTableWrapperFrame for a table.
3636 static nsTableWrapperFrame* GetTableFrame(const Element* aTable);
3639 * GetNumberOfCellsInRow() returns number of actual cell elements in the row.
3640 * If some cells appear by "rowspan" in other rows, they are ignored.
3642 * @param aTableElement The <table> element.
3643 * @param aRowIndex Valid row index in aTableElement. This method
3644 * counts cell elements in the row.
3645 * @return -1 if this meets unexpected error.
3646 * Otherwise, number of cells which this method found.
3648 int32_t GetNumberOfCellsInRow(Element& aTableElement, int32_t aRowIndex);
3651 * Test if all cells in row or column at given index are selected.
3653 bool AllCellsInRowSelected(Element* aTable, int32_t aRowIndex,
3654 int32_t aNumberOfColumns);
3655 bool AllCellsInColumnSelected(Element* aTable, int32_t aColIndex,
3656 int32_t aNumberOfRows);
3658 bool IsEmptyCell(Element* aCell);
3661 * Most insert methods need to get the same basic context data.
3662 * Any of the pointers may be null if you don't need that datum (for more
3663 * efficiency).
3664 * Input: *aCell is a known cell,
3665 * if null, cell is obtained from the anchor node of the selection.
3666 * Returns NS_EDITOR_ELEMENT_NOT_FOUND if cell is not found even if aCell is
3667 * null.
3669 MOZ_CAN_RUN_SCRIPT nsresult GetCellContext(Element** aTable, Element** aCell,
3670 nsINode** aCellParent,
3671 int32_t* aCellOffset,
3672 int32_t* aRowIndex,
3673 int32_t* aColIndex);
3675 nsresult GetCellSpansAt(Element* aTable, int32_t aRowIndex, int32_t aColIndex,
3676 int32_t& aActualRowSpan, int32_t& aActualColSpan);
3678 MOZ_CAN_RUN_SCRIPT nsresult SplitCellIntoColumns(
3679 Element* aTable, int32_t aRowIndex, int32_t aColIndex,
3680 int32_t aColSpanLeft, int32_t aColSpanRight, Element** aNewCell);
3682 MOZ_CAN_RUN_SCRIPT nsresult SplitCellIntoRows(
3683 Element* aTable, int32_t aRowIndex, int32_t aColIndex,
3684 int32_t aRowSpanAbove, int32_t aRowSpanBelow, Element** aNewCell);
3686 MOZ_CAN_RUN_SCRIPT nsresult CopyCellBackgroundColor(Element* aDestCell,
3687 Element* aSourceCell);
3690 * Reduce rowspan/colspan when cells span into nonexistent rows/columns.
3692 MOZ_CAN_RUN_SCRIPT nsresult FixBadRowSpan(Element* aTable, int32_t aRowIndex,
3693 int32_t& aNewRowCount);
3694 MOZ_CAN_RUN_SCRIPT nsresult FixBadColSpan(Element* aTable, int32_t aColIndex,
3695 int32_t& aNewColCount);
3698 * XXX NormalizeTableInternal() is broken. If it meets a cell which has
3699 * bigger or smaller rowspan or colspan than actual number of cells,
3700 * this always failed to scan the table. Therefore, this does nothing
3701 * when the table should be normalized.
3703 * @param aTableOrElementInTable An element which is in a <table> element
3704 * or <table> element itself. Otherwise,
3705 * this returns NS_OK but does nothing.
3707 MOZ_CAN_RUN_SCRIPT nsresult
3708 NormalizeTableInternal(Element& aTableOrElementInTable);
3711 * Fallback method: Call this after using ClearSelection() and you
3712 * failed to set selection to some other content in the document.
3714 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetSelectionAtDocumentStart();
3716 // Methods for handling plaintext quotations
3717 MOZ_CAN_RUN_SCRIPT nsresult PasteAsPlaintextQuotation(int32_t aSelectionType);
3720 * Insert a string as quoted text, replacing the selected text (if any).
3721 * @param aQuotedText The string to insert.
3722 * @param aAddCites Whether to prepend extra ">" to each line
3723 * (usually true, unless those characters
3724 * have already been added.)
3725 * @return aNodeInserted The node spanning the insertion, if applicable.
3726 * If aAddCites is false, this will be null.
3728 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertAsPlaintextQuotation(
3729 const nsAString& aQuotedText, bool aAddCites, nsINode** aNodeInserted);
3732 * InsertObject() inserts given object at aPointToInsert.
3734 * @param aType one of kFileMime, kJPEGImageMime, kJPGImageMime,
3735 * kPNGImageMime, kGIFImageMime.
3737 MOZ_CAN_RUN_SCRIPT nsresult InsertObject(
3738 const nsACString& aType, nsISupports* aObject,
3739 SafeToInsertData aSafeToInsertData, const EditorDOMPoint& aPointToInsert,
3740 DeleteSelectedContent aDeleteSelectedContent);
3742 class HTMLTransferablePreparer;
3743 nsresult PrepareHTMLTransferable(nsITransferable** aTransferable) const;
3745 enum class HavePrivateHTMLFlavor { No, Yes };
3746 MOZ_CAN_RUN_SCRIPT nsresult InsertFromTransferableAtSelection(
3747 nsITransferable* aTransferable, const nsAString& aContextStr,
3748 const nsAString& aInfoStr, HavePrivateHTMLFlavor aHavePrivateHTMLFlavor);
3751 * InsertFromDataTransfer() is called only when user drops data into
3752 * this editor. Don't use this method for other purposes.
3754 * @param aIndex index of aDataTransfer's item to insert.
3756 MOZ_CAN_RUN_SCRIPT nsresult InsertFromDataTransfer(
3757 const dom::DataTransfer* aDataTransfer, uint32_t aIndex,
3758 nsIPrincipal* aSourcePrincipal, const EditorDOMPoint& aDroppedAt,
3759 DeleteSelectedContent aDeleteSelectedContent);
3761 static HavePrivateHTMLFlavor ClipboardHasPrivateHTMLFlavor(
3762 nsIClipboard* clipboard);
3765 * CF_HTML:
3766 * <https://docs.microsoft.com/en-us/windows/win32/dataxchg/html-clipboard-format>.
3768 * @param[in] aCfhtml a CF_HTML string as defined above.
3769 * @param[out] aStuffToPaste the fragment, excluding context.
3770 * @param[out] aCfcontext the context, excluding the fragment, including a
3771 * marker (`kInsertionCookie`) indicating where the
3772 * fragment begins.
3774 nsresult ParseCFHTML(const nsCString& aCfhtml, char16_t** aStuffToPaste,
3775 char16_t** aCfcontext);
3778 * AutoHTMLFragmentBoundariesFixer fixes both edges of topmost child contents
3779 * which are created with SubtreeContentIterator.
3781 class MOZ_STACK_CLASS AutoHTMLFragmentBoundariesFixer final {
3782 public:
3784 * @param aArrayOfTopMostChildContents
3785 * [in/out] The topmost child contents which will be
3786 * inserted into the DOM tree. Both edges, i.e.,
3787 * first node and last node in this array will be
3788 * checked whether they can be inserted into
3789 * another DOM tree. If not, it'll replaces some
3790 * orphan nodes around nodes with proper parent.
3792 explicit AutoHTMLFragmentBoundariesFixer(
3793 nsTArray<OwningNonNull<nsIContent>>& aArrayOfTopMostChildContents);
3795 private:
3797 * EnsureBeginsOrEndsWithValidContent() replaces some nodes starting from
3798 * start or end with proper element node if it's necessary.
3799 * If first or last node of aArrayOfTopMostChildContents is in list and/or
3800 * `<table>` element, looks for topmost list element or `<table>` element
3801 * with `CollectTableAndAnyListElementsOfInclusiveAncestorsAt()` and
3802 * `GetMostDistantAncestorListOrTableElement()`. Then, checks
3803 * whether some nodes are in aArrayOfTopMostChildContents are the topmost
3804 * list/table element or its descendant and if so, removes the nodes from
3805 * aArrayOfTopMostChildContents and inserts the list/table element instead.
3806 * Then, aArrayOfTopMostChildContents won't start/end with list-item nor
3807 * table cells.
3809 enum class StartOrEnd { start, end };
3810 void EnsureBeginsOrEndsWithValidContent(
3811 StartOrEnd aStartOrEnd,
3812 nsTArray<OwningNonNull<nsIContent>>& aArrayOfTopMostChildContents)
3813 const;
3816 * CollectTableAndAnyListElementsOfInclusiveAncestorsAt() collects list
3817 * elements and table related elements from the inclusive ancestors
3818 * (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) of aNode.
3820 static void CollectTableAndAnyListElementsOfInclusiveAncestorsAt(
3821 nsIContent& aContent,
3822 nsTArray<OwningNonNull<Element>>& aOutArrayOfListAndTableElements);
3825 * GetMostDistantAncestorListOrTableElement() returns a list or a
3826 * `<table>` element which is in
3827 * aInclusiveAncestorsTableOrListElements and they are actually
3828 * valid ancestor of at least one of aArrayOfTopMostChildContents.
3830 static Element* GetMostDistantAncestorListOrTableElement(
3831 const nsTArray<OwningNonNull<nsIContent>>& aArrayOfTopMostChildContents,
3832 const nsTArray<OwningNonNull<Element>>&
3833 aInclusiveAncestorsTableOrListElements);
3836 * FindReplaceableTableElement() is a helper method of
3837 * EnsureBeginsOrEndsWithValidContent(). If aNodeMaybeInTableElement is
3838 * a descendant of aTableElement, returns aNodeMaybeInTableElement or its
3839 * nearest ancestor whose tag name is `<td>`, `<th>`, `<tr>`, `<thead>`,
3840 * `<tfoot>`, `<tbody>` or `<caption>`.
3842 * @param aTableElement Must be a `<table>` element.
3843 * @param aContentMaybeInTableElement A node which may be in aTableElement.
3845 Element* FindReplaceableTableElement(
3846 Element& aTableElement, nsIContent& aContentMaybeInTableElement) const;
3849 * IsReplaceableListElement() is a helper method of
3850 * EnsureBeginsOrEndsWithValidContent(). If aNodeMaybeInListElement is a
3851 * descendant of aListElement, returns true. Otherwise, false.
3853 * @param aListElement Must be a list element.
3854 * @param aContentMaybeInListElement A node which may be in aListElement.
3856 bool IsReplaceableListElement(Element& aListElement,
3857 nsIContent& aContentMaybeInListElement) const;
3861 * MakeDefinitionListItemWithTransaction() replaces parent list of current
3862 * selection with <dl> or create new <dl> element and creates a definition
3863 * list item whose name is aTagName.
3865 * @param aTagName Must be nsGkAtoms::dt or nsGkAtoms::dd.
3867 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3868 MakeDefinitionListItemWithTransaction(nsAtom& aTagName);
3871 * FormatBlockContainerAsSubAction() inserts a block element whose name
3872 * is aTagName at selection. If selection is not collapsed and aTagName is
3873 * nsGkAtoms::normal or nsGkAtoms::_empty, this removes block containers.
3875 * @param aTagName A block level element name. Must NOT be
3876 * nsGkAtoms::dt nor nsGkAtoms::dd.
3877 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
3878 * paragraphState command.
3880 MOZ_CAN_RUN_SCRIPT nsresult FormatBlockContainerAsSubAction(
3881 const nsStaticAtom& aTagName, FormatBlockMode aFormatBlockMode);
3884 * Increase/decrease the font size of selection.
3886 MOZ_CAN_RUN_SCRIPT nsresult
3887 IncrementOrDecrementFontSizeAsSubAction(FontSize aIncrementOrDecrement);
3890 * Wrap aContent in <big> or <small> element and make children of
3891 * <font size=n> wrap with <big> or <small> too. Note that if there is
3892 * opposite element for aIncrementOrDecrement, their children will be just
3893 * unwrapped.
3895 * @param aDir Whether increase or decrease the font size of aContent.
3896 * @param aContent The content node whose font size will be changed.
3897 * @return A suggest point to put caret.
3899 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
3900 SetFontSizeWithBigOrSmallElement(nsIContent& aContent,
3901 FontSize aIncrementOrDecrement);
3904 * Adjust font size of font element children recursively with handling
3905 * <big> and <small> elements.
3907 * @param aDir Whether increase or decrease the font size of aContent.
3908 * @param aContent The content node whose font size will be changed.
3909 * All descendants will be handled recursively.
3910 * @return A suggest point to put caret.
3912 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
3913 SetFontSizeOfFontElementChildren(nsIContent& aContent,
3914 FontSize aIncrementOrDecrement);
3917 * Get extended range to select element whose all children are selected by
3918 * aRange.
3920 EditorRawDOMRange GetExtendedRangeWrappingEntirelySelectedElements(
3921 const EditorRawDOMRange& aRange) const;
3924 * Get extended range to select ancestor <a name> elements.
3926 EditorRawDOMRange GetExtendedRangeWrappingNamedAnchor(
3927 const EditorRawDOMRange& aRange) const;
3929 // Declared in HTMLEditorNestedClasses.h and defined in HTMLStyleEditor.cpp
3930 class AutoInlineStyleSetter;
3933 * RemoveStyleInside() removes elements which represent aStyleToRemove
3934 * and removes CSS style. This handles aElement and all its descendants
3935 * (including leaf text nodes) recursively.
3936 * TODO: Rename this to explain that this maybe remove aElement from the DOM
3937 * tree.
3939 * @param aSpecifiedStyle Whether the class and style attributes should
3940 * be preserved or discarded.
3941 * @return A suggest point to put caret.
3943 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
3944 RemoveStyleInside(Element& aElement, const EditorInlineStyle& aStyleToRemove,
3945 SpecifiedStyle aSpecifiedStyle);
3948 * CollectEditableLeafTextNodes() collects text nodes in aElement.
3950 void CollectEditableLeafTextNodes(
3951 Element& aElement, nsTArray<OwningNonNull<Text>>& aLeafTextNodes) const;
3954 * IsRemovableParentStyleWithNewSpanElement() checks whether aStyle of parent
3955 * block can be removed from aContent with creating `<span>` element. Note
3956 * that this does NOT check whether the specified style comes from parent
3957 * block or not.
3958 * XXX This may destroy the editor, but using `Result<bool, nsresult>`
3959 * is not reasonable because code for accessing the result becomes
3960 * messy. However, anybody must forget to check `Destroyed()` after
3961 * calling this. Which is the way to smart to make every caller
3962 * must check the editor state?
3964 MOZ_CAN_RUN_SCRIPT Result<bool, nsresult>
3965 IsRemovableParentStyleWithNewSpanElement(
3966 nsIContent& aContent, const EditorInlineStyle& aStyle) const;
3969 * HasStyleOrIdOrClassAttribute() returns true when at least one of
3970 * `style`, `id` or `class` attribute value of aElement is not empty.
3972 static bool HasStyleOrIdOrClassAttribute(Element& aElement);
3975 * Whether the outer window of the DOM event target has focus or not.
3977 bool OurWindowHasFocus() const;
3979 class HTMLWithContextInserter;
3982 * This function is used to insert a string of HTML input optionally with some
3983 * context information into the editable field. The HTML input either comes
3984 * from a transferable object created as part of a drop/paste operation, or
3985 * from the InsertHTML method. We may want the HTML input to be sanitized
3986 * (for example, if it's coming from a transferable object), in which case
3987 * aTrustedInput should be set to false, otherwise, the caller should set it
3988 * to true, which means that the HTML will be inserted in the DOM verbatim.
3990 enum class InlineStylesAtInsertionPoint {
3991 Preserve, // If you want the paste to be affected by local style, e.g.,
3992 // for the insertHTML command, use "Preserve"
3993 Clear, // If you want the paste to be keep its own style, e.g., pasting
3994 // from clipboard, use "Clear"
3996 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertHTMLWithContextAsSubAction(
3997 const nsAString& aInputString, const nsAString& aContextStr,
3998 const nsAString& aInfoStr, const nsAString& aFlavor,
3999 SafeToInsertData aSafeToInsertData, const EditorDOMPoint& aPointToInsert,
4000 DeleteSelectedContent aDeleteSelectedContent,
4001 InlineStylesAtInsertionPoint aInlineStylesAtInsertionPoint);
4004 * sets the position of an element; warning it does NOT check if the
4005 * element is already positioned or not and that's on purpose.
4006 * @param aStyledElement [IN] the element
4007 * @param aX [IN] the x position in pixels.
4008 * @param aY [IN] the y position in pixels.
4010 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetTopAndLeftWithTransaction(
4011 nsStyledElement& aStyledElement, int32_t aX, int32_t aY);
4014 * Reset a selected cell or collapsed selection (the caret) after table
4015 * editing.
4017 * @param aTable A table in the document.
4018 * @param aRow The row ...
4019 * @param aCol ... and column defining the cell where we will try to
4020 * place the caret.
4021 * @param aSelected If true, we select the whole cell instead of setting
4022 * caret.
4023 * @param aDirection If cell at (aCol, aRow) is not found, search for
4024 * previous cell in the same column (aPreviousColumn) or
4025 * row (ePreviousRow) or don't search for another cell
4026 * (aNoSearch). If no cell is found, caret is place just
4027 * before table; and if that fails, at beginning of
4028 * document. Thus we generally don't worry about the
4029 * return value and can use the
4030 * AutoSelectionSetterAfterTableEdit stack-based object to
4031 * insure we reset the caret in a table-editing method.
4033 MOZ_CAN_RUN_SCRIPT void SetSelectionAfterTableEdit(Element* aTable,
4034 int32_t aRow, int32_t aCol,
4035 int32_t aDirection,
4036 bool aSelected);
4038 void RemoveListenerAndDeleteRef(const nsAString& aEvent,
4039 nsIDOMEventListener* aListener,
4040 bool aUseCapture, ManualNACPtr aElement,
4041 PresShell* aPresShell);
4042 void DeleteRefToAnonymousNode(ManualNACPtr aContent, PresShell* aPresShell);
4045 * RefreshEditingUI() may refresh editing UIs for current Selection, focus,
4046 * etc. If this shows or hides some UIs, it causes reflow. So, this is
4047 * not safe method.
4049 MOZ_CAN_RUN_SCRIPT nsresult RefreshEditingUI();
4052 * Returns the offset of an element's frame to its absolute containing block.
4054 nsresult GetElementOrigin(Element& aElement, int32_t& aX, int32_t& aY);
4055 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetPositionAndDimensions(
4056 Element& aElement, int32_t& aX, int32_t& aY, int32_t& aW, int32_t& aH,
4057 int32_t& aBorderLeft, int32_t& aBorderTop, int32_t& aMarginLeft,
4058 int32_t& aMarginTop);
4060 bool IsInObservedSubtree(nsIContent* aChild);
4062 void UpdateRootElement();
4065 * SetAllResizersPosition() moves all resizers to proper position.
4066 * If the resizers are hidden or replaced with another set of resizers
4067 * while this is running, this returns error. So, callers shouldn't
4068 * keep handling the resizers if this returns error.
4070 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetAllResizersPosition();
4073 * Shows active resizers around an element's frame
4074 * @param aResizedElement [IN] a DOM Element
4076 MOZ_CAN_RUN_SCRIPT nsresult ShowResizersInternal(Element& aResizedElement);
4079 * Hide resizers if they are visible. If this is called while there is no
4080 * visible resizers, this does not return error, but does nothing.
4082 nsresult HideResizersInternal();
4085 * RefreshResizersInternal() moves resizers to proper position. This does
4086 * nothing if there is no resizing target.
4088 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RefreshResizersInternal();
4090 ManualNACPtr CreateResizer(int16_t aLocation, nsIContent& aParentContent);
4091 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4092 SetAnonymousElementPositionWithoutTransaction(nsStyledElement& aStyledElement,
4093 int32_t aX, int32_t aY);
4095 ManualNACPtr CreateShadow(nsIContent& aParentContent,
4096 Element& aOriginalObject);
4099 * SetShadowPosition() moves the shadow element to proper position.
4101 * @param aShadowElement Must be mResizingShadow or mPositioningShadow.
4102 * @param aElement The element which has the shadow.
4103 * @param aElementX Left of aElement.
4104 * @param aElementY Top of aElement.
4106 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4107 SetShadowPosition(Element& aShadowElement, Element& aElement,
4108 int32_t aElementLeft, int32_t aElementTop);
4110 ManualNACPtr CreateResizingInfo(nsIContent& aParentContent);
4111 MOZ_CAN_RUN_SCRIPT nsresult SetResizingInfoPosition(int32_t aX, int32_t aY,
4112 int32_t aW, int32_t aH);
4114 enum class ResizeAt {
4117 eWidth,
4118 eHeight,
4120 [[nodiscard]] int32_t GetNewResizingIncrement(int32_t aX, int32_t aY,
4121 ResizeAt aResizeAt) const;
4123 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult StartResizing(Element& aHandle);
4124 int32_t GetNewResizingX(int32_t aX, int32_t aY);
4125 int32_t GetNewResizingY(int32_t aX, int32_t aY);
4126 int32_t GetNewResizingWidth(int32_t aX, int32_t aY);
4127 int32_t GetNewResizingHeight(int32_t aX, int32_t aY);
4128 void HideShadowAndInfo();
4129 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4130 SetFinalSizeWithTransaction(int32_t aX, int32_t aY);
4131 void SetResizeIncrements(int32_t aX, int32_t aY, int32_t aW, int32_t aH,
4132 bool aPreserveRatio);
4135 * HideAnonymousEditingUIs() forcibly hides all editing UIs (resizers,
4136 * inline-table-editing UI, absolute positioning UI).
4138 void HideAnonymousEditingUIs();
4141 * HideAnonymousEditingUIsIfUnnecessary() hides all editing UIs if some of
4142 * visible UIs are now unnecessary.
4144 void HideAnonymousEditingUIsIfUnnecessary();
4147 * sets the z-index of an element.
4148 * @param aElement [IN] the element
4149 * @param aZorder [IN] the z-index
4151 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4152 SetZIndexWithTransaction(nsStyledElement& aElement, int32_t aZIndex);
4155 * shows a grabber attached to an arbitrary element. The grabber is an image
4156 * positioned on the left hand side of the top border of the element. Draggin
4157 * and dropping it allows to change the element's absolute position in the
4158 * document. See chrome://editor/content/images/grabber.gif
4159 * @param aElement [IN] the element
4161 MOZ_CAN_RUN_SCRIPT nsresult ShowGrabberInternal(Element& aElement);
4164 * Setting grabber to proper position for current mAbsolutelyPositionedObject.
4165 * For example, while an element has grabber, the element may be resized
4166 * or repositioned by script or something. Then, you need to reset grabber
4167 * position with this.
4169 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RefreshGrabberInternal();
4172 * hide the grabber if it shown.
4174 void HideGrabberInternal();
4177 * CreateGrabberInternal() creates a grabber for moving aParentContent.
4178 * This sets mGrabber to the new grabber. If this returns true, it's
4179 * always non-nullptr. Otherwise, i.e., the grabber is hidden during
4180 * creation, this returns false.
4182 bool CreateGrabberInternal(nsIContent& aParentContent);
4184 MOZ_CAN_RUN_SCRIPT nsresult StartMoving();
4185 MOZ_CAN_RUN_SCRIPT nsresult SetFinalPosition(int32_t aX, int32_t aY);
4186 void SnapToGrid(int32_t& newX, int32_t& newY) const;
4187 nsresult GrabberClicked();
4188 MOZ_CAN_RUN_SCRIPT nsresult EndMoving();
4189 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4190 GetTemporaryStyleForFocusedPositionedElement(Element& aElement,
4191 nsAString& aReturn);
4194 * Shows inline table editing UI around a <table> element which contains
4195 * aCellElement. This returns error if creating UI is hidden during this,
4196 * or detects another set of UI during this. In such case, callers
4197 * shouldn't keep handling anything for the UI.
4199 * @param aCellElement Must be an <td> or <th> element.
4201 MOZ_CAN_RUN_SCRIPT nsresult
4202 ShowInlineTableEditingUIInternal(Element& aCellElement);
4205 * Hide all inline table editing UI.
4207 void HideInlineTableEditingUIInternal();
4210 * RefreshInlineTableEditingUIInternal() moves inline table editing UI to
4211 * proper position. This returns error if the UI is hidden or replaced
4212 * during moving.
4214 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4215 RefreshInlineTableEditingUIInternal();
4217 enum class ContentNodeIs { Inserted, Appended };
4218 MOZ_CAN_RUN_SCRIPT void DoContentInserted(nsIContent* aChild,
4219 ContentNodeIs aContentNodeIs);
4222 * Returns an anonymous Element of type aTag,
4223 * child of aParentContent. If aIsCreatedHidden is true, the class
4224 * "hidden" is added to the created element. If aAnonClass is not
4225 * the empty string, it becomes the value of the attribute "_moz_anonclass"
4226 * @return a Element
4227 * @param aTag [IN] desired type of the element to create
4228 * @param aParentContent [IN] the parent node of the created anonymous
4229 * element
4230 * @param aAnonClass [IN] contents of the _moz_anonclass attribute
4231 * @param aIsCreatedHidden [IN] a boolean specifying if the class "hidden"
4232 * is to be added to the created anonymous
4233 * element
4235 ManualNACPtr CreateAnonymousElement(nsAtom* aTag, nsIContent& aParentContent,
4236 const nsAString& aAnonClass,
4237 bool aIsCreatedHidden);
4240 * Reads a blob into memory and notifies the BlobReader object when the read
4241 * operation is finished.
4243 * @param aBlob The input blob
4244 * @param aGlobal The global object under which the read should happen.
4245 * @param aBlobReader The blob reader object to be notified when finished.
4247 static nsresult SlurpBlob(dom::Blob* aBlob, nsIGlobalObject* aGlobal,
4248 BlobReader* aBlobReader);
4251 * OnModifyDocumentInternal() is called by OnModifyDocument().
4253 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult OnModifyDocumentInternal();
4256 * For saving allocation cost in the constructor of
4257 * EditorBase::TopLevelEditSubActionData, we should reuse same RangeItem
4258 * instance with all top level edit sub actions.
4259 * The instance is always cleared when TopLevelEditSubActionData is
4260 * destructed and the class is stack only class so that we don't need
4261 * to (and also should not) add the RangeItem into the cycle collection.
4263 [[nodiscard]] inline already_AddRefed<RangeItem>
4264 GetSelectedRangeItemForTopLevelEditSubAction() const;
4267 * For saving allocation cost in the constructor of
4268 * EditorBase::TopLevelEditSubActionData, we should reuse same nsRange
4269 * instance with all top level edit sub actions.
4270 * The instance is always cleared when TopLevelEditSubActionData is
4271 * destructed, but AbstractRange::mOwner keeps grabbing the owner document
4272 * so that we need to make it in the cycle collection.
4274 [[nodiscard]] inline already_AddRefed<nsRange>
4275 GetChangedRangeForTopLevelEditSubAction() const;
4277 MOZ_CAN_RUN_SCRIPT void DidDoTransaction(
4278 TransactionManager& aTransactionManager, nsITransaction& aTransaction,
4279 nsresult aDoTransactionResult) {
4280 if (mComposerCommandsUpdater) {
4281 RefPtr<ComposerCommandsUpdater> updater(mComposerCommandsUpdater);
4282 updater->DidDoTransaction(aTransactionManager);
4286 MOZ_CAN_RUN_SCRIPT void DidUndoTransaction(
4287 TransactionManager& aTransactionManager, nsITransaction& aTransaction,
4288 nsresult aUndoTransactionResult) {
4289 if (mComposerCommandsUpdater) {
4290 RefPtr<ComposerCommandsUpdater> updater(mComposerCommandsUpdater);
4291 updater->DidUndoTransaction(aTransactionManager);
4295 MOZ_CAN_RUN_SCRIPT void DidRedoTransaction(
4296 TransactionManager& aTransactionManager, nsITransaction& aTransaction,
4297 nsresult aRedoTransactionResult) {
4298 if (mComposerCommandsUpdater) {
4299 RefPtr<ComposerCommandsUpdater> updater(mComposerCommandsUpdater);
4300 updater->DidRedoTransaction(aTransactionManager);
4304 protected:
4306 * IndentListChildWithTransaction() is a helper method of
4307 * Handle(CSS|HTML)IndentAtSelectionInternal().
4309 * @param aSubListElement [in/out] Specify a sub-list element of the
4310 * container of aPointInListElement or nullptr.
4311 * When there is no proper sub-list element to
4312 * move aContentMovingToSubList, this method
4313 * inserts a new sub-list element and update this
4314 * to it.
4315 * @param aPointInListElement A point in a list element whose child should
4316 * be indented. If this method creates new list
4317 * element into the list element, this inserts
4318 * the new list element to this point.
4319 * @param aContentMovingToSubList
4320 * A content node which is a child of a list
4321 * element and should be moved into a sub-list
4322 * element.
4323 * @param aEditingHost The editing host.
4324 * @return A candidate caret position.
4326 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
4327 IndentListChildWithTransaction(RefPtr<Element>* aSubListElement,
4328 const EditorDOMPoint& aPointInListElement,
4329 nsIContent& aContentMovingToSubList,
4330 const Element& aEditingHost);
4333 * Stack based helper class for saving/restoring selection. Note that this
4334 * assumes that the nodes involved are still around afterwords!
4336 class AutoSelectionRestorer final {
4337 public:
4338 AutoSelectionRestorer() = delete;
4339 explicit AutoSelectionRestorer(const AutoSelectionRestorer& aOther) =
4340 delete;
4341 AutoSelectionRestorer(AutoSelectionRestorer&& aOther) = delete;
4344 * Constructor responsible for remembering all state needed to restore
4345 * aSelection.
4346 * XXX This constructor and the destructor should be marked as
4347 * `MOZ_CAN_RUN_SCRIPT`, but it's impossible due to this may be used
4348 * with `Maybe`.
4350 MOZ_CAN_RUN_SCRIPT_BOUNDARY explicit AutoSelectionRestorer(
4351 HTMLEditor& aHTMLEditor);
4354 * Destructor restores mSelection to its former state
4356 MOZ_CAN_RUN_SCRIPT_BOUNDARY ~AutoSelectionRestorer();
4359 * Abort() cancels to restore the selection.
4361 void Abort();
4363 bool MaybeRestoreSelectionLater() const { return !!mHTMLEditor; }
4365 protected:
4366 // The lifetime must be guaranteed by the creator of this instance.
4367 MOZ_KNOWN_LIVE HTMLEditor* mHTMLEditor = nullptr;
4371 * Stack based helper class for calling EditorBase::EndTransactionInternal().
4372 * NOTE: This does not suppress multiple input events. In most cases,
4373 * only one "input" event should be fired for an edit action rather
4374 * than per edit sub-action. In such case, you should use
4375 * EditorBase::AutoPlaceholderBatch instead.
4377 class MOZ_RAII AutoTransactionBatch final {
4378 public:
4380 * @param aRequesterFuncName function name which wants to end the batch.
4381 * This won't be stored nor exposed to selection listeners etc, used only
4382 * for logging. This MUST be alive when the destructor runs.
4384 MOZ_CAN_RUN_SCRIPT explicit AutoTransactionBatch(
4385 HTMLEditor& aHTMLEditor, const char* aRequesterFuncName)
4386 : mHTMLEditor(aHTMLEditor), mRequesterFuncName(aRequesterFuncName) {
4387 MOZ_KnownLive(mHTMLEditor).BeginTransactionInternal(mRequesterFuncName);
4390 MOZ_CAN_RUN_SCRIPT ~AutoTransactionBatch() {
4391 MOZ_KnownLive(mHTMLEditor).EndTransactionInternal(mRequesterFuncName);
4394 protected:
4395 // The lifetime must be guaranteed by the creator of this instance.
4396 MOZ_KNOWN_LIVE HTMLEditor& mHTMLEditor;
4397 const char* const mRequesterFuncName;
4400 RefPtr<PendingStyles> mPendingStylesToApplyToNewContent;
4401 RefPtr<ComposerCommandsUpdater> mComposerCommandsUpdater;
4403 // Used by TopLevelEditSubActionData::mSelectedRange.
4404 mutable RefPtr<RangeItem> mSelectedRangeForTopLevelEditSubAction;
4405 // Used by TopLevelEditSubActionData::mChangedRange.
4406 mutable RefPtr<nsRange> mChangedRangeForTopLevelEditSubAction;
4408 RefPtr<Runnable> mPendingRootElementUpdatedRunner;
4409 RefPtr<Runnable> mPendingDocumentModifiedRunner;
4411 // mPaddingBRElementForEmptyEditor should be used for placing caret
4412 // at proper position when editor is empty.
4413 RefPtr<dom::HTMLBRElement> mPaddingBRElementForEmptyEditor;
4415 bool mCRInParagraphCreatesParagraph;
4417 // resizing
4418 bool mIsObjectResizingEnabled;
4419 bool mIsResizing;
4420 bool mPreserveRatio;
4421 bool mResizedObjectIsAnImage;
4423 // absolute positioning
4424 bool mIsAbsolutelyPositioningEnabled;
4425 bool mResizedObjectIsAbsolutelyPositioned;
4426 bool mGrabberClicked;
4427 bool mIsMoving;
4429 bool mSnapToGridEnabled;
4431 // inline table editing
4432 bool mIsInlineTableEditingEnabled;
4434 bool mIsCSSPrefChecked;
4436 // resizing
4437 ManualNACPtr mTopLeftHandle;
4438 ManualNACPtr mTopHandle;
4439 ManualNACPtr mTopRightHandle;
4440 ManualNACPtr mLeftHandle;
4441 ManualNACPtr mRightHandle;
4442 ManualNACPtr mBottomLeftHandle;
4443 ManualNACPtr mBottomHandle;
4444 ManualNACPtr mBottomRightHandle;
4446 RefPtr<Element> mActivatedHandle;
4448 ManualNACPtr mResizingShadow;
4449 ManualNACPtr mResizingInfo;
4451 RefPtr<Element> mResizedObject;
4453 int32_t mOriginalX;
4454 int32_t mOriginalY;
4456 int32_t mResizedObjectX;
4457 int32_t mResizedObjectY;
4458 int32_t mResizedObjectWidth;
4459 int32_t mResizedObjectHeight;
4461 int32_t mResizedObjectMarginLeft;
4462 int32_t mResizedObjectMarginTop;
4463 int32_t mResizedObjectBorderLeft;
4464 int32_t mResizedObjectBorderTop;
4466 int32_t mXIncrementFactor;
4467 int32_t mYIncrementFactor;
4468 int32_t mWidthIncrementFactor;
4469 int32_t mHeightIncrementFactor;
4471 int8_t mInfoXIncrement;
4472 int8_t mInfoYIncrement;
4474 // absolute positioning
4475 int32_t mPositionedObjectX;
4476 int32_t mPositionedObjectY;
4477 int32_t mPositionedObjectWidth;
4478 int32_t mPositionedObjectHeight;
4480 int32_t mPositionedObjectMarginLeft;
4481 int32_t mPositionedObjectMarginTop;
4482 int32_t mPositionedObjectBorderLeft;
4483 int32_t mPositionedObjectBorderTop;
4485 RefPtr<Element> mAbsolutelyPositionedObject;
4486 ManualNACPtr mGrabber;
4487 ManualNACPtr mPositioningShadow;
4489 int32_t mGridSize;
4491 // inline table editing
4492 RefPtr<Element> mInlineEditedCell;
4494 ManualNACPtr mAddColumnBeforeButton;
4495 ManualNACPtr mRemoveColumnButton;
4496 ManualNACPtr mAddColumnAfterButton;
4498 ManualNACPtr mAddRowBeforeButton;
4499 ManualNACPtr mRemoveRowButton;
4500 ManualNACPtr mAddRowAfterButton;
4502 void AddMouseClickListener(Element* aElement);
4503 void RemoveMouseClickListener(Element* aElement);
4505 bool mDisabledLinkHandling = false;
4506 bool mOldLinkHandlingEnabled = false;
4508 bool mHasBeforeInputBeenCanceled = false;
4510 ParagraphSeparator mDefaultParagraphSeparator;
4512 friend class AlignStateAtSelection; // CollectEditableTargetNodes,
4513 // CollectNonEditableNodes
4514 friend class AutoRangeArray; // RangeUpdaterRef, SplitNodeWithTransaction,
4515 // SplitInlineAncestorsAtRangeBoundaries
4516 friend class AutoSelectionSetterAfterTableEdit; // SetSelectionAfterEdit
4517 friend class
4518 AutoSetTemporaryAncestorLimiter; // InitializeSelectionAncestorLimit
4519 friend class CSSEditUtils; // DoTransactionInternal, HasAttributes,
4520 // RemoveContainerWithTransaction
4521 friend class EditorBase; // ComputeTargetRanges,
4522 // GetChangedRangeForTopLevelEditSubAction,
4523 // GetSelectedRangeItemForTopLevelEditSubAction,
4524 // MaybeCreatePaddingBRElementForEmptyEditor,
4525 // PrepareToInsertBRElement,
4526 // ReflectPaddingBRElementForEmptyEditor,
4527 // RefreshEditingUI,
4528 // RemoveEmptyInclusiveAncestorInlineElements,
4529 // mComposerUpdater, mHasBeforeInputBeenCanceled
4530 friend class JoinNodesTransaction; // DidJoinNodesTransaction, DoJoinNodes,
4531 // DoSplitNode, // RangeUpdaterRef
4532 friend class ListElementSelectionState; // CollectEditTargetNodes,
4533 // CollectNonEditableNodes
4534 friend class ListItemElementSelectionState; // CollectEditTargetNodes,
4535 // CollectNonEditableNodes
4536 friend class MoveNodeTransaction; // AllowsTransactionsToChangeSelection,
4537 // CollapseSelectionTo, MarkElementDirty,
4538 // RangeUpdaterRef
4539 friend class ParagraphStateAtSelection; // CollectChildren,
4540 // CollectEditTargetNodes,
4541 // CollectListChildren,
4542 // CollectNonEditableNodes,
4543 // CollectTableChildren
4544 friend class SlurpBlobEventListener; // BlobReader
4545 friend class SplitNodeTransaction; // DoJoinNodes, DoSplitNode
4546 friend class TransactionManager; // DidDoTransaction, DidRedoTransaction,
4547 // DidUndoTransaction
4548 friend class
4549 WhiteSpaceVisibilityKeeper; // AutoMoveOneLineHandler
4550 // CanMoveChildren,
4551 // ChangeListElementType,
4552 // DeleteNodeWithTransaction,
4553 // DeleteTextAndTextNodesWithTransaction,
4554 // JoinNearestEditableNodesWithTransaction,
4555 // MoveChildrenWithTransaction,
4556 // SplitAncestorStyledInlineElementsAt,
4557 // TreatEmptyTextNodes
4561 * ListElementSelectionState class gets which list element is selected right
4562 * now.
4564 class MOZ_STACK_CLASS ListElementSelectionState final {
4565 public:
4566 ListElementSelectionState() = delete;
4567 ListElementSelectionState(HTMLEditor& aHTMLEditor, ErrorResult& aRv);
4569 bool IsOLElementSelected() const { return mIsOLElementSelected; }
4570 bool IsULElementSelected() const { return mIsULElementSelected; }
4571 bool IsDLElementSelected() const { return mIsDLElementSelected; }
4572 bool IsNotOneTypeListElementSelected() const {
4573 return (mIsOLElementSelected + mIsULElementSelected + mIsDLElementSelected +
4574 mIsOtherContentSelected) > 1;
4577 private:
4578 bool mIsOLElementSelected = false;
4579 bool mIsULElementSelected = false;
4580 bool mIsDLElementSelected = false;
4581 bool mIsOtherContentSelected = false;
4585 * ListItemElementSelectionState class gets which list item element is selected
4586 * right now.
4588 class MOZ_STACK_CLASS ListItemElementSelectionState final {
4589 public:
4590 ListItemElementSelectionState() = delete;
4591 ListItemElementSelectionState(HTMLEditor& aHTMLEditor, ErrorResult& aRv);
4593 bool IsLIElementSelected() const { return mIsLIElementSelected; }
4594 bool IsDTElementSelected() const { return mIsDTElementSelected; }
4595 bool IsDDElementSelected() const { return mIsDDElementSelected; }
4596 bool IsNotOneTypeDefinitionListItemElementSelected() const {
4597 return (mIsDTElementSelected + mIsDDElementSelected +
4598 mIsOtherElementSelected) > 1;
4601 private:
4602 bool mIsLIElementSelected = false;
4603 bool mIsDTElementSelected = false;
4604 bool mIsDDElementSelected = false;
4605 bool mIsOtherElementSelected = false;
4609 * AlignStateAtSelection class gets alignment at selection.
4610 * XXX This currently returns only first alignment.
4612 class MOZ_STACK_CLASS AlignStateAtSelection final {
4613 public:
4614 AlignStateAtSelection() = delete;
4615 MOZ_CAN_RUN_SCRIPT AlignStateAtSelection(HTMLEditor& aHTMLEditor,
4616 ErrorResult& aRv);
4618 nsIHTMLEditor::EAlignment AlignmentAtSelectionStart() const {
4619 return mFirstAlign;
4621 bool IsSelectionRangesFound() const { return mFoundSelectionRanges; }
4623 private:
4624 nsIHTMLEditor::EAlignment mFirstAlign = nsIHTMLEditor::eLeft;
4625 bool mFoundSelectionRanges = false;
4629 * ParagraphStateAtSelection class gets format block types around selection.
4631 class MOZ_STACK_CLASS ParagraphStateAtSelection final {
4632 public:
4633 using FormatBlockMode = HTMLEditor::FormatBlockMode;
4635 ParagraphStateAtSelection() = delete;
4637 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4638 * paragraphState command.
4640 ParagraphStateAtSelection(HTMLEditor& aHTMLEditor,
4641 FormatBlockMode aFormatBlockMode, ErrorResult& aRv);
4644 * GetFirstParagraphStateAtSelection() returns:
4645 * - nullptr if there is no format blocks nor inline nodes.
4646 * - nsGkAtoms::_empty if first node is not in any format block.
4647 * - a tag name of format block at first node.
4648 * XXX See the private method explanations. If selection ranges contains
4649 * non-format block first, it'll be check after its siblings. Therefore,
4650 * this may return non-first paragraph state.
4652 nsAtom* GetFirstParagraphStateAtSelection() const {
4653 return mIsMixed && mIsInDLElement ? nsGkAtoms::dl
4654 : mFirstParagraphState.get();
4658 * If selected nodes are not in same format node nor only in no-format blocks,
4659 * this returns true.
4661 bool IsMixed() const { return mIsMixed && !mIsInDLElement; }
4663 private:
4664 using EditorType = EditorBase::EditorType;
4666 [[nodiscard]] static bool IsFormatElement(FormatBlockMode aFormatBlockMode,
4667 const nsIContent& aContent);
4670 * AppendDescendantFormatNodesAndFirstInlineNode() appends descendant
4671 * format blocks and first inline child node in aNonFormatBlockElement to
4672 * the last of the array (not inserting where aNonFormatBlockElement is,
4673 * so that the node order becomes randomly).
4675 * @param aArrayOfContents [in/out] Found descendant format blocks
4676 * and first inline node in each non-format
4677 * block will be appended to this.
4678 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4679 * paragraphState command.
4680 * @param aNonFormatBlockElement Must be a non-format block element.
4682 static void AppendDescendantFormatNodesAndFirstInlineNode(
4683 nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
4684 FormatBlockMode aFormatBlockMode, dom::Element& aNonFormatBlockElement);
4687 * CollectEditableFormatNodesInSelection() collects only editable nodes
4688 * around selection ranges (with `AutoRangeArray::ExtendRangesToWrapLines()`
4689 * and `HTMLEditor::CollectEditTargetNodes()`, see its document for the
4690 * detail). If it includes list, list item or table related elements, they
4691 * will be replaced their children.
4693 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4694 * paragraphState command.
4696 static nsresult CollectEditableFormatNodesInSelection(
4697 HTMLEditor& aHTMLEditor, FormatBlockMode aFormatBlockMode,
4698 const dom::Element& aEditingHost,
4699 nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents);
4701 RefPtr<nsAtom> mFirstParagraphState;
4702 bool mIsInDLElement = false;
4703 bool mIsMixed = false;
4706 } // namespace mozilla
4708 mozilla::HTMLEditor* nsIEditor::AsHTMLEditor() {
4709 MOZ_DIAGNOSTIC_ASSERT(IsHTMLEditor());
4710 return static_cast<mozilla::HTMLEditor*>(this);
4713 const mozilla::HTMLEditor* nsIEditor::AsHTMLEditor() const {
4714 MOZ_DIAGNOSTIC_ASSERT(IsHTMLEditor());
4715 return static_cast<const mozilla::HTMLEditor*>(this);
4718 mozilla::HTMLEditor* nsIEditor::GetAsHTMLEditor() {
4719 return AsEditorBase()->IsHTMLEditor() ? AsHTMLEditor() : nullptr;
4722 const mozilla::HTMLEditor* nsIEditor::GetAsHTMLEditor() const {
4723 return AsEditorBase()->IsHTMLEditor() ? AsHTMLEditor() : nullptr;
4726 #endif // #ifndef mozilla_HTMLEditor_h