/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 |