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