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/. */
5 
6 #ifndef mozilla_TextEditor_h
7 #define mozilla_TextEditor_h
8 
9 #include "mozilla/EditorBase.h"
10 #include "mozilla/TextControlState.h"
11 #include "mozilla/UniquePtr.h"
12 
13 #include "nsCOMPtr.h"
14 #include "nsCycleCollectionParticipant.h"
15 #include "nsINamed.h"
16 #include "nsISupportsImpl.h"
17 #include "nsITimer.h"
18 #include "nscore.h"
19 
20 class nsIContent;
21 class nsIDocumentEncoder;
22 class nsIOutputStream;
23 class nsIPrincipal;
24 class nsISelectionController;
25 class nsITransferable;
26 
27 namespace mozilla {
28 class DeleteNodeTransaction;
29 class InsertNodeTransaction;
30 enum class EditSubAction : int32_t;
31 
32 namespace dom {
33 class Selection;
34 }  // namespace dom
35 
36 /**
37  * The text editor implementation.
38  * Use to edit text document represented as a DOM tree.
39  */
40 class TextEditor final : public EditorBase,
41                          public nsITimerCallback,
42                          public nsINamed {
43  public:
44   /****************************************************************************
45    * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other
46    *       classes under libeditor except EditorEventListener and
47    *       HTMLEditorEventListener because each public method which may fire
48    *       eEditorInput event will need to instantiate new stack class for
49    *       managing input type value of eEditorInput and cache some objects
50    *       for smarter handling.  In other words, when you add new root
51    *       method to edit the DOM tree, you can make your new method public.
52    ****************************************************************************/
53 
54   NS_DECL_ISUPPORTS_INHERITED
55   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TextEditor, EditorBase)
56 
57   TextEditor();
58 
59   /**
60    * Note that TextEditor::Init() shouldn't cause running script synchronously.
61    * So, `MOZ_CAN_RUN_SCRIPT_BOUNDARY` is safe here.
62    *
63    * @param aDocument   The document which aAnonymousDivElement belongs to.
64    * @param aAnonymousDivElement
65    *                    The root editable element for this editor.
66    * @param aSelectionController
67    *                    The selection controller for independent selections
68    *                    in the `<input>` or `<textarea>` element.
69    * @param aFlags      Some of nsIEditor::eEditor*Mask flags.
70    * @param aPasswordMaskData
71    *                    Set to an instance only when aFlags includes
72    *                    `nsIEditor::eEditorPasswordMask`.  Otherwise, must be
73    *                    `nullptr`.
74    */
75   MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
76   Init(Document& aDocument, Element& aAnonymousDivElement,
77        nsISelectionController& aSelectionController, uint32_t aFlags,
78        UniquePtr<PasswordMaskData>&& aPasswordMaskData);
79 
80   /**
81    * PostCreate() should be called after Init, and is the time that the editor
82    * tells its documentStateObservers that the document has been created.
83    * Note that TextEditor::PostCreate() shouldn't cause running script
84    * synchronously. So, `MOZ_CAN_RUN_SCRIPT_BOUNDARY` is safe here.
85    */
86   MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult PostCreate();
87 
88   /**
89    * PreDestroy() is called before the editor goes away, and gives the editor a
90    * chance to tell its documentStateObservers that the document is going away.
91    * Note that TextEditor::PreDestroy() shouldn't cause running script
92    * synchronously. So, `MOZ_CAN_RUN_SCRIPT_BOUNDARY` is safe here.
93    */
94   [[nodiscard]] MOZ_CAN_RUN_SCRIPT_BOUNDARY UniquePtr<PasswordMaskData>
95   PreDestroy();
96 
GetFrom(nsIEditor * aEditor)97   static TextEditor* GetFrom(nsIEditor* aEditor) {
98     return aEditor ? aEditor->GetAsTextEditor() : nullptr;
99   }
GetFrom(const nsIEditor * aEditor)100   static const TextEditor* GetFrom(const nsIEditor* aEditor) {
101     return aEditor ? aEditor->GetAsTextEditor() : nullptr;
102   }
103 
104   NS_DECL_NSITIMERCALLBACK
105   NS_DECL_NSINAMED
106 
107   // Overrides of nsIEditor
108   MOZ_CAN_RUN_SCRIPT NS_IMETHOD InsertLineBreak() final;
109   NS_IMETHOD GetTextLength(uint32_t* aCount) final;
Paste(int32_t aClipboardType)110   MOZ_CAN_RUN_SCRIPT NS_IMETHOD Paste(int32_t aClipboardType) final {
111     const nsresult rv = TextEditor::PasteAsAction(aClipboardType, true);
112     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
113                          "HTMLEditor::PasteAsAction() failed");
114     return rv;
115   }
116 
117   // Shouldn't be used internally, but we need these using declarations for
118   // avoiding warnings of clang.
119   using EditorBase::CanCopy;
120   using EditorBase::CanCut;
121   using EditorBase::CanPaste;
122 
123   // Overrides of EditorBase
124   bool IsEmpty() const final;
125 
126   bool CanPaste(int32_t aClipboardType) const final;
127 
128   MOZ_CAN_RUN_SCRIPT nsresult PasteTransferableAsAction(
129       nsITransferable* aTransferable, nsIPrincipal* aPrincipal = nullptr) final;
130 
131   bool CanPasteTransferable(nsITransferable* aTransferable) final;
132 
133   MOZ_CAN_RUN_SCRIPT nsresult
134   HandleKeyPressEvent(WidgetKeyboardEvent* aKeyboardEvent) final;
135 
136   dom::EventTarget* GetDOMEventTarget() const final;
137 
138   MOZ_CAN_RUN_SCRIPT nsresult
139   PasteAsAction(int32_t aClipboardType, bool aDispatchPasteEvent,
140                 nsIPrincipal* aPrincipal = nullptr) final;
141 
142   MOZ_CAN_RUN_SCRIPT nsresult
143   PasteAsQuotationAsAction(int32_t aClipboardType, bool aDispatchPasteEvent,
144                            nsIPrincipal* aPrincipal = nullptr) final;
145 
146   /**
147    * The maximum number of characters allowed.
148    *   default: -1 (unlimited).
149    */
MaxTextLength()150   int32_t MaxTextLength() const { return mMaxTextLength; }
SetMaxTextLength(int32_t aLength)151   void SetMaxTextLength(int32_t aLength) { mMaxTextLength = aLength; }
152 
153   /**
154    * Replace existed string with a string.
155    * This is fast path to replace all string when using single line control.
156    *
157    * @param aString             The string to be set
158    * @param aAllowBeforeInputEventCancelable
159    *                            Whether `beforeinput` event which will be
160    *                            dispatched for this can be cancelable or not.
161    * @param aPrincipal          Set subject principal if it may be called by
162    *                            JS.  If set to nullptr, will be treated as
163    *                            called by system.
164    */
165   MOZ_CAN_RUN_SCRIPT nsresult SetTextAsAction(
166       const nsAString& aString,
167       AllowBeforeInputEventCancelable aAllowBeforeInputEventCancelable,
168       nsIPrincipal* aPrincipal = nullptr);
169 
170   MOZ_CAN_RUN_SCRIPT nsresult
171   InsertLineBreakAsAction(nsIPrincipal* aPrincipal = nullptr) final;
172 
173   /**
174    * ComputeTextValue() computes plaintext value of this editor.  This may be
175    * too expensive if it's in hot path.
176    *
177    * @param aDocumentEncoderFlags   Flags of nsIDocumentEncoder.
178    * @param aCharset                Encoding of the document.
179    */
ComputeTextValue(uint32_t aDocumentEncoderFlags,nsAString & aOutputString)180   nsresult ComputeTextValue(uint32_t aDocumentEncoderFlags,
181                             nsAString& aOutputString) const {
182     AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
183     if (NS_WARN_IF(!editActionData.CanHandle())) {
184       return NS_ERROR_NOT_INITIALIZED;
185     }
186     nsresult rv = ComputeValueInternal(u"text/plain"_ns, aDocumentEncoderFlags,
187                                        aOutputString);
188     if (NS_WARN_IF(NS_FAILED(rv))) {
189       return EditorBase::ToGenericNSResult(rv);
190     }
191     return NS_OK;
192   }
193 
194   /**
195    * The following methods are available only when the instance is a password
196    * editor.  They return whether there is unmasked range or not and range
197    * start and length.
198    */
IsAllMasked()199   MOZ_ALWAYS_INLINE bool IsAllMasked() const {
200     MOZ_ASSERT(IsPasswordEditor());
201     return !mPasswordMaskData || mPasswordMaskData->IsAllMasked();
202   }
UnmaskedStart()203   MOZ_ALWAYS_INLINE uint32_t UnmaskedStart() const {
204     MOZ_ASSERT(IsPasswordEditor());
205     return mPasswordMaskData ? mPasswordMaskData->mUnmaskedStart : UINT32_MAX;
206   }
UnmaskedLength()207   MOZ_ALWAYS_INLINE uint32_t UnmaskedLength() const {
208     MOZ_ASSERT(IsPasswordEditor());
209     return mPasswordMaskData ? mPasswordMaskData->mUnmaskedLength : 0;
210   }
UnmaskedEnd()211   MOZ_ALWAYS_INLINE uint32_t UnmaskedEnd() const {
212     MOZ_ASSERT(IsPasswordEditor());
213     return mPasswordMaskData ? mPasswordMaskData->UnmaskedEnd() : UINT32_MAX;
214   }
215 
216   /**
217    * IsMaskingPassword() returns false when the last caller of `Unmask()`
218    * didn't want to mask again automatically.  When this returns true, user
219    * input causes masking the password even before timed-out.
220    */
IsMaskingPassword()221   bool IsMaskingPassword() const {
222     MOZ_ASSERT(IsPasswordEditor());
223     return mPasswordMaskData && mPasswordMaskData->mIsMaskingPassword;
224   }
225 
226   /**
227    * PasswordMask() returns a character which masks each character in password
228    * fields.
229    */
230   static char16_t PasswordMask();
231 
232   /**
233    * If you want to prevent to echo password temporarily, use the following
234    * methods.
235    */
EchoingPasswordPrevented()236   bool EchoingPasswordPrevented() const {
237     return mPasswordMaskData && mPasswordMaskData->mEchoingPasswordPrevented;
238   }
PreventToEchoPassword()239   void PreventToEchoPassword() {
240     if (mPasswordMaskData) {
241       mPasswordMaskData->mEchoingPasswordPrevented = true;
242     }
243   }
AllowToEchoPassword()244   void AllowToEchoPassword() {
245     if (mPasswordMaskData) {
246       mPasswordMaskData->mEchoingPasswordPrevented = false;
247     }
248   }
249 
GetTextNode()250   dom::Text* GetTextNode() {
251     MOZ_DIAGNOSTIC_ASSERT(GetRoot());
252     MOZ_DIAGNOSTIC_ASSERT(GetRoot()->GetFirstChild());
253     MOZ_DIAGNOSTIC_ASSERT(GetRoot()->GetFirstChild()->IsText());
254     if (MOZ_UNLIKELY(!GetRoot() || !GetRoot()->GetFirstChild())) {
255       return nullptr;
256     }
257     return GetRoot()->GetFirstChild()->GetAsText();
258   }
GetTextNode()259   const dom::Text* GetTextNode() const {
260     return const_cast<TextEditor*>(this)->GetTextNode();
261   }
262 
263  protected:  // May be called by friends.
264   /****************************************************************************
265    * Some friend classes are allowed to call the following protected methods.
266    * However, those methods won't prepare caches of some objects which are
267    * necessary for them.  So, if you call them from friend classes, you need
268    * to make sure that AutoEditActionDataSetter is created.
269    ****************************************************************************/
270 
271   // Overrides of EditorBase
272   MOZ_CAN_RUN_SCRIPT nsresult RemoveAttributeOrEquivalent(
273       Element* aElement, nsAtom* aAttribute, bool aSuppressTransaction) final;
274   MOZ_CAN_RUN_SCRIPT nsresult SetAttributeOrEquivalent(
275       Element* aElement, nsAtom* aAttribute, const nsAString& aValue,
276       bool aSuppressTransaction) final;
277   using EditorBase::RemoveAttributeOrEquivalent;
278   using EditorBase::SetAttributeOrEquivalent;
279 
280   /**
281    * InsertLineBreakAsSubAction() inserts a line break.
282    */
283   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertLineBreakAsSubAction();
284 
285   /**
286    * Replace existed string with aString.  Caller must guarantee that there
287    * is a placeholder transaction which will have the transaction.
288    *
289    * @ param aString   The string to be set.
290    */
291   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
292   SetTextAsSubAction(const nsAString& aString);
293 
294   /**
295    * MaybeDoAutoPasswordMasking() may mask password if we're doing auto-masking.
296    */
MaybeDoAutoPasswordMasking()297   void MaybeDoAutoPasswordMasking() {
298     if (IsPasswordEditor() && IsMaskingPassword()) {
299       MaskAllCharacters();
300     }
301   }
302 
303   /**
304    * SetUnmaskRange() is available only when the instance is a password
305    * editor.  This just updates unmask range.  I.e., caller needs to
306    * guarantee to update the layout.
307    *
308    * @param aStart      First index to show the character.
309    *                    If aLength is 0, this value is ignored.
310    * @param aLength     Optional, Length to show characters.
311    *                    If UINT32_MAX, it means unmasking all characters after
312    *                    aStart.
313    *                    If 0, it means that masking all characters.
314    * @param aTimeout    Optional, specify milliseconds to hide the unmasked
315    *                    characters after this call.
316    *                    If 0, it means this won't mask the characters
317    *                    automatically.
318    *                    If aLength is 0, this value is ignored.
319    */
320   MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult SetUnmaskRange(
321       uint32_t aStart, uint32_t aLength = UINT32_MAX, uint32_t aTimeout = 0) {
322     return SetUnmaskRangeInternal(aStart, aLength, aTimeout, false, false);
323   }
324 
325   /**
326    * SetUnmaskRangeAndNotify() is available only when the instance is a
327    * password editor.  This updates unmask range and notifying the text frame
328    * to update the visible characters.
329    *
330    * @param aStart      First index to show the character.
331    *                    If UINT32_MAX, it means masking all.
332    * @param aLength     Optional, Length to show characters.
333    *                    If UINT32_MAX, it means unmasking all characters after
334    *                    aStart.
335    * @param aTimeout    Optional, specify milliseconds to hide the unmasked
336    *                    characters after this call.
337    *                    If 0, it means this won't mask the characters
338    *                    automatically.
339    *                    If aLength is 0, this value is ignored.
340    */
341   MOZ_CAN_RUN_SCRIPT nsresult SetUnmaskRangeAndNotify(
342       uint32_t aStart, uint32_t aLength = UINT32_MAX, uint32_t aTimeout = 0) {
343     return SetUnmaskRangeInternal(aStart, aLength, aTimeout, true, false);
344   }
345 
346   /**
347    * MaskAllCharacters() is an alias of SetUnmaskRange() to mask all characters.
348    * In other words, this removes existing unmask range.
349    * After this is called, TextEditor starts masking password automatically.
350    */
MaskAllCharacters()351   MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult MaskAllCharacters() {
352     if (!mPasswordMaskData) {
353       return NS_OK;  // Already we don't have masked range data.
354     }
355     return SetUnmaskRangeInternal(UINT32_MAX, 0, 0, false, true);
356   }
357 
358   /**
359    * MaskAllCharactersAndNotify() is an alias of SetUnmaskRangeAndNotify() to
360    * mask all characters and notifies the text frame.  In other words, this
361    * removes existing unmask range.
362    * After this is called, TextEditor starts masking password automatically.
363    */
MaskAllCharactersAndNotify()364   MOZ_CAN_RUN_SCRIPT nsresult MaskAllCharactersAndNotify() {
365     return SetUnmaskRangeInternal(UINT32_MAX, 0, 0, true, true);
366   }
367 
368   /**
369    * WillDeleteText() is called before `DeleteTextTransaction` or something
370    * removes text in a text node.  Note that this won't be called if the
371    * instance is `HTMLEditor` since supporting it makes the code complicated
372    * due to mutation events.
373    *
374    * @param aCurrentLength      Current text length of the node.
375    * @param aRemoveStartOffset  Start offset of the range to be removed.
376    * @param aRemoveLength       Length of the range to be removed.
377    */
378   void WillDeleteText(uint32_t aCurrentLength, uint32_t aRemoveStartOffset,
379                       uint32_t aRemoveLength);
380 
381   /**
382    * DidInsertText() is called after `InsertTextTransaction` or something
383    * inserts text into a text node.  Note that this won't be called if the
384    * instance is `HTMLEditor` since supporting it makes the code complicated
385    * due to mutatione events.
386    *
387    * @param aNewLength          New text length after the insertion.
388    * @param aInsertedOffset     Start offset of the inserted text.
389    * @param aInsertedLength     Length of the inserted text.
390    * @return                    NS_OK or NS_ERROR_EDITOR_DESTROYED.
391    */
392   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult DidInsertText(
393       uint32_t aNewLength, uint32_t aInsertedOffset, uint32_t aInsertedLength);
394 
395  protected:  // edit sub-action handler
396   /**
397    * MaybeTruncateInsertionStringForMaxLength() truncates aInsertionString to
398    * `maxlength` if it was not pasted in by the user.
399    *
400    * @param aInsertionString    [in/out] New insertion string.  This is
401    *                            truncated to `maxlength` if it was not pasted in
402    *                            by the user.
403    * @return                    If aInsertionString is truncated, it returns "as
404    *                            handled", else "as ignored."
405    */
406   EditActionResult MaybeTruncateInsertionStringForMaxLength(
407       nsAString& aInsertionString);
408 
409   /**
410    * InsertLineFeedCharacterAtSelection() inserts a linefeed character at
411    * selection.
412    */
413   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
414   InsertLineFeedCharacterAtSelection();
415 
416   /**
417    * Handles the newline characters according to the default system prefs
418    * (editor.singleLine.pasteNewlines).
419    * Each value means:
420    *   nsIEditor::eNewlinesReplaceWithSpaces (2, Firefox default):
421    *     replace newlines with spaces.
422    *   nsIEditor::eNewlinesStrip (3):
423    *     remove newlines from the string.
424    *   nsIEditor::eNewlinesReplaceWithCommas (4, Thunderbird default):
425    *     replace newlines with commas.
426    *   nsIEditor::eNewlinesStripSurroundingWhitespace (5):
427    *     collapse newlines and surrounding white-space characters and
428    *     remove them from the string.
429    *   nsIEditor::eNewlinesPasteIntact (0):
430    *     only remove the leading and trailing newlines.
431    *   nsIEditor::eNewlinesPasteToFirst (1) or any other value:
432    *     remove the first newline and all characters following it.
433    *
434    * @param aString the string to be modified in place.
435    */
436   void HandleNewLinesInStringForSingleLineEditor(nsString& aString) const;
437 
438   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult HandleInsertText(
439       EditSubAction aEditSubAction, const nsAString& aInsertionString,
440       SelectionHandling aSelectionHandling) final;
441 
442   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertDroppedDataTransferAsAction(
443       AutoEditActionDataSetter& aEditActionData,
444       dom::DataTransfer& aDataTransfer, const EditorDOMPoint& aDroppedAt,
445       nsIPrincipal* aSourcePrincipal) final;
446 
447   /**
448    * HandleDeleteSelectionInternal() is a helper method of
449    * HandleDeleteSelection().  Must be called only when the instance is
450    * TextEditor.
451    * NOTE: This method creates SelectionBatcher.  Therefore, each caller
452    *       needs to check if the editor is still available even if this returns
453    *       NS_OK.
454    */
455   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
456   HandleDeleteSelectionInternal(nsIEditor::EDirection aDirectionAndAmount,
457                                 nsIEditor::EStripWrappers aStripWrappers);
458 
459   /**
460    * This method handles "delete selection" commands.
461    *
462    * @param aDirectionAndAmount Direction of the deletion.
463    * @param aStripWrappers      Must be nsIEditor::eNoStrip.
464    */
465   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
466   HandleDeleteSelection(nsIEditor::EDirection aDirectionAndAmount,
467                         nsIEditor::EStripWrappers aStripWrappers) final;
468 
469   /**
470    * ComputeValueFromTextNodeAndBRElement() tries to compute "value" of
471    * this editor content only with text nodes and `<br>` elements.
472    * If this succeeds to compute the value, it's returned with aValue and
473    * the result is marked as "handled".  Otherwise, the caller needs to
474    * compute it with another way.
475    */
476   EditActionResult ComputeValueFromTextNodeAndBRElement(
477       nsAString& aValue) const;
478 
479   /**
480    * SetTextWithoutTransaction() is optimized method to set `<input>.value`
481    * and `<textarea>.value` to aValue without transaction.  This must be
482    * called only when it's not `HTMLEditor` and undo/redo is disabled.
483    */
484   [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
485   SetTextWithoutTransaction(const nsAString& aValue);
486 
487   /**
488    * EnsureCaretNotAtEndOfTextNode() collapses selection at the padding `<br>`
489    * element (i.e., container becomes the anonymous `<div>` element) if
490    * `Selection` is at end of the text node.
491    */
492   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult EnsureCaretNotAtEndOfTextNode();
493 
494  protected:  // Called by helper classes.
495   MOZ_CAN_RUN_SCRIPT void OnStartToHandleTopLevelEditSubAction(
496       EditSubAction aTopLevelEditSubAction,
497       nsIEditor::EDirection aDirectionOfTopLevelEditSubAction,
498       ErrorResult& aRv) final;
499   MOZ_CAN_RUN_SCRIPT nsresult OnEndHandlingTopLevelEditSubAction() final;
500 
501   /**
502    * HandleInlineSpellCheckAfterEdit() does spell-check after handling top level
503    * edit subaction.
504    */
HandleInlineSpellCheckAfterEdit()505   nsresult HandleInlineSpellCheckAfterEdit() {
506     MOZ_ASSERT(IsEditActionDataAvailable());
507     if (!GetSpellCheckRestartPoint().IsSet()) {
508       return NS_OK;  // Maybe being initialized.
509     }
510     nsresult rv = HandleInlineSpellCheck(GetSpellCheckRestartPoint());
511     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to spellcheck");
512     ClearSpellCheckRestartPoint();
513     return rv;
514   }
515 
516  protected:  // Shouldn't be used by friend classes
517   virtual ~TextEditor();
518 
519   /**
520    * CanEchoPasswordNow() returns true if currently we can echo password.
521    * If it's direct user input such as pasting or dropping text, this
522    * returns false even if we may echo password.
523    */
524   bool CanEchoPasswordNow() const;
525 
526   /**
527    * Make the given selection span the entire document.
528    */
529   MOZ_CAN_RUN_SCRIPT nsresult SelectEntireDocument() final;
530 
531   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
532   InsertWithQuotationsAsSubAction(const nsAString& aQuotedText) final;
533 
534   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
535   InsertTextFromTransferable(nsITransferable* transferable);
536 
537   bool IsCopyToClipboardAllowedInternal() const final;
538 
539   already_AddRefed<Element> GetInputEventTargetElement() const final;
540 
541   /**
542    * See SetUnmaskRange() and SetUnmaskRangeAndNotify() for the detail.
543    *
544    * @param aForceStartMasking  If true, forcibly starts masking.  This should
545    *                            be used only when `nsIEditor::Mask()` is called.
546    */
547   MOZ_CAN_RUN_SCRIPT nsresult SetUnmaskRangeInternal(uint32_t aStart,
548                                                      uint32_t aLength,
549                                                      uint32_t aTimeout,
550                                                      bool aNotify,
551                                                      bool aForceStartMasking);
552 
HasAutoMaskingTimer()553   MOZ_ALWAYS_INLINE bool HasAutoMaskingTimer() const {
554     return mPasswordMaskData && mPasswordMaskData->mTimer;
555   }
556 
557  protected:
558   UniquePtr<PasswordMaskData> mPasswordMaskData;
559 
560   int32_t mMaxTextLength = -1;
561 
562   friend class DeleteNodeTransaction;
563   friend class EditorBase;
564   friend class InsertNodeTransaction;
565 };
566 
567 }  // namespace mozilla
568 
AsTextEditor()569 mozilla::TextEditor* nsIEditor::AsTextEditor() {
570   MOZ_DIAGNOSTIC_ASSERT(IsTextEditor());
571   return static_cast<mozilla::TextEditor*>(this);
572 }
573 
AsTextEditor()574 const mozilla::TextEditor* nsIEditor::AsTextEditor() const {
575   MOZ_DIAGNOSTIC_ASSERT(IsTextEditor());
576   return static_cast<const mozilla::TextEditor*>(this);
577 }
578 
GetAsTextEditor()579 mozilla::TextEditor* nsIEditor::GetAsTextEditor() {
580   return AsEditorBase()->IsTextEditor() ? AsTextEditor() : nullptr;
581 }
582 
GetAsTextEditor()583 const mozilla::TextEditor* nsIEditor::GetAsTextEditor() const {
584   return AsEditorBase()->IsTextEditor() ? AsTextEditor() : nullptr;
585 }
586 
587 #endif  // #ifndef mozilla_TextEditor_h
588