/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/EditorBase.h" #include "mozilla/DebugOnly.h" // for DebugOnly #include "mozilla/Encoding.h" // for Encoding #include // for nullptr, stdout #include // for strcmp #include "ChangeAttributeTransaction.h" // for ChangeAttributeTransaction #include "CompositionTransaction.h" // for CompositionTransaction #include "CreateElementTransaction.h" // for CreateElementTransaction #include "DeleteNodeTransaction.h" // for DeleteNodeTransaction #include "DeleteRangeTransaction.h" // for DeleteRangeTransaction #include "DeleteTextTransaction.h" // for DeleteTextTransaction #include "EditAggregateTransaction.h" // for EditAggregateTransaction #include "EditorEventListener.h" // for EditorEventListener #include "HTMLEditRules.h" // for HTMLEditRules #include "InsertNodeTransaction.h" // for InsertNodeTransaction #include "InsertTextTransaction.h" // for InsertTextTransaction #include "JoinNodeTransaction.h" // for JoinNodeTransaction #include "PlaceholderTransaction.h" // for PlaceholderTransaction #include "SplitNodeTransaction.h" // for SplitNodeTransaction #include "StyleSheetTransactions.h" // for AddStyleSheetTransaction, etc. #include "TextEditUtils.h" // for TextEditUtils #include "mozilla/CheckedInt.h" // for CheckedInt #include "mozilla/ComputedStyle.h" // for ComputedStyle #include "mozilla/EditAction.h" // for EditAction #include "mozilla/EditorDOMPoint.h" // for EditorDOMPoint #include "mozilla/EditorSpellCheck.h" // for EditorSpellCheck #include "mozilla/EditorUtils.h" // for AutoRules, etc. #include "mozilla/EditTransactionBase.h" // for EditTransactionBase #include "mozilla/FlushType.h" // for FlushType::Frames #include "mozilla/IMEContentObserver.h" // for IMEContentObserver #include "mozilla/IMEStateManager.h" // for IMEStateManager #include "mozilla/mozalloc.h" // for operator new, etc. #include "mozilla/mozInlineSpellChecker.h" // for mozInlineSpellChecker #include "mozilla/mozSpellChecker.h" // for mozSpellChecker #include "mozilla/Preferences.h" // for Preferences #include "mozilla/RangeBoundary.h" // for RawRangeBoundary, RangeBoundary #include "mozilla/dom/Selection.h" // for Selection, etc. #include "mozilla/Services.h" // for GetObserverService #include "mozilla/TextComposition.h" // for TextComposition #include "mozilla/TextInputListener.h" // for TextInputListener #include "mozilla/TextServicesDocument.h" // for TextServicesDocument #include "mozilla/TextEvents.h" #include "mozilla/TransactionManager.h" // for TransactionManager #include "mozilla/dom/CharacterData.h" // for CharacterData #include "mozilla/dom/Element.h" // for Element, nsINode::AsElement #include "mozilla/dom/HTMLBodyElement.h" #include "mozilla/dom/Text.h" #include "mozilla/dom/Event.h" #include "nsAString.h" // for nsAString::Length, etc. #include "nsCCUncollectableMarker.h" // for nsCCUncollectableMarker #include "nsCaret.h" // for nsCaret #include "nsCaseTreatment.h" #include "nsCharTraits.h" // for NS_IS_HIGH_SURROGATE, etc. #include "nsComponentManagerUtils.h" // for do_CreateInstance #include "nsComputedDOMStyle.h" // for nsComputedDOMStyle #include "nsContentUtils.h" // for nsContentUtils #include "nsDOMString.h" // for DOMStringIsNull #include "nsDebug.h" // for NS_ENSURE_TRUE, etc. #include "nsError.h" // for NS_OK, etc. #include "nsFocusManager.h" // for nsFocusManager #include "nsFrameSelection.h" // for nsFrameSelection #include "nsGenericHTMLElement.h" // for nsGenericHTMLElement #include "nsGkAtoms.h" // for nsGkAtoms, nsGkAtoms::dir #include "nsIAbsorbingTransaction.h" // for nsIAbsorbingTransaction #include "nsAtom.h" // for nsAtom #include "nsIContent.h" // for nsIContent #include "nsIDOMDocument.h" // for nsIDOMDocument #include "nsIDOMElement.h" // for nsIDOMElement #include "nsIDOMEvent.h" // for nsIDOMEvent #include "nsIDOMEventListener.h" // for nsIDOMEventListener #include "nsIDOMEventTarget.h" // for nsIDOMEventTarget #include "nsIDOMNode.h" // for nsIDOMNode, etc. #include "nsIDocumentStateListener.h" // for nsIDocumentStateListener #include "nsIEditActionListener.h" // for nsIEditActionListener #include "nsIEditorObserver.h" // for nsIEditorObserver #include "nsIEditorSpellCheck.h" // for nsIEditorSpellCheck #include "nsIFrame.h" // for nsIFrame #include "nsIHTMLDocument.h" // for nsIHTMLDocument #include "nsIInlineSpellChecker.h" // for nsIInlineSpellChecker, etc. #include "nsNameSpaceManager.h" // for kNameSpaceID_None, etc. #include "nsINode.h" // for nsINode, etc. #include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc. #include "nsIPresShell.h" // for nsIPresShell #include "nsISelectionController.h" // for nsISelectionController, etc. #include "nsISelectionDisplay.h" // for nsISelectionDisplay, etc. #include "nsISupportsBase.h" // for nsISupports #include "nsISupportsUtils.h" // for NS_ADDREF, NS_IF_ADDREF #include "nsITransaction.h" // for nsITransaction #include "nsITransactionManager.h" #include "nsIWeakReference.h" // for nsISupportsWeakReference #include "nsIWidget.h" // for nsIWidget, IMEState, etc. #include "nsPIDOMWindow.h" // for nsPIDOMWindow #include "nsPresContext.h" // for nsPresContext #include "nsRange.h" // for nsRange #include "nsReadableUtils.h" // for EmptyString, ToNewCString #include "nsString.h" // for nsAutoString, nsString, etc. #include "nsStringFwd.h" // for nsString #include "nsStyleConsts.h" // for NS_STYLE_DIRECTION_RTL, etc. #include "nsStyleStruct.h" // for nsStyleDisplay, nsStyleText, etc. #include "nsStyleStructFwd.h" // for nsIFrame::StyleUIReset, etc. #include "nsTextNode.h" // for nsTextNode #include "nsThreadUtils.h" // for nsRunnable #include "prtime.h" // for PR_Now class nsIOutputStream; class nsITransferable; namespace mozilla { using namespace dom; using namespace widget; /***************************************************************************** * mozilla::EditorBase *****************************************************************************/ template already_AddRefed EditorBase::CreateNode(nsAtom* aTag, const EditorDOMPoint& aPointToInsert); template already_AddRefed EditorBase::CreateNode(nsAtom* aTag, const EditorRawDOMPoint& aPointToInsert); template nsresult EditorBase::InsertNode(nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert); template nsresult EditorBase::InsertNode(nsIContent& aContentToInsert, const EditorRawDOMPoint& aPointToInsert); template already_AddRefed EditorBase::SplitNode(const EditorDOMPoint& aStartOfRightNode, ErrorResult& aError); template already_AddRefed EditorBase::SplitNode(const EditorRawDOMPoint& aStartOfRightNode, ErrorResult& aError); template SplitNodeResult EditorBase::SplitNodeDeep(nsIContent& aMostAncestorToSplit, const EditorDOMPoint& aStartOfDeepestRightNode, SplitAtEdges aSplitAtEdges); template SplitNodeResult EditorBase::SplitNodeDeep(nsIContent& aMostAncestorToSplit, const EditorRawDOMPoint& aStartOfDeepestRightNode, SplitAtEdges aSplitAtEdges); EditorBase::EditorBase() : mPlaceholderName(nullptr) , mModCount(0) , mFlags(0) , mUpdateCount(0) , mPlaceholderBatch(0) , mAction(EditAction::none) , mDirection(eNone) , mDocDirtyState(-1) , mSpellcheckCheckboxState(eTriUnset) , mShouldTxnSetSelection(true) , mDidPreDestroy(false) , mDidPostCreate(false) , mDispatchInputEvent(true) , mIsInEditAction(false) , mHidingCaret(false) , mSpellCheckerDictionaryUpdated(true) , mIsHTMLEditorClass(false) { } EditorBase::~EditorBase() { MOZ_ASSERT(!IsInitialized() || mDidPreDestroy, "Why PreDestroy hasn't been called?"); if (mComposition) { mComposition->OnEditorDestroyed(); mComposition = nullptr; } // If this editor is still hiding the caret, we need to restore it. HideCaret(false); mTransactionManager = nullptr; } NS_IMPL_CYCLE_COLLECTION_CLASS(EditorBase) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(EditorBase) NS_IMPL_CYCLE_COLLECTION_UNLINK(mRootElement) NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectionController) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK(mIMEContentObserver) NS_IMPL_CYCLE_COLLECTION_UNLINK(mInlineSpellChecker) NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextServicesDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextInputListener) NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransactionManager) NS_IMPL_CYCLE_COLLECTION_UNLINK(mActionListeners) NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditorObservers) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocStateListeners) NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventTarget) if (tmp->mEventListener) { tmp->mEventListener->Disconnect(); tmp->mEventListener = nullptr; } NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlaceholderTransaction) NS_IMPL_CYCLE_COLLECTION_UNLINK(mSavedSel); NS_IMPL_CYCLE_COLLECTION_UNLINK(mRangeUpdater); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(EditorBase) nsIDocument* currentDoc = tmp->mRootElement ? tmp->mRootElement->GetUncomposedDoc() : nullptr; if (currentDoc && nsCCUncollectableMarker::InGeneration(cb, currentDoc->GetMarkedCCGeneration())) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRootElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectionController) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIMEContentObserver) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInlineSpellChecker) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextServicesDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextInputListener) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransactionManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mActionListeners) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditorObservers) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocStateListeners) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventTarget) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventListener) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlaceholderTransaction) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSavedSel); NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRangeUpdater); NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EditorBase) NS_INTERFACE_MAP_ENTRY(nsISelectionListener) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsIEditor) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(EditorBase) NS_IMPL_CYCLE_COLLECTING_RELEASE(EditorBase) nsresult EditorBase::Init(nsIDocument& aDocument, Element* aRoot, nsISelectionController* aSelectionController, uint32_t aFlags, const nsAString& aValue) { MOZ_ASSERT(mAction == EditAction::none, "Initializing during an edit action is an error"); // First only set flags, but other stuff shouldn't be initialized now. // Don't move this call after initializing mDocument. // SetFlags() can check whether it's called during initialization or not by // them. Note that SetFlags() will be called by PostCreate(). #ifdef DEBUG nsresult rv = #endif SetFlags(aFlags); NS_ASSERTION(NS_SUCCEEDED(rv), "SetFlags() failed"); mDocument = &aDocument; // HTML editors currently don't have their own selection controller, // so they'll pass null as aSelCon, and we'll get the selection controller // off of the presshell. nsCOMPtr selectionController; if (aSelectionController) { mSelectionController = aSelectionController; selectionController = aSelectionController; } else { nsCOMPtr presShell = GetPresShell(); selectionController = do_QueryInterface(presShell); } MOZ_ASSERT(selectionController, "Selection controller should be available at this point"); //set up root element if we are passed one. if (aRoot) { mRootElement = aRoot; } mUpdateCount=0; // If this is an editor for or