/* -*- 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 "nsEditor.h" #include "mozilla/DebugOnly.h" // for DebugOnly #include // for nullptr, stdout #include // for strcmp #include "ChangeAttributeTxn.h" // for ChangeAttributeTxn #include "CreateElementTxn.h" // for CreateElementTxn #include "DeleteNodeTxn.h" // for DeleteNodeTxn #include "DeleteRangeTxn.h" // for DeleteRangeTxn #include "DeleteTextTxn.h" // for DeleteTextTxn #include "EditAggregateTxn.h" // for EditAggregateTxn #include "EditTxn.h" // for EditTxn #include "IMETextTxn.h" // for IMETextTxn #include "InsertNodeTxn.h" // for InsertNodeTxn #include "InsertTextTxn.h" // for InsertTextTxn #include "JoinNodeTxn.h" // for JoinNodeTxn #include "PlaceholderTxn.h" // for PlaceholderTxn #include "SplitNodeTxn.h" // for SplitNodeTxn #include "mozFlushType.h" // for mozFlushType::Flush_Frames #include "mozInlineSpellChecker.h" // for mozInlineSpellChecker #include "mozilla/CheckedInt.h" // for CheckedInt #include "mozilla/IMEStateManager.h" // for IMEStateManager #include "mozilla/Preferences.h" // for Preferences #include "mozilla/dom/Selection.h" // for Selection, etc #include "mozilla/Services.h" // for GetObserverService #include "mozilla/TextComposition.h" // for TextComposition #include "mozilla/TextEvents.h" #include "mozilla/dom/Element.h" // for Element, nsINode::AsElement #include "mozilla/dom/Text.h" #include "mozilla/mozalloc.h" // for operator new, etc #include "nsAString.h" // for nsAString_internal::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 "nsEditorEventListener.h" // for nsEditorEventListener #include "nsEditorUtils.h" // for nsAutoRules, etc #include "nsError.h" // for NS_OK, etc #include "nsFocusManager.h" // for nsFocusManager #include "nsFrameSelection.h" // for nsFrameSelection #include "nsGkAtoms.h" // for nsGkAtoms, nsGkAtoms::dir #include "nsIAbsorbingTransaction.h" // for nsIAbsorbingTransaction #include "nsIAtom.h" // for nsIAtom #include "nsIContent.h" // for nsIContent #include "nsIDOMAttr.h" // for nsIDOMAttr #include "nsIDOMCharacterData.h" // for nsIDOMCharacterData #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 "nsIDOMHTMLElement.h" // for nsIDOMHTMLElement #include "nsIDOMKeyEvent.h" // for nsIDOMKeyEvent, etc #include "nsIDOMMozNamedAttrMap.h" // for nsIDOMMozNamedAttrMap #include "nsIDOMMouseEvent.h" // for nsIDOMMouseEvent #include "nsIDOMNode.h" // for nsIDOMNode, etc #include "nsIDOMNodeList.h" // for nsIDOMNodeList #include "nsIDOMText.h" // for nsIDOMText #include "nsIDocument.h" // for nsIDocument #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 nsAFlatString #include "nsStyleConsts.h" // for NS_STYLE_DIRECTION_RTL, etc #include "nsStyleContext.h" // for nsStyleContext #include "nsStyleSheetTxns.h" // for AddStyleSheetTxn, etc #include "nsStyleStruct.h" // for nsStyleDisplay, nsStyleText, etc #include "nsStyleStructFwd.h" // for nsIFrame::StyleUIReset, etc #include "nsTextEditUtils.h" // for nsTextEditUtils #include "nsTextNode.h" // for nsTextNode #include "nsThreadUtils.h" // for nsRunnable #include "nsTransactionManager.h" // for nsTransactionManager #include "prtime.h" // for PR_Now class nsIOutputStream; class nsIParserService; class nsITransferable; #ifdef DEBUG #include "nsIDOMHTMLDocument.h" // for nsIDOMHTMLDocument #endif using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::widget; // Defined in nsEditorRegistration.cpp extern nsIParserService *sParserService; //--------------------------------------------------------------------------- // // nsEditor: base editor class implementation // //--------------------------------------------------------------------------- nsEditor::nsEditor() : mPlaceHolderName(nullptr) , mSelState(nullptr) , mPhonetic(nullptr) , mModCount(0) , mFlags(0) , mUpdateCount(0) , mPlaceHolderBatch(0) , mAction(EditAction::none) , mIMETextOffset(0) , mIMETextLength(0) , mDirection(eNone) , mDocDirtyState(-1) , mSpellcheckCheckboxState(eTriUnset) , mShouldTxnSetSelection(true) , mDidPreDestroy(false) , mDidPostCreate(false) , mDispatchInputEvent(true) , mIsInEditAction(false) , mHidingCaret(false) , mSpellCheckerDictionaryUpdated(true) { } nsEditor::~nsEditor() { NS_ASSERTION(!mDocWeak || 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); mTxnMgr = nullptr; delete mPhonetic; } NS_IMPL_CYCLE_COLLECTION_CLASS(nsEditor) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsEditor) NS_IMPL_CYCLE_COLLECTION_UNLINK(mRootElement) NS_IMPL_CYCLE_COLLECTION_UNLINK(mInlineSpellChecker) NS_IMPL_CYCLE_COLLECTION_UNLINK(mTxnMgr) NS_IMPL_CYCLE_COLLECTION_UNLINK(mIMETextNode) 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) { nsEditorEventListener* listener = reinterpret_cast(tmp->mEventListener.get()); listener->Disconnect(); tmp->mEventListener = nullptr; } NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsEditor) nsIDocument* currentDoc = tmp->mRootElement ? tmp->mRootElement->GetCurrentDoc() : nullptr; if (currentDoc && nsCCUncollectableMarker::InGeneration(cb, currentDoc->GetMarkedCCGeneration())) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRootElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInlineSpellChecker) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTxnMgr) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIMETextNode) 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_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEditor) NS_INTERFACE_MAP_ENTRY(nsIPhonetic) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsIEditorIMESupport) NS_INTERFACE_MAP_ENTRY(nsIEditor) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(nsEditor) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsEditor) NS_IMETHODIMP nsEditor::Init(nsIDOMDocument *aDoc, nsIContent *aRoot, nsISelectionController *aSelCon, uint32_t aFlags, const nsAString& aValue) { NS_PRECONDITION(aDoc, "bad arg"); if (!aDoc) return NS_ERROR_NULL_POINTER; // First only set flags, but other stuff shouldn't be initialized now. // Don't move this call after initializing mDocWeak. // 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"); mDocWeak = do_GetWeakReference(aDoc); // weak reference to doc // 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 selCon; if (aSelCon) { mSelConWeak = do_GetWeakReference(aSelCon); // weak reference to selectioncontroller selCon = aSelCon; } else { nsCOMPtr presShell = GetPresShell(); selCon = do_QueryInterface(presShell); } NS_ASSERTION(selCon, "Selection controller should be available at this point"); //set up root element if we are passed one. if (aRoot) mRootElement = do_QueryInterface(aRoot); mUpdateCount=0; // If this is an editor for or