Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/TextEditRules.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_TextEditRules_h
7
#define mozilla_TextEditRules_h
8
9
#include "mozilla/EditAction.h"
10
#include "mozilla/EditorDOMPoint.h"
11
#include "mozilla/EditorUtils.h"
12
#include "mozilla/HTMLEditor.h" // for nsIEditor::AsHTMLEditor()
13
#include "mozilla/TextEditor.h"
14
#include "nsCOMPtr.h"
15
#include "nsCycleCollectionParticipant.h"
16
#include "nsIEditor.h"
17
#include "nsINamed.h"
18
#include "nsISupportsImpl.h"
19
#include "nsITimer.h"
20
#include "nsString.h"
21
#include "nscore.h"
22
23
namespace mozilla {
24
25
class AutoLockRulesSniffing;
26
class EditSubActionInfo;
27
class HTMLEditor;
28
class HTMLEditRules;
29
namespace dom {
30
class Selection;
31
} // namespace dom
32
33
/**
34
 * Object that encapsulates HTML text-specific editing rules.
35
 *
36
 * To be a good citizen, edit rules must live by these restrictions:
37
 * 1. All data manipulation is through the editor.
38
 *    Content nodes in the document tree must <B>not</B> be manipulated
39
 *    directly.  Content nodes in document fragments that are not part of the
40
 *    document itself may be manipulated at will.  Operations on document
41
 *    fragments must <B>not</B> go through the editor.
42
 * 2. Selection must not be explicitly set by the rule method.
43
 *    Any manipulation of Selection must be done by the editor.
44
 * 3. Stop handling edit action if method returns NS_ERROR_EDITOR_DESTROYED
45
 *    since if mutation event lister or selectionchange event listener disables
46
 *    the editor, we should not modify the DOM tree anymore.
47
 * 4. Any method callers have to check nsresult return value (both directly or
48
 *    with simple class like EditActionResult) whether the value is
49
 *    NS_ERROR_EDITOR_DESTROYED at least.
50
 * 5. Callers of methods of other classes such as TextEditor, have to check
51
 *    CanHandleEditAction() before checking its result and if the result is
52
 *    false, the method have to return NS_ERROR_EDITOR_DESTROYED.  In other
53
 *    words, any methods which may change Selection or the DOM tree have to
54
 *    return nsresult directly or with simple class like EditActionResult.
55
 *    And such methods should be marked as MOZ_MUST_USE.
56
 */
57
class TextEditRules : public nsITimerCallback
58
                    , public nsINamed
59
{
60
public:
61
  typedef dom::Element Element;
62
  typedef dom::Selection Selection;
63
  typedef dom::Text Text;
64
  template<typename T> using OwningNonNull = OwningNonNull<T>;
65
66
  NS_DECL_NSITIMERCALLBACK
67
  NS_DECL_NSINAMED
68
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
69
  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(TextEditRules, nsITimerCallback)
70
71
  TextEditRules();
72
73
  HTMLEditRules* AsHTMLEditRules();
74
  const HTMLEditRules* AsHTMLEditRules() const;
75
76
  virtual nsresult Init(TextEditor* aTextEditor);
77
  virtual nsresult SetInitialValue(const nsAString& aValue);
78
  virtual nsresult DetachEditor();
79
  virtual nsresult BeforeEdit(EditSubAction aEditSubAction,
80
                              nsIEditor::EDirection aDirection);
81
  virtual nsresult AfterEdit(EditSubAction aEditSubAction,
82
                             nsIEditor::EDirection aDirection);
83
  virtual nsresult WillDoAction(Selection* aSelection,
84
                                EditSubActionInfo& aInfo,
85
                                bool* aCancel,
86
                                bool* aHandled);
87
  virtual nsresult DidDoAction(Selection* aSelection,
88
                               EditSubActionInfo& aInfo,
89
                               nsresult aResult);
90
91
  /**
92
   * Return false if the editor has non-empty text nodes or non-text
93
   * nodes.  Otherwise, i.e., there is no meaningful content,
94
   * return true.
95
   */
96
  virtual bool DocumentIsEmpty();
97
98
  virtual nsresult DocumentModified();
99
100
protected:
101
  virtual ~TextEditRules();
102
103
public:
104
  void ResetIMETextPWBuf();
105
106
  /**
107
   * Handles the newline characters according to the default system prefs
108
   * (editor.singleLine.pasteNewlines).
109
   * Each value means:
110
   *   nsIPlaintextEditor::eNewlinesReplaceWithSpaces (2, Firefox default):
111
   *     replace newlines with spaces.
112
   *   nsIPlaintextEditor::eNewlinesStrip (3):
113
   *     remove newlines from the string.
114
   *   nsIPlaintextEditor::eNewlinesReplaceWithCommas (4, Thunderbird default):
115
   *     replace newlines with commas.
116
   *   nsIPlaintextEditor::eNewlinesStripSurroundingWhitespace (5):
117
   *     collapse newlines and surrounding whitespace characters and
118
   *     remove them from the string.
119
   *   nsIPlaintextEditor::eNewlinesPasteIntact (0):
120
   *     only remove the leading and trailing newlines.
121
   *   nsIPlaintextEditor::eNewlinesPasteToFirst (1) or any other value:
122
   *     remove the first newline and all characters following it.
123
   *
124
   * @param aString the string to be modified in place.
125
   */
126
  void HandleNewLines(nsString& aString);
127
128
  /**
129
   * Prepare a string buffer for being displayed as the contents of a password
130
   * field.  This function uses the platform-specific character for representing
131
   * characters entered into password fields.
132
   *
133
   * @param aOutString the output string.  When this function returns,
134
   *        aOutString will contain aLength password characters.
135
   * @param aLength the number of password characters that aOutString should
136
   *        contain.
137
   */
138
  static void FillBufWithPWChars(nsAString* aOutString, int32_t aLength);
139
140
  bool HasBogusNode()
141
0
  {
142
0
    return !!mBogusNode;
143
0
  }
144
145
protected:
146
147
  void InitFields();
148
149
  // TextEditRules implementation methods
150
151
  /**
152
   * Called before inserting text.
153
   * This method may actually inserts text into the editor.  Therefore, this
154
   * might cause destroying the editor.
155
   *
156
   * @param aEditSubAction      Must be EditSubAction::eInsertTextComingFromIME
157
   *                            or EditSubAction::eInsertText.
158
   * @param aCancel             Returns true if the operation is canceled.
159
   * @param aHandled            Returns true if the edit action is handled.
160
   * @param inString            String to be inserted.
161
   * @param outString           String actually inserted.
162
   * @param aMaxLength          The maximum string length which the editor
163
   *                            allows to set.
164
   */
165
  MOZ_MUST_USE nsresult
166
  WillInsertText(EditSubAction aEditSubAction, bool* aCancel, bool* aHandled,
167
                 const nsAString* inString, nsAString* outString,
168
                 int32_t aMaxLength);
169
170
  /**
171
   * Called before inserting a line break into the editor.
172
   * This method removes selected text if selection isn't collapsed.
173
   * Therefore, this might cause destroying the editor.
174
   *
175
   * @param aCancel             Returns true if the operation is canceled.
176
   * @param aHandled            Returns true if the edit action is handled.
177
   * @param aMaxLength          The maximum string length which the editor
178
   *                            allows to set.
179
   */
180
  MOZ_MUST_USE nsresult
181
  WillInsertBreak(bool* aCancel, bool* aHandled, int32_t aMaxLength);
182
183
  /**
184
   * Called before setting text to the text editor.
185
   * This method may actually set text to it.  Therefore, this might cause
186
   * destroying the text editor.
187
   *
188
   * @param aCancel             Returns true if the operation is canceled.
189
   * @param aHandled            Returns true if the edit action is handled.
190
   * @param inString            String to be set.
191
   * @param aMaxLength          The maximum string length which the text editor
192
   *                            allows to set.
193
   */
194
  MOZ_MUST_USE nsresult
195
  WillSetText(bool* aCancel, bool* aHandled,
196
              const nsAString* inString, int32_t aMaxLength);
197
198
  /**
199
   * Called before inserting something into the editor.
200
   * This method may removes mBougsNode if there is.  Therefore, this method
201
   * might cause destroying the editor.
202
   *
203
   * @param aCancel             Returns true if the operation is canceled.
204
   *                            This can be nullptr.
205
   */
206
  MOZ_MUST_USE nsresult WillInsert(bool* aCancel = nullptr);
207
208
  /**
209
   * Called before deleting selected content.
210
   * This method may actually remove the selected content with
211
   * DeleteSelectionWithTransaction().  So, this might cause destroying the
212
   * editor.
213
   *
214
   * @param aCaollapsedAction   Direction to extend the selection.
215
   * @param aCancel             Returns true if the operation is canceled.
216
   * @param aHandled            Returns true if the edit action is handled.
217
   */
218
  MOZ_MUST_USE nsresult
219
  WillDeleteSelection(nsIEditor::EDirection aCollapsedAction,
220
                      bool* aCancel, bool* aHandled);
221
222
  /**
223
   * DeleteSelectionWithTransaction() is internal method of
224
   * WillDeleteSelection() since it needs to create SelectionBatcher in
225
   * big scope and destroying it might causes destroying the editor.
226
   * So, after calling this method, callers need to check CanHandleEditAction()
227
   * manually.
228
   *
229
   * @param aCaollapsedAction   Direction to extend the selection.
230
   * @param aCancel             Returns true if the operation is canceled.
231
   * @param aHandled            Returns true if the edit action is handled.
232
   */
233
  MOZ_MUST_USE nsresult
234
  DeleteSelectionWithTransaction(nsIEditor::EDirection aCollapsedAction,
235
                                 bool* aCancel, bool* aHandled);
236
237
  /**
238
   * Called after deleted selected content.
239
   * This method may remove empty text node and makes guarantee that caret
240
   * is never at left of <br> element.
241
   */
242
  MOZ_MUST_USE nsresult DidDeleteSelection();
243
244
  nsresult WillSetTextProperty(bool* aCancel, bool* aHandled);
245
246
  nsresult WillRemoveTextProperty(bool* aCancel, bool* aHandled);
247
248
  nsresult WillUndo(bool* aCancel, bool* aHandled);
249
  nsresult DidUndo(nsresult aResult);
250
251
  nsresult WillRedo(bool* aCancel, bool* aHandled);
252
  nsresult DidRedo(nsresult aResult);
253
254
  /**
255
   * Called prior to nsIEditor::OutputToString.
256
   *
257
   * @param aInFormat  The format requested for the output, a MIME type.
258
   * @param aOutText   The string to use for output, if aCancel is set to true.
259
   * @param aOutCancel If set to true, the caller should cancel the operation
260
   *                   and use aOutText as the result.
261
   */
262
  nsresult WillOutputText(const nsAString* aInFormat,
263
                          nsAString* aOutText,
264
                          uint32_t aFlags,
265
                          bool* aOutCancel,
266
                          bool* aHandled);
267
268
  /**
269
   * Check for and replace a redundant trailing break.
270
   */
271
  MOZ_MUST_USE nsresult RemoveRedundantTrailingBR();
272
273
  /**
274
   * Creates a trailing break in the text doc if there is not one already.
275
   */
276
  MOZ_MUST_USE nsresult CreateTrailingBRIfNeeded();
277
278
  /**
279
   * Creates a bogus <br> node if the root element has no editable content.
280
   */
281
  MOZ_MUST_USE nsresult CreateBogusNodeIfNeeded();
282
283
  /**
284
   * Returns a truncated insertion string if insertion would place us over
285
   * aMaxLength
286
   */
287
  nsresult TruncateInsertionIfNeeded(const nsAString* aInString,
288
                                     nsAString* aOutString,
289
                                     int32_t aMaxLength,
290
                                     bool* aTruncated);
291
292
  /**
293
   * Remove IME composition text from password buffer.
294
   */
295
  void RemoveIMETextFromPWBuf(uint32_t& aStart, nsAString* aIMEString);
296
297
  /**
298
   * Create a normal <br> element and insert it to aPointToInsert.
299
   *
300
   * @param aPointToInsert  The point where the new <br> element will be
301
   *                        inserted.
302
   * @return                Returns created <br> element or an error code
303
   *                        if couldn't create new <br> element.
304
   */
305
  template<typename PT, typename CT>
306
  CreateElementResult
307
  CreateBR(const EditorDOMPointBase<PT, CT>& aPointToInsert)
308
0
  {
309
0
    CreateElementResult ret = CreateBRInternal(aPointToInsert, false);
310
#ifdef DEBUG
311
    // If editor is destroyed, it must return NS_ERROR_EDITOR_DESTROYED.
312
    if (!CanHandleEditAction()) {
313
      MOZ_ASSERT(ret.Rv() == NS_ERROR_EDITOR_DESTROYED);
314
    }
315
#endif // #ifdef DEBUG
316
    return ret;
317
0
  }
318
319
  /**
320
   * Create a moz-<br> element and insert it to aPointToInsert.
321
   *
322
   * @param aPointToInsert  The point where the new moz-<br> element will be
323
   *                        inserted.
324
   * @return                Returns created <br> element or an error code
325
   *                        if couldn't create new <br> element.
326
   */
327
  template<typename PT, typename CT>
328
  CreateElementResult
329
  CreateMozBR(const EditorDOMPointBase<PT, CT>& aPointToInsert)
330
0
  {
331
0
    CreateElementResult ret = CreateBRInternal(aPointToInsert, true);
332
#ifdef DEBUG
333
    // If editor is destroyed, it must return NS_ERROR_EDITOR_DESTROYED.
334
    if (!CanHandleEditAction()) {
335
      MOZ_ASSERT(ret.Rv() == NS_ERROR_EDITOR_DESTROYED);
336
    }
337
#endif // #ifdef DEBUG
338
    return ret;
339
0
  }
Unexecuted instantiation: mozilla::CreateNodeResultBase<mozilla::dom::Element> mozilla::TextEditRules::CreateMozBR<nsINode*, nsIContent*>(mozilla::EditorDOMPointBase<nsINode*, nsIContent*> const&)
Unexecuted instantiation: mozilla::CreateNodeResultBase<mozilla::dom::Element> mozilla::TextEditRules::CreateMozBR<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >(mozilla::EditorDOMPointBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> > const&)
340
341
  void UndefineCaretBidiLevel();
342
343
  nsresult CheckBidiLevelForDeletion(const EditorRawDOMPoint& aSelectionPoint,
344
                                     nsIEditor::EDirection aAction,
345
                                     bool* aCancel);
346
347
  /**
348
   * HideLastPWInput() replaces last password characters which have not
349
   * been replaced with mask character like '*' with with the mask character.
350
   * This method may cause destroying the editor.
351
   */
352
  MOZ_MUST_USE nsresult HideLastPWInput();
353
354
  /**
355
   * CollapseSelectionToTrailingBRIfNeeded() collapses selection after the
356
   * text node if:
357
   * - the editor is text editor
358
   * - and Selection is collapsed at the end of the text node
359
   * - and the text node is followed by moz-<br>.
360
   */
361
  MOZ_MUST_USE nsresult CollapseSelectionToTrailingBRIfNeeded();
362
363
  bool IsPasswordEditor() const;
364
  bool IsSingleLineEditor() const;
365
  bool IsPlaintextEditor() const;
366
  bool IsReadonly() const;
367
  bool IsDisabled() const;
368
  bool IsMailEditor() const;
369
  bool DontEchoPassword() const;
370
371
private:
372
  TextEditor* MOZ_NON_OWNING_REF mTextEditor;
373
374
  /**
375
   * Create a normal <br> element or a moz-<br> element and insert it to
376
   * aPointToInsert.
377
   *
378
   * @param aParentToInsert     The point where the new <br> element will be
379
   *                            inserted.
380
   * @param aCreateMozBR        true if the caller wants to create a moz-<br>
381
   *                            element.  Otherwise, false.
382
   * @return                    Returns created <br> element and error code.
383
   *                            If it succeeded, never returns nullptr.
384
   */
385
  template<typename PT, typename CT>
386
  CreateElementResult
387
  CreateBRInternal(const EditorDOMPointBase<PT, CT>& aPointToInsert,
388
                   bool aCreateMozBR);
389
390
protected:
391
  /**
392
   * AutoSafeEditorData grabs editor instance and related instances during
393
   * handling an edit action.  When this is created, its pointer is set to
394
   * the mSafeData, and this guarantees the lifetime of grabbing objects
395
   * until it's destroyed.
396
   */
397
  class MOZ_STACK_CLASS AutoSafeEditorData
398
  {
399
  public:
400
    AutoSafeEditorData(TextEditRules& aTextEditRules,
401
                       TextEditor& aTextEditor,
402
                       Selection& aSelection)
403
      : mTextEditRules(aTextEditRules)
404
      , mHTMLEditor(nullptr)
405
0
    {
406
0
      // mTextEditRules may have AutoSafeEditorData instance since in some
407
0
      // cases. E.g., while public methods of *EditRules are called, it
408
0
      // calls attaching editor's method, then, editor will call public
409
0
      // methods of *EditRules again.
410
0
      if (mTextEditRules.mData) {
411
0
        return;
412
0
      }
413
0
      mTextEditor = &aTextEditor;
414
0
      mHTMLEditor = aTextEditor.AsHTMLEditor();
415
0
      mSelection = &aSelection;
416
0
      mTextEditRules.mData = this;
417
0
    }
418
419
    ~AutoSafeEditorData()
420
0
    {
421
0
      if (mTextEditRules.mData != this) {
422
0
        return;
423
0
      }
424
0
      mTextEditRules.mData = nullptr;
425
0
    }
426
427
0
    TextEditor& TextEditorRef() const { return *mTextEditor; }
428
    HTMLEditor& HTMLEditorRef() const
429
0
    {
430
0
      MOZ_ASSERT(mHTMLEditor);
431
0
      return *mHTMLEditor;
432
0
    }
433
0
    Selection& SelectionRef() const { return *mSelection; }
434
435
  private:
436
    // This class should be created by public methods TextEditRules and
437
    // HTMLEditRules and in the stack.  So, the lifetime of this should
438
    // be guaranteed the callers of the public methods.
439
    TextEditRules& MOZ_NON_OWNING_REF mTextEditRules;
440
    RefPtr<TextEditor> mTextEditor;
441
    // Shortcut for HTMLEditorRef().  So, not necessary to use RefPtr.
442
    HTMLEditor* MOZ_NON_OWNING_REF mHTMLEditor;
443
    RefPtr<Selection> mSelection;
444
  };
445
  AutoSafeEditorData* mData;
446
447
  TextEditor& TextEditorRef() const
448
0
  {
449
0
    MOZ_ASSERT(mData);
450
0
    return mData->TextEditorRef();
451
0
  }
452
  Selection& SelectionRef() const
453
0
  {
454
0
    MOZ_ASSERT(mData);
455
0
    return mData->SelectionRef();
456
0
  }
457
  bool CanHandleEditAction() const
458
0
  {
459
0
    if (!mTextEditor) {
460
0
      return false;
461
0
    }
462
0
    if (mTextEditor->Destroyed()) {
463
0
      return false;
464
0
    }
465
0
    MOZ_ASSERT(mTextEditor->IsInitialized());
466
0
    return true;
467
0
  }
468
469
#ifdef DEBUG
470
  bool IsEditorDataAvailable() const { return !!mData; }
471
#endif // #ifdef DEBUG
472
473
  /**
474
   * GetTextNodeAroundSelectionStartContainer() may return a Text node around
475
   * start container of Selection.  If current selection container is not
476
   * a text node, this will look for descendants and next siblings of the
477
   * container.
478
   */
479
  inline already_AddRefed<nsINode> GetTextNodeAroundSelectionStartContainer();
480
481
  // A buffer we use to store the real value of password editors.
482
  nsString mPasswordText;
483
  // A buffer we use to track the IME composition string.
484
  nsString mPasswordIMEText;
485
  uint32_t mPasswordIMEIndex;
486
  // Magic node acts as placeholder in empty doc.
487
  nsCOMPtr<nsIContent> mBogusNode;
488
  // Cached selected node.
489
  nsCOMPtr<nsINode> mCachedSelectionNode;
490
  // Cached selected offset.
491
  uint32_t mCachedSelectionOffset;
492
  uint32_t mActionNesting;
493
  bool mLockRulesSniffing;
494
  bool mDidExplicitlySetInterline;
495
  // In bidirectional text, delete characters not visually adjacent to the
496
  // caret without moving the caret first.
497
  bool mDeleteBidiImmediately;
498
  bool mIsHTMLEditRules;
499
  // The top level editor action.
500
  EditSubAction mTopLevelEditSubAction;
501
  nsCOMPtr<nsITimer> mTimer;
502
  uint32_t mLastStart;
503
  uint32_t mLastLength;
504
505
  // friends
506
  friend class AutoLockRulesSniffing;
507
};
508
509
/**
510
 * An object to encapsulate any additional info needed to be passed
511
 * to rules system by the editor.
512
 * TODO: This class (almost struct, though) is ugly and its size isn't
513
 *       optimized.  Should be refined later.
514
 */
515
class MOZ_STACK_CLASS EditSubActionInfo final
516
{
517
public:
518
  explicit EditSubActionInfo(EditSubAction aEditSubAction)
519
    : mEditSubAction(aEditSubAction)
520
    , inString(nullptr)
521
    , outString(nullptr)
522
    , outputFormat(nullptr)
523
    , maxLength(-1)
524
    , flags(0)
525
    , collapsedAction(nsIEditor::eNext)
526
    , stripWrappers(nsIEditor::eStrip)
527
    , entireList(false)
528
    , bulletType(nullptr)
529
    , alignType(nullptr)
530
    , blockType(nullptr)
531
0
  {}
532
533
  EditSubAction mEditSubAction;
534
535
  // EditSubAction::eInsertText / EditSubAction::eInsertTextComingFromIME
536
  const nsAString* inString;
537
  nsAString* outString;
538
  const nsAString* outputFormat;
539
  int32_t maxLength;
540
541
  // EditSubAction::eComputeTextToOutput
542
  uint32_t flags;
543
544
  // EditSubAction::eDeleteSelectedContent
545
  nsIEditor::EDirection collapsedAction;
546
  nsIEditor::EStripWrappers stripWrappers;
547
548
  // EditSubAction::eCreateOrChangeList
549
  bool entireList;
550
  const nsAString* bulletType;
551
552
  // EditSubAction::eSetOrClearAlignment
553
  const nsAString* alignType;
554
555
  // EditSubAction::eCreateOrRemoveBlock
556
  const nsAString* blockType;
557
};
558
559
/**
560
 * Stack based helper class for managing TextEditRules::mLockRluesSniffing.
561
 * This class sets a bool letting us know to ignore any rules sniffing
562
 * that tries to occur reentrantly.
563
 */
564
class MOZ_STACK_CLASS AutoLockRulesSniffing final
565
{
566
public:
567
  explicit AutoLockRulesSniffing(TextEditRules* aRules)
568
    : mRules(aRules)
569
0
  {
570
0
    if (mRules) {
571
0
      mRules->mLockRulesSniffing = true;
572
0
    }
573
0
  }
574
575
  ~AutoLockRulesSniffing()
576
0
  {
577
0
    if (mRules) {
578
0
      mRules->mLockRulesSniffing = false;
579
0
    }
580
0
  }
581
582
protected:
583
  TextEditRules* mRules;
584
};
585
586
/**
587
 * Stack based helper class for turning on/off the edit listener.
588
 */
589
class MOZ_STACK_CLASS AutoLockListener final
590
{
591
public:
592
  explicit AutoLockListener(bool* aEnabled)
593
    : mEnabled(aEnabled)
594
    , mOldState(false)
595
0
  {
596
0
    if (mEnabled) {
597
0
      mOldState = *mEnabled;
598
0
      *mEnabled = false;
599
0
    }
600
0
  }
601
602
  ~AutoLockListener()
603
0
  {
604
0
    if (mEnabled) {
605
0
      *mEnabled = mOldState;
606
0
    }
607
0
  }
608
609
protected:
610
  bool* mEnabled;
611
  bool mOldState;
612
};
613
614
} // namespace mozilla
615
616
#endif // #ifndef mozilla_TextEditRules_h