Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / editor / libeditor / HTMLEditor.h
blob8e55e619d39c6c4985452cc0626951385c24ce7f
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 nsRange;
41 class nsStaticAtom;
42 class nsStyledElement;
43 class nsTableCellFrame;
44 class nsTableWrapperFrame;
45 template <class E>
46 class nsTArray;
48 namespace mozilla {
49 class AlignStateAtSelection;
50 class AutoSelectionSetterAfterTableEdit;
51 class EmptyEditableFunctor;
52 class ListElementSelectionState;
53 class ListItemElementSelectionState;
54 class ParagraphStateAtSelection;
55 class ResizerSelectionListener;
56 class Runnable;
57 template <class T>
58 class OwningNonNull;
59 namespace dom {
60 class AbstractRange;
61 class Blob;
62 class DocumentFragment;
63 class Event;
64 class HTMLBRElement;
65 class MouseEvent;
66 class StaticRange;
67 } // namespace dom
68 namespace widget {
69 struct IMEState;
70 } // namespace widget
72 enum class ParagraphSeparator { div, p, br };
74 /**
75 * The HTML editor implementation.<br>
76 * Use to edit HTML document represented as a DOM tree.
78 class HTMLEditor final : public EditorBase,
79 public nsIHTMLEditor,
80 public nsIHTMLObjectResizer,
81 public nsIHTMLAbsPosEditor,
82 public nsITableEditor,
83 public nsIHTMLInlineTableEditor,
84 public nsStubMutationObserver,
85 public nsIEditorMailSupport {
86 public:
87 /****************************************************************************
88 * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other
89 * classes under libeditor except EditorEventListener and
90 * HTMLEditorEventListener because each public method which may fire
91 * eEditorInput event will need to instantiate new stack class for
92 * managing input type value of eEditorInput and cache some objects
93 * for smarter handling. In other words, when you add new root
94 * method to edit the DOM tree, you can make your new method public.
95 ****************************************************************************/
97 NS_DECL_ISUPPORTS_INHERITED
98 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLEditor, EditorBase)
100 // nsStubMutationObserver overrides
101 NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
102 NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
103 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
104 NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
106 // nsIHTMLEditor methods
107 NS_DECL_NSIHTMLEDITOR
109 // nsIHTMLObjectResizer methods (implemented in HTMLObjectResizer.cpp)
110 NS_DECL_NSIHTMLOBJECTRESIZER
112 // nsIHTMLAbsPosEditor methods (implemented in HTMLAbsPositionEditor.cpp)
113 NS_DECL_NSIHTMLABSPOSEDITOR
115 // nsIHTMLInlineTableEditor methods (implemented in HTMLInlineTableEditor.cpp)
116 NS_DECL_NSIHTMLINLINETABLEEDITOR
118 // nsIEditorMailSupport methods
119 NS_DECL_NSIEDITORMAILSUPPORT
121 // nsITableEditor methods
122 NS_DECL_NSITABLEEDITOR
124 // nsISelectionListener overrides
125 NS_DECL_NSISELECTIONLISTENER
128 * @param aDocument The document whose content will be editable.
130 explicit HTMLEditor(const Document& aDocument);
133 * @param aDocument The document whose content will be editable.
134 * @param aComposerCommandsUpdater The composer command updater.
135 * @param aFlags Some of nsIEditor::eEditor*Mask flags.
137 MOZ_CAN_RUN_SCRIPT nsresult
138 Init(Document& aDocument, ComposerCommandsUpdater& aComposerCommandsUpdater,
139 uint32_t aFlags);
142 * PostCreate() should be called after Init, and is the time that the editor
143 * tells its documentStateObservers that the document has been created.
145 MOZ_CAN_RUN_SCRIPT nsresult PostCreate();
148 * PreDestroy() is called before the editor goes away, and gives the editor a
149 * chance to tell its documentStateObservers that the document is going away.
151 MOZ_CAN_RUN_SCRIPT void PreDestroy();
153 static HTMLEditor* GetFrom(nsIEditor* aEditor) {
154 return aEditor ? aEditor->GetAsHTMLEditor() : nullptr;
156 static const HTMLEditor* GetFrom(const nsIEditor* aEditor) {
157 return aEditor ? aEditor->GetAsHTMLEditor() : nullptr;
160 [[nodiscard]] bool GetReturnInParagraphCreatesNewParagraph() const;
162 // EditorBase overrides
163 MOZ_CAN_RUN_SCRIPT NS_IMETHOD BeginningOfDocument() final;
164 MOZ_CAN_RUN_SCRIPT NS_IMETHOD EndOfDocument() final;
166 NS_IMETHOD GetDocumentCharacterSet(nsACString& aCharacterSet) final;
167 MOZ_CAN_RUN_SCRIPT NS_IMETHOD
168 SetDocumentCharacterSet(const nsACString& aCharacterSet) final;
170 bool IsEmpty() const final;
172 bool CanPaste(nsIClipboard::ClipboardType aClipboardType) const final;
173 using EditorBase::CanPaste;
175 MOZ_CAN_RUN_SCRIPT NS_IMETHOD DeleteNode(nsINode* aNode,
176 bool aPreseveSelection,
177 uint8_t aOptionalArgCount) final;
179 MOZ_CAN_RUN_SCRIPT NS_IMETHOD InsertLineBreak() final;
182 * PreHandleMouseDown() and PreHandleMouseUp() are called before
183 * HTMLEditorEventListener handles them. The coming event may be
184 * non-acceptable event.
186 void PreHandleMouseDown(const dom::MouseEvent& aMouseDownEvent);
187 void PreHandleMouseUp(const dom::MouseEvent& aMouseUpEvent);
190 * PreHandleSelectionChangeCommand() and PostHandleSelectionChangeCommand()
191 * are called before or after handling a command which may change selection
192 * and/or scroll position.
194 void PreHandleSelectionChangeCommand(Command aCommand);
195 void PostHandleSelectionChangeCommand(Command aCommand);
197 MOZ_CAN_RUN_SCRIPT nsresult
198 HandleKeyPressEvent(WidgetKeyboardEvent* aKeyboardEvent) final;
199 Element* GetFocusedElement() const final;
200 bool IsActiveInDOMWindow() const final;
201 dom::EventTarget* GetDOMEventTarget() const final;
202 [[nodiscard]] Element* FindSelectionRoot(const nsINode& aNode) const final;
203 bool IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent) const final;
204 nsresult GetPreferredIMEState(widget::IMEState* aState) final;
205 MOZ_CAN_RUN_SCRIPT nsresult
206 OnFocus(const nsINode& aOriginalEventTargetNode) final;
207 nsresult OnBlur(const dom::EventTarget* aEventTarget) final;
210 * Called when aDocument or aElement becomes editable without focus change.
211 * E.g., when the design mode is enabled or the contenteditable attribute
212 * is set to the focused element.
214 MOZ_CAN_RUN_SCRIPT nsresult FocusedElementOrDocumentBecomesEditable(
215 Document& aDocument, Element* aElement);
218 * Called when aDocument or aElement becomes not editable without focus
219 * change. E.g., when the design mode ends or the contenteditable attribute is
220 * removed or set to "false".
222 MOZ_CAN_RUN_SCRIPT static nsresult FocusedElementOrDocumentBecomesNotEditable(
223 HTMLEditor* aHTMLEditor, Document& aDocument, Element* aElement);
226 * GetBackgroundColorState() returns what the background color of the
227 * selection.
229 * @param aMixed true if there is more than one font color
230 * @param aOutColor Color string. "" is returned for none.
232 MOZ_CAN_RUN_SCRIPT nsresult GetBackgroundColorState(bool* aMixed,
233 nsAString& aOutColor);
236 * PasteNoFormattingAsAction() pastes content in clipboard without any style
237 * information.
239 * @param aClipboardType nsIClipboard::kGlobalClipboard or
240 * nsIClipboard::kSelectionClipboard.
241 * @param aDispatchPasteEvent Yes if this should dispatch ePaste event
242 * before pasting. Otherwise, No.
243 * @param aDataTransfer The object containing the data to use for the
244 * paste operation. May be nullptr, in which case
245 * this will just get the data from the clipboard.
246 * @param aPrincipal Set subject principal if it may be called by
247 * JS. If set to nullptr, will be treated as
248 * called by system.
250 MOZ_CAN_RUN_SCRIPT nsresult
251 PasteNoFormattingAsAction(nsIClipboard::ClipboardType aClipboardType,
252 DispatchPasteEvent aDispatchPasteEvent,
253 DataTransfer* aDataTransfer = nullptr,
254 nsIPrincipal* aPrincipal = nullptr);
256 bool CanPasteTransferable(nsITransferable* aTransferable) final;
258 MOZ_CAN_RUN_SCRIPT nsresult
259 InsertLineBreakAsAction(nsIPrincipal* aPrincipal = nullptr) final;
262 * InsertParagraphSeparatorAsAction() is called when user tries to separate
263 * current paragraph with Enter key press in HTMLEditor or something.
265 * @param aPrincipal Set subject principal if it may be called by
266 * JS. If set to nullptr, will be treated as
267 * called by system.
269 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
270 InsertParagraphSeparatorAsAction(nsIPrincipal* aPrincipal = nullptr);
272 enum class InsertElementOption {
273 // Delete selection if set, otherwise, insert aElement at start or end of
274 // selection.
275 DeleteSelection,
276 // Whether split all inline ancestors or not.
277 SplitAncestorInlineElements,
279 using InsertElementOptions = EnumSet<InsertElementOption>;
280 MOZ_CAN_RUN_SCRIPT nsresult InsertElementAtSelectionAsAction(
281 Element* aElement, const InsertElementOptions aOptions,
282 nsIPrincipal* aPrincipal = nullptr);
284 MOZ_CAN_RUN_SCRIPT nsresult InsertLinkAroundSelectionAsAction(
285 Element* aAnchorElement, nsIPrincipal* aPrincipal = nullptr);
288 * CreateElementWithDefaults() creates new element whose name is
289 * aTagName with some default attributes are set. Note that this is a
290 * public utility method. I.e., just creates element, not insert it
291 * into the DOM tree.
292 * NOTE: This is available for internal use too since this does not change
293 * the DOM tree nor undo transactions, and does not refer Selection,
294 * etc.
296 * @param aTagName The new element's tag name. If the name is
297 * one of "href", "anchor" or "namedanchor",
298 * this creates an <a> element.
299 * @return Newly created element.
301 MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> CreateElementWithDefaults(
302 const nsAtom& aTagName);
305 * Indent or outdent content around Selection.
307 * @param aPrincipal Set subject principal if it may be called by
308 * JS. If set to nullptr, will be treated as
309 * called by system.
311 MOZ_CAN_RUN_SCRIPT nsresult
312 IndentAsAction(nsIPrincipal* aPrincipal = nullptr);
313 MOZ_CAN_RUN_SCRIPT nsresult
314 OutdentAsAction(nsIPrincipal* aPrincipal = nullptr);
317 * The Document.execCommand("formatBlock") handler.
319 * @param aParagraphFormat Must not be an empty string, and the value must
320 * be one of address, article, aside, blockquote,
321 * div, footer, h1, h2, h3, h4, h5, h6, header,
322 * hgroup, main, nav, p, pre, selection, dt or dd.
324 MOZ_CAN_RUN_SCRIPT nsresult FormatBlockAsAction(
325 const nsAString& aParagraphFormat, nsIPrincipal* aPrincipal = nullptr);
328 * The cmd_paragraphState command handler.
330 * @param aParagraphFormat Can be empty string. If this is empty string,
331 * this removes ancestor format elements.
332 * Otherwise, the value must be one of p, pre,
333 * h1, h2, h3, h4, h5, h6, address, dt or dl.
335 MOZ_CAN_RUN_SCRIPT nsresult SetParagraphStateAsAction(
336 const nsAString& aParagraphFormat, nsIPrincipal* aPrincipal = nullptr);
338 MOZ_CAN_RUN_SCRIPT nsresult AlignAsAction(const nsAString& aAlignType,
339 nsIPrincipal* aPrincipal = nullptr);
341 MOZ_CAN_RUN_SCRIPT nsresult RemoveListAsAction(
342 const nsAString& aListType, nsIPrincipal* aPrincipal = nullptr);
345 * MakeOrChangeListAsAction() makes selected hard lines list element(s).
347 * @param aListElementTagName The new list element tag name. Must be
348 * nsGkAtoms::ul, nsGkAtoms::ol or
349 * nsGkAtoms::dl.
350 * @param aBulletType If this is not empty string, it's set
351 * to `type` attribute of new list item
352 * elements. Otherwise, existing `type`
353 * attributes will be removed.
354 * @param aSelectAllOfCurrentList Yes if this should treat all of
355 * ancestor list element at selection.
357 enum class SelectAllOfCurrentList { Yes, No };
358 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult MakeOrChangeListAsAction(
359 const nsStaticAtom& aListElementTagName, const nsAString& aBulletType,
360 SelectAllOfCurrentList aSelectAllOfCurrentList,
361 nsIPrincipal* aPrincipal = nullptr);
364 * If aTargetElement is a resizer, start to drag the resizer. Otherwise, if
365 * aTargetElement is the grabber, start to handle drag gester on it.
367 * @param aMouseDownEvent A `mousedown` event fired on aTargetElement.
368 * @param aEventTargetElement The target element being pressed. This must
369 * be same as explicit original event target of
370 * aMouseDownEvent.
372 MOZ_CAN_RUN_SCRIPT nsresult StartToDragResizerOrHandleDragGestureOnGrabber(
373 dom::MouseEvent& aMouseDownEvent, Element& aEventTargetElement);
376 * If the editor is handling dragging a resizer, handling drag gesture on
377 * the grabber or dragging the grabber, this finalize it. Otherwise,
378 * does nothing.
380 * @param aClientPoint The final point of the drag.
382 MOZ_CAN_RUN_SCRIPT nsresult
383 StopDraggingResizerOrGrabberAt(const CSSIntPoint& aClientPoint);
386 * If the editor is handling dragging a resizer, handling drag gesture to
387 * start dragging the grabber or dragging the grabber, this method updates
388 * it's position.
390 * @param aClientPoint The new point of the drag.
392 MOZ_CAN_RUN_SCRIPT nsresult
393 UpdateResizerOrGrabberPositionTo(const CSSIntPoint& aClientPoint);
396 * IsCSSEnabled() returns true if this editor treats styles with style
397 * attribute of HTML elements. Otherwise, if this editor treats all styles
398 * with "font style elements" like <b>, <i>, etc, and <blockquote> to indent,
399 * align attribute to align contents, returns false.
401 bool IsCSSEnabled() const { return mIsCSSPrefChecked; }
404 * Enable/disable object resizers for <img> elements, <table> elements,
405 * absolute positioned elements (required absolute position editor enabled).
407 MOZ_CAN_RUN_SCRIPT void EnableObjectResizer(bool aEnable) {
408 if (mIsObjectResizingEnabled == aEnable) {
409 return;
412 AutoEditActionDataSetter editActionData(
413 *this, EditAction::eEnableOrDisableResizer);
414 if (NS_WARN_IF(!editActionData.CanHandle())) {
415 return;
418 mIsObjectResizingEnabled = aEnable;
419 RefreshEditingUI();
421 bool IsObjectResizerEnabled() const { return mIsObjectResizingEnabled; }
423 Element* GetResizerTarget() const { return mResizedObject; }
426 * Enable/disable inline table editor, e.g., adding new row or column,
427 * removing existing row or column.
429 MOZ_CAN_RUN_SCRIPT void EnableInlineTableEditor(bool aEnable) {
430 if (mIsInlineTableEditingEnabled == aEnable) {
431 return;
434 AutoEditActionDataSetter editActionData(
435 *this, EditAction::eEnableOrDisableInlineTableEditingUI);
436 if (NS_WARN_IF(!editActionData.CanHandle())) {
437 return;
440 mIsInlineTableEditingEnabled = aEnable;
441 RefreshEditingUI();
443 bool IsInlineTableEditorEnabled() const {
444 return mIsInlineTableEditingEnabled;
448 * Enable/disable absolute position editor, resizing absolute positioned
449 * elements (required object resizers enabled) or positioning them with
450 * dragging grabber.
452 MOZ_CAN_RUN_SCRIPT void EnableAbsolutePositionEditor(bool aEnable) {
453 if (mIsAbsolutelyPositioningEnabled == aEnable) {
454 return;
457 AutoEditActionDataSetter editActionData(
458 *this, EditAction::eEnableOrDisableAbsolutePositionEditor);
459 if (NS_WARN_IF(!editActionData.CanHandle())) {
460 return;
463 mIsAbsolutelyPositioningEnabled = aEnable;
464 RefreshEditingUI();
466 bool IsAbsolutePositionEditorEnabled() const {
467 return mIsAbsolutelyPositioningEnabled;
471 * returns the deepest absolutely positioned container of the selection
472 * if it exists or null.
474 MOZ_CAN_RUN_SCRIPT already_AddRefed<Element>
475 GetAbsolutelyPositionedSelectionContainer() const;
477 Element* GetPositionedElement() const { return mAbsolutelyPositionedObject; }
480 * extracts the selection from the normal flow of the document and
481 * positions it.
483 * @param aEnabled [IN] true to absolutely position the selection,
484 * false to put it back in the normal flow
485 * @param aPrincipal Set subject principal if it may be called by
486 * JS. If set to nullptr, will be treated as
487 * called by system.
489 MOZ_CAN_RUN_SCRIPT nsresult SetSelectionToAbsoluteOrStaticAsAction(
490 bool aEnabled, nsIPrincipal* aPrincipal = nullptr);
493 * returns the absolute z-index of a positioned element. Never returns 'auto'
494 * @return the z-index of the element
495 * @param aElement [IN] the element.
497 MOZ_CAN_RUN_SCRIPT int32_t GetZIndex(Element& aElement);
500 * adds aChange to the z-index of the currently positioned element.
502 * @param aChange [IN] relative change to apply to current z-index
503 * @param aPrincipal Set subject principal if it may be called by
504 * JS. If set to nullptr, will be treated as
505 * called by system.
507 MOZ_CAN_RUN_SCRIPT nsresult
508 AddZIndexAsAction(int32_t aChange, nsIPrincipal* aPrincipal = nullptr);
510 MOZ_CAN_RUN_SCRIPT nsresult SetBackgroundColorAsAction(
511 const nsAString& aColor, nsIPrincipal* aPrincipal = nullptr);
514 * SetInlinePropertyAsAction() sets a property which changes inline style of
515 * text. E.g., bold, italic, super and sub.
516 * This automatically removes exclusive style, however, treats all changes
517 * as a transaction.
519 * @param aPrincipal Set subject principal if it may be called by
520 * JS. If set to nullptr, will be treated as
521 * called by system.
523 MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertyAsAction(
524 nsStaticAtom& aProperty, nsStaticAtom* aAttribute,
525 const nsAString& aValue, nsIPrincipal* aPrincipal = nullptr);
528 * GetInlineProperty() gets aggregate properties of the current selection.
529 * All object in the current selection are scanned and their attributes are
530 * represented in a list of Property object.
531 * TODO: Make this return Result<Something> instead of bool out arguments.
533 * @param aHTMLProperty the property to get on the selection
534 * @param aAttribute the attribute of the property, if applicable.
535 * May be null.
536 * Example: aHTMLProperty=nsGkAtoms::font,
537 * aAttribute=nsGkAtoms::color
538 * @param aValue if aAttribute is not null, the value of the
539 * attribute. May be null.
540 * Example: aHTMLProperty=nsGkAtoms::font,
541 * aAttribute=nsGkAtoms::color,
542 * aValue="0x00FFFF"
543 * @param aFirst [OUT] true if the first text node in the
544 * selection has the property
545 * @param aAny [OUT] true if any of the text nodes in the
546 * selection have the property
547 * @param aAll [OUT] true if all of the text nodes in the
548 * selection have the property
550 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlineProperty(
551 nsStaticAtom& aHTMLProperty, nsAtom* aAttribute, const nsAString& aValue,
552 bool* aFirst, bool* aAny, bool* aAll) const;
554 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlinePropertyWithAttrValue(
555 nsStaticAtom& aHTMLProperty, nsAtom* aAttribute, const nsAString& aValue,
556 bool* aFirst, bool* aAny, bool* aAll, nsAString& outValue);
559 * RemoveInlinePropertyAsAction() removes a property which changes inline
560 * style of text. E.g., bold, italic, super and sub.
562 * @param aHTMLProperty Tag name whcih represents the inline style you want
563 * to remove. E.g., nsGkAtoms::strong, nsGkAtoms::b,
564 * etc. If nsGkAtoms::href, <a> element which has
565 * href attribute will be removed.
566 * If nsGkAtoms::name, <a> element which has non-empty
567 * name attribute will be removed.
568 * @param aAttribute If aHTMLProperty is nsGkAtoms::font, aAttribute should
569 * be nsGkAtoms::fase, nsGkAtoms::size, nsGkAtoms::color
570 * or nsGkAtoms::bgcolor. Otherwise, set nullptr.
571 * Must not use nsGkAtoms::_empty here.
572 * @param aPrincipal Set subject principal if it may be called by JS. If
573 * set to nullptr, will be treated as called by system.
575 MOZ_CAN_RUN_SCRIPT nsresult RemoveInlinePropertyAsAction(
576 nsStaticAtom& aHTMLProperty, nsStaticAtom* aAttribute,
577 nsIPrincipal* aPrincipal = nullptr);
579 MOZ_CAN_RUN_SCRIPT nsresult
580 RemoveAllInlinePropertiesAsAction(nsIPrincipal* aPrincipal = nullptr);
582 MOZ_CAN_RUN_SCRIPT nsresult
583 IncreaseFontSizeAsAction(nsIPrincipal* aPrincipal = nullptr);
585 MOZ_CAN_RUN_SCRIPT nsresult
586 DecreaseFontSizeAsAction(nsIPrincipal* aPrincipal = nullptr);
589 * GetFontColorState() returns foreground color information in first
590 * range of Selection.
591 * If first range of Selection is collapsed and there is a cache of style for
592 * new text, aIsMixed is set to false and aColor is set to the cached color.
593 * If first range of Selection is collapsed and there is no cached color,
594 * this returns the color of the node, aIsMixed is set to false and aColor is
595 * set to the color.
596 * If first range of Selection is not collapsed, this collects colors of
597 * each node in the range. If there are two or more colors, aIsMixed is set
598 * to true and aColor is truncated. If only one color is set to all of the
599 * range, aIsMixed is set to false and aColor is set to the color.
600 * If there is no Selection ranges, aIsMixed is set to false and aColor is
601 * truncated.
603 * @param aIsMixed Must not be nullptr. This is set to true
604 * if there is two or more colors in first
605 * range of Selection.
606 * @param aColor Returns the color if only one color is set to
607 * all of first range in Selection. Otherwise,
608 * returns empty string.
609 * @return Returns error only when illegal cases, e.g.,
610 * Selection instance has gone, first range
611 * Selection is broken.
613 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
614 GetFontColorState(bool* aIsMixed, nsAString& aColor);
617 * Detach aComposerCommandsUpdater from this.
619 void Detach(const ComposerCommandsUpdater& aComposerCommandsUpdater);
621 nsStaticAtom& DefaultParagraphSeparatorTagName() const {
622 return HTMLEditor::ToParagraphSeparatorTagName(mDefaultParagraphSeparator);
624 ParagraphSeparator GetDefaultParagraphSeparator() const {
625 return mDefaultParagraphSeparator;
627 void SetDefaultParagraphSeparator(ParagraphSeparator aSep) {
628 mDefaultParagraphSeparator = aSep;
630 static nsStaticAtom& ToParagraphSeparatorTagName(
631 ParagraphSeparator aSeparator) {
632 switch (aSeparator) {
633 case ParagraphSeparator::div:
634 return *nsGkAtoms::div;
635 case ParagraphSeparator::p:
636 return *nsGkAtoms::p;
637 case ParagraphSeparator::br:
638 return *nsGkAtoms::br;
639 default:
640 MOZ_ASSERT_UNREACHABLE("New paragraph separator isn't handled here");
641 return *nsGkAtoms::div;
646 * Modifies the table containing the selection according to the
647 * activation of an inline table editing UI element
648 * @param aUIAnonymousElement [IN] the inline table editing UI element
650 MOZ_CAN_RUN_SCRIPT nsresult
651 DoInlineTableEditingAction(const Element& aUIAnonymousElement);
654 * GetInclusiveAncestorByTagName() looks for an element node whose name
655 * matches aTagName from aNode or anchor node of Selection to <body> element.
657 * @param aTagName The tag name which you want to look for.
658 * Must not be nsGkAtoms::_empty.
659 * If nsGkAtoms::list, the result may be <ul>, <ol> or
660 * <dl> element.
661 * If nsGkAtoms::td, the result may be <td> or <th>.
662 * If nsGkAtoms::href, the result may be <a> element
663 * which has "href" attribute with non-empty value.
664 * If nsGkAtoms::anchor, the result may be <a> which
665 * has "name" attribute with non-empty value.
666 * @param aContent Start node to look for the result.
667 * @return If an element which matches aTagName, returns
668 * an Element. Otherwise, nullptr.
670 Element* GetInclusiveAncestorByTagName(const nsStaticAtom& aTagName,
671 nsIContent& aContent) const;
674 * Compute editing host for aContent. If this editor isn't active in the DOM
675 * window, this returns nullptr.
677 enum class LimitInBodyElement { No, Yes };
678 [[nodiscard]] Element* ComputeEditingHost(
679 const nsIContent& aContent,
680 LimitInBodyElement aLimitInBodyElement = LimitInBodyElement::Yes) const {
681 return ComputeEditingHostInternal(&aContent, aLimitInBodyElement);
685 * Compute editing host for the focus node of the Selection. If this editor
686 * isn't active in the DOM window, this returns nullptr.
688 [[nodiscard]] Element* ComputeEditingHost(
689 LimitInBodyElement aLimitInBodyElement = LimitInBodyElement::Yes) const {
690 return ComputeEditingHostInternal(nullptr, aLimitInBodyElement);
694 * Return true if this editor was notified of focus, but has not been notified
695 * of the blur.
697 [[nodiscard]] bool HasFocus() const { return mHasFocus; }
700 * Return true if this editor is in the designMode.
702 [[nodiscard]] bool IsInDesignMode() const { return mIsInDesignMode; }
705 * Return true if entire the document is editable (although the document
706 * may have non-editable nodes, e.g.,
707 * <body contenteditable><div contenteditable="false"></div></body>
709 bool EntireDocumentIsEditable() const;
712 * Basically, this always returns true if we're for `contenteditable` or
713 * `designMode` editor in web apps. However, e.g., Composer of SeaMonkey
714 * can make the editor not tabbable.
716 bool IsTabbable() const { return IsInteractionAllowed(); }
719 * NotifyEditingHostMaybeChanged() is called when new element becomes
720 * contenteditable when the document already had contenteditable elements.
722 void NotifyEditingHostMaybeChanged();
724 /** Insert a string as quoted text
725 * (whose representation is dependant on the editor type),
726 * replacing the selected text (if any).
728 * @param aQuotedText The actual text to be quoted
729 * @parem aNodeInserted Return the node which was inserted.
731 MOZ_CAN_RUN_SCRIPT // USED_BY_COMM_CENTRAL
732 nsresult
733 InsertAsQuotation(const nsAString& aQuotedText, nsINode** aNodeInserted);
735 MOZ_CAN_RUN_SCRIPT nsresult InsertHTMLAsAction(
736 const nsAString& aInString, nsIPrincipal* aPrincipal = nullptr);
739 * Refresh positions of resizers. If you change size of target of resizers,
740 * you need to refresh position of resizers with calling this.
742 MOZ_CAN_RUN_SCRIPT nsresult RefreshResizers();
744 bool IsWrapHackEnabled() const {
745 return (mFlags & nsIEditor::eEditorEnableWrapHackMask) != 0;
749 * Return true if this is in the plaintext mail composer mode of
750 * Thunderbird or something.
751 * NOTE: This is different from contenteditable="plaintext-only"
753 bool IsPlaintextMailComposer() const {
754 const bool isPlaintextMode =
755 (mFlags & nsIEditor::eEditorPlaintextMask) != 0;
756 MOZ_ASSERT_IF(IsTextEditor(), isPlaintextMode);
757 return isPlaintextMode;
760 protected: // May be called by friends.
761 /****************************************************************************
762 * Some friend classes are allowed to call the following protected methods.
763 * However, those methods won't prepare caches of some objects which are
764 * necessary for them. So, if you call them from friend classes, you need
765 * to make sure that AutoEditActionDataSetter is created.
766 ****************************************************************************/
768 enum class LineBreakType : bool {
769 BRElement, // <br>
770 Linefeed, // Preformatted linefeed
772 friend std::ostream& operator<<(std::ostream& aStream,
773 const LineBreakType aLineBreakType) {
774 switch (aLineBreakType) {
775 case LineBreakType::BRElement:
776 return aStream << "LineBreakType::BRElement";
777 case LineBreakType::Linefeed:
778 return aStream << "LineBreakType::BRElement";
780 MOZ_ASSERT_UNREACHABLE("Invalid LineBreakType");
781 return aStream;
785 * Return preferred line break when you insert a line break in aNode (if
786 * aNode is a Text node, this assumes that line break will be inserted to
787 * its parent element).
789 * @param aNode The node where you want to insert a line break.
790 * This should be a inclusive descendant of
791 * aEditingHost because if it's not connected, we can
792 * not refer the proper style information.
793 * @param aEditingHost The editing host.
795 Maybe<LineBreakType> GetPreferredLineBreakType(
796 const nsINode& aNode, const Element& aEditingHost) const;
799 * InsertLineBreak() creates a <br> element or a Text node which has only
800 * preformatted linefeed and inserts it at aPointToInsert.
802 * @param aWithTransaction Whether the inserting is new element is undoable
803 * or not. WithTransaction::No is useful only when
804 * the new element is inserted into a new element
805 * which has not been connected yet.
806 * @param aLineBreakType Whether a <br> element or a linefeed should be
807 * used.
808 * @param aPointToInsert The DOM point where a <br> element or a Text
809 * node should be inserted.
810 * @param aSelect If eNone, returns a point to put caret which is
811 * suggested by InsertNodeTransaction.
812 * If eNext, returns a point after the new <br>
813 * element.
814 * If ePrevious, returns a point at the new <br>
815 * element.
816 * @return The new <br> or Text node and suggesting point
817 * to put caret with respecting aSelect.
819 MOZ_CAN_RUN_SCRIPT Result<CreateLineBreakResult, nsresult> InsertLineBreak(
820 WithTransaction aWithTransaction, LineBreakType aLineBreakType,
821 const EditorDOMPoint& aPointToInsert, EDirection aSelect = eNone);
824 * Delete text in the range in aTextNode. If aTextNode is not editable, this
825 * does nothing.
827 * @param aTextNode The text node which should be modified.
828 * @param aOffset Start offset of removing text in aTextNode.
829 * @param aLength Length of removing text.
831 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
832 DeleteTextWithTransaction(dom::Text& aTextNode, uint32_t aOffset,
833 uint32_t aLength);
836 * Replace text in the range with aStringToInsert. If there is a DOM range
837 * exactly same as the replacing range, it'll be collapsed to
838 * {aTextNode, aOffset} because of the order of deletion and insertion.
839 * Therefore, the callers may need to handle `Selection` even when callers
840 * do not want to update `Selection`.
842 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<InsertTextResult, nsresult>
843 ReplaceTextWithTransaction(dom::Text& aTextNode, uint32_t aOffset,
844 uint32_t aLength,
845 const nsAString& aStringToInsert);
848 * Insert aStringToInsert to aPointToInsert. If the point is not editable,
849 * this returns error.
851 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<InsertTextResult, nsresult>
852 InsertTextWithTransaction(Document& aDocument,
853 const nsAString& aStringToInsert,
854 const EditorDOMPoint& aPointToInsert,
855 InsertTextTo aInsertTextTo) final;
858 * CopyLastEditableChildStyles() clones inline container elements into
859 * aPreviousBlock to aNewBlock to keep using same style in it.
861 * @param aPreviousBlock The previous block element. All inline
862 * elements which are last sibling of each level
863 * are cloned to aNewBlock.
864 * @param aNewBlock New block container element. All children of
865 * this is deleted first.
866 * @param aEditingHost The editing host.
867 * @return If succeeded, returns a suggesting point to put
868 * caret.
870 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
871 CopyLastEditableChildStylesWithTransaction(Element& aPreviousBlock,
872 Element& aNewBlock,
873 const Element& aEditingHost);
876 * RemoveBlockContainerWithTransaction() removes aElement from the DOM tree
877 * but moves its all children to its parent node and if its parent needs <br>
878 * element to have at least one line-height, this inserts <br> element
879 * automatically.
881 * @param aElement Block element to be removed.
882 * @return If succeeded, returns a suggesting point to put
883 * caret.
885 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
886 RemoveBlockContainerWithTransaction(Element& aElement);
888 MOZ_CAN_RUN_SCRIPT nsresult RemoveAttributeOrEquivalent(
889 Element* aElement, nsAtom* aAttribute, bool aSuppressTransaction) final;
890 MOZ_CAN_RUN_SCRIPT nsresult SetAttributeOrEquivalent(
891 Element* aElement, nsAtom* aAttribute, const nsAString& aValue,
892 bool aSuppressTransaction) final;
893 using EditorBase::RemoveAttributeOrEquivalent;
894 using EditorBase::SetAttributeOrEquivalent;
897 * Returns container element of ranges in Selection. If Selection is
898 * collapsed, returns focus container node (or its parent element).
899 * If Selection selects only one element node, returns the element node.
900 * If Selection is only one range, returns common ancestor of the range.
901 * XXX If there are two or more Selection ranges, this returns parent node
902 * of start container of a range which starts with different node from
903 * start container of the first range.
905 Element* GetSelectionContainerElement() const;
908 * DeleteTableCellContentsWithTransaction() removes any contents in cell
909 * elements. If two or more cell elements are selected, this removes
910 * all selected cells' contents. Otherwise, this removes contents of
911 * a cell which contains first selection range. This does not return
912 * error even if selection is not in cell element, just does nothing.
914 MOZ_CAN_RUN_SCRIPT nsresult DeleteTableCellContentsWithTransaction();
917 * extracts an element from the normal flow of the document and
918 * positions it, and puts it back in the normal flow.
919 * @param aElement [IN] the element
920 * @param aEnabled [IN] true to absolutely position the element,
921 * false to put it back in the normal flow
923 MOZ_CAN_RUN_SCRIPT nsresult SetPositionToAbsoluteOrStatic(Element& aElement,
924 bool aEnabled);
927 * adds aChange to the z-index of an arbitrary element.
928 * @param aElement [IN] the element
929 * @param aChange [IN] relative change to apply to current z-index of
930 * the element
931 * @return The new z-index of the element
933 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<int32_t, nsresult>
934 AddZIndexWithTransaction(nsStyledElement& aStyledElement, int32_t aChange);
937 * Join together adjacent editable text nodes in the range except preformatted
938 * linefeed only nodes.
940 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
941 CollapseAdjacentTextNodes(nsRange& aRange);
943 static dom::Element* GetLinkElement(nsINode* aNode);
946 * Helper routines for font size changing.
948 enum class FontSize { incr, decr };
949 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
950 SetFontSizeOnTextNode(Text& aTextNode, uint32_t aStartOffset,
951 uint32_t aEndOffset, FontSize aIncrementOrDecrement);
953 enum class SplitAtEdges {
954 // SplitNodeDeepWithTransaction() won't split container element
955 // nodes at their edges. I.e., when split point is start or end of
956 // container, it won't be split.
957 eDoNotCreateEmptyContainer,
958 // SplitNodeDeepWithTransaction() always splits containers even
959 // if the split point is at edge of a container. E.g., if split point is
960 // start of an inline element, empty inline element is created as a new left
961 // node.
962 eAllowToCreateEmptyContainer,
966 * SplitAncestorStyledInlineElementsAtRangeEdges() splits all ancestor inline
967 * elements in the block at aRange if given style matches with some of them.
969 * @param aRange Ancestor inline elements of the start and end
970 * boundaries will be split.
971 * @param aStyle The style which you want to split.
972 * RemoveAllStyles instance is allowed to split any
973 * inline elements.
974 * @param aSplitAtEdges Whether this should split elements at start or
975 * end of inline elements or not.
977 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffResult, nsresult>
978 SplitAncestorStyledInlineElementsAtRangeEdges(const EditorDOMRange& aRange,
979 const EditorInlineStyle& aStyle,
980 SplitAtEdges aSplitAtEdges);
983 * SplitAncestorStyledInlineElementsAt() splits ancestor inline elements at
984 * aPointToSplit if specified style matches with them.
986 * @param aPointToSplit The point to split style at.
987 * @param aStyle The style which you want to split.
988 * RemoveAllStyles instance is allowed to split any
989 * inline elements.
990 * @param aSplitAtEdges Whether this should split elements at start or
991 * end of inline elements or not.
992 * @return The result of SplitNodeDeepWithTransaction()
993 * with topmost split element. If this didn't
994 * find inline elements to be split, Handled()
995 * returns false.
997 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
998 SplitAncestorStyledInlineElementsAt(const EditorDOMPoint& aPointToSplit,
999 const EditorInlineStyle& aStyle,
1000 SplitAtEdges aSplitAtEdges);
1002 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlinePropertyBase(
1003 const EditorInlineStyle& aStyle, const nsAString* aValue, bool* aFirst,
1004 bool* aAny, bool* aAll, nsAString* outValue) const;
1007 * ClearStyleAt() splits parent elements to remove the specified style.
1008 * If this splits some parent elements at near their start or end, such
1009 * empty elements will be removed. Then, remove the specified style
1010 * from the point and returns DOM point to put caret.
1012 * @param aPoint The point to clear style at.
1013 * @param aStyleToRemove The style which you want to clear.
1014 * @param aSpecifiedStyle Whether the class and style attributes should
1015 * be preserved or discarded.
1016 * @param aEditingHost The editing host.
1017 * @return A candidate position to put caret. If there is
1018 * AutoTransactionsConserveSelection instances, this stops
1019 * suggesting caret point only in some cases.
1021 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1022 ClearStyleAt(const EditorDOMPoint& aPoint,
1023 const EditorInlineStyle& aStyleToRemove,
1024 SpecifiedStyle aSpecifiedStyle, const Element& aEditingHost);
1026 MOZ_CAN_RUN_SCRIPT nsresult SetPositionToAbsolute(Element& aElement);
1027 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1028 SetPositionToStatic(Element& aElement);
1030 class DocumentModifiedEvent final : public Runnable {
1031 public:
1032 explicit DocumentModifiedEvent(HTMLEditor& aHTMLEditor)
1033 : Runnable("DocumentModifiedEvent"), mHTMLEditor(aHTMLEditor) {}
1035 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() {
1036 Unused << MOZ_KnownLive(mHTMLEditor)->OnModifyDocument(*this);
1037 return NS_OK;
1040 const nsTArray<EditorDOMPointInText>& NewInvisibleWhiteSpacesRef() const {
1041 return mNewInvisibleWhiteSpaces;
1044 void MaybeAppendNewInvisibleWhiteSpace(
1045 const nsIContent* aContentWillBeRemoved);
1047 private:
1048 ~DocumentModifiedEvent() = default;
1050 const OwningNonNull<HTMLEditor> mHTMLEditor;
1051 nsTArray<EditorDOMPointInText> mNewInvisibleWhiteSpaces;
1055 * OnModifyDocument() is called when the editor is changed. This should
1056 * be called only by DocumentModifiedEvent when AutoEditActionDataSetter
1057 * instance is in the stack.
1059 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1060 OnModifyDocument(const DocumentModifiedEvent& aRunner);
1063 * DoSplitNode() inserts aNewNode and moves all content before or after
1064 * aStartOfRightNode to aNewNode.
1066 * @param aStartOfRightNode The point to split. The container will keep
1067 * having following or previous content of this.
1068 * @param aNewNode The new node called. The previous or following
1069 * content of aStartOfRightNode will be moved into
1070 * this node.
1072 MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult> DoSplitNode(
1073 const EditorDOMPoint& aStartOfRightNode, nsIContent& aNewNode);
1076 * DoJoinNodes() merges contents in aContentToRemove to aContentToKeep and
1077 * remove aContentToRemove from the DOM tree. aContentToRemove and
1078 * aContentToKeep must have same parent. Additionally, if one of
1079 * aContentToRemove or aContentToKeep is a text node, the other must be a
1080 * text node.
1082 * @param aContentToKeep The node that will remain after the join.
1083 * @param aContentToRemove The node that will be joined with aContentToKeep.
1084 * There is no requirement that the two nodes be of
1085 * the same type.
1087 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1088 DoJoinNodes(nsIContent& aContentToKeep, nsIContent& aContentToRemove);
1091 * Called when JoinNodesTransaction::DoTransaction() did its transaction.
1092 * Note that this is not called when undoing nor redoing.
1094 * @param aTransaction The transaction which did join nodes.
1095 * @param aDoJoinNodesResult Result of the doing join nodes.
1097 MOZ_CAN_RUN_SCRIPT void DidJoinNodesTransaction(
1098 const JoinNodesTransaction& aTransaction, nsresult aDoJoinNodesResult);
1100 protected: // edit sub-action handler
1102 * CanHandleHTMLEditSubAction() checks whether there is at least one
1103 * selection range or not, and whether the first range is editable.
1104 * If it's not editable, `Canceled()` of the result returns true.
1105 * If `Selection` is in odd situation, returns an error.
1107 * XXX I think that `IsSelectionEditable()` is better name, but it's already
1108 * in `EditorBase`...
1110 enum class CheckSelectionInReplacedElement { Yes, OnlyWhenNotInSameNode };
1111 Result<EditActionResult, nsresult> CanHandleHTMLEditSubAction(
1112 CheckSelectionInReplacedElement aCheckSelectionInReplacedElement =
1113 CheckSelectionInReplacedElement::Yes) const;
1116 * EnsureCaretNotAfterInvisibleBRElement() makes sure that caret is NOT after
1117 * padding `<br>` element for preventing insertion after padding `<br>`
1118 * element at empty last line.
1119 * NOTE: This method should be called only when `Selection` is collapsed
1120 * because `Selection` is a pain to work with when not collapsed.
1121 * (no good way to extend start or end of selection), so we need to
1122 * ignore those types of selections.
1124 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1125 EnsureCaretNotAfterInvisibleBRElement(const Element& aEditingHost);
1128 * MaybeCreatePaddingBRElementForEmptyEditor() creates padding <br> element
1129 * for empty editor if there is no children.
1131 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1132 MaybeCreatePaddingBRElementForEmptyEditor();
1135 * EnsureNoPaddingBRElementForEmptyEditor() removes padding <br> element
1136 * for empty editor if there is.
1138 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1139 EnsureNoPaddingBRElementForEmptyEditor();
1142 * ReflectPaddingBRElementForEmptyEditor() scans the tree from the root
1143 * element and sets mPaddingBRElementForEmptyEditor if exists, or otherwise
1144 * nullptr. Can be used to manage undo/redo.
1146 [[nodiscard]] nsresult ReflectPaddingBRElementForEmptyEditor();
1149 * PrepareInlineStylesForCaret() consider inline styles from top level edit
1150 * sub-action and setting it to `mPendingStylesToApplyToNewContent` and clear
1151 * inline style cache if necessary.
1152 * NOTE: This method should be called only when `Selection` is collapsed.
1154 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult PrepareInlineStylesForCaret();
1156 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
1157 HandleInsertText(EditSubAction aEditSubAction,
1158 const nsAString& aInsertionString,
1159 SelectionHandling aSelectionHandling) final;
1161 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertDroppedDataTransferAsAction(
1162 AutoEditActionDataSetter& aEditActionData, DataTransfer& aDataTransfer,
1163 const EditorDOMPoint& aDroppedAt, nsIPrincipal* aSourcePrincipal) final;
1166 * GetInlineStyles() retrieves the style of aElement and modifies each item of
1167 * aPendingStyleCacheArray. This might cause flushing layout at retrieving
1168 * computed values of CSS properties.
1170 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlineStyles(
1171 Element& aElement, AutoPendingStyleCacheArray& aPendingStyleCacheArray);
1174 * CacheInlineStyles() caches style of aElement into mCachedPendingStyles of
1175 * TopLevelEditSubAction. This may cause flushing layout at retrieving
1176 * computed value of CSS properties.
1178 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1179 CacheInlineStyles(Element& aElement);
1182 * ReapplyCachedStyles() restores some styles which are disappeared during
1183 * handling edit action and it should be restored. This may cause flushing
1184 * layout at retrieving computed value of CSS properties.
1186 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult ReapplyCachedStyles();
1189 * CreateStyleForInsertText() sets CSS properties which are stored in
1190 * PendingStyles to proper element node.
1192 * @param aPointToInsertText The point to insert text.
1193 * @param aEditingHost The editing host.
1194 * @return A suggest point to put caret or unset point.
1196 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1197 CreateStyleForInsertText(const EditorDOMPoint& aPointToInsertText,
1198 const Element& aEditingHost);
1201 * GetMostDistantAncestorMailCiteElement() returns most-ancestor mail cite
1202 * element. "mail cite element" is <pre> element when it's in plaintext editor
1203 * mode or an element with which calling HTMLEditUtils::IsMailCite() returns
1204 * true.
1206 * @param aNode The start node to look for parent mail cite elements.
1208 Element* GetMostDistantAncestorMailCiteElement(const nsINode& aNode) const;
1211 * HandleInsertParagraphInMailCiteElement() splits aMailCiteElement at
1212 * aPointToSplit.
1214 * @param aMailCiteElement The mail-cite element which should be split.
1215 * @param aPointToSplit The point to split.
1216 * @return Candidate caret position where is at inserted
1217 * <br> element into the split point.
1219 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
1220 HandleInsertParagraphInMailCiteElement(Element& aMailCiteElement,
1221 const EditorDOMPoint& aPointToSplit);
1224 * HandleInsertBRElement() inserts a <br> element into aPointToBreak.
1225 * This may split container elements at the point and/or may move following
1226 * <br> element to immediately after the new <br> element if necessary.
1228 * @param aPointToBreak The point where new <br> element will be
1229 * inserted before.
1230 * @param aEditingHost Current active editing host.
1231 * @return If succeeded, returns new <br> element and
1232 * candidate caret point.
1234 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1235 HandleInsertBRElement(const EditorDOMPoint& aPointToBreak,
1236 const Element& aEditingHost);
1239 * HandleInsertLinefeed() inserts a linefeed character into aPointToBreak.
1241 * @param aPointToBreak The point where new linefeed character will be
1242 * inserted before.
1243 * @param aEditingHost Current active editing host.
1244 * @return A suggest point to put caret.
1246 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1247 HandleInsertLinefeed(const EditorDOMPoint& aPointToBreak,
1248 const Element& aEditingHost);
1251 * Splits inclusive inline ancestors at both start and end of aRangeItem. If
1252 * this splits at every point, this modifies aRangeItem to point each split
1253 * point (typically, at right node).
1255 * @param aRangeItem [in/out] One or two DOM points where should be
1256 * split. Will be modified to split point if
1257 * they're split.
1258 * @param aBlockInlineCheck [in] Whether this method considers block vs.
1259 * inline with computed style or the default style.
1260 * @param aEditingHost [in] The editing host.
1261 * @param aAncestorLimiter [in/optional] If specified, this stops splitting
1262 * ancestors when meets this node.
1263 * @return A suggest point to put caret if succeeded, but
1264 * it may be unset.
1266 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1267 SplitInlineAncestorsAtRangeBoundaries(
1268 RangeItem& aRangeItem, BlockInlineCheck aBlockInlineCheck,
1269 const Element& aEditingHost,
1270 const nsIContent* aAncestorLimiter = nullptr);
1273 * SplitElementsAtEveryBRElement() splits before all <br> elements in
1274 * aMostAncestorToBeSplit. All <br> nodes will be moved before right node
1275 * at splitting its parent. Finally, this returns left node, first <br>
1276 * element, next left node, second <br> element... and right-most node.
1278 * @param aMostAncestorToBeSplit Most-ancestor element which should
1279 * be split.
1280 * @param aOutArrayOfNodes First left node, first <br> element,
1281 * Second left node, second <br> element,
1282 * ...right-most node. So, all nodes
1283 * in this list should be siblings (may be
1284 * broken the relation by mutation event
1285 * listener though). If first <br> element
1286 * is first leaf node of
1287 * aMostAncestorToBeSplit, starting from
1288 * the first <br> element.
1289 * @return A suggest point to put caret if
1290 * succeeded, but it may unset.
1292 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1293 SplitElementsAtEveryBRElement(
1294 nsIContent& aMostAncestorToBeSplit,
1295 nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents);
1298 * MaybeSplitElementsAtEveryBRElement() calls SplitElementsAtEveryBRElement()
1299 * for each given node when this needs to do that for aEditSubAction.
1300 * If split a node, it in aArrayOfContents is replaced with split nodes and
1301 * <br> elements.
1303 * @return A suggest point to put caret if
1304 * succeeded, but it may unset.
1306 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1307 MaybeSplitElementsAtEveryBRElement(
1308 nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
1309 EditSubAction aEditSubAction);
1312 * CreateRangeIncludingAdjuscentWhiteSpaces() creates an nsRange instance
1313 * which may be expanded from the given range to include adjuscent
1314 * white-spaces. If this fails handling something, returns nullptr.
1316 template <typename EditorDOMRangeType>
1317 already_AddRefed<nsRange> CreateRangeIncludingAdjuscentWhiteSpaces(
1318 const EditorDOMRangeType& aRange);
1319 template <typename EditorDOMPointType1, typename EditorDOMPointType2>
1320 already_AddRefed<nsRange> CreateRangeIncludingAdjuscentWhiteSpaces(
1321 const EditorDOMPointType1& aStartPoint,
1322 const EditorDOMPointType2& aEndPoint);
1325 * GetRangeExtendedToHardLineEdgesForBlockEditAction() returns an extended
1326 * range if aRange should be extended before handling a block level editing.
1327 * If aRange start and/or end point <br> or something non-editable point, they
1328 * should be moved to nearest text node or something where the other methods
1329 * easier to handle edit action.
1331 [[nodiscard]] Result<EditorRawDOMRange, nsresult>
1332 GetRangeExtendedToHardLineEdgesForBlockEditAction(
1333 const nsRange* aRange, const Element& aEditingHost) const;
1336 * InitializeInsertingElement is a callback type of methods which inserts
1337 * an element into the DOM tree. This is called immediately before inserting
1338 * aNewElement into the DOM tree.
1340 * @param aHTMLEditor The HTML editor which modifies the DOM tree.
1341 * @param aNewElement The new element which will be or was inserted into
1342 * the DOM tree.
1343 * @param aPointToInsert The position aNewElement will be or was inserted.
1345 using InitializeInsertingElement =
1346 std::function<nsresult(HTMLEditor& aHTMLEditor, Element& aNewElement,
1347 const EditorDOMPoint& aPointToInsert)>;
1348 static InitializeInsertingElement DoNothingForNewElement;
1349 static InitializeInsertingElement InsertNewBRElement;
1352 * Helper methods to implement InitializeInsertingElement.
1354 MOZ_CAN_RUN_SCRIPT static Result<CreateElementResult, nsresult>
1355 AppendNewElementToInsertingElement(
1356 HTMLEditor& aHTMLEditor, const nsStaticAtom& aTagName,
1357 Element& aNewElement,
1358 const InitializeInsertingElement& aInitializer = DoNothingForNewElement);
1359 MOZ_CAN_RUN_SCRIPT static Result<CreateElementResult, nsresult>
1360 AppendNewElementWithBRToInsertingElement(HTMLEditor& aHTMLEditor,
1361 const nsStaticAtom& aTagName,
1362 Element& aNewElement);
1365 * Create an element node whose name is aTag at before aPointToInsert. When
1366 * this succeed to create an element node, this inserts the element to
1367 * aPointToInsert.
1369 * @param aWithTransaction Whether the inserting is new element is undoable
1370 * or not. WithTransaction::No is useful only when
1371 * the new element is inserted into a new element
1372 * which has not been connected yet.
1373 * @param aTagName The element name to create.
1374 * @param aPointToInsert The insertion point of new element.
1375 * If this refers end of the container or after,
1376 * the transaction will append the element to the
1377 * container.
1378 * Otherwise, will insert the element before the
1379 * child node referred by this.
1380 * Note that this point will be invalid once this
1381 * method inserts the new element.
1382 * @param aInitializer A function to initialize the new element before
1383 * connecting the element into the DOM tree. Note
1384 * that this should not touch outside given element
1385 * because doing it would break range updater's
1386 * result.
1387 * @return The created new element node and candidate caret
1388 * position.
1390 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1391 CreateAndInsertElement(
1392 WithTransaction aWithTransaction, const nsAtom& aTagName,
1393 const EditorDOMPoint& aPointToInsert,
1394 const InitializeInsertingElement& aInitializer = DoNothingForNewElement);
1397 * Callback of CopyAttributes().
1399 * @param aHTMLEditor The HTML editor.
1400 * @param aSrcElement The element which have the attribute.
1401 * @param aDestElement The element which will have the attribute.
1402 * @param aNamespaceID [in] The namespace ID of aAttrName.
1403 * @param aAttrName [in] The attribute name which will be copied.
1404 * @param aValue [in/out] The attribute value which will be copied.
1405 * Once updated, the new value is used.
1406 * @return true if the attribute should be copied, otherwise,
1407 * false.
1409 using AttributeFilter = std::function<bool(
1410 HTMLEditor& aHTMLEditor, Element& aSrcElement, Element& aDestElement,
1411 int32_t aNamespaceID, const nsAtom& aAttrName, nsString& aValue)>;
1412 static AttributeFilter CopyAllAttributes;
1413 static AttributeFilter CopyAllAttributesExceptId;
1414 static AttributeFilter CopyAllAttributesExceptDir;
1415 static AttributeFilter CopyAllAttributesExceptIdAndDir;
1418 * Copy all attributes of aSrcElement to aDestElement as-is. Different from
1419 * EditorBase::CloneAttributesWithTransaction(), this does not use
1420 * SetAttributeOrEquivalent() nor does not clear existing attributes of
1421 * aDestElement.
1423 * @param aWithTransaction Whether recoding with transactions or not.
1424 * @param aDestElement The element will have attributes.
1425 * @param aSrcElement The element whose attributes will be copied.
1427 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult CopyAttributes(
1428 WithTransaction aWithTransaction, Element& aDestElement,
1429 Element& aSrcElement, const AttributeFilter& = CopyAllAttributes);
1432 * MaybeSplitAncestorsForInsertWithTransaction() does nothing if container of
1433 * aStartOfDeepestRightNode can have an element whose tag name is aTag.
1434 * Otherwise, looks for an ancestor node which is or is in active editing
1435 * host and can have an element whose name is aTag. If there is such
1436 * ancestor, its descendants are split.
1438 * Note that this may create empty elements while splitting ancestors.
1440 * @param aTag The name of element to be inserted
1441 * after calling this method.
1442 * @param aStartOfDeepestRightNode The start point of deepest right node.
1443 * This point must be in aEditingHost.
1444 * @param aEditingHost The editing host.
1445 * @return When succeeded, SplitPoint() returns
1446 * the point to insert the element.
1448 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
1449 MaybeSplitAncestorsForInsertWithTransaction(
1450 const nsAtom& aTag, const EditorDOMPoint& aStartOfDeepestRightNode,
1451 const Element& aEditingHost);
1454 * InsertElementWithSplittingAncestorsWithTransaction() is a wrapper of
1455 * MaybeSplitAncestorsForInsertWithTransaction() and CreateAndInsertElement().
1456 * I.e., will create an element whose tag name is aTagName and split ancestors
1457 * if it's necessary, then, insert it.
1459 * @param aTagName The tag name which you want to insert new
1460 * element at aPointToInsert.
1461 * @param aPointToInsert The insertion point. New element will be
1462 * inserted before here.
1463 * @param aBRElementNextToSplitPoint
1464 * Whether <br> element should be deleted or
1465 * kept if and only if a <br> element follows
1466 * split point.
1467 * @param aEditingHost The editing host with which we're handling it.
1468 * @param aInitializer A function to initialize the new element before
1469 * connecting the element into the DOM tree. Note
1470 * that this should not touch outside given element
1471 * because doing it would break range updater's
1472 * result.
1473 * @return If succeeded, returns the new element node and
1474 * suggesting point to put caret.
1476 enum class BRElementNextToSplitPoint { Keep, Delete };
1477 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1478 InsertElementWithSplittingAncestorsWithTransaction(
1479 const nsAtom& aTagName, const EditorDOMPoint& aPointToInsert,
1480 BRElementNextToSplitPoint aBRElementNextToSplitPoint,
1481 const Element& aEditingHost,
1482 const InitializeInsertingElement& aInitializer = DoNothingForNewElement);
1485 * Split aElementToSplit at two points, before aStartOfMiddleElement and after
1486 * aEndOfMiddleElement. If they are very start or very end of aBlockElement,
1487 * this won't create empty block.
1489 * @param aElementToSplit An element which will be split.
1490 * @param aStartOfMiddleElement Start node of middle block element.
1491 * @param aEndOfMiddleElement End node of middle block element.
1493 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffFromNodeResult, nsresult>
1494 SplitRangeOffFromElement(Element& aElementToSplit,
1495 nsIContent& aStartOfMiddleElement,
1496 nsIContent& aEndOfMiddleElement);
1499 * RemoveBlockContainerElementWithTransactionBetween() splits the nodes
1500 * at aStartOfRange and aEndOfRange, then, removes the middle element which
1501 * was split off from aBlockContainerElement and moves the ex-children to
1502 * where the middle element was. I.e., all nodes between aStartOfRange and
1503 * aEndOfRange (including themselves) will be unwrapped from
1504 * aBlockContainerElement.
1506 * @param aBlockContainerElement The node which will be split.
1507 * @param aStartOfRange The first node which will be unwrapped
1508 * from aBlockContainerElement.
1509 * @param aEndOfRange The last node which will be unwrapped from
1510 * aBlockContainerElement.
1511 * @param aBlockInlineCheck Whether this method considers block vs.
1512 * inline with computed style or the default
1513 * style.
1514 * @return The left content is new created left
1515 * element of aBlockContainerElement.
1516 * The right content is split element,
1517 * i.e., must be aBlockContainerElement.
1518 * The middle content is nullptr since
1519 * removing it is the job of this method.
1521 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffFromNodeResult, nsresult>
1522 RemoveBlockContainerElementWithTransactionBetween(
1523 Element& aBlockContainerElement, nsIContent& aStartOfRange,
1524 nsIContent& aEndOfRange, BlockInlineCheck aBlockInlineCheck);
1527 * WrapContentsInBlockquoteElementsWithTransaction() inserts at least one
1528 * <blockquote> element and moves nodes in aArrayOfContents into new
1529 * <blockquote> elements. If aArrayOfContents includes a table related element
1530 * except <table>, this calls itself recursively to insert <blockquote> into
1531 * the cell.
1533 * @param aArrayOfContents Nodes which will be moved into created
1534 * <blockquote> elements.
1535 * @param aEditingHost The editing host.
1536 * @return A blockquote element which is created at last
1537 * and a suggest of caret position if succeeded.
1538 * The caret suggestion may be unset if there is
1539 * no suggestion.
1541 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1542 WrapContentsInBlockquoteElementsWithTransaction(
1543 const nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
1544 const Element& aEditingHost);
1547 * Our traditional formatBlock was same as XUL cmd_paragraphState command.
1548 * However, the behavior is pretty different from the others and aligning
1549 * the XUL command behavior may break Thunderbird a lot because it handles
1550 * <blockquote> in a special path and <div> (generic block element) is not
1551 * treated as a format node and these things may be used for designing
1552 * current roles of the elements in the email composer of Thunderbird.
1553 * Therefore, we create a new mode for HTMLFormatBlockCommand to align
1554 * the behavior to the others but does not harm Thunderbird.
1556 enum class FormatBlockMode {
1557 // Document.execCommand("formatBlock"). Cannot set new format to "normal"
1558 // nor "". So, the paths to handle these ones are not used in this mode.
1559 HTMLFormatBlockCommand,
1560 // cmd_paragraphState. Can set new format to "normal" or "" to remove
1561 // ancestor format blocks.
1562 XULParagraphStateCommand,
1566 * RemoveBlockContainerElementsWithTransaction() removes all format blocks,
1567 * table related element, etc in aArrayOfContents from the DOM tree. If
1568 * aArrayOfContents has a format node, it will be removed and its contents
1569 * will be moved to where it was.
1570 * If aArrayOfContents has a table related element, <li>, <blockquote> or
1571 * <div>, it will be removed and its contents will be moved to where it was.
1573 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
1574 * paragraphState command.
1576 * @return A suggest point to put caret if succeeded, but it may be
1577 * unset if there is no suggestion.
1579 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1580 RemoveBlockContainerElementsWithTransaction(
1581 const nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
1582 FormatBlockMode aFormatBlockMode, BlockInlineCheck aBlockInlineCheck);
1585 * CreateOrChangeFormatContainerElement() formats all nodes in
1586 * aArrayOfContents with block elements whose name is aNewFormatTagName.
1588 * If aArrayOfContents has an inline element, a block element is created and
1589 * the inline element and following inline elements are moved into the new
1590 * block element.
1591 * If aArrayOfContents has <br> elements, they'll be removed from the DOM tree
1592 * and new block element will be created when there are some remaining inline
1593 * elements.
1594 * If aArrayOfContents has a block element, this calls itself with children of
1595 * the block element. Then, new block element will be created when there are
1596 * some remaining inline elements.
1598 * @param aArrayOfContents Must be descendants of a node.
1599 * @param aNewFormatTagName The element name of new block elements.
1600 * @param aFormatBlockMode The replacing block element target type is for
1601 * whether HTML formatBLock command or XUL
1602 * paragraphState command.
1603 * @param aEditingHost The editing host.
1604 * @return The latest created new block element and a
1605 * suggest point to put caret.
1607 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1608 CreateOrChangeFormatContainerElement(
1609 nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
1610 const nsStaticAtom& aNewFormatTagName, FormatBlockMode aFormatBlockMode,
1611 const Element& aEditingHost);
1614 * FormatBlockContainerWithTransaction() is implementation of "formatBlock"
1615 * command of `Document.execCommand()`. This applies block style or removes
1616 * it.
1618 * @param aSelectionRanges The ranges which are cloned by selection or
1619 * updated from it with doing something before
1620 * calling this.
1621 * @param aNewFormatTagName New block tag name.
1622 * If nsGkAtoms::normal or nsGkAtoms::_empty,
1623 * RemoveBlockContainerElementsWithTransaction()
1624 * will be called.
1625 * If nsGkAtoms::blockquote,
1626 * WrapContentsInBlockquoteElementsWithTransaction()
1627 * will be called.
1628 * Otherwise, CreateOrChangeBlockContainerElement()
1629 * will be called.
1630 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
1631 * paragraphState command.
1632 * @param aEditingHost The editing host.
1633 * @return If selection should be finally collapsed in a
1634 * created block element, this returns the element.
1636 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<RefPtr<Element>, nsresult>
1637 FormatBlockContainerWithTransaction(
1638 AutoClonedSelectionRangeArray& aSelectionRanges,
1639 const nsStaticAtom& aNewFormatTagName, FormatBlockMode aFormatBlockMode,
1640 const Element& aEditingHost);
1643 * Retrun true if the specified line break can be inserted around aContent.
1644 * If aContent is an Element, this checks whether the element can have the
1645 * line break.
1646 * If aContent is a Text, this check whether its container element can have
1647 * the line break.
1649 [[nodiscard]] static bool CanInsertLineBreak(LineBreakType aLineBreakType,
1650 const nsIContent& aContent);
1653 * If aPointToInsert is between line breaks or block boundaries, this
1654 * puts a <br> element to make an empty line between them.
1656 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateLineBreakResult, nsresult>
1657 InsertPaddingBRElementToMakeEmptyLineVisibleIfNeeded(
1658 const EditorDOMPoint& aPointToInsert);
1661 * Insert a padding <br> if aPoint is in an empty block.
1663 * @param aPoint The place where you want to put a padding line
1664 * break.
1665 * @param aDeleteEmptyInlines If nsIEditor::eStrip, this deletes empty inlines
1666 * before inserting a line break from the inserting
1667 * point.
1669 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateLineBreakResult, nsresult>
1670 InsertPaddingBRElementIfInEmptyBlock(
1671 const EditorDOMPoint& aPoint,
1672 nsIEditor::EStripWrappers aDeleteEmptyInlines);
1675 * Insert a padding <br> element for making preceding collapsible white-spaces
1676 * visible or the point is empty between block boundaries.
1678 * @param aPoint Where you want to check. A padding <br> may be
1679 * inserted different from this point.
1680 * @param aDeleteEmptyInlines If nsIEditor::eStrip, this deletes empty inlines
1681 * before inserting <br> from the inserting point.
1682 * @param aEditingHost The editing host.
1684 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateLineBreakResult, nsresult>
1685 InsertPaddingBRElementIfNeeded(const EditorDOMPoint& aPoint,
1686 nsIEditor::EStripWrappers aDeleteEmptyInlines,
1687 const Element& aEditingHost);
1689 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
1690 DeleteRangesWithTransaction(
1691 nsIEditor::EDirection aDirectionAndAmount,
1692 nsIEditor::EStripWrappers aStripWrappers,
1693 const AutoClonedRangeArray& aRangesToDelete) override;
1696 * SplitParagraphWithTransaction() splits the parent block, aParentDivOrP, at
1697 * aStartOfRightNode.
1699 * @param aParentDivOrP The parent block to be split. This must be <p>
1700 * or <div> element.
1701 * @param aStartOfRightNode The point to be start of right node after
1702 * split. This must be descendant of
1703 * aParentDivOrP.
1704 * @param aMayBecomeVisibleBRElement
1705 * Next <br> element of the split point if there
1706 * is. Otherwise, nullptr. If this is not nullptr,
1707 * the <br> element may be removed if it becomes
1708 * visible.
1709 * @param aEditingHost The editing host.
1711 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
1712 SplitParagraphWithTransaction(Element& aParentDivOrP,
1713 const EditorDOMPoint& aStartOfRightNode,
1714 dom::HTMLBRElement* aMayBecomeVisibleBRElement,
1715 const Element& aEditingHost);
1718 * HandleInsertParagraphInParagraph() does the right thing for Enter key
1719 * press or 'insertParagraph' command in aParentDivOrP. aParentDivOrP will
1720 * be split **around** aCandidatePointToSplit. If this thinks that it should
1721 * be handled to insert a <br> instead, this returns "not handled".
1723 * @param aParentDivOrP The parent block. This must be <p> or <div>
1724 * element.
1725 * @param aCandidatePointToSplit
1726 * The point where the caller want to split
1727 * aParentDivOrP. However, in some cases, this is not
1728 * used as-is. E.g., this method avoids to create new
1729 * empty <a href> in the right paragraph. So this may
1730 * be adjusted to proper position around it.
1731 * @param aEditingHost The editing host.
1732 * @return If the caller should default to inserting <br>
1733 * element, returns "not handled".
1735 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
1736 HandleInsertParagraphInParagraph(Element& aParentDivOrP,
1737 const EditorDOMPoint& aCandidatePointToSplit,
1738 const Element& aEditingHost);
1741 * HandleInsertParagraphInHeadingElement() handles insertParagraph command
1742 * (i.e., handling Enter key press) in a heading element. This splits
1743 * aHeadingElement element at aPointToSplit. Then, if right heading element
1744 * is empty, it'll be removed and new paragraph is created (its type is
1745 * decided with default paragraph separator).
1747 * @param aHeadingElement The heading element to be split.
1748 * @param aPointToSplit The point to split aHeadingElement.
1749 * @return New paragraph element, meaning right heading
1750 * element if aHeadingElement is split, or newly
1751 * created or existing paragraph element.
1753 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<InsertParagraphResult, nsresult>
1754 HandleInsertParagraphInHeadingElement(Element& aHeadingElement,
1755 const EditorDOMPoint& aPointToSplit);
1758 * HandleInsertParagraphInListItemElement() handles insertParagraph command
1759 * (i.e., handling Enter key press) in a list item element.
1761 * @param aListItemElement The list item which has the following point.
1762 * @param aPointToSplit The point to split aListItemElement.
1763 * @param aEditingHost The editing host.
1764 * @return New paragraph element, meaning right list item
1765 * element if aListItemElement is split, or newly
1766 * created paragraph element.
1768 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<InsertParagraphResult, nsresult>
1769 HandleInsertParagraphInListItemElement(Element& aListItemElement,
1770 const EditorDOMPoint& aPointToSplit,
1771 const Element& aEditingHost);
1774 * InsertParagraphSeparatorAsSubAction() handles insertPargraph commad
1775 * (i.e., handling Enter key press) with the above helper methods.
1777 * @param aEditingHost The editing host.
1779 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
1780 InsertParagraphSeparatorAsSubAction(const Element& aEditingHost);
1783 * InsertLineBreakAsSubAction() inserts a new <br> element or a linefeed
1784 * character at selection. If there is non-collapsed selection ranges, the
1785 * selected ranges is deleted first.
1787 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertLineBreakAsSubAction();
1790 * ChangeListElementType() replaces child list items of aListElement with
1791 * new list item element whose tag name is aNewListItemTag.
1792 * Note that if there are other list elements as children of aListElement,
1793 * this calls itself recursively even though it's invalid structure.
1795 * @param aListElement The list element whose list items will be
1796 * replaced.
1797 * @param aNewListTag New list tag name.
1798 * @param aNewListItemTag New list item tag name.
1799 * @return New list element or an error code if it fails.
1800 * New list element may be aListElement if its
1801 * tag name is same as aNewListTag.
1803 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1804 ChangeListElementType(Element& aListElement, nsAtom& aListType,
1805 nsAtom& aItemType);
1807 class AutoListElementCreator;
1809 [[nodiscard]] static bool IsFormatElement(FormatBlockMode aFormatBlockMode,
1810 const nsIContent& aContent);
1813 * MakeOrChangeListAndListItemAsSubAction() handles create list commands with
1814 * current selection. If
1816 * @param aListElementOrListItemElementTagName
1817 * The new list element tag name or
1818 * new list item tag name.
1819 * If the former, list item tag name will
1820 * be computed automatically. Otherwise,
1821 * list tag name will be computed.
1822 * @param aBulletType If this is not empty string, it's set
1823 * to `type` attribute of new list item
1824 * elements. Otherwise, existing `type`
1825 * attributes will be removed.
1826 * @param aSelectAllOfCurrentList Yes if this should treat all of
1827 * ancestor list element at selection.
1828 * @param aEditingHost The editing host.
1830 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
1831 MakeOrChangeListAndListItemAsSubAction(
1832 const nsStaticAtom& aListElementOrListItemElementTagName,
1833 const nsAString& aBulletType,
1834 SelectAllOfCurrentList aSelectAllOfCurrentList,
1835 const Element& aEditingHost);
1838 * DeleteTextAndTextNodesWithTransaction() removes text or text nodes in
1839 * the given range.
1841 enum class TreatEmptyTextNodes {
1842 // KeepIfContainerOfRangeBoundaries:
1843 // Will remove empty text nodes middle of the range, but keep empty
1844 // text nodes which are containers of range boundaries.
1845 KeepIfContainerOfRangeBoundaries,
1846 // Remove:
1847 // Will remove all empty text nodes.
1848 Remove,
1849 // RemoveAllEmptyInlineAncestors:
1850 // Will remove all empty text nodes and its inline ancestors which
1851 // become empty due to removing empty text nodes.
1852 RemoveAllEmptyInlineAncestors,
1854 template <typename EditorDOMPointType>
1855 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
1856 DeleteTextAndTextNodesWithTransaction(
1857 const EditorDOMPointType& aStartPoint,
1858 const EditorDOMPointType& aEndPoint,
1859 TreatEmptyTextNodes aTreatEmptyTextNodes);
1862 * Delete the line break with DeleteNodeTransaction or DeleteTextTransaction.
1864 * @param aLineBreak The line break to be deleted.
1865 * @param aDeleteEmptyInlines If nsIEditor::eStrip, this deletes new empty
1866 * inline element if and only if this deletes the
1867 * line break node.
1868 * @param aEditingHost The editing host.
1869 * @return The point where the line break was.
1871 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1872 DeleteLineBreakWithTransaction(const EditorLineBreak& aLineBreak,
1873 nsIEditor::EStripWrappers aDeleteEmptyInlines,
1874 const Element& aEditingHost);
1877 * JoinNodesWithTransaction() joins aLeftContent and aRightContent. Content
1878 * of aLeftContent will be merged into aRightContent. Actual implemenation of
1879 * this method is JoinNodesImpl(). So, see its explanation for the detail.
1881 * @param aLeftContent Will be removed from the DOM tree.
1882 * @param aRightContent The node which will be new container of the content
1883 * of aLeftContent.
1885 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<JoinNodesResult, nsresult>
1886 JoinNodesWithTransaction(nsIContent& aLeftContent, nsIContent& aRightContent);
1889 * JoinNearestEditableNodesWithTransaction() joins two editable nodes which
1890 * are themselves or the nearest editable node of aLeftNode and aRightNode.
1891 * XXX This method's behavior is odd. For example, if user types Backspace
1892 * key at the second editable paragraph in this case:
1893 * <div contenteditable>
1894 * <p>first editable paragraph</p>
1895 * <p contenteditable="false">non-editable paragraph</p>
1896 * <p>second editable paragraph</p>
1897 * </div>
1898 * The first editable paragraph's content will be moved into the second
1899 * editable paragraph and the non-editable paragraph becomes the first
1900 * paragraph of the editor. I don't think that it's expected behavior of
1901 * any users...
1903 * @param aLeftNode The node which will be removed.
1904 * @param aRightNode The node which will be inserted the content of
1905 * aLeftNode.
1906 * @param aNewFirstChildOfRightNode
1907 * [out] The point at the first child of aRightNode.
1909 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1910 JoinNearestEditableNodesWithTransaction(
1911 nsIContent& aLeftNode, nsIContent& aRightNode,
1912 EditorDOMPoint* aNewFirstChildOfRightNode);
1915 * ReplaceContainerAndCloneAttributesWithTransaction() creates new element
1916 * whose name is aTagName, copies all attributes from aOldContainer to the
1917 * new element, moves all children in aOldContainer to the new element, then,
1918 * removes aOldContainer from the DOM tree.
1920 * @param aOldContainer The element node which should be replaced
1921 * with new element.
1922 * @param aTagName The name of new element node.
1924 [[nodiscard]] inline MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1925 ReplaceContainerAndCloneAttributesWithTransaction(Element& aOldContainer,
1926 const nsAtom& aTagName);
1929 * ReplaceContainerWithTransaction() creates new element whose name is
1930 * aTagName, sets aAttributes of the new element to aAttributeValue, moves
1931 * all children in aOldContainer to the new element, then, removes
1932 * aOldContainer from the DOM tree.
1934 * @param aOldContainer The element node which should be replaced
1935 * with new element.
1936 * @param aTagName The name of new element node.
1937 * @param aAttribute Attribute name to be set to the new element.
1938 * @param aAttributeValue Attribute value to be set to aAttribute.
1940 [[nodiscard]] inline MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1941 ReplaceContainerWithTransaction(Element& aOldContainer,
1942 const nsAtom& aTagName,
1943 const nsAtom& aAttribute,
1944 const nsAString& aAttributeValue);
1947 * ReplaceContainerWithTransaction() creates new element whose name is
1948 * aTagName, moves all children in aOldContainer to the new element, then,
1949 * removes aOldContainer from the DOM tree.
1951 * @param aOldContainer The element node which should be replaced
1952 * with new element.
1953 * @param aTagName The name of new element node.
1955 [[nodiscard]] inline MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1956 ReplaceContainerWithTransaction(Element& aOldContainer,
1957 const nsAtom& aTagName);
1960 * RemoveContainerWithTransaction() removes aElement from the DOM tree and
1961 * moves all its children to the parent of aElement.
1963 * @param aElement The element to be removed.
1964 * @return A suggestion point to put caret.
1966 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
1967 RemoveContainerWithTransaction(Element& aElement);
1970 * InsertContainerWithTransaction() creates new element whose name is
1971 * aWrapperTagName, moves aContentToBeWrapped into the new element, then,
1972 * inserts the new element into where aContentToBeWrapped was.
1973 * NOTE: This method does not check if aContentToBeWrapped is valid child
1974 * of the new element. So, callers need to guarantee it.
1976 * @param aContentToBeWrapped The content which will be wrapped with new
1977 * element.
1978 * @param aWrapperTagName Element name of new element which will wrap
1979 * aContent and be inserted into where aContent
1980 * was.
1981 * @param aInitializer A callback to initialize new element before
1982 * inserting to the DOM tree.
1984 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
1985 InsertContainerWithTransaction(
1986 nsIContent& aContentToBeWrapped, const nsAtom& aWrapperTagName,
1987 const InitializeInsertingElement& aInitializer = DoNothingForNewElement);
1990 * MoveNodeWithTransaction() moves aContentToMove to aPointToInsert.
1992 * @param aContentToMove The node to be moved.
1993 * @param aPointToInsert The point where aContentToMove will be inserted.
1995 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<MoveNodeResult, nsresult>
1996 MoveNodeWithTransaction(nsIContent& aContentToMove,
1997 const EditorDOMPoint& aPointToInsert);
2000 * MoveNodeToEndWithTransaction() moves aContentToMove to end of
2001 * aNewContainer.
2003 * @param aContentToMove The node to be moved.
2004 * @param aNewContainer The new container which will contain aContentToMove
2005 * as its last child.
2007 [[nodiscard]] inline MOZ_CAN_RUN_SCRIPT Result<MoveNodeResult, nsresult>
2008 MoveNodeToEndWithTransaction(nsIContent& aContentToMove,
2009 nsINode& aNewContainer);
2012 * MoveNodeOrChildrenWithTransaction() moves aContent to aPointToInsert. If
2013 * cannot insert aContent due to invalid relation, moves only its children
2014 * recursively and removes aContent from the DOM tree.
2016 * @param aContent Content which should be moved.
2017 * @param aPointToInsert The point to be inserted aContent or its
2018 * descendants.
2019 * @param aPreserveWhiteSpaceStyle
2020 * If yes and if it's possible to keep white-space
2021 * style, this method will set `style` attribute to
2022 * moving node or creating new <span> element.
2023 * @param aRemoveIfCommentNode
2024 * If yes, this removes a comment node instead of
2025 * moving it to the destination. Note that this
2026 * does not remove comment nodes in moving nodes
2027 * because it requires additional scan.
2029 enum class PreserveWhiteSpaceStyle { No, Yes };
2030 friend std::ostream& operator<<(
2031 std::ostream& aStream,
2032 const PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle);
2033 enum class RemoveIfCommentNode { No, Yes };
2034 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<MoveNodeResult, nsresult>
2035 MoveNodeOrChildrenWithTransaction(
2036 nsIContent& aContentToMove, const EditorDOMPoint& aPointToInsert,
2037 PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle,
2038 RemoveIfCommentNode aRemoveIfCommentNode);
2041 * CanMoveNodeOrChildren() returns true if
2042 * `MoveNodeOrChildrenWithTransaction()` can move or delete at least a
2043 * descendant of aElement into aNewContainer. I.e., when this returns true,
2044 * `MoveNodeOrChildrenWithTransaction()` must return "handled".
2046 Result<bool, nsresult> CanMoveNodeOrChildren(
2047 const nsIContent& aContent, const nsINode& aNewContainer) const;
2050 * MoveChildrenWithTransaction() moves the children of aElement to
2051 * aPointToInsert. If cannot insert some children due to invalid relation,
2052 * calls MoveNodeOrChildrenWithTransaction() to remove the children but keep
2053 * moving its children.
2055 * @param aElement Container element whose children should be
2056 * moved.
2057 * @param aPointToInsert The point to be inserted children of aElement
2058 * or its descendants.
2059 * @param aPreserveWhiteSpaceStyle
2060 * If yes and if it's possible to keep white-space
2061 * style, this method will set `style` attribute to
2062 * moving node or creating new <span> element.
2063 * @param aRemoveIfCommentNode
2064 * If yes, this removes a comment node instead of
2065 * moving it to the destination. Note that this
2066 * does not remove comment nodes in moving nodes
2067 * because it requires additional scan.
2069 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<MoveNodeResult, nsresult>
2070 MoveChildrenWithTransaction(Element& aElement,
2071 const EditorDOMPoint& aPointToInsert,
2072 PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle,
2073 RemoveIfCommentNode aRemoveIfCommentNode);
2076 * CanMoveChildren() returns true if `MoveChildrenWithTransaction()` can move
2077 * at least a descendant of aElement into aNewContainer. I.e., when this
2078 * returns true, `MoveChildrenWithTransaction()` return "handled".
2080 Result<bool, nsresult> CanMoveChildren(const Element& aElement,
2081 const nsINode& aNewContainer) const;
2084 * MoveAllChildren() moves all children of aContainer to before
2085 * aPointToInsert.GetChild().
2086 * See explanation of MoveChildrenBetween() for the detail of the behavior.
2088 * @param aContainer The container node whose all children should
2089 * be moved.
2090 * @param aPointToInsert The insertion point. The container must not
2091 * be a data node like a text node.
2093 [[nodiscard]] nsresult MoveAllChildren(
2094 nsINode& aContainer, const EditorRawDOMPoint& aPointToInsert);
2097 * MoveChildrenBetween() moves all children between aFirstChild and aLastChild
2098 * to before aPointToInsert.GetChild(). If some children are moved to
2099 * different container while this method moves other children, they are just
2100 * ignored. If the child node referred by aPointToInsert is moved to different
2101 * container while this method moves children, returns error.
2103 * @param aFirstChild The first child which should be moved to
2104 * aPointToInsert.
2105 * @param aLastChild The last child which should be moved. This
2106 * must be a sibling of aFirstChild and it should
2107 * be positioned after aFirstChild in the DOM tree
2108 * order.
2109 * @param aPointToInsert The insertion point. The container must not
2110 * be a data node like a text node.
2112 [[nodiscard]] nsresult MoveChildrenBetween(
2113 nsIContent& aFirstChild, nsIContent& aLastChild,
2114 const EditorRawDOMPoint& aPointToInsert);
2117 * MovePreviousSiblings() moves all siblings before aChild (i.e., aChild
2118 * won't be moved) to before aPointToInsert.GetChild().
2119 * See explanation of MoveChildrenBetween() for the detail of the behavior.
2121 * @param aChild The node which is next sibling of the last
2122 * node to be moved.
2123 * @param aPointToInsert The insertion point. The container must not
2124 * be a data node like a text node.
2126 [[nodiscard]] nsresult MovePreviousSiblings(
2127 nsIContent& aChild, const EditorRawDOMPoint& aPointToInsert);
2130 * MoveInclusiveNextSiblings() moves aChild and all siblings after it to
2131 * before aPointToInsert.GetChild().
2132 * See explanation of MoveChildrenBetween() for the detail of the behavior.
2134 * @param aChild The node which is first node to be moved.
2135 * @param aPointToInsert The insertion point. The container must not
2136 * be a data node like a text node.
2138 [[nodiscard]] nsresult MoveInclusiveNextSiblings(
2139 nsIContent& aChild, const EditorRawDOMPoint& aPointToInsert);
2142 * SplitNodeWithTransaction() creates a transaction to create a new node
2143 * (left node) identical to an existing node (right node), and split the
2144 * contents between the same point in both nodes, then, execute the
2145 * transaction.
2147 * @param aStartOfRightNode The point to split. Its container will be
2148 * the right node, i.e., become the new node's
2149 * next sibling. And the point will be start
2150 * of the right node.
2152 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
2153 SplitNodeWithTransaction(const EditorDOMPoint& aStartOfRightNode);
2156 * SplitNodeDeepWithTransaction() splits aMostAncestorToSplit deeply.
2158 * @param aMostAncestorToSplit The most ancestor node which should be
2159 * split.
2160 * @param aStartOfDeepestRightNode The start point of deepest right node.
2161 * This point must be descendant of
2162 * aMostAncestorToSplit.
2163 * @param aSplitAtEdges Whether the caller allows this to
2164 * create empty container element when
2165 * split point is start or end of an
2166 * element.
2167 * @return SplitPoint() returns split point in
2168 * aMostAncestorToSplit. The point must
2169 * be good to insert something if the
2170 * caller want to do it.
2172 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitNodeResult, nsresult>
2173 SplitNodeDeepWithTransaction(nsIContent& aMostAncestorToSplit,
2174 const EditorDOMPoint& aDeepestStartOfRightNode,
2175 SplitAtEdges aSplitAtEdges);
2178 * DeleteEmptyInclusiveAncestorInlineElements() removes empty inclusive
2179 * ancestor inline elements in inclusive ancestor block element of aContent.
2181 * @param aContent Must be an empty content.
2182 * @param aEditingHost The editing host.
2184 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
2185 DeleteEmptyInclusiveAncestorInlineElements(nsIContent& aContent,
2186 const Element& aEditingHost);
2189 * DeleteTextAndNormalizeSurroundingWhiteSpaces() deletes text between
2190 * aStartToDelete and immediately before aEndToDelete and return new caret
2191 * position. If surrounding characters are white-spaces, this normalize them
2192 * too. Finally, inserts `<br>` element if it's required.
2193 * Note that if you wants only normalizing white-spaces, you can set same
2194 * point to both aStartToDelete and aEndToDelete. Then, this tries to
2195 * normalize white-space sequence containing previous character of
2196 * aStartToDelete.
2198 enum class DeleteDirection {
2199 Forward,
2200 Backward,
2202 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
2203 DeleteTextAndNormalizeSurroundingWhiteSpaces(
2204 const EditorDOMPointInText& aStartToDelete,
2205 const EditorDOMPointInText& aEndToDelete,
2206 TreatEmptyTextNodes aTreatEmptyTextNodes,
2207 DeleteDirection aDeleteDirection, const Element& aEditingHost);
2210 * ExtendRangeToDeleteWithNormalizingWhiteSpaces() is a helper method of
2211 * DeleteTextAndNormalizeSurroundingWhiteSpaces(). This expands
2212 * aStartToDelete and/or aEndToDelete if there are white-spaces which need
2213 * normalizing.
2215 * @param aStartToDelete [In/Out] Start to delete. If this point
2216 * follows white-spaces, this may be modified.
2217 * @param aEndToDelete [In/Out] Next point of last content to be
2218 * deleted. If this point is a white-space,
2219 * this may be modified.
2220 * @param aNormalizedWhiteSpacesInStartNode
2221 * [Out] If container text node of aStartToDelete
2222 * should be modified, this offers new string
2223 * in the range in the text node.
2224 * @param aNormalizedWhiteSpacesInEndNode
2225 * [Out] If container text node of aEndToDelete
2226 * is different from the container of
2227 * aStartToDelete and it should be modified, this
2228 * offers new string in the range in the text node.
2230 void ExtendRangeToDeleteWithNormalizingWhiteSpaces(
2231 EditorDOMPointInText& aStartToDelete, EditorDOMPointInText& aEndToDelete,
2232 nsAString& aNormalizedWhiteSpacesInStartNode,
2233 nsAString& aNormalizedWhiteSpacesInEndNode) const;
2236 * CharPointType let the following helper methods of
2237 * ExtendRangeToDeleteWithNormalizingWhiteSpaces() know what type of
2238 * character will be previous or next char point after deletion.
2240 enum class CharPointType {
2241 TextEnd, // Start or end of the text (hardline break or replaced inline
2242 // element)
2243 ASCIIWhiteSpace, // One of ASCII white-spaces (collapsible white-space)
2244 NoBreakingSpace, // NBSP
2245 VisibleChar, // Non-white-space characters
2246 PreformattedChar, // Any character except a linefeed in a preformatted
2247 // node.
2248 PreformattedLineBreak, // Preformatted linebreak
2252 * GetPreviousCharPointType() and GetCharPointType() get type of
2253 * previous/current char point from current DOM tree. In other words, if the
2254 * point will be deleted, you cannot use these methods.
2256 template <typename EditorDOMPointType>
2257 static CharPointType GetPreviousCharPointType(
2258 const EditorDOMPointType& aPoint);
2259 template <typename EditorDOMPointType>
2260 static CharPointType GetCharPointType(const EditorDOMPointType& aPoint);
2263 * CharPointData let the following helper methods of
2264 * ExtendRangeToDeleteWithNormalizingWhiteSpaces() know what type of
2265 * character will be previous or next char point and the point is
2266 * in same or different text node after deletion.
2268 class MOZ_STACK_CLASS CharPointData final {
2269 public:
2270 static CharPointData InDifferentTextNode(CharPointType aCharPointType) {
2271 CharPointData result;
2272 result.mIsInDifferentTextNode = true;
2273 result.mType = aCharPointType;
2274 return result;
2276 static CharPointData InSameTextNode(CharPointType aCharPointType) {
2277 CharPointData result;
2278 // Let's mark this as in different text node if given one indicates
2279 // that there is end of text because it means that adjacent content
2280 // from point of text node view is another element.
2281 result.mIsInDifferentTextNode = aCharPointType == CharPointType::TextEnd;
2282 result.mType = aCharPointType;
2283 return result;
2286 bool AcrossTextNodeBoundary() const { return mIsInDifferentTextNode; }
2287 bool IsCollapsibleWhiteSpace() const {
2288 return mType == CharPointType::ASCIIWhiteSpace ||
2289 mType == CharPointType::NoBreakingSpace;
2291 CharPointType Type() const { return mType; }
2293 private:
2294 CharPointData() = default;
2296 CharPointType mType;
2297 bool mIsInDifferentTextNode;
2301 * GetPreviousCharPointDataForNormalizingWhiteSpaces() and
2302 * GetInclusiveNextCharPointDataForNormalizingWhiteSpaces() is helper methods
2303 * of ExtendRangeToDeleteWithNormalizingWhiteSpaces(). This retrieves
2304 * previous or inclusive next editable char point and returns its data.
2306 CharPointData GetPreviousCharPointDataForNormalizingWhiteSpaces(
2307 const EditorDOMPointInText& aPoint) const;
2308 CharPointData GetInclusiveNextCharPointDataForNormalizingWhiteSpaces(
2309 const EditorDOMPointInText& aPoint) const;
2312 * GenerateWhiteSpaceSequence() generates white-space sequence which won't
2313 * be collapsed.
2315 * @param aResult [out] White space sequence which won't be
2316 * collapsed, but wrapable.
2317 * @param aLength Length of generating white-space sequence.
2318 * Must be 1 or larger.
2319 * @param aPreviousCharPointData
2320 * Specify the previous char point where it'll be
2321 * inserted. Currently, for keepin this method
2322 * simple, does not support to generate a part
2323 * of white-space sequence in a text node. So,
2324 * if the type is white-space, it must indicate
2325 * different text nodes white-space.
2326 * @param aNextCharPointData Specify the next char point where it'll be
2327 * inserted. Same as aPreviousCharPointData,
2328 * this must node indidate white-space in same
2329 * text node.
2331 static void GenerateWhiteSpaceSequence(
2332 nsAString& aResult, uint32_t aLength,
2333 const CharPointData& aPreviousCharPointData,
2334 const CharPointData& aNextCharPointData);
2337 * ComputeTargetRanges() computes actual delete ranges which will be deleted
2338 * unless the following `beforeinput` event is canceled.
2340 * @param aDirectionAndAmount The direction and amount of deletion.
2341 * @param aRangesToDelete [In/Out] The ranges to be deleted,
2342 * typically, initialized with the
2343 * selection ranges. This may be modified
2344 * if selection ranges should be extened.
2346 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2347 ComputeTargetRanges(nsIEditor::EDirection aDirectionAndAmount,
2348 AutoClonedSelectionRangeArray& aRangesToDelete) const;
2351 * This method handles "delete selection" commands.
2353 * @param aDirectionAndAmount Direction of the deletion.
2354 * @param aStripWrappers Must be eStrip or eNoStrip.
2356 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2357 HandleDeleteSelection(nsIEditor::EDirection aDirectionAndAmount,
2358 nsIEditor::EStripWrappers aStripWrappers) final;
2360 class AutoDeleteRangesHandler;
2361 class AutoMoveOneLineHandler;
2364 * DeleteMostAncestorMailCiteElementIfEmpty() deletes most ancestor
2365 * mail cite element (`<blockquote type="cite">` or
2366 * `<span _moz_quote="true">`, the former can be created with middle click
2367 * paste with `Control` or `Command` even in the web) of aContent if it
2368 * becomes empty.
2370 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2371 DeleteMostAncestorMailCiteElementIfEmpty(nsIContent& aContent);
2374 * LiftUpListItemElement() moves aListItemElement outside its parent.
2375 * If it's in a middle of a list element, the parent list element is split
2376 * before aListItemElement. Then, moves aListItemElement to before its
2377 * parent list element. I.e., moves aListItemElement between the 2 list
2378 * elements if original parent was split. Then, if new parent becomes not a
2379 * list element, the list item element is removed and its contents are moved
2380 * to where the list item element was. If aListItemElement becomse not a
2381 * child of list element, its contents are unwrapped from aListItemElement.
2383 * @param aListItemElement Must be a <li>, <dt> or <dd> element.
2384 * @param aLiftUpFromAllParentListElements
2385 * If Yes, this method calls itself recursively
2386 * to unwrap the contents in aListItemElement
2387 * from any ancestor list elements.
2388 * XXX This checks only direct parent of list
2389 * elements. Therefore, if a parent list
2390 * element in a list item element, the
2391 * list item element and its list element
2392 * won't be unwrapped.
2394 enum class LiftUpFromAllParentListElements { Yes, No };
2395 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult LiftUpListItemElement(
2396 dom::Element& aListItemElement,
2397 LiftUpFromAllParentListElements aLiftUpFromAllParentListElements);
2400 * DestroyListStructureRecursively() destroys the list structure of
2401 * aListElement recursively.
2402 * If aListElement has <li>, <dl> or <dt> as a child, the element is removed
2403 * but its descendants are moved to where the list item element was.
2404 * If aListElement has another <ul>, <ol> or <dl> as a child, this method is
2405 * called recursively.
2406 * If aListElement has other nodes as its child, they are just removed.
2407 * Finally, aListElement is removed. and its all children are moved to
2408 * where the aListElement was.
2410 * @param aListElement A <ul>, <ol> or <dl> element.
2412 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2413 DestroyListStructureRecursively(Element& aListElement);
2416 * RemoveListAtSelectionAsSubAction() removes list elements and list item
2417 * elements at Selection. And move contents in them where the removed list
2418 * was.
2420 * @param aEditingHost The editing host.
2422 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2423 RemoveListAtSelectionAsSubAction(const Element& aEditingHost);
2426 * ChangeMarginStart() changes margin of aElement to indent or outdent.
2427 * If it's rtl text, margin-right will be changed. Otherwise, margin-left.
2428 * XXX This is not aware of vertical writing-mode.
2430 * @param aElement The element whose start margin should be
2431 * changed.
2432 * @param aChangeMargin Whether increase or decrease the margin.
2433 * @param aEditingHost The editing host.
2434 * @return May suggest a suggest point to put caret.
2436 enum class ChangeMargin { Increase, Decrease };
2437 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
2438 ChangeMarginStart(Element& aElement, ChangeMargin aChangeMargin,
2439 const Element& aEditingHost);
2442 * HandleCSSIndentAroundRanges() indents around aRanges with CSS.
2444 * @param aRanges The ranges where the content should be indented.
2445 * @param aEditingHost The editing host.
2447 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult HandleCSSIndentAroundRanges(
2448 AutoClonedSelectionRangeArray& aRanges, const Element& aEditingHost);
2451 * HandleCSSIndentAroundRanges() indents around aRanges with HTML.
2453 * @param aRanges The ranges where the content should be indented.
2454 * @param aEditingHost The editing host.
2456 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult HandleHTMLIndentAroundRanges(
2457 AutoClonedSelectionRangeArray& aRanges, const Element& aEditingHost);
2460 * HandleIndentAtSelection() indents around Selection with HTML or CSS.
2462 * @param aEditingHost The editing host.
2464 // TODO: Make this take AutoClonedSelectionRangeArray instead of retrieving
2465 // `Selection`
2466 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2467 HandleIndentAtSelection(const Element& aEditingHost);
2470 * OutdentPartOfBlock() outdents the nodes between aStartOfOutdent and
2471 * aEndOfOutdent. This splits the range off from aBlockElement first.
2472 * Then, removes the middle element if aIsBlockIndentedWithCSS is false.
2473 * Otherwise, decreases the margin of the middle element.
2475 * @param aBlockElement A block element which includes both
2476 * aStartOfOutdent and aEndOfOutdent.
2477 * @param aStartOfOutdent First node which is descendant of
2478 * aBlockElement will be outdented.
2479 * @param aEndOfOutdent Last node which is descandant of
2480 * aBlockElement will be outdented.
2481 * @param aBlockIndentedWith `CSS` if aBlockElement is indented with
2482 * CSS margin property.
2483 * `HTML` if aBlockElement is `<blockquote>`
2484 * or something.
2485 * @param aEditingHost The editing host.
2486 * @return The left content is new created element
2487 * splitting before aStartOfOutdent.
2488 * The right content is existing element.
2489 * The middle content is outdented element
2490 * if aBlockIndentedWith is `CSS`.
2491 * Otherwise, nullptr.
2493 enum class BlockIndentedWith { CSS, HTML };
2494 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffFromNodeResult, nsresult>
2495 OutdentPartOfBlock(Element& aBlockElement, nsIContent& aStartOfOutdent,
2496 nsIContent& aEndOfOutdent,
2497 BlockIndentedWith aBlockIndentedWith,
2498 const Element& aEditingHost);
2501 * HandleOutdentAtSelectionInternal() outdents contents around Selection.
2502 * This method creates AutoSelectionRestorer. Therefore, each caller
2503 * needs to check if the editor is still available even if this returns
2504 * NS_OK.
2505 * NOTE: Call `HandleOutdentAtSelection()` instead.
2507 * @param aEditingHost The editing host.
2508 * @return The left content is left content of last
2509 * outdented element.
2510 * The right content is right content of last
2511 * outdented element.
2512 * The middle content is middle content of last
2513 * outdented element.
2515 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffFromNodeResult, nsresult>
2516 HandleOutdentAtSelectionInternal(const Element& aEditingHost);
2519 * HandleOutdentAtSelection() outdents contents around Selection.
2521 * @param aEditingHost The editing host.
2523 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2524 HandleOutdentAtSelection(const Element& aEditingHost);
2527 * AlignBlockContentsWithDivElement() sets align attribute of <div> element
2528 * which is only child of aBlockElement to aAlignType. If aBlockElement
2529 * has 2 or more children or does not have a `<div>` element, inserts a
2530 * new `<div>` element into aBlockElement and move all children of
2531 * aBlockElement into the new `<div>` element.
2533 * @param aBlockElement The element node whose contents should be
2534 * aligned to aAlignType. This should be
2535 * an element which can have `<div>` element
2536 * as its child.
2537 * @param aAlignType New value of align attribute of `<div>`
2538 * element.
2539 * @return A candidate position to put caret.
2541 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
2542 AlignBlockContentsWithDivElement(Element& aBlockElement,
2543 const nsAString& aAlignType);
2546 * AlignContentsInAllTableCellsAndListItems() calls
2547 * AlignBlockContentsWithDivElement() for aligning contents in every list
2548 * item element and table cell element in aElement.
2550 * @param aElement The node which is or whose descendants should
2551 * be aligned to aAlignType.
2552 * @param aAlignType New value of `align` attribute of `<div>`.
2553 * @return A candidate position to put caret.
2555 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
2556 AlignContentsInAllTableCellsAndListItems(dom::Element& aElement,
2557 const nsAString& aAlignType);
2560 * MakeTransitionList() detects all the transitions in the array, where a
2561 * transition means that adjacent nodes in the array don't have the same
2562 * parent.
2564 static void MakeTransitionList(
2565 const nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
2566 nsTArray<bool>& aTransitionArray);
2569 * EnsureHardLineBeginsWithFirstChildOf() inserts `<br>` element before
2570 * first child of aRemovingContainerElement if it will not be start of a
2571 * hard line after removing aRemovingContainerElement.
2573 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
2574 EnsureHardLineBeginsWithFirstChildOf(Element& aRemovingContainerElement);
2577 * EnsureHardLineEndsWithLastChildOf() inserts `<br>` element after last
2578 * child of aRemovingContainerElement if it will not be end of a hard line
2579 * after removing aRemovingContainerElement.
2581 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
2582 EnsureHardLineEndsWithLastChildOf(Element& aRemovingContainerElement);
2585 * RemoveAlignFromDescendants() removes align attributes, text-align
2586 * properties and <center> elements in aElement.
2588 * @param aElement Alignment information of the node and/or its
2589 * descendants will be removed.
2590 * NOTE: aElement must not be a `<table>` element.
2591 * @param aAlignType New align value to be set only when it's in
2592 * CSS mode and this method meets <table> or <hr>.
2593 * XXX This is odd and not clear when you see caller of
2594 * this method. Do you have better idea?
2595 * @param aEditTarget If `OnlyDescendantsExceptTable`, modifies only
2596 * descendants of aElement.
2597 * If `NodeAndDescendantsExceptTable`, modifies `aElement`
2598 * and its descendants.
2599 * @return A candidate point to put caret.
2601 enum class EditTarget {
2602 OnlyDescendantsExceptTable,
2603 NodeAndDescendantsExceptTable
2605 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
2606 RemoveAlignFromDescendants(Element& aElement, const nsAString& aAlignType,
2607 EditTarget aEditTarget);
2610 * SetBlockElementAlign() resets `align` attribute, `text-align` property
2611 * of descendants of aBlockOrHRElement except `<table>` element descendants.
2612 * Then, set `align` attribute or `text-align` property of aBlockOrHRElement.
2614 * @param aBlockOrHRElement The element whose contents will be aligned.
2615 * This must be a block element or `<hr>` element.
2616 * If we're not in CSS mode, this element has
2617 * to support `align` attribute (i.e.,
2618 * `HTMLEditUtils::SupportsAlignAttr()` must
2619 * return true).
2620 * @param aAlignType Boundary or "center" which contents should be
2621 * aligned on.
2622 * @param aEditTarget If `OnlyDescendantsExceptTable`, modifies only
2623 * descendants of aBlockOrHRElement.
2624 * If `NodeAndDescendantsExceptTable`, modifies
2625 * aBlockOrHRElement and its descendants.
2626 * @return A candidate point to put caret.
2628 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
2629 SetBlockElementAlign(Element& aBlockOrHRElement, const nsAString& aAlignType,
2630 EditTarget aEditTarget);
2633 * InsertDivElementToAlignContents() inserts a new <div> element (which has
2634 * only a padding <br> element) to aPointToInsert for a placeholder whose
2635 * contents will be aligned.
2637 * @param aPointToInsert A point to insert new empty <div>.
2638 * @param aAlignType New align attribute value where the contents
2639 * should be aligned to.
2640 * @param aEditingHost The editing host.
2641 * @return New <div> element which has only a padding <br>
2642 * element and is styled to align contents.
2644 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
2645 InsertDivElementToAlignContents(const EditorDOMPoint& aPointToInsert,
2646 const nsAString& aAlignType,
2647 const Element& aEditingHost);
2650 * AlignNodesAndDescendants() make contents of nodes in aArrayOfContents and
2651 * their descendants aligned to aAlignType.
2653 * @param aAlignType New align attribute value where the contents
2654 * should be aligned to.
2655 * @param aEditingHost The editing host.
2656 * @return Last created <div> element which should contain
2657 * caret and candidate position which may be
2658 * outside the <div> element.
2660 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
2661 AlignNodesAndDescendants(
2662 nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
2663 const nsAString& aAlignType, const Element& aEditingHost);
2666 * AlignContentsAtRanges() aligns contents around aRanges to aAlignType.
2668 * @param aRanges The ranges where should be aligned.
2669 * @param aAlignType New align attribute value where the contents
2670 * should be aligned to.
2671 * @param aEditingHost The editing host.
2673 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult AlignContentsAtRanges(
2674 AutoClonedSelectionRangeArray& aRanges, const nsAString& aAlignType,
2675 const Element& aEditingHost);
2678 * AlignAsSubAction() handles "align" command with `Selection`.
2680 * @param aAlignType New align attribute value where the contents
2681 * should be aligned to.
2682 * @param aEditingHost The editing host.
2684 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2685 AlignAsSubAction(const nsAString& aAlignType, const Element& aEditingHost);
2688 * AdjustCaretPositionAndEnsurePaddingBRElement() may adjust caret
2689 * position to nearest editable content and if padding `<br>` element is
2690 * necessary at caret position, this creates it.
2692 * @param aDirectionAndAmount Direction of the edit action.
2694 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2695 AdjustCaretPositionAndEnsurePaddingBRElement(
2696 nsIEditor::EDirection aDirectionAndAmount);
2699 * EnsureSelectionInBodyOrDocumentElement() collapse `Selection` to the
2700 * primary `<body>` element or document element when `Selection` crosses
2701 * `<body>` element's boundary.
2703 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2704 EnsureSelectionInBodyOrDocumentElement();
2707 * InsertBRElementToEmptyListItemsAndTableCellsInRange() inserts
2708 * `<br>` element into empty list item or table cell elements between
2709 * aStartRef and aEndRef.
2711 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2712 InsertBRElementToEmptyListItemsAndTableCellsInRange(
2713 const RawRangeBoundary& aStartRef, const RawRangeBoundary& aEndRef);
2716 * RemoveEmptyNodesIn() removes all empty nodes in aRange. However, if
2717 * mail-cite node has only a `<br>` element, the node will be removed
2718 * but <br> element is moved to where the mail-cite node was.
2719 * XXX This method is expensive if aRange is too wide and may remove
2720 * unexpected empty element, e.g., it was created by JS, but we haven't
2721 * touched it. Cannot we remove this method and make guarantee that
2722 * empty nodes won't be created?
2724 * @param aRange Must be positioned.
2726 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2727 RemoveEmptyNodesIn(const EditorDOMRange& aRange);
2730 * SetSelectionInterlinePosition() may set interline position if caret is
2731 * positioned around `<br>` or block boundary. Don't call this when
2732 * `Selection` is not collapsed.
2734 void SetSelectionInterlinePosition();
2737 * Called by `HTMLEditor::OnEndHandlingTopLevelEditSubAction()`. This may
2738 * adjust Selection, remove unnecessary empty nodes, create `<br>` elements
2739 * if needed, etc.
2741 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2742 OnEndHandlingTopLevelEditSubActionInternal();
2745 * MoveSelectedContentsToDivElementToMakeItAbsolutePosition() looks for
2746 * a `<div>` element in selection first. If not, creates new `<div>`
2747 * element. Then, move all selected contents into the target `<div>`
2748 * element.
2749 * Note that this creates AutoSelectionRestorer. Therefore, callers need
2750 * to check whether we have been destroyed even when this returns NS_OK.
2752 * @param aTargetElement Returns target `<div>` element which should be
2753 * changed to absolute positioned.
2754 * @param aEditingHost The editing host.
2756 // TODO: Rewrite this with `Result<RefPtr<Element>, nsresult>`.
2757 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2758 MoveSelectedContentsToDivElementToMakeItAbsolutePosition(
2759 RefPtr<Element>* aTargetElement, const Element& aEditingHost);
2762 * SetSelectionToAbsoluteAsSubAction() move selected contents to first
2763 * selected `<div>` element or newly created `<div>` element and make
2764 * the `<div>` element positioned absolutely.
2766 * @param aEditingHost The editing host.
2768 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2769 SetSelectionToAbsoluteAsSubAction(const Element& aEditingHost);
2772 * SetSelectionToStaticAsSubAction() sets the `position` property of a
2773 * selection parent's block whose `position` is `absolute` to `static`.
2775 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2776 SetSelectionToStaticAsSubAction();
2779 * AddZIndexAsSubAction() adds aChange to `z-index` of nearest parent
2780 * absolute-positioned element from current selection.
2782 * @param aChange Amount to change `z-index`.
2784 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
2785 AddZIndexAsSubAction(int32_t aChange);
2788 * OnDocumentModified() is called when editor content is changed.
2790 MOZ_CAN_RUN_SCRIPT nsresult
2791 OnDocumentModified(const nsIContent* aContentWillBeRemoved = nullptr);
2793 protected: // Called by helper classes.
2794 MOZ_CAN_RUN_SCRIPT void OnStartToHandleTopLevelEditSubAction(
2795 EditSubAction aTopLevelEditSubAction,
2796 nsIEditor::EDirection aDirectionOfTopLevelEditSubAction,
2797 ErrorResult& aRv) final;
2798 MOZ_CAN_RUN_SCRIPT nsresult OnEndHandlingTopLevelEditSubAction() final;
2800 protected: // Shouldn't be used by friend classes
2801 virtual ~HTMLEditor();
2804 * InitEditorContentAndSelection() may insert `<br>` elements and padding
2805 * `<br>` elements if they are required for `<body>` or document element.
2806 * And collapse selection at the end if there is no selection ranges.
2808 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InitEditorContentAndSelection();
2811 * Collapse `Selection` to the last leaf content of the <body> or the document
2812 * element.
2814 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2815 CollapseSelectionToEndOfLastLeafNodeOfDocument() const;
2817 MOZ_CAN_RUN_SCRIPT nsresult SelectAllInternal() final;
2819 [[nodiscard]] Element* ComputeEditingHostInternal(
2820 const nsIContent* aContent, LimitInBodyElement aLimitInBodyElement) const;
2823 * Creates a range with just the supplied node and appends that to the
2824 * selection.
2826 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2827 AppendContentToSelectionAsRange(nsIContent& aContent);
2830 * When you are using AppendContentToSelectionAsRange(), call this first to
2831 * start a new selection.
2833 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult ClearSelection();
2836 * SelectContentInternal() sets Selection to aContentToSelect to
2837 * aContentToSelect + 1 in parent of aContentToSelect.
2839 * @param aContentToSelect The content which should be selected.
2841 MOZ_CAN_RUN_SCRIPT nsresult
2842 SelectContentInternal(nsIContent& aContentToSelect);
2845 * GetInclusiveAncestorByTagNameAtSelection() looks for an element node whose
2846 * name matches aTagName from anchor node of Selection to <body> element.
2848 * @param aTagName The tag name which you want to look for.
2849 * Must not be nsGkAtoms::_empty.
2850 * If nsGkAtoms::list, the result may be <ul>, <ol> or
2851 * <dl> element.
2852 * If nsGkAtoms::td, the result may be <td> or <th>.
2853 * If nsGkAtoms::href, the result may be <a> element
2854 * which has "href" attribute with non-empty value.
2855 * If nsGkAtoms::anchor, the result may be <a> which
2856 * has "name" attribute with non-empty value.
2857 * @return If an element which matches aTagName, returns
2858 * an Element. Otherwise, nullptr.
2860 Element* GetInclusiveAncestorByTagNameAtSelection(
2861 const nsStaticAtom& aTagName) const;
2864 * GetInclusiveAncestorByTagNameInternal() looks for an element node whose
2865 * name matches aTagName from aNode to <body> element.
2867 * @param aTagName The tag name which you want to look for.
2868 * Must not be nsGkAtoms::_empty.
2869 * If nsGkAtoms::list, the result may be <ul>, <ol> or
2870 * <dl> element.
2871 * If nsGkAtoms::td, the result may be <td> or <th>.
2872 * If nsGkAtoms::href, the result may be <a> element
2873 * which has "href" attribute with non-empty value.
2874 * If nsGkAtoms::anchor, the result may be <a> which
2875 * has "name" attribute with non-empty value.
2876 * @param aContent Start node to look for the element. This should
2877 * not be an orphan node.
2878 * @return If an element which matches aTagName, returns
2879 * an Element. Otherwise, nullptr.
2881 Element* GetInclusiveAncestorByTagNameInternal(
2882 const nsStaticAtom& aTagName, const nsIContent& aContent) const;
2885 * GetSelectedElement() returns a "selected" element node. "selected" means:
2886 * - there is only one selection range
2887 * - the range starts from an element node or in an element
2888 * - the range ends at immediately after same element
2889 * - and the range does not include any other element nodes.
2890 * Additionally, only when aTagName is nsGkAtoms::href, this thinks that an
2891 * <a> element which has non-empty "href" attribute includes the range, the
2892 * <a> element is selected.
2894 * NOTE: This method is implementation of nsIHTMLEditor.getSelectedElement()
2895 * and comm-central depends on this behavior. Therefore, if you need to use
2896 * this method internally but you need to change, perhaps, you should create
2897 * another method for avoiding breakage of comm-central apps.
2899 * @param aTagName The atom of tag name in lower case. Set this to
2900 * result of EditorUtils::GetTagNameAtom() if you have a
2901 * tag name with nsString.
2902 * If nullptr, this returns any element node or nullptr.
2903 * If nsGkAtoms::href, this returns an <a> element which
2904 * has non-empty "href" attribute or nullptr.
2905 * If nsGkAtoms::anchor, this returns an <a> element which
2906 * has non-empty "name" attribute or nullptr.
2907 * Otherwise, returns an element node whose name is
2908 * same as aTagName or nullptr.
2909 * @param aRv Returns error code.
2910 * @return A "selected" element.
2912 already_AddRefed<Element> GetSelectedElement(const nsAtom* aTagName,
2913 ErrorResult& aRv);
2916 * GetFirstTableRowElement() returns the first <tr> element in the most
2917 * nearest ancestor of aTableOrElementInTable or itself.
2918 * When aTableOrElementInTable is neither <table> nor in a <table> element,
2919 * returns NS_ERROR_FAILURE. However, if <table> does not have <tr> element,
2920 * returns nullptr.
2922 * @param aTableOrElementInTable <table> element or another element.
2923 * If this is a <table> element, returns
2924 * first <tr> element in it. Otherwise,
2925 * returns first <tr> element in nearest
2926 * ancestor <table> element.
2928 Result<RefPtr<Element>, nsresult> GetFirstTableRowElement(
2929 const Element& aTableOrElementInTable) const;
2932 * GetNextTableRowElement() returns next <tr> element of aTableRowElement.
2933 * This won't cross <table> element boundary but may cross table section
2934 * elements like <tbody>.
2935 * Note that if given element is <tr> but there is no next <tr> element, this
2936 * returns nullptr but does not return error.
2938 * @param aTableRowElement A <tr> element.
2940 Result<RefPtr<Element>, nsresult> GetNextTableRowElement(
2941 const Element& aTableRowElement) const;
2943 struct CellData;
2946 * CellIndexes store both row index and column index of a table cell.
2948 struct MOZ_STACK_CLASS CellIndexes final {
2949 int32_t mRow;
2950 int32_t mColumn;
2953 * This constructor initializes mRowIndex and mColumnIndex with indexes of
2954 * aCellElement.
2956 * @param aCellElement An <td> or <th> element.
2958 MOZ_CAN_RUN_SCRIPT CellIndexes(Element& aCellElement, PresShell* aPresShell)
2959 : mRow(-1), mColumn(-1) {
2960 Update(aCellElement, aPresShell);
2964 * Update mRowIndex and mColumnIndex with indexes of aCellElement.
2966 * @param See above.
2968 MOZ_CAN_RUN_SCRIPT void Update(Element& aCellElement,
2969 PresShell* aPresShell);
2972 * This constructor initializes mRowIndex and mColumnIndex with indexes of
2973 * cell element which contains anchor of Selection.
2975 * @param aHTMLEditor The editor which creates the instance.
2976 * @param aSelection The Selection for the editor.
2978 MOZ_CAN_RUN_SCRIPT CellIndexes(HTMLEditor& aHTMLEditor,
2979 Selection& aSelection)
2980 : mRow(-1), mColumn(-1) {
2981 Update(aHTMLEditor, aSelection);
2985 * Update mRowIndex and mColumnIndex with indexes of cell element which
2986 * contains anchor of Selection.
2988 * @param See above.
2990 MOZ_CAN_RUN_SCRIPT void Update(HTMLEditor& aHTMLEditor,
2991 Selection& aSelection);
2993 bool operator==(const CellIndexes& aOther) const {
2994 return mRow == aOther.mRow && mColumn == aOther.mColumn;
2996 bool operator!=(const CellIndexes& aOther) const {
2997 return mRow != aOther.mRow || mColumn != aOther.mColumn;
3000 [[nodiscard]] bool isErr() const { return mRow < 0 || mColumn < 0; }
3002 private:
3003 CellIndexes() : mRow(-1), mColumn(-1) {}
3004 CellIndexes(int32_t aRowIndex, int32_t aColumnIndex)
3005 : mRow(aRowIndex), mColumn(aColumnIndex) {}
3007 friend struct CellData;
3010 struct MOZ_STACK_CLASS CellData final {
3011 MOZ_KNOWN_LIVE RefPtr<Element> mElement;
3012 // Current indexes which this is initialized with.
3013 CellIndexes mCurrent;
3014 // First column/row indexes of the cell. When current position is spanned
3015 // from other column/row, this value becomes different from mCurrent.
3016 CellIndexes mFirst;
3017 // Computed rowspan/colspan values which are specified to the cell.
3018 // Note that if the cell has larger rowspan/colspan value than actual
3019 // table size, these values are the larger values.
3020 int32_t mRowSpan = -1;
3021 int32_t mColSpan = -1;
3022 // Effective rowspan/colspan value at the index. For example, if first
3023 // cell element in first row has rowspan="3", then, if this is initialized
3024 // with 0-0 indexes, effective rowspan is 3. However, if this is
3025 // initialized with 1-0 indexes, effective rowspan is 2.
3026 int32_t mEffectiveRowSpan = -1;
3027 int32_t mEffectiveColSpan = -1;
3028 // mIsSelected is set to true if mElement itself or its parent <tr> or
3029 // <table> is selected. Otherwise, e.g., the cell just contains selection
3030 // range, this is set to false.
3031 bool mIsSelected = false;
3033 CellData() = delete;
3036 * This returns an instance which is initialized with a <table> element and
3037 * both row and column index to specify a cell element.
3039 [[nodiscard]] static CellData AtIndexInTableElement(
3040 const HTMLEditor& aHTMLEditor, const Element& aTableElement,
3041 int32_t aRowIndex, int32_t aColumnIndex);
3042 [[nodiscard]] static CellData AtIndexInTableElement(
3043 const HTMLEditor& aHTMLEditor, const Element& aTableElement,
3044 const CellIndexes& aIndexes) {
3045 MOZ_ASSERT(!aIndexes.isErr());
3046 return AtIndexInTableElement(aHTMLEditor, aTableElement, aIndexes.mRow,
3047 aIndexes.mColumn);
3051 * Treated as error if fails to compute current index or first index of the
3052 * cell. Note that even if the cell is not found due to no corresponding
3053 * frame at current index, it's not an error situation.
3055 [[nodiscard]] bool isOk() const { return !isErr(); }
3056 [[nodiscard]] bool isErr() const { return mFirst.isErr(); }
3059 * FailedOrNotFound() returns true if this failed to initialize/update
3060 * or succeeded but found no cell element.
3062 [[nodiscard]] bool FailedOrNotFound() const { return isErr() || !mElement; }
3065 * IsSpannedFromOtherRowOrColumn(), IsSpannedFromOtherColumn and
3066 * IsSpannedFromOtherRow() return true if there is no cell element
3067 * at the index because of spanning from other row and/or column.
3069 [[nodiscard]] bool IsSpannedFromOtherRowOrColumn() const {
3070 return mElement && mCurrent != mFirst;
3072 [[nodiscard]] bool IsSpannedFromOtherColumn() const {
3073 return mElement && mCurrent.mColumn != mFirst.mColumn;
3075 [[nodiscard]] bool IsSpannedFromOtherRow() const {
3076 return mElement && mCurrent.mRow != mFirst.mRow;
3078 [[nodiscard]] bool IsNextColumnSpannedFromOtherColumn() const {
3079 return mElement && mCurrent.mColumn + 1 < NextColumnIndex();
3083 * NextColumnIndex() and NextRowIndex() return column/row index of
3084 * next cell. Note that this does not check whether there is next
3085 * cell or not actually.
3087 [[nodiscard]] int32_t NextColumnIndex() const {
3088 if (NS_WARN_IF(FailedOrNotFound())) {
3089 return -1;
3091 return mCurrent.mColumn + mEffectiveColSpan;
3093 [[nodiscard]] int32_t NextRowIndex() const {
3094 if (NS_WARN_IF(FailedOrNotFound())) {
3095 return -1;
3097 return mCurrent.mRow + mEffectiveRowSpan;
3101 * LastColumnIndex() and LastRowIndex() return column/row index of
3102 * column/row which is spanned by the cell.
3104 [[nodiscard]] int32_t LastColumnIndex() const {
3105 if (NS_WARN_IF(FailedOrNotFound())) {
3106 return -1;
3108 return NextColumnIndex() - 1;
3110 [[nodiscard]] int32_t LastRowIndex() const {
3111 if (NS_WARN_IF(FailedOrNotFound())) {
3112 return -1;
3114 return NextRowIndex() - 1;
3118 * NumberOfPrecedingColmuns() and NumberOfPrecedingRows() return number of
3119 * preceding columns/rows if current index is spanned from other column/row.
3120 * Otherwise, i.e., current point is not spanned form other column/row,
3121 * returns 0.
3123 [[nodiscard]] int32_t NumberOfPrecedingColmuns() const {
3124 if (NS_WARN_IF(FailedOrNotFound())) {
3125 return -1;
3127 return mCurrent.mColumn - mFirst.mColumn;
3129 [[nodiscard]] int32_t NumberOfPrecedingRows() const {
3130 if (NS_WARN_IF(FailedOrNotFound())) {
3131 return -1;
3133 return mCurrent.mRow - mFirst.mRow;
3137 * NumberOfFollowingColumns() and NumberOfFollowingRows() return
3138 * number of remaining columns/rows if the cell spans to other
3139 * column/row.
3141 [[nodiscard]] int32_t NumberOfFollowingColumns() const {
3142 if (NS_WARN_IF(FailedOrNotFound())) {
3143 return -1;
3145 return mEffectiveColSpan - 1;
3147 [[nodiscard]] int32_t NumberOfFollowingRows() const {
3148 if (NS_WARN_IF(FailedOrNotFound())) {
3149 return -1;
3151 return mEffectiveRowSpan - 1;
3154 private:
3155 explicit CellData(int32_t aCurrentRowIndex, int32_t aCurrentColumnIndex,
3156 int32_t aFirstRowIndex, int32_t aFirstColumnIndex)
3157 : mCurrent(aCurrentRowIndex, aCurrentColumnIndex),
3158 mFirst(aFirstRowIndex, aFirstColumnIndex) {}
3159 explicit CellData(Element& aElement, int32_t aRowIndex,
3160 int32_t aColumnIndex, nsTableCellFrame& aTableCellFrame,
3161 nsTableWrapperFrame& aTableWrapperFrame);
3163 [[nodiscard]] static CellData Error(int32_t aRowIndex,
3164 int32_t aColumnIndex) {
3165 return CellData(aRowIndex, aColumnIndex, -1, -1);
3167 [[nodiscard]] static CellData NotFound(int32_t aRowIndex,
3168 int32_t aColumnIndex) {
3169 return CellData(aRowIndex, aColumnIndex, aRowIndex, aColumnIndex);
3174 * TableSize stores and computes number of rows and columns of a <table>
3175 * element.
3177 struct MOZ_STACK_CLASS TableSize final {
3178 int32_t mRowCount;
3179 int32_t mColumnCount;
3181 TableSize() = delete;
3184 * @param aHTMLEditor The editor which creates the instance.
3185 * @param aTableOrElementInTable If a <table> element, computes number
3186 * of rows and columns of it.
3187 * If another element in a <table> element,
3188 * computes number of rows and columns
3189 * of nearest ancestor <table> element.
3190 * Otherwise, i.e., non-<table> element
3191 * not in <table>, returns error.
3193 [[nodiscard]] static Result<TableSize, nsresult> Create(
3194 HTMLEditor& aHTMLEditor, Element& aTableOrElementInTable);
3196 [[nodiscard]] bool IsEmpty() const { return !mRowCount || !mColumnCount; }
3198 private:
3199 TableSize(int32_t aRowCount, int32_t aColumCount)
3200 : mRowCount(aRowCount), mColumnCount(aColumCount) {}
3204 * GetTableCellElementAt() returns a <td> or <th> element of aTableElement
3205 * if there is a cell at the indexes.
3207 * @param aTableElement Must be a <table> element.
3208 * @param aCellIndexes Indexes of cell which you want.
3209 * If rowspan and/or colspan is specified 2 or
3210 * larger, any indexes are allowed to retrieve
3211 * the cell in the area.
3212 * @return The cell element if there is in the <table>.
3213 * Returns nullptr without error if the indexes
3214 * are out of bounds.
3216 [[nodiscard]] inline Element* GetTableCellElementAt(
3217 Element& aTableElement, const CellIndexes& aCellIndexes) const;
3218 [[nodiscard]] Element* GetTableCellElementAt(Element& aTableElement,
3219 int32_t aRowIndex,
3220 int32_t aColumnIndex) const;
3223 * GetSelectedOrParentTableElement() returns <td>, <th>, <tr> or <table>
3224 * element:
3225 * #1 if the first selection range selects a cell, returns it.
3226 * #2 if the first selection range does not select a cell and
3227 * the selection anchor refers a <table>, returns it.
3228 * #3 if the first selection range does not select a cell and
3229 * the selection anchor refers a <tr>, returns it.
3230 * #4 if the first selection range does not select a cell and
3231 * the selection anchor refers a <td>, returns it.
3232 * #5 otherwise, nearest ancestor <td> or <th> element of the
3233 * selection anchor if there is.
3234 * In #1 and #4, *aIsCellSelected will be set to true (i.e,, when
3235 * a selection range selects a cell element).
3237 Result<RefPtr<Element>, nsresult> GetSelectedOrParentTableElement(
3238 bool* aIsCellSelected = nullptr) const;
3241 * GetFirstSelectedCellElementInTable() returns <td> or <th> element at
3242 * first selection (using GetSelectedOrParentTableElement). If found cell
3243 * element is not in <table> or <tr> element, this returns nullptr.
3245 Result<RefPtr<Element>, nsresult> GetFirstSelectedCellElementInTable() const;
3247 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3248 HandlePaste(AutoEditActionDataSetter& aEditActionData,
3249 nsIClipboard::ClipboardType aClipboardType,
3250 DataTransfer* aDataTransfer) final;
3251 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3252 HandlePasteAsQuotation(AutoEditActionDataSetter& aEditActionData,
3253 nsIClipboard::ClipboardType aClipboardType,
3254 DataTransfer* aDataTransfer) final;
3255 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3256 HandlePasteTransferable(AutoEditActionDataSetter& aEditActionData,
3257 nsITransferable& aTransferable) final;
3260 * PasteInternal() pasts text with replacing selected content.
3261 * This tries to dispatch ePaste event first. If its defaultPrevent() is
3262 * called, this does nothing but returns NS_OK.
3264 * @param aClipboardType nsIClipboard::kGlobalClipboard or
3265 * nsIClipboard::kSelectionClipboard.
3266 * @param aEditingHost The editing host.
3268 MOZ_CAN_RUN_SCRIPT nsresult
3269 PasteInternal(nsIClipboard::ClipboardType aClipboardType,
3270 DataTransfer* aDataTransfer, const Element& aEditingHost);
3272 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3273 InsertWithQuotationsAsSubAction(const nsAString& aQuotedText) final;
3276 * InsertAsCitedQuotationInternal() inserts a <blockquote> element whose
3277 * cite attribute is aCitation and whose content is aQuotedText.
3278 * Note that this shouldn't be called when IsPlaintextMailComposer() is true.
3280 * @param aQuotedText HTML source if aInsertHTML is true. Otherwise,
3281 * plain text. This is inserted into new <blockquote>
3282 * element.
3283 * @param aCitation cite attribute value of new <blockquote> element.
3284 * @param aInsertHTML true if aQuotedText should be treated as HTML
3285 * source.
3286 * false if aQuotedText should be treated as plain
3287 * text.
3288 * @param aEditingHost The editing host.
3289 * @param aNodeInserted [OUT] The new <blockquote> element.
3291 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertAsCitedQuotationInternal(
3292 const nsAString& aQuotedText, const nsAString& aCitation,
3293 bool aInsertHTML, const Element& aEditingHost, nsINode** aNodeInserted);
3296 * InsertNodeIntoProperAncestorWithTransaction() attempts to insert aNode
3297 * into the document, at aPointToInsert. Checks with strict dtd to see if
3298 * containment is allowed. If not allowed, will attempt to find a parent
3299 * in the parent hierarchy of aPointToInsert.GetContainer() that will accept
3300 * aNode as a child. If such a parent is found, will split the document
3301 * tree from aPointToInsert up to parent, and then insert aNode.
3302 * aPointToInsert is then adjusted to point to the actual location that
3303 * aNode was inserted at. aSplitAtEdges specifies if the splitting process
3304 * is allowed to result in empty nodes.
3306 * @param aContent The content node to insert.
3307 * @param aPointToInsert Insertion point.
3308 * @param aSplitAtEdges Splitting can result in empty nodes?
3310 template <typename NodeType>
3311 [[nodiscard]] MOZ_CAN_RUN_SCRIPT
3312 Result<CreateNodeResultBase<NodeType>, nsresult>
3313 InsertNodeIntoProperAncestorWithTransaction(
3314 NodeType& aContent, const EditorDOMPoint& aPointToInsert,
3315 SplitAtEdges aSplitAtEdges);
3318 * InsertTextWithQuotationsInternal() replaces selection with new content.
3319 * First, this method splits aStringToInsert to multiple chunks which start
3320 * with non-linebreaker except first chunk and end with a linebreaker except
3321 * last chunk. Then, each chunk starting with ">" is inserted after wrapping
3322 * with <span _moz_quote="true">, and each chunk not starting with ">" is
3323 * inserted as normal text.
3325 MOZ_CAN_RUN_SCRIPT nsresult InsertTextWithQuotationsInternal(
3326 const nsAString& aStringToInsert, const Element& aEditingHost);
3329 * ReplaceContainerWithTransactionInternal() is implementation of
3330 * ReplaceContainerWithTransaction() and
3331 * ReplaceContainerAndCloneAttributesWithTransaction().
3333 * @param aOldContainer The element which will be replaced with new
3334 * element.
3335 * @param aTagName The name of new element node.
3336 * @param aAttribute Attribute name which will be set to the new
3337 * element. This will be ignored if
3338 * aCloneAllAttributes is set to true.
3339 * @param aAttributeValue Attribute value which will be set to
3340 * aAttribute.
3341 * @param aCloneAllAttributes If true, all attributes of aOldContainer will
3342 * be copied to the new element.
3344 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
3345 ReplaceContainerWithTransactionInternal(Element& aOldContainer,
3346 const nsAtom& aTagName,
3347 const nsAtom& aAttribute,
3348 const nsAString& aAttributeValue,
3349 bool aCloneAllAttributes);
3352 * DeleteSelectionAndCreateElement() creates a element whose name is aTag.
3353 * And insert it into the DOM tree after removing the selected content.
3355 * @param aTag The element name to be created.
3356 * @param aInitializer A function to initialize the new element before
3357 * or after (depends on the pref) connecting the
3358 * element into the DOM tree. Note that this should
3359 * not touch outside given element because doing it
3360 * would break range updater's result.
3362 MOZ_CAN_RUN_SCRIPT Result<RefPtr<Element>, nsresult>
3363 DeleteSelectionAndCreateElement(
3364 nsAtom& aTag,
3365 const InitializeInsertingElement& aInitializer = DoNothingForNewElement);
3368 * This method first deletes the selection, if it's not collapsed. Then if
3369 * the selection lies in a CharacterData node, it splits it. If the
3370 * selection is at this point collapsed in a CharacterData node, it's
3371 * adjusted to be collapsed right before or after the node instead (which is
3372 * always possible, since the node was split).
3374 MOZ_CAN_RUN_SCRIPT nsresult DeleteSelectionAndPrepareToCreateNode();
3377 * PrepareToInsertLineBreak() returns a point where a new line break node
3378 * should be inserted. If aPointToInsert points middle of a text node, this
3379 * method splits the text node and returns the point before right node.
3381 * @param aLineBreakType Whether you will insert <br> or a preformatted
3382 * linefeed.
3383 * @param aPointToInsert Candidate point to insert new line break node.
3384 * @return Computed point to insert new line break node.
3385 * If something failed, this return error.
3387 MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult> PrepareToInsertLineBreak(
3388 LineBreakType aLineBreakType, const EditorDOMPoint& aPointToInsert);
3391 * If unnecessary line break is there immediately after aPoint, this deletes
3392 * the line break. Note that unnecessary line break means that the line break
3393 * is a padding line break for empty line immediately before a block boundary
3394 * and it's not a placeholder of ancestor inline elements.
3396 * @param aNextOrAfterModifiedPoint If you inserted something, this should
3397 * be next point or after the inserted
3398 * content.
3399 * If you deleted something, this should be
3400 * end of the deleted range.
3402 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3403 EnsureNoFollowingUnnecessaryLineBreak(
3404 const EditorDOMPoint& aNextOrAfterModifiedPoint);
3407 * IndentAsSubAction() indents the content around Selection.
3409 * @param aEditingHost The editing host.
3411 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
3412 IndentAsSubAction(const Element& aEditingHost);
3415 * OutdentAsSubAction() outdents the content around Selection.
3417 * @param aEditingHost The editing host.
3419 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
3420 OutdentAsSubAction(const Element& aEditingHost);
3422 MOZ_CAN_RUN_SCRIPT nsresult LoadHTML(const nsAString& aInputString);
3425 * UpdateMetaCharsetWithTransaction() scans all <meta> elements in the
3426 * document and if and only if there is a <meta> element having `httpEquiv`
3427 * attribute and whose value includes `content-type`, updates its `content`
3428 * attribute value to aCharacterSet.
3430 MOZ_CAN_RUN_SCRIPT bool UpdateMetaCharsetWithTransaction(
3431 Document& aDocument, const nsACString& aCharacterSet);
3434 * SetInlinePropertiesAsSubAction() stores new styles with
3435 * mPendingStylesToApplyToNewContent if `Selection` is collapsed. Otherwise,
3436 * applying the styles to all selected contents.
3438 * @param aStylesToSet The styles which should be applied to the
3439 * selected content.
3440 * @param aEditingHost The editing host.
3442 template <size_t N>
3443 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertiesAsSubAction(
3444 const AutoTArray<EditorInlineStyleAndValue, N>& aStylesToSet,
3445 const Element& aEditingHost);
3448 * SetInlinePropertiesAroundRanges() applying the styles to the ranges even if
3449 * the ranges are collapsed.
3451 template <size_t N>
3452 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertiesAroundRanges(
3453 AutoClonedRangeArray& aRanges,
3454 const AutoTArray<EditorInlineStyleAndValue, N>& aStylesToSet);
3457 * RemoveInlinePropertiesAsSubAction() removes specified styles from
3458 * mPendingStylesToApplyToNewContent if `Selection` is collapsed. Otherwise,
3459 * removing the style.
3461 * @param aStylesToRemove Styles to remove from the selected contents.
3462 * @param aEditingHost The editing host.
3464 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveInlinePropertiesAsSubAction(
3465 const nsTArray<EditorInlineStyle>& aStylesToRemove,
3466 const Element& aEditingHost);
3469 * Helper method to call RemoveInlinePropertiesAsSubAction(). If you want to
3470 * remove other elements to remove the style completely, this will append
3471 * related elements of aStyleToRemove and aStyleToRemove itself to the array.
3472 * E.g., nsGkAtoms::strong and nsGkAtoms::b will be appended if aStyleToRemove
3473 * is nsGkAtoms::b.
3475 void AppendInlineStyleAndRelatedStyle(
3476 const EditorInlineStyle& aStyleToRemove,
3477 nsTArray<EditorInlineStyle>& aStylesToRemove) const;
3480 * ReplaceHeadContentsWithSourceWithTransaction() replaces all children of
3481 * <head> element with given source code. This is undoable.
3483 * @param aSourceToInsert HTML source fragment to replace the children
3484 * of <head> element.
3486 MOZ_CAN_RUN_SCRIPT nsresult ReplaceHeadContentsWithSourceWithTransaction(
3487 const nsAString& aSourceToInsert);
3489 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetCSSBackgroundColorState(
3490 bool* aMixed, nsAString& aOutColor, bool aBlockLevel);
3491 nsresult GetHTMLBackgroundColorState(bool* aMixed, nsAString& outColor);
3494 * This sets background on the appropriate container element (table, cell,)
3495 * or calls to set the page background.
3497 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3498 SetBlockBackgroundColorWithCSSAsSubAction(const nsAString& aColor);
3499 MOZ_CAN_RUN_SCRIPT nsresult
3500 SetHTMLBackgroundColorWithTransaction(const nsAString& aColor);
3502 MOZ_CAN_RUN_SCRIPT_BOUNDARY void InitializeSelectionAncestorLimit(
3503 Element& aAncestorLimit) const final;
3506 * Make the given selection span the entire document.
3508 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SelectEntireDocument() final;
3511 * Use this to assure that selection is set after attribute nodes when
3512 * trying to collapse selection at begining of a block node
3513 * e.g., when setting at beginning of a table cell
3514 * This will stop at a table, however, since we don't want to
3515 * "drill down" into nested tables.
3517 MOZ_CAN_RUN_SCRIPT void CollapseSelectionToDeepestNonTableFirstChild(
3518 nsINode* aNode);
3520 * MaybeCollapseSelectionAtFirstEditableNode() may collapse selection at
3521 * proper position to staring to edit. If there is a non-editable node
3522 * before any editable text nodes or inline elements which can have text
3523 * nodes as their children, collapse selection at start of the editing
3524 * host. If there is an editable text node which is not collapsed, collapses
3525 * selection at the start of the text node. If there is an editable inline
3526 * element which cannot have text nodes as its child, collapses selection at
3527 * before the element node. Otherwise, collapses selection at start of the
3528 * editing host.
3530 * @param aIgnoreIfSelectionInEditingHost
3531 * This method does nothing if selection is in the
3532 * editing host except if it's collapsed at start of
3533 * the editing host.
3534 * Note that if selection ranges were outside of
3535 * current selection limiter, selection was collapsed
3536 * at the start of the editing host therefore, if
3537 * you call this with setting this to true, you can
3538 * keep selection ranges if user has already been
3539 * changed.
3541 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
3542 MaybeCollapseSelectionAtFirstEditableNode(
3543 bool aIgnoreIfSelectionInEditingHost) const;
3545 class BlobReader final {
3546 using AutoEditActionDataSetter = EditorBase::AutoEditActionDataSetter;
3548 public:
3549 MOZ_CAN_RUN_SCRIPT BlobReader(dom::BlobImpl* aBlob, HTMLEditor* aHTMLEditor,
3550 SafeToInsertData aSafeToInsertData,
3551 const EditorDOMPoint& aPointToInsert,
3552 DeleteSelectedContent aDeleteSelectedContent,
3553 const Element& aEditingHost);
3555 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BlobReader)
3556 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(BlobReader)
3558 MOZ_CAN_RUN_SCRIPT nsresult OnResult(const nsACString& aResult);
3559 nsresult OnError(const nsAString& aErrorName);
3561 private:
3562 ~BlobReader() = default;
3564 RefPtr<dom::BlobImpl> mBlob;
3565 RefPtr<HTMLEditor> mHTMLEditor;
3566 RefPtr<const Element> mEditingHost;
3567 RefPtr<DataTransfer> mDataTransfer;
3568 EditorDOMPoint mPointToInsert;
3569 EditAction mEditAction;
3570 SafeToInsertData mSafeToInsertData;
3571 DeleteSelectedContent mDeleteSelectedContent;
3572 bool mNeedsToDispatchBeforeInputEvent;
3575 void CreateEventListeners() final;
3576 nsresult InstallEventListeners() final;
3578 bool ShouldReplaceRootElement() const;
3579 MOZ_CAN_RUN_SCRIPT void NotifyRootChanged();
3580 Element* GetBodyElement() const;
3583 * Get the focused node of this editor.
3584 * @return If the editor has focus, this returns the focused node.
3585 * Otherwise, returns null.
3587 nsINode* GetFocusedNode() const;
3589 already_AddRefed<Element> GetInputEventTargetElement() const final;
3592 * Return TRUE if aElement is a table-related elemet and caret was set.
3594 MOZ_CAN_RUN_SCRIPT bool SetCaretInTableCell(dom::Element* aElement);
3597 * HandleTabKeyPressInTable() handles "Tab" key press in table if selection
3598 * is in a `<table>` element.
3600 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
3601 HandleTabKeyPressInTable(WidgetKeyboardEvent* aKeyboardEvent);
3604 * InsertPosition is an enum to indicate where the method should insert to.
3606 enum class InsertPosition {
3607 // Before selected cell or a cell containing first selection range.
3608 eBeforeSelectedCell,
3609 // After selected cell or a cell containing first selection range.
3610 eAfterSelectedCell,
3614 * InsertTableCellsWithTransaction() inserts <td> elements at aPointToInsert.
3615 * Note that this simply inserts <td> elements, i.e., colspan and rowspan
3616 * around the cell containing selection are not modified. So, for example,
3617 * adding a cell to rectangular table changes non-rectangular table.
3618 * And if the cell containing selection is at left of row-spanning cell,
3619 * it may be moved to right side of the row-spanning cell after inserting
3620 * some cell elements before it. Similarly, colspan won't be adjusted
3621 * for keeping table rectangle.
3622 * Finally, puts caret into previous cell of the insertion point or the
3623 * first inserted cell if aPointToInsert is start of the row.
3625 * @param aPointToInsert The place to insert one or more cell
3626 * elements. The container must be a
3627 * <tr> element.
3628 * @param aNumberOfCellsToInsert Number of cells to insert.
3629 * @return The first inserted cell element and
3630 * start of the last inserted cell element
3631 * as a point to put caret.
3633 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CreateElementResult, nsresult>
3634 InsertTableCellsWithTransaction(const EditorDOMPoint& aPointToInsert,
3635 int32_t aNumberOfCellsToInsert);
3638 * InsertTableColumnsWithTransaction() inserts cell elements to every rows
3639 * at same column index as the cell specified by aPointToInsert.
3641 * @param aNumberOfColumnsToInsert Number of columns to insert.
3643 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertTableColumnsWithTransaction(
3644 const EditorDOMPoint& aPointToInsert, int32_t aNumberOfColumnsToInsert);
3647 * InsertTableRowsWithTransaction() inserts <tr> elements before or after
3648 * aCellElement. When aCellElement spans rows and aInsertPosition is
3649 * eAfterSelectedCell, new rows will be inserted after the most-bottom row
3650 * which contains the cell.
3652 * @param aCellElement The cell element pinting where this will
3653 * insert a row before or after.
3654 * @param aNumberOfRowsToInsert Number of rows to insert.
3655 * @param aInsertPosition Before or after the target cell which
3656 * contains first selection range.
3658 MOZ_CAN_RUN_SCRIPT nsresult InsertTableRowsWithTransaction(
3659 Element& aCellElement, int32_t aNumberOfRowsToInsert,
3660 InsertPosition aInsertPosition);
3663 * Insert a new cell after or before supplied aCell.
3664 * Optional: If aNewCell supplied, returns the newly-created cell (addref'd,
3665 * of course)
3666 * This doesn't change or use the current selection.
3668 MOZ_CAN_RUN_SCRIPT nsresult InsertCell(Element* aCell, int32_t aRowSpan,
3669 int32_t aColSpan, bool aAfter,
3670 bool aIsHeader, Element** aNewCell);
3673 * DeleteSelectedTableColumnsWithTransaction() removes cell elements which
3674 * belong to same columns of selected cell elements.
3675 * If only one cell element is selected or first selection range is
3676 * in a cell, removes cell elements which belong to same column.
3677 * If 2 or more cell elements are selected, removes cell elements which
3678 * belong to any of all selected columns. In this case,
3679 * aNumberOfColumnsToDelete is ignored.
3680 * If there is no selection ranges, returns error.
3681 * If selection is not in a cell element, this does not return error,
3682 * just does nothing.
3683 * WARNING: This does not remove <col> nor <colgroup> elements.
3685 * @param aNumberOfColumnsToDelete Number of columns to remove. This is
3686 * ignored if 2 ore more cells are
3687 * selected.
3689 MOZ_CAN_RUN_SCRIPT nsresult
3690 DeleteSelectedTableColumnsWithTransaction(int32_t aNumberOfColumnsToDelete);
3693 * DeleteTableColumnWithTransaction() removes cell elements which belong
3694 * to the specified column.
3695 * This method adjusts colspan attribute value if cells spanning the
3696 * column to delete.
3697 * WARNING: This does not remove <col> nor <colgroup> elements.
3699 * @param aTableElement The <table> element which contains the
3700 * column which you want to remove.
3701 * @param aRowIndex Index of the column which you want to remove.
3702 * 0 is the first column.
3704 MOZ_CAN_RUN_SCRIPT nsresult DeleteTableColumnWithTransaction(
3705 Element& aTableElement, int32_t aColumnIndex);
3708 * DeleteSelectedTableRowsWithTransaction() removes <tr> elements.
3709 * If only one cell element is selected or first selection range is
3710 * in a cell, removes <tr> elements starting from a <tr> element
3711 * containing the selected cell or first selection range.
3712 * If 2 or more cell elements are selected, all <tr> elements
3713 * which contains selected cell(s). In this case, aNumberOfRowsToDelete
3714 * is ignored.
3715 * If there is no selection ranges, returns error.
3716 * If selection is not in a cell element, this does not return error,
3717 * just does nothing.
3719 * @param aNumberOfRowsToDelete Number of rows to remove. This is ignored
3720 * if 2 or more cells are selected.
3722 MOZ_CAN_RUN_SCRIPT nsresult
3723 DeleteSelectedTableRowsWithTransaction(int32_t aNumberOfRowsToDelete);
3726 * DeleteTableRowWithTransaction() removes a <tr> element whose index in
3727 * the <table> is aRowIndex.
3728 * This method adjusts rowspan attribute value if the <tr> element contains
3729 * cells which spans rows.
3731 * @param aTableElement The <table> element which contains the
3732 * <tr> element which you want to remove.
3733 * @param aRowIndex Index of the <tr> element which you want to
3734 * remove. 0 is the first row.
3736 MOZ_CAN_RUN_SCRIPT nsresult
3737 DeleteTableRowWithTransaction(Element& aTableElement, int32_t aRowIndex);
3740 * DeleteTableCellWithTransaction() removes table cell elements. If two or
3741 * more cell elements are selected, this removes all selected cell elements.
3742 * Otherwise, this removes some cell elements starting from selected cell
3743 * element or a cell containing first selection range. When this removes
3744 * last cell element in <tr> or <table>, this removes the <tr> or the
3745 * <table> too. Note that when removing a cell causes number of its row
3746 * becomes less than the others, this method does NOT fill the place with
3747 * rowspan nor colspan. This does not return error even if selection is not
3748 * in cell element, just does nothing.
3750 * @param aNumberOfCellsToDelete Number of cells to remove. This is ignored
3751 * if 2 or more cells are selected.
3753 MOZ_CAN_RUN_SCRIPT nsresult
3754 DeleteTableCellWithTransaction(int32_t aNumberOfCellsToDelete);
3757 * DeleteAllChildrenWithTransaction() removes all children of aElement from
3758 * the tree.
3760 * @param aElement The element whose children you want to remove.
3762 MOZ_CAN_RUN_SCRIPT nsresult
3763 DeleteAllChildrenWithTransaction(Element& aElement);
3766 * Move all contents from aCellToMerge into aTargetCell (append at end).
3768 MOZ_CAN_RUN_SCRIPT nsresult MergeCells(RefPtr<Element> aTargetCell,
3769 RefPtr<Element> aCellToMerge,
3770 bool aDeleteCellToMerge);
3773 * DeleteTableElementAndChildren() removes aTableElement (and its children)
3774 * from the DOM tree with transaction.
3776 * @param aTableElement The <table> element which you want to remove.
3778 MOZ_CAN_RUN_SCRIPT nsresult
3779 DeleteTableElementAndChildrenWithTransaction(Element& aTableElement);
3781 MOZ_CAN_RUN_SCRIPT nsresult SetColSpan(Element* aCell, int32_t aColSpan);
3782 MOZ_CAN_RUN_SCRIPT nsresult SetRowSpan(Element* aCell, int32_t aRowSpan);
3785 * Helper used to get nsTableWrapperFrame for a table.
3787 static nsTableWrapperFrame* GetTableFrame(const Element* aTable);
3790 * GetNumberOfCellsInRow() returns number of actual cell elements in the row.
3791 * If some cells appear by "rowspan" in other rows, they are ignored.
3793 * @param aTableElement The <table> element.
3794 * @param aRowIndex Valid row index in aTableElement. This method
3795 * counts cell elements in the row.
3796 * @return -1 if this meets unexpected error.
3797 * Otherwise, number of cells which this method found.
3799 int32_t GetNumberOfCellsInRow(Element& aTableElement, int32_t aRowIndex);
3802 * Test if all cells in row or column at given index are selected.
3804 bool AllCellsInRowSelected(Element* aTable, int32_t aRowIndex,
3805 int32_t aNumberOfColumns);
3806 bool AllCellsInColumnSelected(Element* aTable, int32_t aColIndex,
3807 int32_t aNumberOfRows);
3809 bool IsEmptyCell(Element* aCell);
3812 * Most insert methods need to get the same basic context data.
3813 * Any of the pointers may be null if you don't need that datum (for more
3814 * efficiency).
3815 * Input: *aCell is a known cell,
3816 * if null, cell is obtained from the anchor node of the selection.
3817 * Returns NS_EDITOR_ELEMENT_NOT_FOUND if cell is not found even if aCell is
3818 * null.
3820 MOZ_CAN_RUN_SCRIPT nsresult GetCellContext(Element** aTable, Element** aCell,
3821 nsINode** aCellParent,
3822 int32_t* aCellOffset,
3823 int32_t* aRowIndex,
3824 int32_t* aColIndex);
3826 nsresult GetCellSpansAt(Element* aTable, int32_t aRowIndex, int32_t aColIndex,
3827 int32_t& aActualRowSpan, int32_t& aActualColSpan);
3829 MOZ_CAN_RUN_SCRIPT nsresult SplitCellIntoColumns(
3830 Element* aTable, int32_t aRowIndex, int32_t aColIndex,
3831 int32_t aColSpanLeft, int32_t aColSpanRight, Element** aNewCell);
3833 MOZ_CAN_RUN_SCRIPT nsresult SplitCellIntoRows(
3834 Element* aTable, int32_t aRowIndex, int32_t aColIndex,
3835 int32_t aRowSpanAbove, int32_t aRowSpanBelow, Element** aNewCell);
3837 MOZ_CAN_RUN_SCRIPT nsresult CopyCellBackgroundColor(Element* aDestCell,
3838 Element* aSourceCell);
3841 * Reduce rowspan/colspan when cells span into nonexistent rows/columns.
3843 MOZ_CAN_RUN_SCRIPT nsresult FixBadRowSpan(Element* aTable, int32_t aRowIndex,
3844 int32_t& aNewRowCount);
3845 MOZ_CAN_RUN_SCRIPT nsresult FixBadColSpan(Element* aTable, int32_t aColIndex,
3846 int32_t& aNewColCount);
3849 * XXX NormalizeTableInternal() is broken. If it meets a cell which has
3850 * bigger or smaller rowspan or colspan than actual number of cells,
3851 * this always failed to scan the table. Therefore, this does nothing
3852 * when the table should be normalized.
3854 * @param aTableOrElementInTable An element which is in a <table> element
3855 * or <table> element itself. Otherwise,
3856 * this returns NS_OK but does nothing.
3858 MOZ_CAN_RUN_SCRIPT nsresult
3859 NormalizeTableInternal(Element& aTableOrElementInTable);
3862 * Fallback method: Call this after using ClearSelection() and you
3863 * failed to set selection to some other content in the document.
3865 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetSelectionAtDocumentStart();
3867 // Methods for handling plaintext quotations
3868 MOZ_CAN_RUN_SCRIPT nsresult PasteAsPlaintextQuotation(
3869 nsIClipboard::ClipboardType aSelectionType, DataTransfer* aDataTransfer,
3870 const Element& aEditingHost);
3872 enum class AddCites { No, Yes };
3874 * Insert a string as quoted text, replacing the selected text (if any).
3875 * @param aQuotedText The string to insert.
3876 * @param aAddCites Whether to prepend extra ">" to each line
3877 * (usually true, unless those characters
3878 * have already been added.)
3879 * @param aEditingHost The editing host.
3880 * @return aNodeInserted The node spanning the insertion, if applicable.
3881 * If aAddCites is false, this will be null.
3883 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertAsPlaintextQuotation(
3884 const nsAString& aQuotedText, AddCites aAddCites,
3885 const Element& aEditingHost, nsINode** aNodeInserted = nullptr);
3888 * InsertObject() inserts given object at aPointToInsert.
3890 * @param aType one of kFileMime, kJPEGImageMime, kJPGImageMime,
3891 * kPNGImageMime, kGIFImageMime.
3893 MOZ_CAN_RUN_SCRIPT nsresult InsertObject(
3894 const nsACString& aType, nsISupports* aObject,
3895 SafeToInsertData aSafeToInsertData, const EditorDOMPoint& aPointToInsert,
3896 DeleteSelectedContent aDeleteSelectedContent,
3897 const Element& aEditingHost);
3899 class HTMLTransferablePreparer;
3900 nsresult PrepareHTMLTransferable(nsITransferable** aTransferable,
3901 const Element* aEditingHost) const;
3903 enum class HavePrivateHTMLFlavor { No, Yes };
3904 MOZ_CAN_RUN_SCRIPT nsresult InsertFromTransferableAtSelection(
3905 nsITransferable* aTransferable, const nsAString& aContextStr,
3906 const nsAString& aInfoStr, HavePrivateHTMLFlavor aHavePrivateHTMLFlavor,
3907 const Element& aEditingHost);
3910 * InsertFromDataTransfer() is called only when user drops data into
3911 * this editor. Don't use this method for other purposes.
3913 * @param aIndex index of aDataTransfer's item to insert.
3915 MOZ_CAN_RUN_SCRIPT nsresult InsertFromDataTransfer(
3916 const DataTransfer* aDataTransfer, uint32_t aIndex,
3917 nsIPrincipal* aSourcePrincipal, const EditorDOMPoint& aDroppedAt,
3918 DeleteSelectedContent aDeleteSelectedContent,
3919 const Element& aEditingHost);
3921 static HavePrivateHTMLFlavor DataTransferOrClipboardHasPrivateHTMLFlavor(
3922 DataTransfer* aDataTransfer, nsIClipboard* clipboard);
3925 * CF_HTML:
3926 * <https://docs.microsoft.com/en-us/windows/win32/dataxchg/html-clipboard-format>.
3928 * @param[in] aCfhtml a CF_HTML string as defined above.
3929 * @param[out] aStuffToPaste the fragment, excluding context.
3930 * @param[out] aCfcontext the context, excluding the fragment, including a
3931 * marker (`kInsertionCookie`) indicating where the
3932 * fragment begins.
3934 nsresult ParseCFHTML(const nsCString& aCfhtml, char16_t** aStuffToPaste,
3935 char16_t** aCfcontext);
3938 * AutoHTMLFragmentBoundariesFixer fixes both edges of topmost child contents
3939 * which are created with SubtreeContentIterator.
3941 class MOZ_STACK_CLASS AutoHTMLFragmentBoundariesFixer final {
3942 public:
3944 * @param aArrayOfTopMostChildContents
3945 * [in/out] The topmost child contents which will be
3946 * inserted into the DOM tree. Both edges, i.e.,
3947 * first node and last node in this array will be
3948 * checked whether they can be inserted into
3949 * another DOM tree. If not, it'll replaces some
3950 * orphan nodes around nodes with proper parent.
3952 explicit AutoHTMLFragmentBoundariesFixer(
3953 nsTArray<OwningNonNull<nsIContent>>& aArrayOfTopMostChildContents);
3955 private:
3957 * EnsureBeginsOrEndsWithValidContent() replaces some nodes starting from
3958 * start or end with proper element node if it's necessary.
3959 * If first or last node of aArrayOfTopMostChildContents is in list and/or
3960 * `<table>` element, looks for topmost list element or `<table>` element
3961 * with `CollectTableAndAnyListElementsOfInclusiveAncestorsAt()` and
3962 * `GetMostDistantAncestorListOrTableElement()`. Then, checks
3963 * whether some nodes are in aArrayOfTopMostChildContents are the topmost
3964 * list/table element or its descendant and if so, removes the nodes from
3965 * aArrayOfTopMostChildContents and inserts the list/table element instead.
3966 * Then, aArrayOfTopMostChildContents won't start/end with list-item nor
3967 * table cells.
3969 enum class StartOrEnd { start, end };
3970 void EnsureBeginsOrEndsWithValidContent(
3971 StartOrEnd aStartOrEnd,
3972 nsTArray<OwningNonNull<nsIContent>>& aArrayOfTopMostChildContents)
3973 const;
3976 * CollectTableAndAnyListElementsOfInclusiveAncestorsAt() collects list
3977 * elements and table related elements from the inclusive ancestors
3978 * (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) of aNode.
3980 static void CollectTableAndAnyListElementsOfInclusiveAncestorsAt(
3981 nsIContent& aContent,
3982 nsTArray<OwningNonNull<Element>>& aOutArrayOfListAndTableElements);
3985 * GetMostDistantAncestorListOrTableElement() returns a list or a
3986 * `<table>` element which is in
3987 * aInclusiveAncestorsTableOrListElements and they are actually
3988 * valid ancestor of at least one of aArrayOfTopMostChildContents.
3990 static Element* GetMostDistantAncestorListOrTableElement(
3991 const nsTArray<OwningNonNull<nsIContent>>& aArrayOfTopMostChildContents,
3992 const nsTArray<OwningNonNull<Element>>&
3993 aInclusiveAncestorsTableOrListElements);
3996 * FindReplaceableTableElement() is a helper method of
3997 * EnsureBeginsOrEndsWithValidContent(). If aNodeMaybeInTableElement is
3998 * a descendant of aTableElement, returns aNodeMaybeInTableElement or its
3999 * nearest ancestor whose tag name is `<td>`, `<th>`, `<tr>`, `<thead>`,
4000 * `<tfoot>`, `<tbody>` or `<caption>`.
4002 * @param aTableElement Must be a `<table>` element.
4003 * @param aContentMaybeInTableElement A node which may be in aTableElement.
4005 Element* FindReplaceableTableElement(
4006 Element& aTableElement, nsIContent& aContentMaybeInTableElement) const;
4009 * IsReplaceableListElement() is a helper method of
4010 * EnsureBeginsOrEndsWithValidContent(). If aNodeMaybeInListElement is a
4011 * descendant of aListElement, returns true. Otherwise, false.
4013 * @param aListElement Must be a list element.
4014 * @param aContentMaybeInListElement A node which may be in aListElement.
4016 bool IsReplaceableListElement(Element& aListElement,
4017 nsIContent& aContentMaybeInListElement) const;
4021 * MakeDefinitionListItemWithTransaction() replaces parent list of current
4022 * selection with <dl> or create new <dl> element and creates a definition
4023 * list item whose name is aTagName.
4025 * @param aTagName Must be nsGkAtoms::dt or nsGkAtoms::dd.
4027 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4028 MakeDefinitionListItemWithTransaction(nsAtom& aTagName);
4031 * FormatBlockContainerAsSubAction() inserts a block element whose name
4032 * is aTagName at selection. If selection is not collapsed and aTagName is
4033 * nsGkAtoms::normal or nsGkAtoms::_empty, this removes block containers.
4035 * @param aTagName A block level element name. Must NOT be
4036 * nsGkAtoms::dt nor nsGkAtoms::dd.
4037 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4038 * paragraphState command.
4039 * @param aEditingHost The editing host.
4041 MOZ_CAN_RUN_SCRIPT nsresult FormatBlockContainerAsSubAction(
4042 const nsStaticAtom& aTagName, FormatBlockMode aFormatBlockMode,
4043 const Element& aEditingHost);
4046 * Increase/decrease the font size of selection.
4048 MOZ_CAN_RUN_SCRIPT nsresult
4049 IncrementOrDecrementFontSizeAsSubAction(FontSize aIncrementOrDecrement);
4052 * Wrap aContent in <big> or <small> element and make children of
4053 * <font size=n> wrap with <big> or <small> too. Note that if there is
4054 * opposite element for aIncrementOrDecrement, their children will be just
4055 * unwrapped.
4057 * @param aDir Whether increase or decrease the font size of aContent.
4058 * @param aContent The content node whose font size will be changed.
4059 * @return A suggest point to put caret.
4061 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
4062 SetFontSizeWithBigOrSmallElement(nsIContent& aContent,
4063 FontSize aIncrementOrDecrement);
4066 * Adjust font size of font element children recursively with handling
4067 * <big> and <small> elements.
4069 * @param aDir Whether increase or decrease the font size of aContent.
4070 * @param aContent The content node whose font size will be changed.
4071 * All descendants will be handled recursively.
4072 * @return A suggest point to put caret.
4074 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
4075 SetFontSizeOfFontElementChildren(nsIContent& aContent,
4076 FontSize aIncrementOrDecrement);
4079 * Get extended range to select element whose all children are selected by
4080 * aRange.
4082 EditorRawDOMRange GetExtendedRangeWrappingEntirelySelectedElements(
4083 const EditorRawDOMRange& aRange) const;
4086 * Get extended range to select ancestor <a name> elements.
4088 EditorRawDOMRange GetExtendedRangeWrappingNamedAnchor(
4089 const EditorRawDOMRange& aRange) const;
4091 // Declared in HTMLEditorNestedClasses.h and defined in HTMLStyleEditor.cpp
4092 class AutoInlineStyleSetter;
4095 * RemoveStyleInside() removes elements which represent aStyleToRemove
4096 * and removes CSS style. This handles aElement and all its descendants
4097 * (including leaf text nodes) recursively.
4098 * TODO: Rename this to explain that this maybe remove aElement from the DOM
4099 * tree.
4101 * @param aSpecifiedStyle Whether the class and style attributes should
4102 * be preserved or discarded.
4103 * @return A suggest point to put caret.
4105 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
4106 RemoveStyleInside(Element& aElement, const EditorInlineStyle& aStyleToRemove,
4107 SpecifiedStyle aSpecifiedStyle);
4110 * CollectEditableLeafTextNodes() collects text nodes in aElement.
4112 void CollectEditableLeafTextNodes(
4113 Element& aElement, nsTArray<OwningNonNull<Text>>& aLeafTextNodes) const;
4116 * IsRemovableParentStyleWithNewSpanElement() checks whether aStyle of parent
4117 * block can be removed from aContent with creating `<span>` element. Note
4118 * that this does NOT check whether the specified style comes from parent
4119 * block or not.
4120 * XXX This may destroy the editor, but using `Result<bool, nsresult>`
4121 * is not reasonable because code for accessing the result becomes
4122 * messy. However, anybody must forget to check `Destroyed()` after
4123 * calling this. Which is the way to smart to make every caller
4124 * must check the editor state?
4126 MOZ_CAN_RUN_SCRIPT Result<bool, nsresult>
4127 IsRemovableParentStyleWithNewSpanElement(
4128 nsIContent& aContent, const EditorInlineStyle& aStyle) const;
4131 * HasStyleOrIdOrClassAttribute() returns true when at least one of
4132 * `style`, `id` or `class` attribute value of aElement is not empty.
4134 static bool HasStyleOrIdOrClassAttribute(Element& aElement);
4137 * Whether the outer window of the DOM event target has focus or not.
4139 bool OurWindowHasFocus() const;
4141 class HTMLWithContextInserter;
4144 * This function is used to insert a string of HTML input optionally with some
4145 * context information into the editable field. The HTML input either comes
4146 * from a transferable object created as part of a drop/paste operation, or
4147 * from the InsertHTML method. We may want the HTML input to be sanitized
4148 * (for example, if it's coming from a transferable object), in which case
4149 * aTrustedInput should be set to false, otherwise, the caller should set it
4150 * to true, which means that the HTML will be inserted in the DOM verbatim.
4152 enum class InlineStylesAtInsertionPoint {
4153 Preserve, // If you want the paste to be affected by local style, e.g.,
4154 // for the insertHTML command, use "Preserve"
4155 Clear, // If you want the paste to be keep its own style, e.g., pasting
4156 // from clipboard, use "Clear"
4158 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertHTMLWithContextAsSubAction(
4159 const nsAString& aInputString, const nsAString& aContextStr,
4160 const nsAString& aInfoStr, const nsAString& aFlavor,
4161 SafeToInsertData aSafeToInsertData, const EditorDOMPoint& aPointToInsert,
4162 DeleteSelectedContent aDeleteSelectedContent,
4163 InlineStylesAtInsertionPoint aInlineStylesAtInsertionPoint,
4164 const Element& aEditingHost);
4167 * sets the position of an element; warning it does NOT check if the
4168 * element is already positioned or not and that's on purpose.
4169 * @param aStyledElement [IN] the element
4170 * @param aX [IN] the x position in pixels.
4171 * @param aY [IN] the y position in pixels.
4173 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetTopAndLeftWithTransaction(
4174 nsStyledElement& aStyledElement, int32_t aX, int32_t aY);
4177 * Reset a selected cell or collapsed selection (the caret) after table
4178 * editing.
4180 * @param aTable A table in the document.
4181 * @param aRow The row ...
4182 * @param aCol ... and column defining the cell where we will try to
4183 * place the caret.
4184 * @param aSelected If true, we select the whole cell instead of setting
4185 * caret.
4186 * @param aDirection If cell at (aCol, aRow) is not found, search for
4187 * previous cell in the same column (aPreviousColumn) or
4188 * row (ePreviousRow) or don't search for another cell
4189 * (aNoSearch). If no cell is found, caret is place just
4190 * before table; and if that fails, at beginning of
4191 * document. Thus we generally don't worry about the
4192 * return value and can use the
4193 * AutoSelectionSetterAfterTableEdit stack-based object to
4194 * insure we reset the caret in a table-editing method.
4196 MOZ_CAN_RUN_SCRIPT void SetSelectionAfterTableEdit(Element* aTable,
4197 int32_t aRow, int32_t aCol,
4198 int32_t aDirection,
4199 bool aSelected);
4201 void RemoveListenerAndDeleteRef(const nsAString& aEvent,
4202 nsIDOMEventListener* aListener,
4203 bool aUseCapture, ManualNACPtr aElement,
4204 PresShell* aPresShell);
4205 void DeleteRefToAnonymousNode(ManualNACPtr aContent, PresShell* aPresShell);
4208 * RefreshEditingUI() may refresh editing UIs for current Selection, focus,
4209 * etc. If this shows or hides some UIs, it causes reflow. So, this is
4210 * not safe method.
4212 MOZ_CAN_RUN_SCRIPT nsresult RefreshEditingUI();
4215 * Returns the offset of an element's frame to its absolute containing block.
4217 nsresult GetElementOrigin(Element& aElement, int32_t& aX, int32_t& aY);
4218 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetPositionAndDimensions(
4219 Element& aElement, int32_t& aX, int32_t& aY, int32_t& aW, int32_t& aH,
4220 int32_t& aBorderLeft, int32_t& aBorderTop, int32_t& aMarginLeft,
4221 int32_t& aMarginTop);
4223 bool IsInObservedSubtree(nsIContent* aChild);
4225 void UpdateRootElement();
4228 * SetAllResizersPosition() moves all resizers to proper position.
4229 * If the resizers are hidden or replaced with another set of resizers
4230 * while this is running, this returns error. So, callers shouldn't
4231 * keep handling the resizers if this returns error.
4233 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetAllResizersPosition();
4236 * Shows active resizers around an element's frame
4237 * @param aResizedElement [IN] a DOM Element
4239 MOZ_CAN_RUN_SCRIPT nsresult ShowResizersInternal(Element& aResizedElement);
4242 * Hide resizers if they are visible. If this is called while there is no
4243 * visible resizers, this does not return error, but does nothing.
4245 nsresult HideResizersInternal();
4248 * RefreshResizersInternal() moves resizers to proper position. This does
4249 * nothing if there is no resizing target.
4251 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RefreshResizersInternal();
4253 ManualNACPtr CreateResizer(int16_t aLocation, nsIContent& aParentContent);
4254 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4255 SetAnonymousElementPositionWithoutTransaction(nsStyledElement& aStyledElement,
4256 int32_t aX, int32_t aY);
4258 ManualNACPtr CreateShadow(nsIContent& aParentContent,
4259 Element& aOriginalObject);
4262 * SetShadowPosition() moves the shadow element to proper position.
4264 * @param aShadowElement Must be mResizingShadow or mPositioningShadow.
4265 * @param aElement The element which has the shadow.
4266 * @param aElementX Left of aElement.
4267 * @param aElementY Top of aElement.
4269 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4270 SetShadowPosition(Element& aShadowElement, Element& aElement,
4271 int32_t aElementLeft, int32_t aElementTop);
4273 ManualNACPtr CreateResizingInfo(nsIContent& aParentContent);
4274 MOZ_CAN_RUN_SCRIPT nsresult SetResizingInfoPosition(int32_t aX, int32_t aY,
4275 int32_t aW, int32_t aH);
4277 enum class ResizeAt {
4280 eWidth,
4281 eHeight,
4283 [[nodiscard]] int32_t GetNewResizingIncrement(int32_t aX, int32_t aY,
4284 ResizeAt aResizeAt) const;
4286 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult StartResizing(Element& aHandle);
4287 int32_t GetNewResizingX(int32_t aX, int32_t aY);
4288 int32_t GetNewResizingY(int32_t aX, int32_t aY);
4289 int32_t GetNewResizingWidth(int32_t aX, int32_t aY);
4290 int32_t GetNewResizingHeight(int32_t aX, int32_t aY);
4291 void HideShadowAndInfo();
4292 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4293 SetFinalSizeWithTransaction(int32_t aX, int32_t aY);
4294 void SetResizeIncrements(int32_t aX, int32_t aY, int32_t aW, int32_t aH,
4295 bool aPreserveRatio);
4298 * HideAnonymousEditingUIs() forcibly hides all editing UIs (resizers,
4299 * inline-table-editing UI, absolute positioning UI).
4301 void HideAnonymousEditingUIs();
4304 * HideAnonymousEditingUIsIfUnnecessary() hides all editing UIs if some of
4305 * visible UIs are now unnecessary.
4307 void HideAnonymousEditingUIsIfUnnecessary();
4310 * sets the z-index of an element.
4311 * @param aElement [IN] the element
4312 * @param aZorder [IN] the z-index
4314 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4315 SetZIndexWithTransaction(nsStyledElement& aElement, int32_t aZIndex);
4318 * shows a grabber attached to an arbitrary element. The grabber is an image
4319 * positioned on the left hand side of the top border of the element. Draggin
4320 * and dropping it allows to change the element's absolute position in the
4321 * document. See chrome://editor/content/images/grabber.gif
4322 * @param aElement [IN] the element
4324 MOZ_CAN_RUN_SCRIPT nsresult ShowGrabberInternal(Element& aElement);
4327 * Setting grabber to proper position for current mAbsolutelyPositionedObject.
4328 * For example, while an element has grabber, the element may be resized
4329 * or repositioned by script or something. Then, you need to reset grabber
4330 * position with this.
4332 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RefreshGrabberInternal();
4335 * hide the grabber if it shown.
4337 void HideGrabberInternal();
4340 * CreateGrabberInternal() creates a grabber for moving aParentContent.
4341 * This sets mGrabber to the new grabber. If this returns true, it's
4342 * always non-nullptr. Otherwise, i.e., the grabber is hidden during
4343 * creation, this returns false.
4345 bool CreateGrabberInternal(nsIContent& aParentContent);
4347 MOZ_CAN_RUN_SCRIPT nsresult StartMoving();
4348 MOZ_CAN_RUN_SCRIPT nsresult SetFinalPosition(int32_t aX, int32_t aY);
4349 void SnapToGrid(int32_t& newX, int32_t& newY) const;
4350 nsresult GrabberClicked();
4351 MOZ_CAN_RUN_SCRIPT nsresult EndMoving();
4352 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4353 GetTemporaryStyleForFocusedPositionedElement(Element& aElement,
4354 nsAString& aReturn);
4357 * Shows inline table editing UI around a <table> element which contains
4358 * aCellElement. This returns error if creating UI is hidden during this,
4359 * or detects another set of UI during this. In such case, callers
4360 * shouldn't keep handling anything for the UI.
4362 * @param aCellElement Must be an <td> or <th> element.
4364 MOZ_CAN_RUN_SCRIPT nsresult
4365 ShowInlineTableEditingUIInternal(Element& aCellElement);
4368 * Hide all inline table editing UI.
4370 void HideInlineTableEditingUIInternal();
4373 * RefreshInlineTableEditingUIInternal() moves inline table editing UI to
4374 * proper position. This returns error if the UI is hidden or replaced
4375 * during moving.
4377 [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
4378 RefreshInlineTableEditingUIInternal();
4380 enum class ContentNodeIs { Inserted, Appended };
4381 MOZ_CAN_RUN_SCRIPT void DoContentInserted(nsIContent* aChild,
4382 ContentNodeIs aContentNodeIs);
4385 * Returns an anonymous Element of type aTag,
4386 * child of aParentContent. If aIsCreatedHidden is true, the class
4387 * "hidden" is added to the created element. If aClass is not the empty
4388 * string, it becomes the value of the class attribute
4389 * @return a Element
4390 * @param aTag [IN] desired type of the element to create
4391 * @param aParentContent [IN] the parent node of the created anonymous
4392 * element
4393 * @param aClass [IN] contents of the _moz_anonclass attribute
4394 * @param aIsCreatedHidden [IN] a boolean specifying if the class "hidden"
4395 * is to be added to the created anonymous
4396 * element
4398 ManualNACPtr CreateAnonymousElement(nsAtom* aTag, nsIContent& aParentContent,
4399 const nsAString& aClass,
4400 bool aIsCreatedHidden);
4403 * Reads a blob into memory and notifies the BlobReader object when the read
4404 * operation is finished.
4406 * @param aBlob The input blob
4407 * @param aGlobal The global object under which the read should happen.
4408 * @param aBlobReader The blob reader object to be notified when finished.
4410 static nsresult SlurpBlob(dom::Blob* aBlob, nsIGlobalObject* aGlobal,
4411 BlobReader* aBlobReader);
4414 * For saving allocation cost in the constructor of
4415 * EditorBase::TopLevelEditSubActionData, we should reuse same RangeItem
4416 * instance with all top level edit sub actions.
4417 * The instance is always cleared when TopLevelEditSubActionData is
4418 * destructed and the class is stack only class so that we don't need
4419 * to (and also should not) add the RangeItem into the cycle collection.
4421 [[nodiscard]] inline already_AddRefed<RangeItem>
4422 GetSelectedRangeItemForTopLevelEditSubAction() const;
4425 * For saving allocation cost in the constructor of
4426 * EditorBase::TopLevelEditSubActionData, we should reuse same nsRange
4427 * instance with all top level edit sub actions.
4428 * The instance is always cleared when TopLevelEditSubActionData is
4429 * destructed, but AbstractRange::mOwner keeps grabbing the owner document
4430 * so that we need to make it in the cycle collection.
4432 [[nodiscard]] inline already_AddRefed<nsRange>
4433 GetChangedRangeForTopLevelEditSubAction() const;
4435 MOZ_CAN_RUN_SCRIPT void DidDoTransaction(
4436 TransactionManager& aTransactionManager, nsITransaction& aTransaction,
4437 nsresult aDoTransactionResult) {
4438 if (mComposerCommandsUpdater) {
4439 RefPtr<ComposerCommandsUpdater> updater(mComposerCommandsUpdater);
4440 updater->DidDoTransaction(aTransactionManager);
4444 MOZ_CAN_RUN_SCRIPT void DidUndoTransaction(
4445 TransactionManager& aTransactionManager, nsITransaction& aTransaction,
4446 nsresult aUndoTransactionResult) {
4447 if (mComposerCommandsUpdater) {
4448 RefPtr<ComposerCommandsUpdater> updater(mComposerCommandsUpdater);
4449 updater->DidUndoTransaction(aTransactionManager);
4453 MOZ_CAN_RUN_SCRIPT void DidRedoTransaction(
4454 TransactionManager& aTransactionManager, nsITransaction& aTransaction,
4455 nsresult aRedoTransactionResult) {
4456 if (mComposerCommandsUpdater) {
4457 RefPtr<ComposerCommandsUpdater> updater(mComposerCommandsUpdater);
4458 updater->DidRedoTransaction(aTransactionManager);
4462 protected:
4464 * IndentListChildWithTransaction() is a helper method of
4465 * Handle(CSS|HTML)IndentAtSelectionInternal().
4467 * @param aSubListElement [in/out] Specify a sub-list element of the
4468 * container of aPointInListElement or nullptr.
4469 * When there is no proper sub-list element to
4470 * move aContentMovingToSubList, this method
4471 * inserts a new sub-list element and update this
4472 * to it.
4473 * @param aPointInListElement A point in a list element whose child should
4474 * be indented. If this method creates new list
4475 * element into the list element, this inserts
4476 * the new list element to this point.
4477 * @param aContentMovingToSubList
4478 * A content node which is a child of a list
4479 * element and should be moved into a sub-list
4480 * element.
4481 * @param aEditingHost The editing host.
4482 * @return A candidate caret position.
4484 [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
4485 IndentListChildWithTransaction(RefPtr<Element>* aSubListElement,
4486 const EditorDOMPoint& aPointInListElement,
4487 nsIContent& aContentMovingToSubList,
4488 const Element& aEditingHost);
4491 * Stack based helper class for calling EditorBase::EndTransactionInternal().
4492 * NOTE: This does not suppress multiple input events. In most cases,
4493 * only one "input" event should be fired for an edit action rather
4494 * than per edit sub-action. In such case, you should use
4495 * EditorBase::AutoPlaceholderBatch instead.
4497 class MOZ_RAII AutoTransactionBatch final {
4498 public:
4500 * @param aRequesterFuncName function name which wants to end the batch.
4501 * This won't be stored nor exposed to selection listeners etc, used only
4502 * for logging. This MUST be alive when the destructor runs.
4504 MOZ_CAN_RUN_SCRIPT explicit AutoTransactionBatch(
4505 HTMLEditor& aHTMLEditor, const char* aRequesterFuncName)
4506 : mHTMLEditor(aHTMLEditor), mRequesterFuncName(aRequesterFuncName) {
4507 MOZ_KnownLive(mHTMLEditor).BeginTransactionInternal(mRequesterFuncName);
4510 MOZ_CAN_RUN_SCRIPT ~AutoTransactionBatch() {
4511 MOZ_KnownLive(mHTMLEditor).EndTransactionInternal(mRequesterFuncName);
4514 protected:
4515 // The lifetime must be guaranteed by the creator of this instance.
4516 MOZ_KNOWN_LIVE HTMLEditor& mHTMLEditor;
4517 const char* const mRequesterFuncName;
4520 RefPtr<PendingStyles> mPendingStylesToApplyToNewContent;
4521 RefPtr<ComposerCommandsUpdater> mComposerCommandsUpdater;
4523 // Used by TopLevelEditSubActionData::mSelectedRange.
4524 mutable RefPtr<RangeItem> mSelectedRangeForTopLevelEditSubAction;
4525 // Used by TopLevelEditSubActionData::mChangedRange.
4526 mutable RefPtr<nsRange> mChangedRangeForTopLevelEditSubAction;
4528 RefPtr<Runnable> mPendingRootElementUpdatedRunner;
4529 RefPtr<DocumentModifiedEvent> mPendingDocumentModifiedRunner;
4531 // mPaddingBRElementForEmptyEditor should be used for placing caret
4532 // at proper position when editor is empty.
4533 RefPtr<dom::HTMLBRElement> mPaddingBRElementForEmptyEditor;
4535 // This is set only when HandleInsertText appended a collapsible white-space.
4536 RefPtr<dom::Text> mLastCollapsibleWhiteSpaceAppendedTextNode;
4538 bool mCRInParagraphCreatesParagraph;
4540 // resizing
4541 bool mIsObjectResizingEnabled;
4542 bool mIsResizing;
4543 bool mPreserveRatio;
4544 bool mResizedObjectIsAnImage;
4546 // absolute positioning
4547 bool mIsAbsolutelyPositioningEnabled;
4548 bool mResizedObjectIsAbsolutelyPositioned;
4549 bool mGrabberClicked;
4550 bool mIsMoving;
4552 bool mSnapToGridEnabled;
4554 // inline table editing
4555 bool mIsInlineTableEditingEnabled;
4557 bool mIsCSSPrefChecked;
4559 // resizing
4560 ManualNACPtr mTopLeftHandle;
4561 ManualNACPtr mTopHandle;
4562 ManualNACPtr mTopRightHandle;
4563 ManualNACPtr mLeftHandle;
4564 ManualNACPtr mRightHandle;
4565 ManualNACPtr mBottomLeftHandle;
4566 ManualNACPtr mBottomHandle;
4567 ManualNACPtr mBottomRightHandle;
4569 RefPtr<Element> mActivatedHandle;
4571 ManualNACPtr mResizingShadow;
4572 ManualNACPtr mResizingInfo;
4574 RefPtr<Element> mResizedObject;
4576 int32_t mOriginalX;
4577 int32_t mOriginalY;
4579 int32_t mResizedObjectX;
4580 int32_t mResizedObjectY;
4581 int32_t mResizedObjectWidth;
4582 int32_t mResizedObjectHeight;
4584 int32_t mResizedObjectMarginLeft;
4585 int32_t mResizedObjectMarginTop;
4586 int32_t mResizedObjectBorderLeft;
4587 int32_t mResizedObjectBorderTop;
4589 int32_t mXIncrementFactor;
4590 int32_t mYIncrementFactor;
4591 int32_t mWidthIncrementFactor;
4592 int32_t mHeightIncrementFactor;
4594 int8_t mInfoXIncrement;
4595 int8_t mInfoYIncrement;
4597 // absolute positioning
4598 int32_t mPositionedObjectX;
4599 int32_t mPositionedObjectY;
4600 int32_t mPositionedObjectWidth;
4601 int32_t mPositionedObjectHeight;
4603 int32_t mPositionedObjectMarginLeft;
4604 int32_t mPositionedObjectMarginTop;
4605 int32_t mPositionedObjectBorderLeft;
4606 int32_t mPositionedObjectBorderTop;
4608 RefPtr<Element> mAbsolutelyPositionedObject;
4609 ManualNACPtr mGrabber;
4610 ManualNACPtr mPositioningShadow;
4612 int32_t mGridSize;
4614 // inline table editing
4615 RefPtr<Element> mInlineEditedCell;
4617 ManualNACPtr mAddColumnBeforeButton;
4618 ManualNACPtr mRemoveColumnButton;
4619 ManualNACPtr mAddColumnAfterButton;
4621 ManualNACPtr mAddRowBeforeButton;
4622 ManualNACPtr mRemoveRowButton;
4623 ManualNACPtr mAddRowAfterButton;
4625 void AddPointerClickListener(Element* aElement);
4626 void RemovePointerClickListener(Element* aElement);
4628 bool mDisabledLinkHandling = false;
4629 bool mOldLinkHandlingEnabled = false;
4631 bool mHasBeforeInputBeenCanceled = false;
4633 bool mHasFocus = false;
4634 bool mIsInDesignMode = false;
4636 ParagraphSeparator mDefaultParagraphSeparator;
4638 friend class AlignStateAtSelection; // CollectEditableTargetNodes,
4639 // CollectNonEditableNodes
4640 friend class AutoClonedRangeArray; // RangeUpdaterRef,
4641 // SplitNodeWithTransaction,
4642 // SplitInlineAncestorsAtRangeBoundaries
4643 friend class AutoClonedSelectionRangeArray; // RangeUpdaterRef,
4644 friend class AutoSelectionRestore;
4645 friend class AutoSelectionSetterAfterTableEdit; // SetSelectionAfterEdit
4646 friend class CSSEditUtils; // DoTransactionInternal, HasAttributes,
4647 // RemoveContainerWithTransaction
4648 friend class EditorBase; // ComputeTargetRanges,
4649 // GetChangedRangeForTopLevelEditSubAction,
4650 // GetSelectedRangeItemForTopLevelEditSubAction,
4651 // MaybeCreatePaddingBRElementForEmptyEditor,
4652 // PrepareToInsertBRElement,
4653 // ReflectPaddingBRElementForEmptyEditor,
4654 // RefreshEditingUI,
4655 // mComposerUpdater, mHasBeforeInputBeenCanceled
4656 friend class JoinNodesTransaction; // DidJoinNodesTransaction, DoJoinNodes,
4657 // DoSplitNode, // RangeUpdaterRef
4658 friend class ListElementSelectionState; // CollectEditTargetNodes,
4659 // CollectNonEditableNodes
4660 friend class ListItemElementSelectionState; // CollectEditTargetNodes,
4661 // CollectNonEditableNodes
4662 friend class MoveNodeTransaction; // AllowsTransactionsToChangeSelection,
4663 // CollapseSelectionTo, MarkElementDirty,
4664 // RangeUpdaterRef
4665 friend class ParagraphStateAtSelection; // CollectChildren,
4666 // CollectEditTargetNodes,
4667 // CollectListChildren,
4668 // CollectNonEditableNodes,
4669 // CollectTableChildren
4670 friend class SlurpBlobEventListener; // BlobReader
4671 friend class SplitNodeTransaction; // DoJoinNodes, DoSplitNode
4672 friend class TransactionManager; // DidDoTransaction, DidRedoTransaction,
4673 // DidUndoTransaction
4674 friend class
4675 WhiteSpaceVisibilityKeeper; // AutoMoveOneLineHandler
4676 // CanMoveChildren,
4677 // ChangeListElementType,
4678 // DeleteNodeWithTransaction,
4679 // DeleteTextAndTextNodesWithTransaction,
4680 // InsertLineBreak,
4681 // JoinNearestEditableNodesWithTransaction,
4682 // LineBreakType,
4683 // MoveChildrenWithTransaction,
4684 // SplitAncestorStyledInlineElementsAt,
4685 // TreatEmptyTextNodes
4689 * ListElementSelectionState class gets which list element is selected right
4690 * now.
4692 class MOZ_STACK_CLASS ListElementSelectionState final {
4693 public:
4694 ListElementSelectionState() = delete;
4695 ListElementSelectionState(HTMLEditor& aHTMLEditor, ErrorResult& aRv);
4697 bool IsOLElementSelected() const { return mIsOLElementSelected; }
4698 bool IsULElementSelected() const { return mIsULElementSelected; }
4699 bool IsDLElementSelected() const { return mIsDLElementSelected; }
4700 bool IsNotOneTypeListElementSelected() const {
4701 return (mIsOLElementSelected + mIsULElementSelected + mIsDLElementSelected +
4702 mIsOtherContentSelected) > 1;
4705 private:
4706 bool mIsOLElementSelected = false;
4707 bool mIsULElementSelected = false;
4708 bool mIsDLElementSelected = false;
4709 bool mIsOtherContentSelected = false;
4713 * ListItemElementSelectionState class gets which list item element is selected
4714 * right now.
4716 class MOZ_STACK_CLASS ListItemElementSelectionState final {
4717 public:
4718 ListItemElementSelectionState() = delete;
4719 ListItemElementSelectionState(HTMLEditor& aHTMLEditor, ErrorResult& aRv);
4721 bool IsLIElementSelected() const { return mIsLIElementSelected; }
4722 bool IsDTElementSelected() const { return mIsDTElementSelected; }
4723 bool IsDDElementSelected() const { return mIsDDElementSelected; }
4724 bool IsNotOneTypeDefinitionListItemElementSelected() const {
4725 return (mIsDTElementSelected + mIsDDElementSelected +
4726 mIsOtherElementSelected) > 1;
4729 private:
4730 bool mIsLIElementSelected = false;
4731 bool mIsDTElementSelected = false;
4732 bool mIsDDElementSelected = false;
4733 bool mIsOtherElementSelected = false;
4737 * AlignStateAtSelection class gets alignment at selection.
4738 * XXX This currently returns only first alignment.
4740 class MOZ_STACK_CLASS AlignStateAtSelection final {
4741 public:
4742 AlignStateAtSelection() = delete;
4743 MOZ_CAN_RUN_SCRIPT AlignStateAtSelection(HTMLEditor& aHTMLEditor,
4744 ErrorResult& aRv);
4746 nsIHTMLEditor::EAlignment AlignmentAtSelectionStart() const {
4747 return mFirstAlign;
4749 bool IsSelectionRangesFound() const { return mFoundSelectionRanges; }
4751 private:
4752 nsIHTMLEditor::EAlignment mFirstAlign = nsIHTMLEditor::eLeft;
4753 bool mFoundSelectionRanges = false;
4757 * ParagraphStateAtSelection class gets format block types around selection.
4759 class MOZ_STACK_CLASS ParagraphStateAtSelection final {
4760 public:
4761 using FormatBlockMode = HTMLEditor::FormatBlockMode;
4763 ParagraphStateAtSelection() = delete;
4765 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4766 * paragraphState command.
4768 ParagraphStateAtSelection(HTMLEditor& aHTMLEditor,
4769 FormatBlockMode aFormatBlockMode, ErrorResult& aRv);
4772 * GetFirstParagraphStateAtSelection() returns:
4773 * - nullptr if there is no format blocks nor inline nodes.
4774 * - nsGkAtoms::_empty if first node is not in any format block.
4775 * - a tag name of format block at first node.
4776 * XXX See the private method explanations. If selection ranges contains
4777 * non-format block first, it'll be check after its siblings. Therefore,
4778 * this may return non-first paragraph state.
4780 nsAtom* GetFirstParagraphStateAtSelection() const {
4781 return mIsMixed && mIsInDLElement ? nsGkAtoms::dl
4782 : mFirstParagraphState.get();
4786 * If selected nodes are not in same format node nor only in no-format blocks,
4787 * this returns true.
4789 bool IsMixed() const { return mIsMixed && !mIsInDLElement; }
4791 private:
4792 using EditorType = EditorBase::EditorType;
4794 [[nodiscard]] static bool IsFormatElement(FormatBlockMode aFormatBlockMode,
4795 const nsIContent& aContent);
4798 * AppendDescendantFormatNodesAndFirstInlineNode() appends descendant
4799 * format blocks and first inline child node in aNonFormatBlockElement to
4800 * the last of the array (not inserting where aNonFormatBlockElement is,
4801 * so that the node order becomes randomly).
4803 * @param aArrayOfContents [in/out] Found descendant format blocks
4804 * and first inline node in each non-format
4805 * block will be appended to this.
4806 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4807 * paragraphState command.
4808 * @param aNonFormatBlockElement Must be a non-format block element.
4810 static void AppendDescendantFormatNodesAndFirstInlineNode(
4811 nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
4812 FormatBlockMode aFormatBlockMode, dom::Element& aNonFormatBlockElement);
4815 * CollectEditableFormatNodesInSelection() collects only editable nodes
4816 * around selection ranges (with
4817 * AutoClonedRangeArray::ExtendRangesToWrapLines() and
4818 * HTMLEditor::CollectEditTargetNodes(), see its document for the detail).
4819 * If it includes list, list item or table related elements, they will be
4820 * replaced their children.
4822 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4823 * paragraphState command.
4825 static nsresult CollectEditableFormatNodesInSelection(
4826 HTMLEditor& aHTMLEditor, FormatBlockMode aFormatBlockMode,
4827 const dom::Element& aEditingHost,
4828 nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents);
4830 RefPtr<nsAtom> mFirstParagraphState;
4831 bool mIsInDLElement = false;
4832 bool mIsMixed = false;
4835 } // namespace mozilla
4837 mozilla::HTMLEditor* nsIEditor::AsHTMLEditor() {
4838 MOZ_DIAGNOSTIC_ASSERT(IsHTMLEditor());
4839 return static_cast<mozilla::HTMLEditor*>(this);
4842 const mozilla::HTMLEditor* nsIEditor::AsHTMLEditor() const {
4843 MOZ_DIAGNOSTIC_ASSERT(IsHTMLEditor());
4844 return static_cast<const mozilla::HTMLEditor*>(this);
4847 mozilla::HTMLEditor* nsIEditor::GetAsHTMLEditor() {
4848 return AsEditorBase()->IsHTMLEditor() ? AsHTMLEditor() : nullptr;
4851 const mozilla::HTMLEditor* nsIEditor::GetAsHTMLEditor() const {
4852 return AsEditorBase()->IsHTMLEditor() ? AsHTMLEditor() : nullptr;
4855 #endif // #ifndef mozilla_HTMLEditor_h