Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/TextEditor.h
Line
Count
Source (jump to first uncovered line)
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 "nsCOMPtr.h"
11
#include "nsCycleCollectionParticipant.h"
12
#include "nsIPlaintextEditor.h"
13
#include "nsISupportsImpl.h"
14
#include "nscore.h"
15
16
class nsIContent;
17
class nsIDocumentEncoder;
18
class nsIOutputStream;
19
class nsISelectionController;
20
class nsITransferable;
21
22
namespace mozilla {
23
class AutoEditInitRulesTrigger;
24
enum class EditSubAction : int32_t;
25
26
namespace dom {
27
class DragEvent;
28
class Selection;
29
} // namespace dom
30
31
/**
32
 * The text editor implementation.
33
 * Use to edit text document represented as a DOM tree.
34
 */
35
class TextEditor : public EditorBase
36
                 , public nsIPlaintextEditor
37
{
38
public:
39
  /****************************************************************************
40
   * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other
41
   *       classes under libeditor except EditorEventListener and
42
   *       HTMLEditorEventListener because each public method which may fire
43
   *       eEditorInput event will need to instantiate new stack class for
44
   *       managing input type value of eEditorInput and cache some objects
45
   *       for smarter handling.  In other words, when you add new root
46
   *       method to edit the DOM tree, you can make your new method public.
47
   ****************************************************************************/
48
49
  NS_DECL_ISUPPORTS_INHERITED
50
  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TextEditor, EditorBase)
51
52
  TextEditor();
53
54
  // nsIPlaintextEditor methods
55
  NS_DECL_NSIPLAINTEXTEDITOR
56
57
  // Overrides of nsIEditor
58
  NS_IMETHOD GetDocumentIsEmpty(bool* aDocumentIsEmpty) override;
59
60
  NS_IMETHOD DeleteSelection(EDirection aAction,
61
                             EStripWrappers aStripWrappers) override;
62
63
  NS_IMETHOD SetDocumentCharacterSet(const nsACString& characterSet) override;
64
65
  // If there are some good name to create non-virtual Undo()/Redo() methods,
66
  // we should create them and those methods should just run them.
67
  NS_IMETHOD Undo(uint32_t aCount) final;
68
  NS_IMETHOD Redo(uint32_t aCount) final;
69
70
  NS_IMETHOD Cut() override;
71
  NS_IMETHOD CanCut(bool* aCanCut) override;
72
  NS_IMETHOD Copy() override;
73
  NS_IMETHOD CanCopy(bool* aCanCopy) override;
74
  NS_IMETHOD CanDelete(bool* aCanDelete) override;
75
  NS_IMETHOD CanPaste(int32_t aSelectionType, bool* aCanPaste) override;
76
  NS_IMETHOD PasteTransferable(nsITransferable* aTransferable) override;
77
78
  NS_IMETHOD OutputToString(const nsAString& aFormatType,
79
                            uint32_t aFlags,
80
                            nsAString& aOutputString) override;
81
82
  /** Can we paste |aTransferable| or, if |aTransferable| is null, will a call
83
    * to pasteTransferable later possibly succeed if given an instance of
84
    * nsITransferable then? True if the doc is modifiable, and, if
85
    * |aTransfeable| is non-null, we have pasteable data in |aTransfeable|.
86
    */
87
  virtual bool CanPasteTransferable(nsITransferable* aTransferable);
88
89
  // Overrides of EditorBase
90
  virtual nsresult Init(nsIDocument& aDoc, Element* aRoot,
91
                        nsISelectionController* aSelCon, uint32_t aFlags,
92
                        const nsAString& aValue) override;
93
94
  /**
95
   * IsEmpty() checks whether the editor is empty.  If editor has only bogus
96
   * node, returns true.  If editor's root element has non-empty text nodes or
97
   * other nodes like <br>, returns false.
98
   */
99
  nsresult IsEmpty(bool* aIsEmpty) const;
100
  bool IsEmpty() const
101
0
  {
102
0
    bool isEmpty = false;
103
0
    nsresult rv = IsEmpty(&isEmpty);
104
0
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
105
0
      "Checking whether the editor is empty failed");
106
0
    return NS_SUCCEEDED(rv) && isEmpty;
107
0
  }
108
109
  virtual nsresult HandleKeyPressEvent(
110
                     WidgetKeyboardEvent* aKeyboardEvent) override;
111
112
  virtual dom::EventTarget* GetDOMEventTarget() override;
113
114
  /**
115
   * PasteAsAction() pastes clipboard content to Selection.  This method
116
   * may dispatch ePaste event first.  If its defaultPrevent() is called,
117
   * this does nothing but returns NS_OK.
118
   *
119
   * @param aClipboardType      nsIClipboard::kGlobalClipboard or
120
   *                            nsIClipboard::kSelectionClipboard.
121
   */
122
  nsresult PasteAsAction(int32_t aClipboardType);
123
124
  /**
125
   * InsertTextAsAction() inserts aStringToInsert at selection.
126
   * Although this method is implementation of nsIPlaintextEditor.insertText(),
127
   * this treats the input is an edit action.  If you'd like to insert text
128
   * as part of edit action, you probably should use InsertTextAsSubAction().
129
   *
130
   * @param aStringToInsert     The string to insert.
131
   */
132
  nsresult InsertTextAsAction(const nsAString& aStringToInsert);
133
134
  /**
135
   * PasteAsQuotationAsAction() pastes content in clipboard as quotation.
136
   * If the editor is TextEditor or in plaintext mode, will paste the content
137
   * with appending ">" to start of each line.
138
   *
139
   * @param aClipboardType      nsIClipboard::kGlobalClipboard or
140
   *                            nsIClipboard::kSelectionClipboard.
141
   */
142
  virtual nsresult PasteAsQuotationAsAction(int32_t aClipboardType);
143
144
  /**
145
   * DeleteSelectionAsAction() removes selection content or content around
146
   * caret with transactions.  This should be used for handling it as an
147
   * edit action.  If you'd like to remove selection for preparing to insert
148
   * something, you probably should use DeleteSelectionAsSubAction().
149
   *
150
   * @param aDirection          How much range should be removed.
151
   * @param aStripWrappers      Whether the parent blocks should be removed
152
   *                            when they become empty.
153
   */
154
  nsresult DeleteSelectionAsAction(EDirection aDirection,
155
                                   EStripWrappers aStripWrappers);
156
157
  /**
158
    * The maximum number of characters allowed.
159
    *   default: -1 (unlimited).
160
    */
161
0
  int32_t MaxTextLength() const { return mMaxTextLength; }
162
0
  void SetMaxTextLength(int32_t aLength) { mMaxTextLength = aLength; }
163
164
  /**
165
   * Replace existed string with a string.
166
   * This is fast path to replace all string when using single line control.
167
   *
168
   * @ param aString   the string to be set
169
   */
170
  nsresult SetText(const nsAString& aString);
171
172
  /**
173
   * Replace text in aReplaceRange or all text in this editor with aString and
174
   * treat the change as inserting the string.
175
   *
176
   * @param aString             The string to set.
177
   * @param aReplaceRange       The range to be replaced.
178
   *                            If nullptr, all contents will be replaced.
179
   */
180
  nsresult ReplaceTextAsAction(const nsAString& aString,
181
                               nsRange* aReplaceRange = nullptr);
182
183
  /**
184
   * OnInputParagraphSeparator() is called when user tries to separate current
185
   * paragraph with Enter key press or something.
186
   */
187
  nsresult OnInputParagraphSeparator();
188
189
  /**
190
   * OnCompositionStart() is called when editor receives eCompositionStart
191
   * event which should be handled in this editor.
192
   */
193
  nsresult OnCompositionStart(WidgetCompositionEvent& aCompositionStartEvent);
194
195
  /**
196
   * OnCompositionChange() is called when editor receives an eCompositioChange
197
   * event which should be handled in this editor.
198
   *
199
   * @param aCompositionChangeEvent     eCompositionChange event which should
200
   *                                    be handled in this editor.
201
   */
202
  nsresult
203
  OnCompositionChange(WidgetCompositionEvent& aCompositionChangeEvent);
204
205
  /**
206
   * OnCompositionEnd() is called when editor receives an eCompositionChange
207
   * event and it's followed by eCompositionEnd event and after
208
   * OnCompositionChange() is called.
209
   */
210
  void OnCompositionEnd(WidgetCompositionEvent& aCompositionEndEvent);
211
212
  /**
213
   * OnDrop() is called from EditorEventListener::Drop that is handler of drop
214
   * event.
215
   */
216
  nsresult OnDrop(dom::DragEvent* aDropEvent);
217
218
  /**
219
   * ComputeTextValue() computes plaintext value of this editor.  This may be
220
   * too expensive if it's in hot path.
221
   *
222
   * @param aDocumentEncoderFlags   Flags of nsIDocumentEncoder.
223
   * @param aCharset                Encoding of the document.
224
   */
225
  nsresult ComputeTextValue(uint32_t aDocumentEncoderFlags,
226
                            nsAString& aOutputString) const
227
0
  {
228
0
    return ComputeValueInternal(NS_LITERAL_STRING("text/plain"),
229
0
                                aDocumentEncoderFlags, aOutputString);
230
0
  }
231
232
protected: // May be called by friends.
233
  /****************************************************************************
234
   * Some classes like TextEditRules, HTMLEditRules, WSRunObject which are
235
   * part of handling edit actions are allowed to call the following protected
236
   * methods.  However, those methods won't prepare caches of some objects
237
   * which are necessary for them.  So, if you want some following methods
238
   * to do that for you, you need to create a wrapper method in public scope
239
   * and call it.
240
   ****************************************************************************/
241
242
  // Overrides of EditorBase
243
  virtual nsresult RemoveAttributeOrEquivalent(
244
                     Element* aElement,
245
                     nsAtom* aAttribute,
246
                     bool aSuppressTransaction) override;
247
  virtual nsresult SetAttributeOrEquivalent(Element* aElement,
248
                                            nsAtom* aAttribute,
249
                                            const nsAString& aValue,
250
                                            bool aSuppressTransaction) override;
251
  using EditorBase::RemoveAttributeOrEquivalent;
252
  using EditorBase::SetAttributeOrEquivalent;
253
254
  /**
255
   * InsertTextAsSubAction() inserts aStringToInsert at selection.  This
256
   * should be used for handling it as an edit sub-action.
257
   *
258
   * @param aStringToInsert     The string to insert.
259
   */
260
  nsresult InsertTextAsSubAction(const nsAString& aStringToInsert);
261
262
  /**
263
   * DeleteSelectionAsSubAction() removes selection content or content around
264
   * caret with transactions.  This should be used for handling it as an
265
   * edit sub-action.
266
   *
267
   * @param aDirection          How much range should be removed.
268
   * @param aStripWrappers      Whether the parent blocks should be removed
269
   *                            when they become empty.
270
   */
271
  nsresult DeleteSelectionAsSubAction(EDirection aDirection,
272
                                      EStripWrappers aStripWrappers);
273
274
  /**
275
   * DeleteSelectionWithTransaction() removes selected content or content
276
   * around caret with transactions.
277
   *
278
   * @param aDirection          How much range should be removed.
279
   * @param aStripWrappers      Whether the parent blocks should be removed
280
   *                            when they become empty.
281
   */
282
  virtual nsresult
283
  DeleteSelectionWithTransaction(EDirection aAction,
284
                                 EStripWrappers aStripWrappers);
285
286
  /**
287
   * Replace existed string with aString.  Caller must guarantee that there
288
   * is a placeholder transaction which will have the transaction.
289
   *
290
   * @ param aString   The string to be set.
291
   */
292
  nsresult SetTextAsSubAction(const nsAString& aString);
293
294
  /**
295
   * ReplaceSelectionAsSubAction() replaces selection with aString.
296
   *
297
   * @param aString    The string to replace.
298
   */
299
  nsresult ReplaceSelectionAsSubAction(const nsAString& aString);
300
301
  /**
302
   * InsertBrElementWithTransaction() creates a <br> element and inserts it
303
   * before aPointToInsert.  Then, tries to collapse selection at or after the
304
   * new <br> node if aSelect is not eNone.
305
   *
306
   * @param aSelection          The selection of this editor.
307
   * @param aPointToInsert      The DOM point where should be <br> node inserted
308
   *                            before.
309
   * @param aSelect             If eNone, this won't change selection.
310
   *                            If eNext, selection will be collapsed after
311
   *                            the <br> element.
312
   *                            If ePrevious, selection will be collapsed at
313
   *                            the <br> element.
314
   * @return                    The new <br> node.  If failed to create new
315
   *                            <br> node, returns nullptr.
316
   */
317
  template<typename PT, typename CT>
318
  already_AddRefed<Element>
319
  InsertBrElementWithTransaction(
320
    Selection& aSelection,
321
    const EditorDOMPointBase<PT, CT>& aPointToInsert,
322
    EDirection aSelect = eNone);
323
324
  /**
325
   * Extends the selection for given deletion operation
326
   * If done, also update aAction to what's actually left to do after the
327
   * extension.
328
   */
329
  nsresult ExtendSelectionForDelete(Selection* aSelection,
330
                                    nsIEditor::EDirection* aAction);
331
332
  static void GetDefaultEditorPrefs(int32_t& aNewLineHandling,
333
                                    int32_t& aCaretStyle);
334
335
protected: // Called by helper classes.
336
337
  virtual void
338
  OnStartToHandleTopLevelEditSubAction(
339
    EditSubAction aEditSubAction, nsIEditor::EDirection aDirection) override;
340
  virtual void OnEndHandlingTopLevelEditSubAction() override;
341
342
  void BeginEditorInit();
343
  nsresult EndEditorInit();
344
345
protected: // Shouldn't be used by friend classes
346
  virtual ~TextEditor();
347
348
0
  int32_t WrapWidth() const { return mWrapColumn; }
349
350
  /**
351
   * Make the given selection span the entire document.
352
   */
353
  virtual nsresult SelectEntireDocument(Selection* aSelection) override;
354
355
  /**
356
   * OnInputText() is called when user inputs text with keyboard or something.
357
   *
358
   * @param aStringToInsert     The string to insert.
359
   */
360
  nsresult OnInputText(const nsAString& aStringToInsert);
361
362
  /**
363
   * InsertParagraphSeparatorAsAction() inserts a line break if it's TextEditor
364
   * or inserts new paragraph if it's HTMLEditor and it's possible.
365
   * Although, this method is implementation of
366
   * nsIPlaintextEditor.insertLineBreak(), this treats the input is an edit
367
   * action.
368
   */
369
  nsresult InsertParagraphSeparatorAsAction();
370
371
  nsresult InsertTextAt(const nsAString& aStringToInsert,
372
                        nsINode* aDestinationNode,
373
                        int32_t aDestOffset,
374
                        bool aDoDeleteSelection);
375
376
  virtual nsresult InsertFromDataTransfer(dom::DataTransfer* aDataTransfer,
377
                                          int32_t aIndex,
378
                                          nsIDocument* aSourceDoc,
379
                                          nsINode* aDestinationNode,
380
                                          int32_t aDestOffset,
381
                                          bool aDoDeleteSelection) override;
382
383
  /**
384
   * InsertWithQuotationsAsSubAction() inserts aQuotedText with appending ">"
385
   * to start of every line.
386
   *
387
   * @param aQuotedText         String to insert.  This will be quoted by ">"
388
   *                            automatically.
389
   */
390
  nsresult InsertWithQuotationsAsSubAction(const nsAString& aQuotedText);
391
392
  /**
393
   * Return true if the data is safe to insert as the source and destination
394
   * principals match, or we are in a editor context where this doesn't matter.
395
   * Otherwise, the data must be sanitized first.
396
   */
397
  bool IsSafeToInsertData(nsIDocument* aSourceDoc);
398
399
  virtual nsresult InitRules();
400
401
  /**
402
   * GetAndInitDocEncoder() returns a document encoder instance for aFormatType
403
   * after initializing it.  The result may be cached for saving recreation
404
   * cost.
405
   *
406
   * @param aFormatType             MIME type like "text/plain".
407
   * @param aDocumentEncoderFlags   Flags of nsIDocumentEncoder.
408
   * @param aCharset                Encoding of the document.
409
   */
410
  already_AddRefed<nsIDocumentEncoder>
411
  GetAndInitDocEncoder(const nsAString& aFormatType,
412
                       uint32_t aDocumentEncoderFlags,
413
                       const nsACString& aCharset) const;
414
415
  /**
416
   * ComputeValueInternal() computes string value of this editor for given
417
   * format.  This may be too expensive if it's in hot path.
418
   *
419
   * @param aFormatType             MIME type like "text/plain".
420
   * @param aDocumentEncoderFlags   Flags of nsIDocumentEncoder.
421
   * @param aCharset                Encoding of the document.
422
   */
423
  nsresult ComputeValueInternal(const nsAString& aFormatType,
424
                                uint32_t aDocumentEncoderFlags,
425
                                nsAString& aOutputString) const;
426
427
  /**
428
   * Factored methods for handling insertion of data from transferables
429
   * (drag&drop or clipboard).
430
   */
431
  virtual nsresult PrepareTransferable(nsITransferable** transferable);
432
433
  nsresult InsertTextFromTransferable(nsITransferable* transferable);
434
435
  /**
436
   * DeleteSelectionAndCreateElement() creates a element whose name is aTag.
437
   * And insert it into the DOM tree after removing the selected content.
438
   *
439
   * @param aTag                The element name to be created.
440
   * @return                    Created new element.
441
   */
442
  already_AddRefed<Element> DeleteSelectionAndCreateElement(nsAtom& aTag);
443
444
  /**
445
   * This method first deletes the selection, if it's not collapsed.  Then if
446
   * the selection lies in a CharacterData node, it splits it.  If the
447
   * selection is at this point collapsed in a CharacterData node, it's
448
   * adjusted to be collapsed right before or after the node instead (which is
449
   * always possible, since the node was split).
450
   */
451
  nsresult DeleteSelectionAndPrepareToCreateNode();
452
453
  /**
454
   * Shared outputstring; returns whether selection is collapsed and resulting
455
   * string.
456
   */
457
  nsresult SharedOutputString(uint32_t aFlags, bool* aIsCollapsed,
458
                              nsAString& aResult);
459
460
  enum PasswordFieldAllowed
461
  {
462
    ePasswordFieldAllowed,
463
    ePasswordFieldNotAllowed
464
  };
465
  bool CanCutOrCopy(PasswordFieldAllowed aPasswordFieldAllowed);
466
  bool FireClipboardEvent(EventMessage aEventMessage,
467
                          int32_t aSelectionType,
468
                          bool* aActionTaken = nullptr);
469
470
  bool UpdateMetaCharset(nsIDocument& aDocument,
471
                         const nsACString& aCharacterSet);
472
473
  /**
474
   * EnsureComposition() should be called by composition event handlers.  This
475
   * tries to get the composition for the event and set it to mComposition.
476
   * However, this may fail because the composition may be committed before
477
   * the event comes to the editor.
478
   *
479
   * @return            true if there is a composition.  Otherwise, for example,
480
   *                    a composition event handler in web contents moved focus
481
   *                    for committing the composition, returns false.
482
   */
483
  bool EnsureComposition(WidgetCompositionEvent& aCompositionEvent);
484
485
  virtual already_AddRefed<nsIContent> GetInputEventTargetContent() override;
486
487
protected:
488
  mutable nsCOMPtr<nsIDocumentEncoder> mCachedDocumentEncoder;
489
  mutable nsString mCachedDocumentEncoderType;
490
  int32_t mWrapColumn;
491
  int32_t mMaxTextLength;
492
  int32_t mInitTriggerCounter;
493
  int32_t mNewlineHandling;
494
  int32_t mCaretStyle;
495
496
  friend class AutoEditInitRulesTrigger;
497
  friend class TextEditRules;
498
};
499
500
} // namespace mozilla
501
502
mozilla::TextEditor*
503
nsIEditor::AsTextEditor()
504
0
{
505
0
  return static_cast<mozilla::TextEditor*>(this);
506
0
}
507
508
const mozilla::TextEditor*
509
nsIEditor::AsTextEditor() const
510
0
{
511
0
  return static_cast<const mozilla::TextEditor*>(this);
512
0
}
513
514
#endif // #ifndef mozilla_TextEditor_h