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_EditorBase_h 7 #define mozilla_EditorBase_h 8 9 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc. 10 #include "mozFlushType.h" // for mozFlushType enum 11 #include "mozilla/OwningNonNull.h" // for OwningNonNull 12 #include "mozilla/SelectionState.h" // for RangeUpdater, etc. 13 #include "mozilla/StyleSheet.h" // for StyleSheet 14 #include "mozilla/dom/Text.h" 15 #include "nsCOMPtr.h" // for already_AddRefed, nsCOMPtr 16 #include "nsCycleCollectionParticipant.h" 17 #include "nsGkAtoms.h" 18 #include "nsIEditor.h" // for nsIEditor::EDirection, etc. 19 #include "nsIEditorIMESupport.h" // for NS_DECL_NSIEDITORIMESUPPORT, etc. 20 #include "nsIObserver.h" // for NS_DECL_NSIOBSERVER, etc. 21 #include "nsIPhonetic.h" // for NS_DECL_NSIPHONETIC, etc. 22 #include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc. 23 #include "nsISelectionController.h" // for nsISelectionController constants 24 #include "nsISupportsImpl.h" // for EditorBase::Release, etc. 25 #include "nsIWeakReferenceUtils.h" // for nsWeakPtr 26 #include "nsLiteralString.h" // for NS_LITERAL_STRING 27 #include "nsString.h" // for nsCString 28 #include "nsWeakReference.h" // for nsSupportsWeakReference 29 #include "nscore.h" // for nsresult, nsAString, etc. 30 31 class nsIAtom; 32 class nsIContent; 33 class nsIDOMDocument; 34 class nsIDOMEvent; 35 class nsIDOMEventListener; 36 class nsIDOMEventTarget; 37 class nsIDOMKeyEvent; 38 class nsIDOMNode; 39 class nsIDocument; 40 class nsIDocumentStateListener; 41 class nsIEditActionListener; 42 class nsIEditorObserver; 43 class nsIInlineSpellChecker; 44 class nsINode; 45 class nsIPresShell; 46 class nsISupports; 47 class nsITransaction; 48 class nsIWidget; 49 class nsRange; 50 class nsString; 51 class nsTransactionManager; 52 53 // This is int32_t instead of int16_t because nsIInlineSpellChecker.idl's 54 // spellCheckAfterEditorChange is defined to take it as a long. 55 // XXX EditAction causes unnecessary include of EditorBase from some places. 56 // Why don't you move this to nsIEditor.idl? 57 enum class EditAction : int32_t 58 { 59 ignore = -1, 60 none = 0, 61 undo, 62 redo, 63 insertNode, 64 createNode, 65 deleteNode, 66 splitNode, 67 joinNode, 68 deleteText = 1003, 69 70 // text commands 71 insertText = 2000, 72 insertIMEText = 2001, 73 deleteSelection = 2002, 74 setTextProperty = 2003, 75 removeTextProperty = 2004, 76 outputText = 2005, 77 78 // html only action 79 insertBreak = 3000, 80 makeList = 3001, 81 indent = 3002, 82 outdent = 3003, 83 align = 3004, 84 makeBasicBlock = 3005, 85 removeList = 3006, 86 makeDefListItem = 3007, 87 insertElement = 3008, 88 insertQuotation = 3009, 89 htmlPaste = 3012, 90 loadHTML = 3013, 91 resetTextProperties = 3014, 92 setAbsolutePosition = 3015, 93 removeAbsolutePosition = 3016, 94 decreaseZIndex = 3017, 95 increaseZIndex = 3018 96 }; 97 98 inline bool operator!(const EditAction& aOp) 99 { 100 return aOp == EditAction::none; 101 } 102 103 namespace mozilla { 104 class AddStyleSheetTransaction; 105 class AutoRules; 106 class AutoSelectionRestorer; 107 class AutoTransactionsConserveSelection; 108 class ChangeAttributeTransaction; 109 class CompositionTransaction; 110 class CreateElementTransaction; 111 class DeleteNodeTransaction; 112 class DeleteTextTransaction; 113 class EditAggregateTransaction; 114 class ErrorResult; 115 class InsertNodeTransaction; 116 class InsertTextTransaction; 117 class JoinNodeTransaction; 118 class RemoveStyleSheetTransaction; 119 class SplitNodeTransaction; 120 class TextComposition; 121 struct EditorDOMPoint; 122 123 namespace dom { 124 class DataTransfer; 125 class Element; 126 class EventTarget; 127 class Selection; 128 class Text; 129 } // namespace dom 130 131 namespace widget { 132 struct IMEState; 133 } // namespace widget 134 135 #define kMOZEditorBogusNodeAttrAtom nsGkAtoms::mozeditorbogusnode 136 #define kMOZEditorBogusNodeValue NS_LITERAL_STRING("TRUE") 137 138 /** 139 * Implementation of an editor object. it will be the controller/focal point 140 * for the main editor services. i.e. the GUIManager, publishing, transaction 141 * manager, event interfaces. the idea for the event interfaces is to have them 142 * delegate the actual commands to the editor independent of the XPFE 143 * implementation. 144 */ 145 class EditorBase : public nsIEditor 146 , public nsIEditorIMESupport 147 , public nsSupportsWeakReference 148 , public nsIPhonetic 149 { 150 public: 151 typedef dom::Element Element; 152 typedef dom::Selection Selection; 153 typedef dom::Text Text; 154 155 enum IterDirection 156 { 157 kIterForward, 158 kIterBackward 159 }; 160 161 /** 162 * The default constructor. This should suffice. the setting of the 163 * interfaces is done after the construction of the editor class. 164 */ 165 EditorBase(); 166 167 protected: 168 /** 169 * The default destructor. This should suffice. Should this be pure virtual 170 * for someone to derive from the EditorBase later? I don't believe so. 171 */ 172 virtual ~EditorBase(); 173 174 public: 175 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 176 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase, nsIEditor) 177 178 already_AddRefed<nsIDOMDocument> GetDOMDocument(); 179 already_AddRefed<nsIDocument> GetDocument(); 180 already_AddRefed<nsIPresShell> GetPresShell(); 181 already_AddRefed<nsIWidget> GetWidget(); 182 enum NotificationForEditorObservers 183 { 184 eNotifyEditorObserversOfEnd, 185 eNotifyEditorObserversOfBefore, 186 eNotifyEditorObserversOfCancel 187 }; 188 void NotifyEditorObservers(NotificationForEditorObservers aNotification); 189 190 // nsIEditor methods 191 NS_DECL_NSIEDITOR 192 193 // nsIEditorIMESupport methods 194 NS_DECL_NSIEDITORIMESUPPORT 195 196 // nsIPhonetic 197 NS_DECL_NSIPHONETIC 198 199 public: 200 virtual bool IsModifiableNode(nsINode* aNode); 201 202 virtual nsresult InsertTextImpl(const nsAString& aStringToInsert, 203 nsCOMPtr<nsINode>* aInOutNode, 204 int32_t* aInOutOffset, 205 nsIDocument* aDoc); 206 nsresult InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert, 207 Text& aTextNode, int32_t aOffset, 208 bool aSuppressIME = false); 209 NS_IMETHOD DeleteSelectionImpl(EDirection aAction, 210 EStripWrappers aStripWrappers); 211 212 already_AddRefed<Element> DeleteSelectionAndCreateElement(nsIAtom& aTag); 213 214 /** 215 * Helper routines for node/parent manipulations. 216 */ 217 nsresult DeleteNode(nsINode* aNode); 218 nsresult InsertNode(nsIContent& aNode, nsINode& aParent, int32_t aPosition); 219 enum ECloneAttributes { eDontCloneAttributes, eCloneAttributes }; 220 already_AddRefed<Element> ReplaceContainer(Element* aOldContainer, 221 nsIAtom* aNodeType, 222 nsIAtom* aAttribute = nullptr, 223 const nsAString* aValue = nullptr, 224 ECloneAttributes aCloneAttributes 225 = eDontCloneAttributes); 226 void CloneAttributes(Element* aDest, Element* aSource); 227 228 nsresult RemoveContainer(nsIContent* aNode); 229 already_AddRefed<Element> InsertContainerAbove(nsIContent* aNode, 230 nsIAtom* aNodeType, 231 nsIAtom* aAttribute = nullptr, 232 const nsAString* aValue = 233 nullptr); 234 nsIContent* SplitNode(nsIContent& aNode, int32_t aOffset, 235 ErrorResult& aResult); 236 nsresult JoinNodes(nsINode& aLeftNode, nsINode& aRightNode); 237 nsresult MoveNode(nsIContent* aNode, nsINode* aParent, int32_t aOffset); 238 239 /** 240 * Method to replace certain CreateElementNS() calls. 241 * 242 * @param aTag Tag you want. 243 */ 244 already_AddRefed<Element> CreateHTMLContent(nsIAtom* aTag); 245 246 /** 247 * IME event handlers. 248 */ 249 virtual nsresult BeginIMEComposition(WidgetCompositionEvent* aEvent); 250 virtual nsresult UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent) = 0; 251 void EndIMEComposition(); 252 253 void SwitchTextDirectionTo(uint32_t aDirection); 254 255 protected: 256 nsresult DetermineCurrentDirection(); 257 void FireInputEvent(); 258 259 /** 260 * Create a transaction for setting aAttribute to aValue on aElement. Never 261 * returns null. 262 */ 263 already_AddRefed<ChangeAttributeTransaction> 264 CreateTxnForSetAttribute(Element& aElement, nsIAtom& aAttribute, 265 const nsAString& aValue); 266 267 /** 268 * Create a transaction for removing aAttribute on aElement. Never returns 269 * null. 270 */ 271 already_AddRefed<ChangeAttributeTransaction> 272 CreateTxnForRemoveAttribute(Element& aElement, nsIAtom& aAttribute); 273 274 /** 275 * Create a transaction for creating a new child node of aParent of type aTag. 276 */ 277 already_AddRefed<CreateElementTransaction> 278 CreateTxnForCreateElement(nsIAtom& aTag, 279 nsINode& aParent, 280 int32_t aPosition); 281 282 already_AddRefed<Element> CreateNode(nsIAtom* aTag, nsINode* aParent, 283 int32_t aPosition); 284 285 /** 286 * Create a transaction for inserting aNode as a child of aParent. 287 */ 288 already_AddRefed<InsertNodeTransaction> 289 CreateTxnForInsertNode(nsIContent& aNode, nsINode& aParent, 290 int32_t aOffset); 291 292 /** 293 * Create a transaction for removing aNode from its parent. 294 */ 295 nsresult CreateTxnForDeleteNode(nsINode* aNode, 296 DeleteNodeTransaction** aTransaction); 297 298 nsresult CreateTxnForDeleteSelection( 299 EDirection aAction, 300 EditAggregateTransaction** aTransaction, 301 nsINode** aNode, 302 int32_t* aOffset, 303 int32_t* aLength); 304 305 nsresult CreateTxnForDeleteInsertionPoint( 306 nsRange* aRange, 307 EDirection aAction, 308 EditAggregateTransaction* aTransaction, 309 nsINode** aNode, 310 int32_t* aOffset, 311 int32_t* aLength); 312 313 314 /** 315 * Create a transaction for inserting aStringToInsert into aTextNode. Never 316 * returns null. 317 */ 318 already_AddRefed<mozilla::InsertTextTransaction> 319 CreateTxnForInsertText(const nsAString& aStringToInsert, Text& aTextNode, 320 int32_t aOffset); 321 322 /** 323 * Never returns null. 324 */ 325 already_AddRefed<mozilla::CompositionTransaction> 326 CreateTxnForComposition(const nsAString& aStringToInsert); 327 328 /** 329 * Create a transaction for adding a style sheet. 330 */ 331 NS_IMETHOD CreateTxnForAddStyleSheet( 332 StyleSheet* aSheet, 333 AddStyleSheetTransaction** aTransaction); 334 335 /** 336 * Create a transaction for removing a style sheet. 337 */ 338 NS_IMETHOD CreateTxnForRemoveStyleSheet( 339 StyleSheet* aSheet, 340 RemoveStyleSheetTransaction** aTransaction); 341 342 nsresult DeleteText(nsGenericDOMDataNode& aElement, 343 uint32_t aOffset, uint32_t aLength); 344 345 already_AddRefed<DeleteTextTransaction> 346 CreateTxnForDeleteText(nsGenericDOMDataNode& aElement, 347 uint32_t aOffset, uint32_t aLength); 348 349 already_AddRefed<DeleteTextTransaction> 350 CreateTxnForDeleteCharacter(nsGenericDOMDataNode& aData, uint32_t aOffset, 351 EDirection aDirection); 352 353 already_AddRefed<SplitNodeTransaction> 354 CreateTxnForSplitNode(nsIContent& aNode, uint32_t aOffset); 355 356 already_AddRefed<JoinNodeTransaction> 357 CreateTxnForJoinNode(nsINode& aLeftNode, nsINode& aRightNode); 358 359 /** 360 * This method first deletes the selection, if it's not collapsed. Then if 361 * the selection lies in a CharacterData node, it splits it. If the 362 * selection is at this point collapsed in a CharacterData node, it's 363 * adjusted to be collapsed right before or after the node instead (which is 364 * always possible, since the node was split). 365 */ 366 nsresult DeleteSelectionAndPrepareToCreateNode(); 367 368 /** 369 * Called after a transaction is done successfully. 370 */ 371 void DoAfterDoTransaction(nsITransaction *aTxn); 372 373 /** 374 * Called after a transaction is undone successfully. 375 */ 376 377 void DoAfterUndoTransaction(); 378 379 /** 380 * Called after a transaction is redone successfully. 381 */ 382 void DoAfterRedoTransaction(); 383 384 enum TDocumentListenerNotification 385 { 386 eDocumentCreated, 387 eDocumentToBeDestroyed, 388 eDocumentStateChanged 389 }; 390 391 /** 392 * Tell the doc state listeners that the doc state has changed. 393 */ 394 NS_IMETHOD NotifyDocumentListeners( 395 TDocumentListenerNotification aNotificationType); 396 397 /** 398 * Make the given selection span the entire document. 399 */ 400 virtual nsresult SelectEntireDocument(Selection* aSelection); 401 402 /** 403 * Helper method for scrolling the selection into view after 404 * an edit operation. aScrollToAnchor should be true if you 405 * want to scroll to the point where the selection was started. 406 * If false, it attempts to scroll the end of the selection into view. 407 * 408 * Editor methods *should* call this method instead of the versions 409 * in the various selection interfaces, since this version makes sure 410 * that the editor's sync/async settings for reflowing, painting, and 411 * scrolling match. 412 */ 413 NS_IMETHOD ScrollSelectionIntoView(bool aScrollToAnchor); 414 415 virtual bool IsBlockNode(nsINode* aNode); 416 417 /** 418 * Helper for GetPriorNode() and GetNextNode(). 419 */ 420 nsIContent* FindNextLeafNode(nsINode* aCurrentNode, 421 bool aGoForward, 422 bool bNoBlockCrossing); 423 424 virtual nsresult InstallEventListeners(); 425 virtual void CreateEventListeners(); 426 virtual void RemoveEventListeners(); 427 428 /** 429 * Return true if spellchecking should be enabled for this editor. 430 */ 431 bool GetDesiredSpellCheckState(); 432 CanEnableSpellCheck()433 bool CanEnableSpellCheck() 434 { 435 // Check for password/readonly/disabled, which are not spellchecked 436 // regardless of DOM. Also, check to see if spell check should be skipped 437 // or not. 438 return !IsPasswordEditor() && !IsReadonly() && !IsDisabled() && 439 !ShouldSkipSpellCheck(); 440 } 441 442 /** 443 * EnsureComposition() should be called by composition event handlers. This 444 * tries to get the composition for the event and set it to mComposition. 445 * However, this may fail because the composition may be committed before 446 * the event comes to the editor. 447 * 448 * @return true if there is a composition. Otherwise, for example, 449 * a composition event handler in web contents moved focus 450 * for committing the composition, returns false. 451 */ 452 bool EnsureComposition(WidgetCompositionEvent* aCompositionEvent); 453 454 nsresult GetSelection(SelectionType aSelectionType, 455 nsISelection** aSelection); 456 457 public: 458 /** 459 * All editor operations which alter the doc should be prefaced 460 * with a call to StartOperation, naming the action and direction. 461 */ 462 NS_IMETHOD StartOperation(EditAction opID, 463 nsIEditor::EDirection aDirection); 464 465 /** 466 * All editor operations which alter the doc should be followed 467 * with a call to EndOperation. 468 */ 469 NS_IMETHOD EndOperation(); 470 471 /** 472 * Routines for managing the preservation of selection across 473 * various editor actions. 474 */ 475 bool ArePreservingSelection(); 476 void PreserveSelectionAcrossActions(Selection* aSel); 477 nsresult RestorePreservedSelection(Selection* aSel); 478 void StopPreservingSelection(); 479 480 /** 481 * SplitNode() creates a new node identical to an existing node, and split 482 * the contents between the two nodes 483 * @param aExistingRightNode The node to split. It will become the new 484 * node's next sibling. 485 * @param aOffset The offset of aExistingRightNode's 486 * content|children to do the split at 487 * @param aNewLeftNode The new node resulting from the split, becomes 488 * aExistingRightNode's previous sibling. 489 */ 490 nsresult SplitNodeImpl(nsIContent& aExistingRightNode, 491 int32_t aOffset, 492 nsIContent& aNewLeftNode); 493 494 /** 495 * JoinNodes() takes 2 nodes and merge their content|children. 496 * @param aNodeToKeep The node that will remain after the join. 497 * @param aNodeToJoin The node that will be joined with aNodeToKeep. 498 * There is no requirement that the two nodes be of the 499 * same type. 500 * @param aParent The parent of aNodeToKeep 501 */ 502 nsresult JoinNodesImpl(nsINode* aNodeToKeep, 503 nsINode* aNodeToJoin, 504 nsINode* aParent); 505 506 /** 507 * Return the offset of aChild in aParent. Asserts fatally if parent or 508 * child is null, or parent is not child's parent. 509 */ 510 static int32_t GetChildOffset(nsIDOMNode* aChild, 511 nsIDOMNode* aParent); 512 513 /** 514 * Set outOffset to the offset of aChild in the parent. 515 * Returns the parent of aChild. 516 */ 517 static already_AddRefed<nsIDOMNode> GetNodeLocation(nsIDOMNode* aChild, 518 int32_t* outOffset); 519 static nsINode* GetNodeLocation(nsINode* aChild, int32_t* aOffset); 520 521 /** 522 * Returns the number of things inside aNode in the out-param aCount. 523 * @param aNode is the node to get the length of. 524 * If aNode is text, returns number of characters. 525 * If not, returns number of children nodes. 526 * @param aCount [OUT] the result of the above calculation. 527 */ 528 static nsresult GetLengthOfDOMNode(nsIDOMNode *aNode, uint32_t &aCount); 529 530 /** 531 * Get the node immediately prior to aCurrentNode. 532 * @param aCurrentNode the node from which we start the search 533 * @param aEditableNode if true, only return an editable node 534 * @param aResultNode [OUT] the node that occurs before aCurrentNode in 535 * the tree, skipping non-editable nodes if 536 * aEditableNode is true. If there is no prior 537 * node, aResultNode will be nullptr. 538 * @param bNoBlockCrossing If true, don't move across "block" nodes, 539 * whatever that means. 540 */ 541 nsIContent* GetPriorNode(nsINode* aCurrentNode, bool aEditableNode, 542 bool aNoBlockCrossing = false); 543 544 /** 545 * And another version that takes a {parent,offset} pair rather than a node. 546 */ 547 nsIContent* GetPriorNode(nsINode* aParentNode, 548 int32_t aOffset, 549 bool aEditableNode, 550 bool aNoBlockCrossing = false); 551 552 553 /** 554 * Get the node immediately after to aCurrentNode. 555 * @param aCurrentNode the node from which we start the search 556 * @param aEditableNode if true, only return an editable node 557 * @param aResultNode [OUT] the node that occurs after aCurrentNode in the 558 * tree, skipping non-editable nodes if 559 * aEditableNode is true. If there is no prior 560 * node, aResultNode will be nullptr. 561 */ 562 nsIContent* GetNextNode(nsINode* aCurrentNode, 563 bool aEditableNode, 564 bool bNoBlockCrossing = false); 565 566 /** 567 * And another version that takes a {parent,offset} pair rather than a node. 568 */ 569 nsIContent* GetNextNode(nsINode* aParentNode, 570 int32_t aOffset, 571 bool aEditableNode, 572 bool aNoBlockCrossing = false); 573 574 /** 575 * Helper for GetNextNode() and GetPriorNode(). 576 */ 577 nsIContent* FindNode(nsINode* aCurrentNode, 578 bool aGoForward, 579 bool aEditableNode, 580 bool bNoBlockCrossing); 581 /** 582 * Get the rightmost child of aCurrentNode; 583 * return nullptr if aCurrentNode has no children. 584 */ 585 nsIContent* GetRightmostChild(nsINode* aCurrentNode, 586 bool bNoBlockCrossing = false); 587 588 /** 589 * Get the leftmost child of aCurrentNode; 590 * return nullptr if aCurrentNode has no children. 591 */ 592 nsIContent* GetLeftmostChild(nsINode *aCurrentNode, 593 bool bNoBlockCrossing = false); 594 595 /** 596 * Returns true if aNode is of the type implied by aTag. 597 */ NodeIsType(nsIDOMNode * aNode,nsIAtom * aTag)598 static inline bool NodeIsType(nsIDOMNode* aNode, nsIAtom* aTag) 599 { 600 return GetTag(aNode) == aTag; 601 } 602 603 /** 604 * Returns true if aParent can contain a child of type aTag. 605 */ 606 bool CanContain(nsINode& aParent, nsIContent& aChild); 607 bool CanContainTag(nsINode& aParent, nsIAtom& aTag); 608 bool TagCanContain(nsIAtom& aParentTag, nsIContent& aChild); 609 virtual bool TagCanContainTag(nsIAtom& aParentTag, nsIAtom& aChildTag); 610 611 /** 612 * Returns true if aNode is our root node. 613 */ 614 bool IsRoot(nsIDOMNode* inNode); 615 bool IsRoot(nsINode* inNode); 616 bool IsEditorRoot(nsINode* aNode); 617 618 /** 619 * Returns true if aNode is a descendant of our root node. 620 */ 621 bool IsDescendantOfRoot(nsIDOMNode* inNode); 622 bool IsDescendantOfRoot(nsINode* inNode); 623 bool IsDescendantOfEditorRoot(nsINode* aNode); 624 625 /** 626 * Returns true if aNode is a container. 627 */ 628 virtual bool IsContainer(nsINode* aNode); 629 virtual bool IsContainer(nsIDOMNode* aNode); 630 631 /** 632 * returns true if aNode is an editable node. 633 */ 634 bool IsEditable(nsIDOMNode* aNode); 635 virtual bool IsEditable(nsINode* aNode); 636 637 /** 638 * Returns true if aNode is a MozEditorBogus node. 639 */ 640 bool IsMozEditorBogusNode(nsINode* aNode); 641 642 /** 643 * Counts number of editable child nodes. 644 */ 645 uint32_t CountEditableChildren(nsINode* aNode); 646 647 /** 648 * Find the deep first and last children. 649 */ 650 nsINode* GetFirstEditableNode(nsINode* aRoot); 651 652 /** 653 * Returns current composition. 654 */ 655 TextComposition* GetComposition() const; 656 657 /** 658 * Returns true if there is composition string and not fixed. 659 */ 660 bool IsIMEComposing() const; 661 662 /** 663 * Returns true when inserting text should be a part of current composition. 664 */ 665 bool ShouldHandleIMEComposition() const; 666 667 /** 668 * From html rules code - migration in progress. 669 */ 670 static nsresult GetTagString(nsIDOMNode* aNode, nsAString& outString); 671 static nsIAtom* GetTag(nsIDOMNode* aNode); 672 673 bool NodesSameType(nsIDOMNode* aNode1, nsIDOMNode* aNode2); 674 virtual bool AreNodesSameType(nsIContent* aNode1, nsIContent* aNode2); 675 676 static bool IsTextNode(nsIDOMNode* aNode); 677 static bool IsTextNode(nsINode* aNode); 678 679 static nsCOMPtr<nsIDOMNode> GetChildAt(nsIDOMNode* aParent, int32_t aOffset); 680 static nsIContent* GetNodeAtRangeOffsetPoint(nsIDOMNode* aParentOrNode, 681 int32_t aOffset); 682 683 static nsresult GetStartNodeAndOffset(Selection* aSelection, 684 nsIDOMNode** outStartNode, 685 int32_t* outStartOffset); 686 static nsresult GetStartNodeAndOffset(Selection* aSelection, 687 nsINode** aStartNode, 688 int32_t* aStartOffset); 689 static nsresult GetEndNodeAndOffset(Selection* aSelection, 690 nsIDOMNode** outEndNode, 691 int32_t* outEndOffset); 692 static nsresult GetEndNodeAndOffset(Selection* aSelection, 693 nsINode** aEndNode, 694 int32_t* aEndOffset); 695 #if DEBUG_JOE 696 static void DumpNode(nsIDOMNode* aNode, int32_t indent = 0); 697 #endif 698 Selection* GetSelection(SelectionType aSelectionType = 699 SelectionType::eNormal); 700 701 /** 702 * Helpers to add a node to the selection. 703 * Used by table cell selection methods. 704 */ 705 nsresult CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset, 706 nsIDOMNode* aEndParent, int32_t aEndOffset, 707 nsRange** aRange); 708 709 /** 710 * Creates a range with just the supplied node and appends that to the 711 * selection. 712 */ 713 nsresult AppendNodeToSelectionAsRange(nsIDOMNode *aNode); 714 715 /** 716 * When you are using AppendNodeToSelectionAsRange(), call this first to 717 * start a new selection. 718 */ 719 nsresult ClearSelection(); 720 721 nsresult IsPreformatted(nsIDOMNode* aNode, bool* aResult); 722 723 enum class EmptyContainers { no, yes }; 724 int32_t SplitNodeDeep(nsIContent& aNode, nsIContent& aSplitPointParent, 725 int32_t aSplitPointOffset, 726 EmptyContainers aEmptyContainers = 727 EmptyContainers::yes, 728 nsIContent** outLeftNode = nullptr, 729 nsIContent** outRightNode = nullptr); 730 EditorDOMPoint JoinNodeDeep(nsIContent& aLeftNode, 731 nsIContent& aRightNode); 732 733 nsresult GetString(const nsAString& name, nsAString& value); 734 735 void BeginUpdateViewBatch(); 736 virtual nsresult EndUpdateViewBatch(); 737 738 bool GetShouldTxnSetSelection(); 739 740 virtual nsresult HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent); 741 742 nsresult HandleInlineSpellCheck(EditAction action, 743 Selection* aSelection, 744 nsIDOMNode* previousSelectedNode, 745 int32_t previousSelectedOffset, 746 nsIDOMNode* aStartNode, 747 int32_t aStartOffset, 748 nsIDOMNode* aEndNode, 749 int32_t aEndOffset); 750 751 virtual already_AddRefed<dom::EventTarget> GetDOMEventTarget() = 0; 752 753 /** 754 * Fast non-refcounting editor root element accessor 755 */ 756 Element* GetRoot(); 757 758 /** 759 * Likewise, but gets the editor's root instead, which is different for HTML 760 * editors. 761 */ 762 virtual Element* GetEditorRoot(); 763 764 /** 765 * Likewise, but gets the text control element instead of the root for 766 * plaintext editors. 767 */ 768 Element* GetExposedRoot(); 769 770 /** 771 * Accessor methods to flags. 772 */ IsPlaintextEditor()773 bool IsPlaintextEditor() const 774 { 775 return (mFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0; 776 } 777 IsSingleLineEditor()778 bool IsSingleLineEditor() const 779 { 780 return (mFlags & nsIPlaintextEditor::eEditorSingleLineMask) != 0; 781 } 782 IsPasswordEditor()783 bool IsPasswordEditor() const 784 { 785 return (mFlags & nsIPlaintextEditor::eEditorPasswordMask) != 0; 786 } 787 IsReadonly()788 bool IsReadonly() const 789 { 790 return (mFlags & nsIPlaintextEditor::eEditorReadonlyMask) != 0; 791 } 792 IsDisabled()793 bool IsDisabled() const 794 { 795 return (mFlags & nsIPlaintextEditor::eEditorDisabledMask) != 0; 796 } 797 IsInputFiltered()798 bool IsInputFiltered() const 799 { 800 return (mFlags & nsIPlaintextEditor::eEditorFilterInputMask) != 0; 801 } 802 IsMailEditor()803 bool IsMailEditor() const 804 { 805 return (mFlags & nsIPlaintextEditor::eEditorMailMask) != 0; 806 } 807 IsWrapHackEnabled()808 bool IsWrapHackEnabled() const 809 { 810 return (mFlags & nsIPlaintextEditor::eEditorEnableWrapHackMask) != 0; 811 } 812 IsFormWidget()813 bool IsFormWidget() const 814 { 815 return (mFlags & nsIPlaintextEditor::eEditorWidgetMask) != 0; 816 } 817 NoCSS()818 bool NoCSS() const 819 { 820 return (mFlags & nsIPlaintextEditor::eEditorNoCSSMask) != 0; 821 } 822 IsInteractionAllowed()823 bool IsInteractionAllowed() const 824 { 825 return (mFlags & nsIPlaintextEditor::eEditorAllowInteraction) != 0; 826 } 827 DontEchoPassword()828 bool DontEchoPassword() const 829 { 830 return (mFlags & nsIPlaintextEditor::eEditorDontEchoPassword) != 0; 831 } 832 ShouldSkipSpellCheck()833 bool ShouldSkipSpellCheck() const 834 { 835 return (mFlags & nsIPlaintextEditor::eEditorSkipSpellCheck) != 0; 836 } 837 IsTabbable()838 bool IsTabbable() const 839 { 840 return IsSingleLineEditor() || IsPasswordEditor() || IsFormWidget() || 841 IsInteractionAllowed(); 842 } 843 HasIndependentSelection()844 bool HasIndependentSelection() const 845 { 846 return !!mSelConWeak; 847 } 848 849 /** 850 * Get the input event target. This might return null. 851 */ 852 virtual already_AddRefed<nsIContent> GetInputEventTargetContent() = 0; 853 854 /** 855 * Get the focused content, if we're focused. Returns null otherwise. 856 */ 857 virtual already_AddRefed<nsIContent> GetFocusedContent(); 858 859 /** 860 * Get the focused content for the argument of some IMEStateManager's 861 * methods. 862 */ 863 virtual already_AddRefed<nsIContent> GetFocusedContentForIME(); 864 865 /** 866 * Whether the editor is active on the DOM window. Note that when this 867 * returns true but GetFocusedContent() returns null, it means that this editor was 868 * focused when the DOM window was active. 869 */ 870 virtual bool IsActiveInDOMWindow(); 871 872 /** 873 * Whether the aEvent should be handled by this editor or not. When this 874 * returns FALSE, The aEvent shouldn't be handled on this editor, 875 * i.e., The aEvent should be handled by another inner editor or ancestor 876 * elements. 877 */ 878 virtual bool IsAcceptableInputEvent(nsIDOMEvent* aEvent); 879 880 /** 881 * FindSelectionRoot() returns a selection root of this editor when aNode 882 * gets focus. aNode must be a content node or a document node. When the 883 * target isn't a part of this editor, returns nullptr. If this is for 884 * designMode, you should set the document node to aNode except that an 885 * element in the document has focus. 886 */ 887 virtual already_AddRefed<nsIContent> FindSelectionRoot(nsINode* aNode); 888 889 /** 890 * Initializes selection and caret for the editor. If aEventTarget isn't 891 * a host of the editor, i.e., the editor doesn't get focus, this does 892 * nothing. 893 */ 894 nsresult InitializeSelection(nsIDOMEventTarget* aFocusEventTarget); 895 896 /** 897 * This method has to be called by EditorEventListener::Focus. 898 * All actions that have to be done when the editor is focused needs to be 899 * added here. 900 */ 901 void OnFocus(nsIDOMEventTarget* aFocusEventTarget); 902 903 /** 904 * Used to insert content from a data transfer into the editable area. 905 * This is called for each item in the data transfer, with the index of 906 * each item passed as aIndex. 907 */ 908 virtual nsresult InsertFromDataTransfer(dom::DataTransfer* aDataTransfer, 909 int32_t aIndex, 910 nsIDOMDocument* aSourceDoc, 911 nsIDOMNode* aDestinationNode, 912 int32_t aDestOffset, 913 bool aDoDeleteSelection) = 0; 914 915 virtual nsresult InsertFromDrop(nsIDOMEvent* aDropEvent) = 0; 916 FindUserSelectAllNode(nsIDOMNode * aNode)917 virtual already_AddRefed<nsIDOMNode> FindUserSelectAllNode(nsIDOMNode* aNode) 918 { 919 return nullptr; 920 } 921 922 /** 923 * GetIMESelectionStartOffsetIn() returns the start offset of IME selection in 924 * the aTextNode. If there is no IME selection, returns -1. 925 */ 926 int32_t GetIMESelectionStartOffsetIn(nsINode* aTextNode); 927 928 /** 929 * FindBetterInsertionPoint() tries to look for better insertion point which 930 * is typically the nearest text node and offset in it. 931 */ 932 void FindBetterInsertionPoint(nsCOMPtr<nsIDOMNode>& aNode, 933 int32_t& aOffset); 934 void FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode, 935 int32_t& aOffset); 936 937 /** 938 * HideCaret() hides caret with nsCaret::AddForceHide() or may show carent 939 * with nsCaret::RemoveForceHide(). This does NOT set visibility of 940 * nsCaret. Therefore, this is stateless. 941 */ 942 void HideCaret(bool aHide); 943 FlushFrames()944 void FlushFrames() 945 { 946 nsCOMPtr<nsIDocument> doc = GetDocument(); 947 if (doc) { 948 doc->FlushPendingNotifications(Flush_Frames); 949 } 950 } 951 952 protected: 953 enum Tristate 954 { 955 eTriUnset, 956 eTriFalse, 957 eTriTrue 958 }; 959 960 // MIME type of the doc we are editing. 961 nsCString mContentMIMEType; 962 963 nsCOMPtr<nsIInlineSpellChecker> mInlineSpellChecker; 964 965 RefPtr<nsTransactionManager> mTxnMgr; 966 // Cached root node. 967 nsCOMPtr<Element> mRootElement; 968 // Current IME text node. 969 RefPtr<Text> mIMETextNode; 970 // The form field as an event receiver. 971 nsCOMPtr<dom::EventTarget> mEventTarget; 972 nsCOMPtr<nsIDOMEventListener> mEventListener; 973 // Weak reference to the nsISelectionController. 974 nsWeakPtr mSelConWeak; 975 // Weak reference to placeholder for begin/end batch purposes. 976 nsWeakPtr mPlaceHolderTxn; 977 // Weak reference to the nsIDOMDocument. 978 nsWeakPtr mDocWeak; 979 // Name of placeholder transaction. 980 nsIAtom* mPlaceHolderName; 981 // Saved selection state for placeholder transaction batching. 982 SelectionState* mSelState; 983 nsString* mPhonetic; 984 // IME composition this is not null between compositionstart and 985 // compositionend. 986 RefPtr<TextComposition> mComposition; 987 988 // Listens to all low level actions on the doc. 989 nsTArray<OwningNonNull<nsIEditActionListener>> mActionListeners; 990 // Just notify once per high level change. 991 nsTArray<OwningNonNull<nsIEditorObserver>> mEditorObservers; 992 // Listen to overall doc state (dirty or not, just created, etc.). 993 nsTArray<OwningNonNull<nsIDocumentStateListener>> mDocStateListeners; 994 995 // Cached selection for AutoSelectionRestorer. 996 SelectionState mSavedSel; 997 // Utility class object for maintaining preserved ranges. 998 RangeUpdater mRangeUpdater; 999 1000 // Number of modifications (for undo/redo stack). 1001 uint32_t mModCount; 1002 // Behavior flags. See nsIPlaintextEditor.idl for the flags we use. 1003 uint32_t mFlags; 1004 1005 int32_t mUpdateCount; 1006 1007 // Nesting count for batching. 1008 int32_t mPlaceHolderBatch; 1009 // The current editor action. 1010 EditAction mAction; 1011 1012 // Offset in text node where IME comp string begins. 1013 uint32_t mIMETextOffset; 1014 // The Length of the composition string or commit string. If this is length 1015 // of commit string, the length is truncated by maxlength attribute. 1016 uint32_t mIMETextLength; 1017 1018 // The current direction of editor action. 1019 EDirection mDirection; 1020 // -1 = not initialized 1021 int8_t mDocDirtyState; 1022 // A Tristate value. 1023 uint8_t mSpellcheckCheckboxState; 1024 1025 // Turn off for conservative selection adjustment by transactions. 1026 bool mShouldTxnSetSelection; 1027 // Whether PreDestroy has been called. 1028 bool mDidPreDestroy; 1029 // Whether PostCreate has been called. 1030 bool mDidPostCreate; 1031 bool mDispatchInputEvent; 1032 // True while the instance is handling an edit action. 1033 bool mIsInEditAction; 1034 // Whether caret is hidden forcibly. 1035 bool mHidingCaret; 1036 1037 friend bool NSCanUnload(nsISupports* serviceMgr); 1038 friend class AutoRules; 1039 friend class AutoSelectionRestorer; 1040 friend class AutoTransactionsConserveSelection; 1041 friend class RangeUpdater; 1042 }; 1043 1044 } // namespace mozilla 1045 1046 #endif // #ifndef mozilla_EditorBase_h 1047