diff options
Diffstat (limited to 'editor')
24 files changed, 770 insertions, 610 deletions
diff --git a/editor/libeditor/EditorBase.cpp b/editor/libeditor/EditorBase.cpp index f7988cd1a..3f419a74e 100644 --- a/editor/libeditor/EditorBase.cpp +++ b/editor/libeditor/EditorBase.cpp @@ -37,6 +37,7 @@ #include "mozilla/TextComposition.h" // for TextComposition #include "mozilla/TextEvents.h" #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 "mozilla/mozalloc.h" // for operator new, etc. @@ -71,7 +72,6 @@ #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 @@ -107,16 +107,12 @@ #include "prtime.h" // for PR_Now class nsIOutputStream; -class nsIParserService; class nsITransferable; #ifdef DEBUG #include "nsIDOMHTMLDocument.h" // for nsIDOMHTMLDocument #endif -// Defined in nsEditorRegistration.cpp -extern nsIParserService *sParserService; - namespace mozilla { using namespace dom; @@ -127,13 +123,13 @@ using namespace widget; *****************************************************************************/ EditorBase::EditorBase() - : mPlaceHolderName(nullptr) + : mPlaceholderName(nullptr) , mSelState(nullptr) , mPhonetic(nullptr) , mModCount(0) , mFlags(0) , mUpdateCount(0) - , mPlaceHolderBatch(0) + , mPlaceholderBatch(0) , mAction(EditAction::none) , mIMETextOffset(0) , mIMETextLength(0) @@ -151,7 +147,8 @@ EditorBase::EditorBase() EditorBase::~EditorBase() { - NS_ASSERTION(!mDocWeak || mDidPreDestroy, "Why PreDestroy hasn't been called?"); + MOZ_ASSERT(!IsInitialized() || mDidPreDestroy, + "Why PreDestroy hasn't been called?"); if (mComposition) { mComposition->OnEditorDestroyed(); @@ -220,20 +217,21 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(EditorBase) NS_IMETHODIMP -EditorBase::Init(nsIDOMDocument* aDoc, +EditorBase::Init(nsIDOMDocument* aDOMDocument, nsIContent* aRoot, - nsISelectionController* aSelCon, + nsISelectionController* aSelectionController, uint32_t aFlags, const nsAString& aValue) { MOZ_ASSERT(mAction == EditAction::none, "Initializing during an edit action is an error"); - MOZ_ASSERT(aDoc); - if (!aDoc) + MOZ_ASSERT(aDOMDocument); + if (!aDOMDocument) { 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. + // Don't move this call after initializing mDocumentWeak. // SetFlags() can check whether it's called during initialization or not by // them. Note that SetFlags() will be called by PostCreate(). #ifdef DEBUG @@ -242,19 +240,21 @@ EditorBase::Init(nsIDOMDocument* aDoc, SetFlags(aFlags); NS_ASSERTION(NS_SUCCEEDED(rv), "SetFlags() failed"); - mDocWeak = do_GetWeakReference(aDoc); // weak reference to doc + nsCOMPtr<nsIDocument> document = do_QueryInterface(aDOMDocument); + mDocumentWeak = document.get(); // 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<nsISelectionController> selCon; - if (aSelCon) { - mSelConWeak = do_GetWeakReference(aSelCon); // weak reference to selectioncontroller - selCon = aSelCon; + nsCOMPtr<nsISelectionController> selectionController; + if (aSelectionController) { + mSelectionControllerWeak = aSelectionController; + selectionController = aSelectionController; } else { nsCOMPtr<nsIPresShell> presShell = GetPresShell(); - selCon = do_QueryInterface(presShell); + selectionController = do_QueryInterface(presShell); } - NS_ASSERTION(selCon, "Selection controller should be available at this point"); + MOZ_ASSERT(selectionController, + "Selection controller should be available at this point"); //set up root element if we are passed one. if (aRoot) @@ -271,13 +271,14 @@ EditorBase::Init(nsIDOMDocument* aDoc, mIMETextNode = nullptr; } - /* Show the caret */ - selCon->SetCaretReadOnly(false); - selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); + // Show the caret. + selectionController->SetCaretReadOnly(false); + selectionController->SetDisplaySelection( + nsISelectionController::SELECTION_ON); + // Show all the selection reflected to user. + selectionController->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL); - selCon->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL);//we want to see all the selection reflected to user - - NS_POSTCONDITION(mDocWeak, "bad state"); + MOZ_ASSERT(IsInitialized()); // Make sure that the editor will be destroyed properly mDidPreDestroy = false; @@ -356,8 +357,9 @@ EditorBase::CreateEventListeners() nsresult EditorBase::InstallEventListeners() { - NS_ENSURE_TRUE(mDocWeak && mEventListener, - NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!IsInitialized()) || NS_WARN_IF(!mEventListener)) { + return NS_ERROR_NOT_INITIALIZED; + } // Initialize the event target. nsCOMPtr<nsIContent> rootContent = GetRoot(); @@ -378,7 +380,7 @@ EditorBase::InstallEventListeners() void EditorBase::RemoveEventListeners() { - if (!mDocWeak || !mEventListener) { + if (!IsInitialized() || !mEventListener) { return; } reinterpret_cast<EditorEventListener*>(mEventListener.get())->Disconnect(); @@ -501,7 +503,7 @@ EditorBase::SetFlags(uint32_t aFlags) bool spellcheckerWasEnabled = CanEnableSpellCheck(); mFlags = aFlags; - if (!mDocWeak) { + if (!IsInitialized()) { // If we're initializing, we shouldn't do anything now. // SetFlags() will be called by PostCreate(), // we should synchronize some stuff for the flags at that time. @@ -567,17 +569,15 @@ EditorBase::GetIsDocumentEditable(bool* aIsDocumentEditable) already_AddRefed<nsIDocument> EditorBase::GetDocument() { - NS_PRECONDITION(mDocWeak, "bad state, mDocWeak weak pointer not initialized"); - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - return doc.forget(); + nsCOMPtr<nsIDocument> document = mDocumentWeak.get(); + return document.forget(); } already_AddRefed<nsIDOMDocument> EditorBase::GetDOMDocument() { - NS_PRECONDITION(mDocWeak, "bad state, mDocWeak weak pointer not initialized"); - nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak); - return doc.forget(); + nsCOMPtr<nsIDOMDocument> domDocument = do_QueryInterface(mDocumentWeak); + return domDocument.forget(); } NS_IMETHODIMP @@ -590,11 +590,12 @@ EditorBase::GetDocument(nsIDOMDocument** aDoc) already_AddRefed<nsIPresShell> EditorBase::GetPresShell() { - NS_PRECONDITION(mDocWeak, "bad state, null mDocWeak"); - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, nullptr); - nsCOMPtr<nsIPresShell> ps = doc->GetShell(); - return ps.forget(); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return nullptr; + } + nsCOMPtr<nsIPresShell> presShell = document->GetShell(); + return presShell.forget(); } already_AddRefed<nsIWidget> @@ -629,20 +630,27 @@ EditorBase::GetSelectionController(nsISelectionController** aSel) { NS_ENSURE_TRUE(aSel, NS_ERROR_NULL_POINTER); *aSel = nullptr; // init out param - nsCOMPtr<nsISelectionController> selCon; - if (mSelConWeak) { - selCon = do_QueryReferent(mSelConWeak); - } else { - nsCOMPtr<nsIPresShell> presShell = GetPresShell(); - selCon = do_QueryInterface(presShell); - } - if (!selCon) { + nsCOMPtr<nsISelectionController> selCon = GetSelectionController(); + if (NS_WARN_IF(!selCon)) { return NS_ERROR_NOT_INITIALIZED; } - NS_ADDREF(*aSel = selCon); + selCon.forget(aSel); return NS_OK; } +already_AddRefed<nsISelectionController> +EditorBase::GetSelectionController() +{ + nsCOMPtr<nsISelectionController> selectionController; + if (mSelectionControllerWeak) { + selectionController = mSelectionControllerWeak.get(); + } else { + nsCOMPtr<nsIPresShell> presShell = GetPresShell(); + selectionController = do_QueryInterface(presShell); + } + return selectionController.forget(); +} + NS_IMETHODIMP EditorBase::DeleteSelection(EDirection aAction, EStripWrappers aStripWrappers) @@ -663,8 +671,7 @@ EditorBase::GetSelection(SelectionType aSelectionType, { NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER); *aSelection = nullptr; - nsCOMPtr<nsISelectionController> selcon; - GetSelectionController(getter_AddRefs(selcon)); + nsCOMPtr<nsISelectionController> selcon = GetSelectionController(); if (!selcon) { return NS_ERROR_NOT_INITIALIZED; } @@ -686,32 +693,29 @@ EditorBase::GetSelection(SelectionType aSelectionType) NS_IMETHODIMP EditorBase::DoTransaction(nsITransaction* aTxn) { - if (mPlaceHolderBatch && !mPlaceHolderTxn) { - nsCOMPtr<nsIAbsorbingTransaction> placeholderTransaction = - new PlaceholderTransaction(); + if (mPlaceholderBatch && !mPlaceholderTransactionWeak) { + RefPtr<PlaceholderTransaction> placeholderTransaction = + new PlaceholderTransaction(*this, mPlaceholderName, Move(mSelState)); // Save off weak reference to placeholder transaction - mPlaceHolderTxn = do_GetWeakReference(placeholderTransaction); - placeholderTransaction->Init(mPlaceHolderName, mSelState, this); - // placeholder txn took ownership of this pointer - mSelState = nullptr; - - // QI to an nsITransaction since that's what DoTransaction() expects - nsCOMPtr<nsITransaction> transaction = - do_QueryInterface(placeholderTransaction); + mPlaceholderTransactionWeak = placeholderTransaction; + // We will recurse, but will not hit this case in the nested call - DoTransaction(transaction); + DoTransaction(placeholderTransaction); if (mTxnMgr) { - nsCOMPtr<nsITransaction> topTxn = mTxnMgr->PeekUndoStack(); - if (topTxn) { - placeholderTransaction = do_QueryInterface(topTxn); - if (placeholderTransaction) { + nsCOMPtr<nsITransaction> topTransaction = mTxnMgr->PeekUndoStack(); + nsCOMPtr<nsIAbsorbingTransaction> topAbsorbingTransaction = + do_QueryInterface(topTransaction); + if (topAbsorbingTransaction) { + RefPtr<PlaceholderTransaction> topPlaceholderTransaction = + topAbsorbingTransaction->AsPlaceholderTransaction(); + if (topPlaceholderTransaction) { // there is a placeholder transaction on top of the undo stack. It // is either the one we just created, or an earlier one that we are // now merging into. From here on out remember this placeholder // instead of the one we just created. - mPlaceHolderTxn = do_GetWeakReference(placeholderTransaction); + mPlaceholderTransactionWeak = topPlaceholderTransaction; } } } @@ -935,28 +939,28 @@ EditorBase::EndTransaction() NS_IMETHODIMP EditorBase::BeginPlaceHolderTransaction(nsIAtom* aName) { - NS_PRECONDITION(mPlaceHolderBatch >= 0, "negative placeholder batch count!"); - if (!mPlaceHolderBatch) { + MOZ_ASSERT(mPlaceholderBatch >= 0, "negative placeholder batch count!"); + if (!mPlaceholderBatch) { NotifyEditorObservers(eNotifyEditorObserversOfBefore); // time to turn on the batch BeginUpdateViewBatch(); - mPlaceHolderTxn = nullptr; - mPlaceHolderName = aName; + mPlaceholderTransactionWeak = nullptr; + mPlaceholderName = aName; RefPtr<Selection> selection = GetSelection(); if (selection) { - mSelState = new SelectionState(); + mSelState = MakeUnique<SelectionState>(); mSelState->SaveSelection(selection); // Composition transaction can modify multiple nodes and it merges text // node for ime into single text node. // So if current selection is into IME text node, it might be failed // to restore selection by UndoTransaction. // So we need update selection by range updater. - if (mPlaceHolderName == nsGkAtoms::IMETxnName) { + if (mPlaceholderName == nsGkAtoms::IMETxnName) { mRangeUpdater.RegisterSelectionState(*mSelState); } } } - mPlaceHolderBatch++; + mPlaceholderBatch++; return NS_OK; } @@ -964,8 +968,9 @@ EditorBase::BeginPlaceHolderTransaction(nsIAtom* aName) NS_IMETHODIMP EditorBase::EndPlaceHolderTransaction() { - NS_PRECONDITION(mPlaceHolderBatch > 0, "zero or negative placeholder batch count when ending batch!"); - if (mPlaceHolderBatch == 1) { + MOZ_ASSERT(mPlaceholderBatch > 0, + "zero or negative placeholder batch count when ending batch!"); + if (mPlaceholderBatch == 1) { RefPtr<Selection> selection = GetSelection(); // By making the assumption that no reflow happens during the calls @@ -1005,22 +1010,16 @@ EditorBase::EndPlaceHolderTransaction() if (mSelState) { // we saved the selection state, but never got to hand it to placeholder // (else we ould have nulled out this pointer), so destroy it to prevent leaks. - if (mPlaceHolderName == nsGkAtoms::IMETxnName) { + if (mPlaceholderName == nsGkAtoms::IMETxnName) { mRangeUpdater.DropSelectionState(*mSelState); } - delete mSelState; mSelState = nullptr; } // We might have never made a placeholder if no action took place. - if (mPlaceHolderTxn) { - nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryReferent(mPlaceHolderTxn); - if (plcTxn) { - plcTxn->EndPlaceHolderBatch(); - } else { - // in the future we will check to make sure undo is off here, - // since that is the only known case where the placeholdertxn would disappear on us. - // For now just removing the assert. - } + if (mPlaceholderTransactionWeak) { + RefPtr<PlaceholderTransaction> placeholderTransaction = + mPlaceholderTransactionWeak.get(); + placeholderTransaction->EndPlaceHolderBatch(); // notify editor observers of action but if composing, it's done by // compositionchange event handler. if (!mComposition) { @@ -1030,7 +1029,7 @@ EditorBase::EndPlaceHolderTransaction() NotifyEditorObservers(eNotifyEditorObserversOfCancel); } } - mPlaceHolderBatch--; + mPlaceholderBatch--; return NS_OK; } @@ -1067,7 +1066,8 @@ EditorBase::GetDocumentIsEmpty(bool* aDocumentIsEmpty) NS_IMETHODIMP EditorBase::SelectAll() { - if (!mDocWeak) { + // XXX Why doesn't this check if the document is alive? + if (!IsInitialized()) { return NS_ERROR_NOT_INITIALIZED; } ForceCompositionEnd(); @@ -1080,7 +1080,8 @@ EditorBase::SelectAll() NS_IMETHODIMP EditorBase::BeginningOfDocument() { - if (!mDocWeak) { + // XXX Why doesn't this check if the document is alive? + if (!IsInitialized()) { return NS_ERROR_NOT_INITIALIZED; } @@ -1117,7 +1118,10 @@ EditorBase::BeginningOfDocument() NS_IMETHODIMP EditorBase::EndOfDocument() { - NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); + // XXX Why doesn't this check if the document is alive? + if (NS_WARN_IF(!IsInitialized())) { + return NS_ERROR_NOT_INITIALIZED; + } // get selection RefPtr<Selection> selection = GetSelection(); @@ -1152,20 +1156,22 @@ EditorBase::GetDocumentModified(bool* outDocModified) NS_IMETHODIMP EditorBase::GetDocumentCharacterSet(nsACString& characterSet) { - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED); - - characterSet = doc->GetDocumentCharacterSet(); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return NS_ERROR_UNEXPECTED; + } + characterSet = document->GetDocumentCharacterSet(); return NS_OK; } NS_IMETHODIMP EditorBase::SetDocumentCharacterSet(const nsACString& characterSet) { - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED); - - doc->SetDocumentCharacterSet(characterSet); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return NS_ERROR_UNEXPECTED; + } + document->SetDocumentCharacterSet(characterSet); return NS_OK; } @@ -1385,9 +1391,12 @@ EditorBase::CreateNode(nsIAtom* aTag, AutoRules beginRulesSniffing(this, EditAction::createNode, nsIEditor::eNext); - for (auto& listener : mActionListeners) { - listener->WillCreateNode(nsDependentAtomString(aTag), - GetAsDOMNode(aParent), aPosition); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->WillCreateNode(nsDependentAtomString(aTag), + GetAsDOMNode(aParent), aPosition); + } } nsCOMPtr<Element> ret; @@ -1402,9 +1411,12 @@ EditorBase::CreateNode(nsIAtom* aTag, mRangeUpdater.SelAdjCreateNode(aParent, aPosition); - for (auto& listener : mActionListeners) { - listener->DidCreateNode(nsDependentAtomString(aTag), GetAsDOMNode(ret), - GetAsDOMNode(aParent), aPosition, rv); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->DidCreateNode(nsDependentAtomString(aTag), GetAsDOMNode(ret), + GetAsDOMNode(aParent), aPosition, rv); + } } return ret.forget(); @@ -1429,9 +1441,12 @@ EditorBase::InsertNode(nsIContent& aNode, { AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext); - for (auto& listener : mActionListeners) { - listener->WillInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(), - aPosition); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->WillInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(), + aPosition); + } } RefPtr<InsertNodeTransaction> transaction = @@ -1440,9 +1455,12 @@ EditorBase::InsertNode(nsIContent& aNode, mRangeUpdater.SelAdjInsertNode(aParent.AsDOMNode(), aPosition); - for (auto& listener : mActionListeners) { - listener->DidInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(), aPosition, - rv); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->DidInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(), aPosition, + rv); + } } return rv; @@ -1468,8 +1486,11 @@ EditorBase::SplitNode(nsIContent& aNode, { AutoRules beginRulesSniffing(this, EditAction::splitNode, nsIEditor::eNext); - for (auto& listener : mActionListeners) { - listener->WillSplitNode(aNode.AsDOMNode(), aOffset); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->WillSplitNode(aNode.AsDOMNode(), aOffset); + } } RefPtr<SplitNodeTransaction> transaction = @@ -1482,9 +1503,12 @@ EditorBase::SplitNode(nsIContent& aNode, mRangeUpdater.SelAdjSplitNode(aNode, aOffset, newNode); nsresult rv = aResult.StealNSResult(); - for (auto& listener : mActionListeners) { - listener->DidSplitNode(aNode.AsDOMNode(), aOffset, GetAsDOMNode(newNode), - rv); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->DidSplitNode(aNode.AsDOMNode(), aOffset, GetAsDOMNode(newNode), + rv); + } } // Note: result might be a success code, so we can't use Throw() to // set it on aResult. @@ -1520,9 +1544,12 @@ EditorBase::JoinNodes(nsINode& aLeftNode, // Find the number of children of the lefthand node uint32_t oldLeftNodeLen = aLeftNode.Length(); - for (auto& listener : mActionListeners) { - listener->WillJoinNodes(aLeftNode.AsDOMNode(), aRightNode.AsDOMNode(), - parent->AsDOMNode()); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->WillJoinNodes(aLeftNode.AsDOMNode(), aRightNode.AsDOMNode(), + parent->AsDOMNode()); + } } nsresult rv = NS_OK; @@ -1535,9 +1562,12 @@ EditorBase::JoinNodes(nsINode& aLeftNode, mRangeUpdater.SelAdjJoinNodes(aLeftNode, aRightNode, *parent, offset, (int32_t)oldLeftNodeLen); - for (auto& listener : mActionListeners) { - listener->DidJoinNodes(aLeftNode.AsDOMNode(), aRightNode.AsDOMNode(), - parent->AsDOMNode(), rv); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->DidJoinNodes(aLeftNode.AsDOMNode(), aRightNode.AsDOMNode(), + parent->AsDOMNode(), rv); + } } return rv; @@ -1558,8 +1588,11 @@ EditorBase::DeleteNode(nsINode* aNode) nsIEditor::ePrevious); // save node location for selection updating code. - for (auto& listener : mActionListeners) { - listener->WillDeleteNode(aNode->AsDOMNode()); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->WillDeleteNode(aNode->AsDOMNode()); + } } RefPtr<DeleteNodeTransaction> transaction; @@ -1568,8 +1601,11 @@ EditorBase::DeleteNode(nsINode* aNode) rv = DoTransaction(transaction); } - for (auto& listener : mActionListeners) { - listener->DidDeleteNode(aNode->AsDOMNode(), rv); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->DidDeleteNode(aNode->AsDOMNode(), rv); + } } NS_ENSURE_SUCCESS(rv, rv); @@ -1844,7 +1880,7 @@ void EditorBase::NotifyEditorObservers(NotificationForEditorObservers aNotification) { // Copy the observers since EditAction()s can modify mEditorObservers. - nsTArray<mozilla::OwningNonNull<nsIEditorObserver>> observers(mEditorObservers); + AutoEditorObserverArray observers(mEditorObservers); switch (aNotification) { case eNotifyEditorObserversOfEnd: mIsInEditAction = false; @@ -1976,12 +2012,17 @@ NS_IMETHODIMP EditorBase::DebugDumpContent() { #ifdef DEBUG - nsCOMPtr<nsIDOMHTMLDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED); - - nsCOMPtr<nsIDOMHTMLElement>bodyElem; - doc->GetBody(getter_AddRefs(bodyElem)); - nsCOMPtr<nsIContent> content = do_QueryInterface(bodyElem); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return NS_ERROR_NOT_INITIALIZED; + } + nsCOMPtr<nsIDOMHTMLDocument> domHTMLDocument = do_QueryInterface(document); + if (NS_WARN_IF(!domHTMLDocument)) { + return NS_ERROR_NOT_INITIALIZED; + } + nsCOMPtr<nsIDOMHTMLElement> bodyElement; + domHTMLDocument->GetBody(getter_AddRefs(bodyElement)); + nsCOMPtr<nsIContent> content = do_QueryInterface(bodyElement); if (content) { content->List(); } @@ -2295,18 +2336,20 @@ EditorBase::CloneAttributes(Element* aDest, NS_IMETHODIMP EditorBase::ScrollSelectionIntoView(bool aScrollToAnchor) { - nsCOMPtr<nsISelectionController> selCon; - if (NS_SUCCEEDED(GetSelectionController(getter_AddRefs(selCon))) && selCon) { - int16_t region = nsISelectionController::SELECTION_FOCUS_REGION; - - if (aScrollToAnchor) { - region = nsISelectionController::SELECTION_ANCHOR_REGION; - } - - selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, - region, nsISelectionController::SCROLL_OVERFLOW_HIDDEN); + nsCOMPtr<nsISelectionController> selectionController = + GetSelectionController(); + if (!selectionController) { + return NS_OK; } + int16_t region = nsISelectionController::SELECTION_FOCUS_REGION; + if (aScrollToAnchor) { + region = nsISelectionController::SELECTION_ANCHOR_REGION; + } + selectionController->ScrollSelectionIntoView( + nsISelectionController::SELECTION_NORMAL, + region, + nsISelectionController::SCROLL_OVERFLOW_HIDDEN); return NS_OK; } @@ -2505,10 +2548,13 @@ EditorBase::InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert, } // Let listeners know what's up - for (auto& listener : mActionListeners) { - listener->WillInsertText( - static_cast<nsIDOMCharacterData*>(insertedTextNode->AsDOMNode()), - insertedOffset, aStringToInsert); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->WillInsertText( + static_cast<nsIDOMCharacterData*>(insertedTextNode->AsDOMNode()), + insertedOffset, aStringToInsert); + } } // XXX We may not need these view batches anymore. This is handled at a @@ -2518,10 +2564,13 @@ EditorBase::InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert, EndUpdateViewBatch(); // let listeners know what happened - for (auto& listener : mActionListeners) { - listener->DidInsertText( - static_cast<nsIDOMCharacterData*>(insertedTextNode->AsDOMNode()), - insertedOffset, aStringToInsert, rv); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->DidInsertText( + static_cast<nsIDOMCharacterData*>(insertedTextNode->AsDOMNode()), + insertedOffset, aStringToInsert, rv); + } } // Added some cruft here for bug 43366. Layout was crashing because we left @@ -2583,8 +2632,7 @@ EditorBase::NotifyDocumentListeners( return NS_OK; } - nsTArray<OwningNonNull<nsIDocumentStateListener>> - listeners(mDocStateListeners); + AutoDocumentStateListenerArray listeners(mDocStateListeners); nsresult rv = NS_OK; switch (aNotificationType) { @@ -2656,19 +2704,25 @@ EditorBase::DeleteText(nsGenericDOMDataNode& aCharData, nsIEditor::ePrevious); // Let listeners know what's up - for (auto& listener : mActionListeners) { - listener->WillDeleteText( - static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset, - aLength); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->WillDeleteText( + static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset, + aLength); + } } nsresult rv = DoTransaction(transaction); // Let listeners know what happened - for (auto& listener : mActionListeners) { - listener->DidDeleteText( - static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset, - aLength, rv); + { + AutoActionListenerArray listeners(mActionListeners); + for (auto& listener : listeners) { + listener->DidDeleteText( + static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset, + aLength, rv); + } } return rv; @@ -4034,17 +4088,20 @@ EditorBase::DeleteSelectionImpl(EDirection aAction, if (NS_SUCCEEDED(rv)) { AutoRules beginRulesSniffing(this, EditAction::deleteSelection, aAction); // Notify nsIEditActionListener::WillDelete[Selection|Text|Node] - if (!deleteNode) { - for (auto& listener : mActionListeners) { - listener->WillDeleteSelection(selection); - } - } else if (deleteCharData) { - for (auto& listener : mActionListeners) { - listener->WillDeleteText(deleteCharData, deleteCharOffset, 1); - } - } else { - for (auto& listener : mActionListeners) { - listener->WillDeleteNode(deleteNode->AsDOMNode()); + { + AutoActionListenerArray listeners(mActionListeners); + if (!deleteNode) { + for (auto& listener : listeners) { + listener->WillDeleteSelection(selection); + } + } else if (deleteCharData) { + for (auto& listener : listeners) { + listener->WillDeleteText(deleteCharData, deleteCharOffset, 1); + } + } else { + for (auto& listener : listeners) { + listener->WillDeleteNode(deleteNode->AsDOMNode()); + } } } @@ -4052,17 +4109,20 @@ EditorBase::DeleteSelectionImpl(EDirection aAction, rv = DoTransaction(transaction); // Notify nsIEditActionListener::DidDelete[Selection|Text|Node] - if (!deleteNode) { - for (auto& listener : mActionListeners) { - listener->DidDeleteSelection(selection); - } - } else if (deleteCharData) { - for (auto& listener : mActionListeners) { - listener->DidDeleteText(deleteCharData, deleteCharOffset, 1, rv); - } - } else { - for (auto& listener : mActionListeners) { - listener->DidDeleteNode(deleteNode->AsDOMNode(), rv); + { + AutoActionListenerArray listeners(mActionListeners); + if (!deleteNode) { + for (auto& listener : mActionListeners) { + listener->DidDeleteSelection(selection); + } + } else if (deleteCharData) { + for (auto& listener : mActionListeners) { + listener->DidDeleteText(deleteCharData, deleteCharOffset, 1, rv); + } + } else { + for (auto& listener : mActionListeners) { + listener->DidDeleteNode(deleteNode->AsDOMNode(), rv); + } } } } @@ -4739,22 +4799,27 @@ EditorBase::InitializeSelection(nsIDOMEventTarget* aFocusEventTarget) nsCOMPtr<nsIPresShell> presShell = GetPresShell(); NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_INITIALIZED); - nsCOMPtr<nsISelectionController> selCon; - nsresult rv = GetSelectionController(getter_AddRefs(selCon)); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsISelectionController> selectionController = + GetSelectionController(); + if (NS_WARN_IF(!selectionController)) { + return NS_ERROR_FAILURE; + } // Init the caret RefPtr<nsCaret> caret = presShell->GetCaret(); NS_ENSURE_TRUE(caret, NS_ERROR_UNEXPECTED); caret->SetIgnoreUserModify(false); caret->SetSelection(selection); - selCon->SetCaretReadOnly(IsReadonly()); - selCon->SetCaretEnabled(true); + selectionController->SetCaretReadOnly(IsReadonly()); + selectionController->SetCaretEnabled(true); // Init selection - selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); - selCon->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL); - selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL); + selectionController->SetDisplaySelection( + nsISelectionController::SELECTION_ON); + selectionController->SetSelectionFlags( + nsISelectionDisplay::DISPLAY_ALL); + selectionController->RepaintSelection( + nsISelectionController::SELECTION_NORMAL); // If the computed selection root isn't root content, we should set it // as selection ancestor limit. However, if that is root element, it means // there is not limitation of the selection, then, we must set nullptr. @@ -4822,9 +4887,11 @@ private: NS_IMETHODIMP EditorBase::FinalizeSelection() { - nsCOMPtr<nsISelectionController> selCon; - nsresult rv = GetSelectionController(getter_AddRefs(selCon)); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsISelectionController> selectionController = + GetSelectionController(); + if (NS_WARN_IF(!selectionController)) { + return NS_ERROR_FAILURE; + } RefPtr<Selection> selection = GetSelection(); NS_ENSURE_STATE(selection); @@ -4834,7 +4901,7 @@ EditorBase::FinalizeSelection() nsCOMPtr<nsIPresShell> presShell = GetPresShell(); NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_INITIALIZED); - selCon->SetCaretEnabled(false); + selectionController->SetCaretEnabled(false); nsFocusManager* fm = nsFocusManager::GetFocusManager(); NS_ENSURE_TRUE(fm, NS_ERROR_NOT_INITIALIZED); @@ -4849,29 +4916,33 @@ EditorBase::FinalizeSelection() ErrorResult ret; if (!doc || !doc->HasFocus(ret)) { // If the document already lost focus, mark the selection as disabled. - selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED); + selectionController->SetDisplaySelection( + nsISelectionController::SELECTION_DISABLED); } else { // Otherwise, mark selection as normal because outside of a // contenteditable element should be selected with normal selection // color after here. - selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); + selectionController->SetDisplaySelection( + nsISelectionController::SELECTION_ON); } } else if (IsFormWidget() || IsPasswordEditor() || IsReadonly() || IsDisabled() || IsInputFiltered()) { // In <input> or <textarea>, the independent selection should be hidden // while this editor doesn't have focus. - selCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN); + selectionController->SetDisplaySelection( + nsISelectionController::SELECTION_HIDDEN); } else { // Otherwise, although we're not sure how this case happens, the // independent selection should be marked as disabled. - selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED); + selectionController->SetDisplaySelection( + nsISelectionController::SELECTION_DISABLED); } // FinalizeSelection might be called from ContentRemoved even if selection // isn't updated. So we need to call RepaintSelection after updated it. nsContentUtils::AddScriptRunner( - new RepaintSelectionRunner(selCon)); + new RepaintSelectionRunner(selectionController)); return NS_OK; } @@ -5082,8 +5153,11 @@ EditorBase::IsActiveInDOMWindow() nsFocusManager* fm = nsFocusManager::GetFocusManager(); NS_ENSURE_TRUE(fm, false); - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - nsPIDOMWindowOuter* ourWindow = doc->GetWindow(); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return false; + } + nsPIDOMWindowOuter* ourWindow = document->GetWindow(); nsCOMPtr<nsPIDOMWindowOuter> win; nsIContent* content = nsFocusManager::GetFocusedDescendant(ourWindow, false, @@ -5191,12 +5265,13 @@ EditorBase::GetIMESelectionStartOffsetIn(nsINode* aTextNode) { MOZ_ASSERT(aTextNode, "aTextNode must not be nullptr"); - nsCOMPtr<nsISelectionController> selectionController; - nsresult rv = GetSelectionController(getter_AddRefs(selectionController)); - NS_ENSURE_SUCCESS(rv, -1); - NS_ENSURE_TRUE(selectionController, -1); + nsCOMPtr<nsISelectionController> selectionController = + GetSelectionController(); + if (NS_WARN_IF(!selectionController)) { + return -1; + } - int32_t minOffset = INT32_MAX; + uint32_t minOffset = UINT32_MAX; static const SelectionType kIMESelectionTypes[] = { SelectionType::eIMERawClause, SelectionType::eIMESelectedRawClause, @@ -5216,15 +5291,11 @@ EditorBase::GetIMESelectionStartOffsetIn(nsINode* aTextNode) if (NS_WARN_IF(range->GetStartParent() != aTextNode)) { // ignore the start offset... } else { - MOZ_ASSERT(range->StartOffset() >= 0, - "start offset shouldn't be negative"); minOffset = std::min(minOffset, range->StartOffset()); } if (NS_WARN_IF(range->GetEndParent() != aTextNode)) { // ignore the end offset... } else { - MOZ_ASSERT(range->EndOffset() >= 0, - "start offset shouldn't be negative"); minOffset = std::min(minOffset, range->EndOffset()); } } diff --git a/editor/libeditor/EditorBase.h b/editor/libeditor/EditorBase.h index dbd00771e..618da12a8 100644 --- a/editor/libeditor/EditorBase.h +++ b/editor/libeditor/EditorBase.h @@ -10,11 +10,14 @@ #include "mozFlushType.h" // for mozFlushType enum #include "mozilla/OwningNonNull.h" // for OwningNonNull #include "mozilla/SelectionState.h" // for RangeUpdater, etc. -#include "mozilla/StyleSheet.h" // for StyleSheet +#include "mozilla/StyleSheet.h" // for StyleSheet +#include "mozilla/UniquePtr.h" +#include "mozilla/WeakPtr.h" // for WeakPtr #include "mozilla/dom/Text.h" #include "nsCOMPtr.h" // for already_AddRefed, nsCOMPtr #include "nsCycleCollectionParticipant.h" #include "nsGkAtoms.h" +#include "nsIDocument.h" // for nsIDocument #include "nsIEditor.h" // for nsIEditor::EDirection, etc. #include "nsIEditorIMESupport.h" // for NS_DECL_NSIEDITORIMESUPPORT, etc. #include "nsIObserver.h" // for NS_DECL_NSIOBSERVER, etc. @@ -30,7 +33,6 @@ class nsIAtom; class nsIContent; -class nsIDOMDocument; class nsIDOMEvent; class nsIDOMEventListener; class nsIDOMEventTarget; @@ -115,6 +117,7 @@ class ErrorResult; class InsertNodeTransaction; class InsertTextTransaction; class JoinNodeTransaction; +class PlaceholderTransaction; class RemoveStyleSheetTransaction; class SplitNodeTransaction; class TextComposition; @@ -132,6 +135,57 @@ namespace widget { struct IMEState; } // namespace widget +/** + * CachedWeakPtr stores a pointer to a class which inherits nsIWeakReference. + * If the instance of the class has already been destroyed, this returns + * nullptr. Otherwise, returns cached pointer. + */ +template<class T> +class CachedWeakPtr final +{ +public: + CachedWeakPtr<T>() + : mCache(nullptr) + { + } + + CachedWeakPtr<T>& operator=(T* aObject) + { + mWeakPtr = do_GetWeakReference(aObject); + mCache = aObject; + return *this; + } + CachedWeakPtr<T>& operator=(const nsCOMPtr<T>& aOther) + { + mWeakPtr = do_GetWeakReference(aOther); + mCache = aOther; + return *this; + } + CachedWeakPtr<T>& operator=(already_AddRefed<T>& aOther) + { + nsCOMPtr<T> other = aOther; + mWeakPtr = do_GetWeakReference(other); + mCache = other; + return *this; + } + + bool IsAlive() const { return mWeakPtr && mWeakPtr->IsAlive(); } + + explicit operator bool() const { return mWeakPtr; } + operator T*() const { return get(); } + T* get() const + { + if (mCache && !mWeakPtr->IsAlive()) { + const_cast<CachedWeakPtr<T>*>(this)->mCache = nullptr; + } + return mCache; + } + +private: + nsWeakPtr mWeakPtr; + T* MOZ_NON_OWNING_REF mCache; +}; + #define kMOZEditorBogusNodeAttrAtom nsGkAtoms::mozeditorbogusnode #define kMOZEditorBogusNodeValue NS_LITERAL_STRING("TRUE") @@ -175,6 +229,7 @@ public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase, nsIEditor) + bool IsInitialized() const { return !!mDocumentWeak; } already_AddRefed<nsIDOMDocument> GetDOMDocument(); already_AddRefed<nsIDocument> GetDocument(); already_AddRefed<nsIPresShell> GetPresShell(); @@ -452,6 +507,7 @@ protected: */ bool EnsureComposition(WidgetCompositionEvent* aCompositionEvent); + already_AddRefed<nsISelectionController> GetSelectionController(); nsresult GetSelection(SelectionType aSelectionType, nsISelection** aSelection); @@ -844,7 +900,7 @@ public: bool HasIndependentSelection() const { - return !!mSelConWeak; + return !!mSelectionControllerWeak; } /** @@ -950,6 +1006,14 @@ public: } } +private: + // Weak reference to the nsISelectionController. + // Use GetSelectionController() to retrieve actual pointer. + CachedWeakPtr<nsISelectionController> mSelectionControllerWeak; + // Weak reference to the nsIDocument. + // Use GetDocument() to retrieve actual pointer. + CachedWeakPtr<nsIDocument> mDocumentWeak; + protected: enum Tristate { @@ -971,27 +1035,29 @@ protected: // The form field as an event receiver. nsCOMPtr<dom::EventTarget> mEventTarget; nsCOMPtr<nsIDOMEventListener> mEventListener; - // Weak reference to the nsISelectionController. - nsWeakPtr mSelConWeak; // Weak reference to placeholder for begin/end batch purposes. - nsWeakPtr mPlaceHolderTxn; - // Weak reference to the nsIDOMDocument. - nsWeakPtr mDocWeak; + WeakPtr<PlaceholderTransaction> mPlaceholderTransactionWeak; // Name of placeholder transaction. - nsIAtom* mPlaceHolderName; + nsIAtom* mPlaceholderName; // Saved selection state for placeholder transaction batching. - SelectionState* mSelState; + mozilla::UniquePtr<SelectionState> mSelState; nsString* mPhonetic; // IME composition this is not null between compositionstart and // compositionend. RefPtr<TextComposition> mComposition; // Listens to all low level actions on the doc. - nsTArray<OwningNonNull<nsIEditActionListener>> mActionListeners; + typedef AutoTArray<OwningNonNull<nsIEditActionListener>, 5> + AutoActionListenerArray; + AutoActionListenerArray mActionListeners; // Just notify once per high level change. - nsTArray<OwningNonNull<nsIEditorObserver>> mEditorObservers; + typedef AutoTArray<OwningNonNull<nsIEditorObserver>, 3> + AutoEditorObserverArray; + AutoEditorObserverArray mEditorObservers; // Listen to overall doc state (dirty or not, just created, etc.). - nsTArray<OwningNonNull<nsIDocumentStateListener>> mDocStateListeners; + typedef AutoTArray<OwningNonNull<nsIDocumentStateListener>, 1> + AutoDocumentStateListenerArray; + AutoDocumentStateListenerArray mDocStateListeners; // Cached selection for AutoSelectionRestorer. SelectionState mSavedSel; @@ -1006,7 +1072,7 @@ protected: int32_t mUpdateCount; // Nesting count for batching. - int32_t mPlaceHolderBatch; + int32_t mPlaceholderBatch; // The current editor action. EditAction mAction; diff --git a/editor/libeditor/HTMLEditRules.cpp b/editor/libeditor/HTMLEditRules.cpp index 545e22f70..805092eb7 100644 --- a/editor/libeditor/HTMLEditRules.cpp +++ b/editor/libeditor/HTMLEditRules.cpp @@ -16,12 +16,13 @@ #include "mozilla/EditorUtils.h" #include "mozilla/HTMLEditor.h" #include "mozilla/MathAlgorithms.h" +#include "mozilla/Move.h" #include "mozilla/Preferences.h" +#include "mozilla/UniquePtr.h" #include "mozilla/dom/Selection.h" #include "mozilla/dom/Element.h" #include "mozilla/OwningNonNull.h" #include "mozilla/mozalloc.h" -#include "nsAutoPtr.h" #include "nsAString.h" #include "nsAlgorithm.h" #include "nsCRT.h" @@ -426,7 +427,7 @@ HTMLEditRules::AfterEditInner(EditAction action, NS_ENSURE_STATE(selection); nsCOMPtr<nsIDOMNode> rangeStartParent, rangeEndParent; - int32_t rangeStartOffset = 0, rangeEndOffset = 0; + uint32_t rangeStartOffset = 0, rangeEndOffset = 0; // do we have a real range to act on? bool bDamagedRange = false; if (mDocChangeRange) { @@ -534,8 +535,8 @@ HTMLEditRules::AfterEditInner(EditAction action, mHTMLEditor->HandleInlineSpellCheck(action, selection, GetAsDOMNode(mRangeItem->startNode), mRangeItem->startOffset, - rangeStartParent, rangeStartOffset, - rangeEndParent, rangeEndOffset); + rangeStartParent, static_cast<int32_t>(rangeStartOffset), + rangeEndParent, static_cast<int32_t>(rangeEndOffset)); NS_ENSURE_SUCCESS(rv, rv); // detect empty doc @@ -1422,16 +1423,15 @@ HTMLEditRules::WillInsertText(EditAction aAction, if (!mDocChangeRange) { mDocChangeRange = new nsRange(selNode); } - rv = mDocChangeRange->SetStart(selNode, selOffset); - NS_ENSURE_SUCCESS(rv, rv); if (curNode) { - rv = mDocChangeRange->SetEnd(curNode, curOffset); + rv = mDocChangeRange->SetStartAndEnd(selNode, selOffset, + curNode, curOffset); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { - rv = mDocChangeRange->SetEnd(selNode, selOffset); + rv = mDocChangeRange->CollapseTo(selNode, selOffset); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -4411,20 +4411,21 @@ HTMLEditRules::CreateStyleForInsertText(Selection& aSelection, NS_ENSURE_STATE(rootElement); // process clearing any styles first - nsAutoPtr<PropItem> item(mHTMLEditor->mTypeInState->TakeClearProperty()); + UniquePtr<PropItem> item = + Move(mHTMLEditor->mTypeInState->TakeClearProperty()); while (item && node != rootElement) { NS_ENSURE_STATE(mHTMLEditor); nsresult rv = mHTMLEditor->ClearStyle(address_of(node), &offset, item->tag, &item->attr); NS_ENSURE_SUCCESS(rv, rv); - item = mHTMLEditor->mTypeInState->TakeClearProperty(); + item = Move(mHTMLEditor->mTypeInState->TakeClearProperty()); weDidSomething = true; } // then process setting any styles int32_t relFontSize = mHTMLEditor->mTypeInState->TakeRelativeFontSize(); - item = mHTMLEditor->mTypeInState->TakeSetProperty(); + item = Move(mHTMLEditor->mTypeInState->TakeSetProperty()); if (item || relFontSize) { // we have at least one style to add; make a new text node to insert style @@ -5093,10 +5094,11 @@ HTMLEditRules::ExpandSelectionForDeletion(Selection& aSelection) // Create a range that represents expanded selection RefPtr<nsRange> range = new nsRange(selStartNode); - nsresult rv = range->SetStart(selStartNode, selStartOffset); - NS_ENSURE_SUCCESS(rv, rv); - rv = range->SetEnd(selEndNode, selEndOffset); - NS_ENSURE_SUCCESS(rv, rv); + nsresult rv = range->SetStartAndEnd(selStartNode, selStartOffset, + selEndNode, selEndOffset); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } // Check if block is entirely inside range if (brBlock) { @@ -5149,9 +5151,8 @@ HTMLEditRules::NormalizeSelection(Selection* inSelection) RefPtr<nsRange> range = inSelection->GetRangeAt(0); NS_ENSURE_TRUE(range, NS_ERROR_NULL_POINTER); nsCOMPtr<nsIDOMNode> startNode, endNode; - int32_t startOffset, endOffset; + uint32_t startOffset, endOffset; nsCOMPtr<nsIDOMNode> newStartNode, newEndNode; - int32_t newStartOffset, newEndOffset; rv = range->GetStartContainer(getter_AddRefs(startNode)); NS_ENSURE_SUCCESS(rv, rv); @@ -5164,22 +5165,22 @@ HTMLEditRules::NormalizeSelection(Selection* inSelection) // adjusted values default to original values newStartNode = startNode; - newStartOffset = startOffset; + uint32_t newStartOffset = startOffset; newEndNode = endNode; - newEndOffset = endOffset; + uint32_t newEndOffset = endOffset; // some locals we need for whitespace code nsCOMPtr<nsINode> unused; - int32_t offset; + int32_t offset = -1; WSType wsType; // let the whitespace code do the heavy lifting - WSRunObject wsEndObj(mHTMLEditor, endNode, endOffset); + WSRunObject wsEndObj(mHTMLEditor, endNode, static_cast<int32_t>(endOffset)); // is there any intervening visible whitespace? if so we can't push selection past that, // it would visibly change maening of users selection nsCOMPtr<nsINode> endNode_(do_QueryInterface(endNode)); - wsEndObj.PriorVisibleNode(endNode_, endOffset, address_of(unused), - &offset, &wsType); + wsEndObj.PriorVisibleNode(endNode_, static_cast<int32_t>(endOffset), + address_of(unused), &offset, &wsType); if (wsType != WSType::text && wsType != WSType::normalWS) { // eThisBlock and eOtherBlock conveniently distinquish cases // of going "down" into a block and "up" out of a block. @@ -5189,36 +5190,44 @@ HTMLEditRules::NormalizeSelection(Selection* inSelection) GetAsDOMNode(mHTMLEditor->GetRightmostChild(wsEndObj.mStartReasonNode, true)); if (child) { - newEndNode = EditorBase::GetNodeLocation(child, &newEndOffset); - ++newEndOffset; // offset *after* child + int32_t offset = -1; + newEndNode = EditorBase::GetNodeLocation(child, &offset); + // offset *after* child + newEndOffset = static_cast<uint32_t>(offset + 1); } // else block is empty - we can leave selection alone here, i think. } else if (wsEndObj.mStartReason == WSType::thisBlock) { // endpoint is just after start of this block nsCOMPtr<nsIDOMNode> child; NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->GetPriorHTMLNode(endNode, endOffset, address_of(child)); + mHTMLEditor->GetPriorHTMLNode(endNode, static_cast<int32_t>(endOffset), + address_of(child)); if (child) { - newEndNode = EditorBase::GetNodeLocation(child, &newEndOffset); - ++newEndOffset; // offset *after* child + int32_t offset = -1; + newEndNode = EditorBase::GetNodeLocation(child, &offset); + // offset *after* child + newEndOffset = static_cast<uint32_t>(offset + 1); } // else block is empty - we can leave selection alone here, i think. } else if (wsEndObj.mStartReason == WSType::br) { // endpoint is just after break. lets adjust it to before it. + int32_t offset = -1; newEndNode = EditorBase::GetNodeLocation(GetAsDOMNode(wsEndObj.mStartReasonNode), - &newEndOffset); + &offset); + newEndOffset = static_cast<uint32_t>(offset);; } } // similar dealio for start of range - WSRunObject wsStartObj(mHTMLEditor, startNode, startOffset); + WSRunObject wsStartObj(mHTMLEditor, startNode, + static_cast<int32_t>(startOffset)); // is there any intervening visible whitespace? if so we can't push selection past that, // it would visibly change maening of users selection nsCOMPtr<nsINode> startNode_(do_QueryInterface(startNode)); - wsStartObj.NextVisibleNode(startNode_, startOffset, address_of(unused), - &offset, &wsType); + wsStartObj.NextVisibleNode(startNode_, static_cast<int32_t>(startOffset), + address_of(unused), &offset, &wsType); if (wsType != WSType::text && wsType != WSType::normalWS) { // eThisBlock and eOtherBlock conveniently distinquish cases // of going "down" into a block and "up" out of a block. @@ -5228,23 +5237,31 @@ HTMLEditRules::NormalizeSelection(Selection* inSelection) GetAsDOMNode(mHTMLEditor->GetLeftmostChild(wsStartObj.mEndReasonNode, true)); if (child) { - newStartNode = EditorBase::GetNodeLocation(child, &newStartOffset); + int32_t offset = -1; + newStartNode = EditorBase::GetNodeLocation(child, &offset); + newStartOffset = static_cast<uint32_t>(offset); } // else block is empty - we can leave selection alone here, i think. } else if (wsStartObj.mEndReason == WSType::thisBlock) { // startpoint is just before end of this block nsCOMPtr<nsIDOMNode> child; NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->GetNextHTMLNode(startNode, startOffset, address_of(child)); + mHTMLEditor->GetNextHTMLNode(startNode, static_cast<int32_t>(startOffset), + address_of(child)); if (child) { - newStartNode = EditorBase::GetNodeLocation(child, &newStartOffset); + int32_t offset = -1; + newStartNode = EditorBase::GetNodeLocation(child, &offset); + newStartOffset = static_cast<uint32_t>(offset); } // else block is empty - we can leave selection alone here, i think. } else if (wsStartObj.mEndReason == WSType::br) { // startpoint is just before a break. lets adjust it to after it. + int32_t offset = -1; newStartNode = EditorBase::GetNodeLocation(GetAsDOMNode(wsStartObj.mEndReasonNode), - &newStartOffset); + &offset); + // offset *after* break + newStartOffset = static_cast<uint32_t>(offset + 1); ++newStartOffset; // offset *after* break } } @@ -5558,26 +5575,27 @@ HTMLEditRules::PromoteRange(nsRange& aRange, // This is tricky. The basic idea is to push out the range endpoints to // truly enclose the blocks that we will affect. - nsCOMPtr<nsIDOMNode> opStartNode; - nsCOMPtr<nsIDOMNode> opEndNode; + nsCOMPtr<nsIDOMNode> opDOMStartNode; + nsCOMPtr<nsIDOMNode> opDOMEndNode; int32_t opStartOffset, opEndOffset; GetPromotedPoint(kStart, GetAsDOMNode(startNode), startOffset, - aOperationType, address_of(opStartNode), &opStartOffset); + aOperationType, address_of(opDOMStartNode), &opStartOffset); GetPromotedPoint(kEnd, GetAsDOMNode(endNode), endOffset, aOperationType, - address_of(opEndNode), &opEndOffset); + address_of(opDOMEndNode), &opEndOffset); // Make sure that the new range ends up to be in the editable section. if (!htmlEditor->IsDescendantOfEditorRoot( - EditorBase::GetNodeAtRangeOffsetPoint(opStartNode, opStartOffset)) || + EditorBase::GetNodeAtRangeOffsetPoint(opDOMStartNode, opStartOffset)) || !htmlEditor->IsDescendantOfEditorRoot( - EditorBase::GetNodeAtRangeOffsetPoint(opEndNode, opEndOffset - 1))) { + EditorBase::GetNodeAtRangeOffsetPoint(opDOMEndNode, opEndOffset - 1))) { return; } - DebugOnly<nsresult> rv = aRange.SetStart(opStartNode, opStartOffset); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - rv = aRange.SetEnd(opEndNode, opEndOffset); + nsCOMPtr<nsINode> opStartNode = do_QueryInterface(opDOMStartNode); + nsCOMPtr<nsINode> opEndNode = do_QueryInterface(opDOMEndNode); + DebugOnly<nsresult> rv = + aRange.SetStartAndEnd(opStartNode, opStartOffset, opEndNode, opEndOffset); MOZ_ASSERT(NS_SUCCEEDED(rv)); } @@ -7179,42 +7197,44 @@ HTMLEditRules::PinSelectionToNewBlock(Selection* aSelection) return NS_OK; } + if (NS_WARN_IF(!mNewBlock)) { + return NS_ERROR_NULL_POINTER; + } + // get the (collapsed) selection location - nsCOMPtr<nsIDOMNode> selNode, temp; + nsCOMPtr<nsIDOMNode> selNode; int32_t selOffset; NS_ENSURE_STATE(mHTMLEditor); nsresult rv = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset); NS_ENSURE_SUCCESS(rv, rv); - temp = selNode; // use ranges and sRangeHelper to compare sel point to new block nsCOMPtr<nsINode> node = do_QueryInterface(selNode); NS_ENSURE_STATE(node); RefPtr<nsRange> range = new nsRange(node); - rv = range->SetStart(selNode, selOffset); - NS_ENSURE_SUCCESS(rv, rv); - rv = range->SetEnd(selNode, selOffset); - NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr<nsIContent> block = mNewBlock.get(); - NS_ENSURE_TRUE(block, NS_ERROR_NO_INTERFACE); + rv = range->CollapseTo(node, selOffset); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } bool nodeBefore, nodeAfter; - rv = nsRange::CompareNodeToRange(block, range, &nodeBefore, &nodeAfter); + rv = nsRange::CompareNodeToRange(mNewBlock, range, &nodeBefore, &nodeAfter); NS_ENSURE_SUCCESS(rv, rv); if (nodeBefore && nodeAfter) { return NS_OK; // selection is inside block } else if (nodeBefore) { // selection is after block. put at end of block. - nsCOMPtr<nsIDOMNode> tmp = GetAsDOMNode(mNewBlock); NS_ENSURE_STATE(mHTMLEditor); - tmp = GetAsDOMNode(mHTMLEditor->GetLastEditableChild(*block)); + nsCOMPtr<nsINode> tmp = mHTMLEditor->GetLastEditableChild(*mNewBlock); + if (!tmp) { + tmp = mNewBlock; + } uint32_t endPoint; if (mHTMLEditor->IsTextNode(tmp) || mHTMLEditor->IsContainer(tmp)) { - rv = EditorBase::GetLengthOfDOMNode(tmp, endPoint); - NS_ENSURE_SUCCESS(rv, rv); + endPoint = tmp->Length(); } else { tmp = EditorBase::GetNodeLocation(tmp, (int32_t*)&endPoint); endPoint++; // want to be after this node @@ -7222,9 +7242,11 @@ HTMLEditRules::PinSelectionToNewBlock(Selection* aSelection) return aSelection->Collapse(tmp, (int32_t)endPoint); } else { // selection is before block. put at start of block. - nsCOMPtr<nsIDOMNode> tmp = GetAsDOMNode(mNewBlock); NS_ENSURE_STATE(mHTMLEditor); - tmp = GetAsDOMNode(mHTMLEditor->GetFirstEditableChild(*block)); + nsCOMPtr<nsINode> tmp = mHTMLEditor->GetFirstEditableChild(*mNewBlock); + if (!tmp) { + tmp = mNewBlock; + } int32_t offset; if (mHTMLEditor->IsTextNode(tmp) || mHTMLEditor->IsContainer(tmp)) { @@ -7967,7 +7989,7 @@ HTMLEditRules::UpdateDocChangeRange(nsRange* aRange) NS_ENSURE_SUCCESS(rv, rv); // Positive result means mDocChangeRange start is after aRange start. if (result > 0) { - int32_t startOffset; + uint32_t startOffset; rv = aRange->GetStartOffset(&startOffset); NS_ENSURE_SUCCESS(rv, rv); rv = mDocChangeRange->SetStart(startNode, startOffset); @@ -7981,9 +8003,9 @@ HTMLEditRules::UpdateDocChangeRange(nsRange* aRange) // Negative result means mDocChangeRange end is before aRange end. if (result < 0) { nsCOMPtr<nsIDOMNode> endNode; - int32_t endOffset; rv = aRange->GetEndContainer(getter_AddRefs(endNode)); NS_ENSURE_SUCCESS(rv, rv); + uint32_t endOffset; rv = aRange->GetEndOffset(&endOffset); NS_ENSURE_SUCCESS(rv, rv); rv = mDocChangeRange->SetEnd(endNode, endOffset); @@ -8091,10 +8113,13 @@ HTMLEditRules::DidSplitNode(nsIDOMNode* aExistingRightNode, if (!mListenerEnabled) { return NS_OK; } - nsresult rv = mUtilRange->SetStart(aNewLeftNode, 0); - NS_ENSURE_SUCCESS(rv, rv); - rv = mUtilRange->SetEnd(aExistingRightNode, 0); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsINode> newLeftNode = do_QueryInterface(aNewLeftNode); + nsCOMPtr<nsINode> existingRightNode = do_QueryInterface(aExistingRightNode); + nsresult rv = mUtilRange->SetStartAndEnd(newLeftNode, 0, + existingRightNode, 0); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } return UpdateDocChangeRange(mUtilRange); } @@ -8119,11 +8144,12 @@ HTMLEditRules::DidJoinNodes(nsIDOMNode* aLeftNode, if (!mListenerEnabled) { return NS_OK; } + nsCOMPtr<nsINode> rightNode = do_QueryInterface(aRightNode); // assumption that Join keeps the righthand node - nsresult rv = mUtilRange->SetStart(aRightNode, mJoinOffset); - NS_ENSURE_SUCCESS(rv, rv); - rv = mUtilRange->SetEnd(aRightNode, mJoinOffset); - NS_ENSURE_SUCCESS(rv, rv); + nsresult rv = mUtilRange->CollapseTo(rightNode, mJoinOffset); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } return UpdateDocChangeRange(mUtilRange); } @@ -8145,11 +8171,12 @@ HTMLEditRules::DidInsertText(nsIDOMCharacterData* aTextNode, return NS_OK; } int32_t length = aString.Length(); - nsCOMPtr<nsIDOMNode> theNode = do_QueryInterface(aTextNode); - nsresult rv = mUtilRange->SetStart(theNode, aOffset); - NS_ENSURE_SUCCESS(rv, rv); - rv = mUtilRange->SetEnd(theNode, aOffset+length); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsINode> theNode = do_QueryInterface(aTextNode); + nsresult rv = mUtilRange->SetStartAndEnd(theNode, aOffset, + theNode, aOffset + length); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } return UpdateDocChangeRange(mUtilRange); } @@ -8170,11 +8197,11 @@ HTMLEditRules::DidDeleteText(nsIDOMCharacterData* aTextNode, if (!mListenerEnabled) { return NS_OK; } - nsCOMPtr<nsIDOMNode> theNode = do_QueryInterface(aTextNode); - nsresult rv = mUtilRange->SetStart(theNode, aOffset); - NS_ENSURE_SUCCESS(rv, rv); - rv = mUtilRange->SetEnd(theNode, aOffset); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsINode> theNode = do_QueryInterface(aTextNode); + nsresult rv = mUtilRange->CollapseTo(theNode, aOffset); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } return UpdateDocChangeRange(mUtilRange); } @@ -8189,22 +8216,27 @@ HTMLEditRules::WillDeleteSelection(nsISelection* aSelection) } RefPtr<Selection> selection = aSelection->AsSelection(); // get the (collapsed) selection location - nsCOMPtr<nsIDOMNode> selNode; - int32_t selOffset; - + nsCOMPtr<nsINode> startNode; + int32_t startOffset; NS_ENSURE_STATE(mHTMLEditor); nsresult rv = mHTMLEditor->GetStartNodeAndOffset(selection, - getter_AddRefs(selNode), &selOffset); - NS_ENSURE_SUCCESS(rv, rv); - rv = mUtilRange->SetStart(selNode, selOffset); - NS_ENSURE_SUCCESS(rv, rv); + getter_AddRefs(startNode), &startOffset); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + nsCOMPtr<nsINode> endNode; + int32_t endOffset; NS_ENSURE_STATE(mHTMLEditor); rv = mHTMLEditor->GetEndNodeAndOffset(selection, - getter_AddRefs(selNode), &selOffset); - NS_ENSURE_SUCCESS(rv, rv); - rv = mUtilRange->SetEnd(selNode, selOffset); - NS_ENSURE_SUCCESS(rv, rv); + getter_AddRefs(endNode), &endOffset); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + rv = mUtilRange->SetStartAndEnd(startNode, startOffset, endNode, endOffset); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } return UpdateDocChangeRange(mUtilRange); } diff --git a/editor/libeditor/HTMLEditUtils.cpp b/editor/libeditor/HTMLEditUtils.cpp index 0adc5d511..aa0afda98 100644 --- a/editor/libeditor/HTMLEditUtils.cpp +++ b/editor/libeditor/HTMLEditUtils.cpp @@ -583,7 +583,7 @@ HTMLEditUtils::SupportsAlignAttr(nsIDOMNode* aNode) struct ElementInfo final { #ifdef DEBUG - eHTMLTags mTag; + nsHTMLTag mTag; #endif uint32_t mGroup; uint32_t mCanContainGroups; @@ -603,9 +603,11 @@ static const ElementInfo kElements[eHTMLTag_userdefined] = { ELEM(a, true, false, GROUP_SPECIAL, GROUP_INLINE_ELEMENT), ELEM(abbr, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT), ELEM(acronym, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT), - ELEM(address, true, true, GROUP_BLOCK, - GROUP_INLINE_ELEMENT | GROUP_P), - ELEM(applet, true, true, GROUP_SPECIAL | GROUP_BLOCK, + ELEM(address, true, true, GROUP_BLOCK, GROUP_INLINE_ELEMENT | GROUP_P), + ELEM(applet, + true, + true, + GROUP_SPECIAL | GROUP_BLOCK, GROUP_FLOW_ELEMENT | GROUP_OBJECT_CONTENT), ELEM(area, false, false, GROUP_MAP_CONTENT, GROUP_NONE), ELEM(article, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT), @@ -620,19 +622,23 @@ static const ElementInfo kElements[eHTMLTag_userdefined] = { ELEM(blockquote, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT), ELEM(body, true, true, GROUP_TOPLEVEL, GROUP_FLOW_ELEMENT), ELEM(br, false, false, GROUP_SPECIAL, GROUP_NONE), - ELEM(button, true, true, GROUP_FORMCONTROL | GROUP_BLOCK, - GROUP_FLOW_ELEMENT), + ELEM(button, true, true, GROUP_FORMCONTROL | GROUP_BLOCK, GROUP_FLOW_ELEMENT), ELEM(canvas, false, false, GROUP_NONE, GROUP_NONE), ELEM(caption, true, true, GROUP_NONE, GROUP_INLINE_ELEMENT), ELEM(center, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT), ELEM(cite, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT), ELEM(code, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT), - ELEM(col, false, false, GROUP_TABLE_CONTENT | GROUP_COLGROUP_CONTENT, + ELEM(col, + false, + false, + GROUP_TABLE_CONTENT | GROUP_COLGROUP_CONTENT, GROUP_NONE), ELEM(colgroup, true, false, GROUP_NONE, GROUP_COLGROUP_CONTENT), - ELEM(content, true, false, GROUP_NONE, GROUP_INLINE_ELEMENT), ELEM(data, true, false, GROUP_PHRASE, GROUP_INLINE_ELEMENT), - ELEM(datalist, true, false, GROUP_PHRASE, + ELEM(datalist, + true, + false, + GROUP_PHRASE, GROUP_OPTIONS | GROUP_INLINE_ELEMENT), ELEM(dd, true, false, GROUP_DL_CONTENT, GROUP_FLOW_ELEMENT), ELEM(del, true, true, GROUP_PHRASE | GROUP_BLOCK, GROUP_FLOW_ELEMENT), @@ -647,33 +653,25 @@ static const ElementInfo kElements[eHTMLTag_userdefined] = { ELEM(embed, false, false, GROUP_NONE, GROUP_NONE), ELEM(fieldset, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT), ELEM(figcaption, true, false, GROUP_FIGCAPTION, GROUP_FLOW_ELEMENT), - ELEM(figure, true, true, GROUP_BLOCK, - GROUP_FLOW_ELEMENT | GROUP_FIGCAPTION), + ELEM(figure, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT | GROUP_FIGCAPTION), ELEM(font, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT), ELEM(footer, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT), ELEM(form, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT), ELEM(frame, false, false, GROUP_FRAME, GROUP_NONE), ELEM(frameset, true, true, GROUP_FRAME, GROUP_FRAME), - ELEM(h1, true, false, GROUP_BLOCK | GROUP_HEADING, - GROUP_INLINE_ELEMENT), - ELEM(h2, true, false, GROUP_BLOCK | GROUP_HEADING, - GROUP_INLINE_ELEMENT), - ELEM(h3, true, false, GROUP_BLOCK | GROUP_HEADING, - GROUP_INLINE_ELEMENT), - ELEM(h4, true, false, GROUP_BLOCK | GROUP_HEADING, - GROUP_INLINE_ELEMENT), - ELEM(h5, true, false, GROUP_BLOCK | GROUP_HEADING, - GROUP_INLINE_ELEMENT), - ELEM(h6, true, false, GROUP_BLOCK | GROUP_HEADING, - GROUP_INLINE_ELEMENT), + ELEM(h1, true, false, GROUP_BLOCK | GROUP_HEADING, GROUP_INLINE_ELEMENT), + ELEM(h2, true, false, GROUP_BLOCK | GROUP_HEADING, GROUP_INLINE_ELEMENT), + ELEM(h3, true, false, GROUP_BLOCK | GROUP_HEADING, GROUP_INLINE_ELEMENT), + ELEM(h4, true, false, GROUP_BLOCK | GROUP_HEADING, GROUP_INLINE_ELEMENT), + ELEM(h5, true, false, GROUP_BLOCK | GROUP_HEADING, GROUP_INLINE_ELEMENT), + ELEM(h6, true, false, GROUP_BLOCK | GROUP_HEADING, GROUP_INLINE_ELEMENT), ELEM(head, true, false, GROUP_TOPLEVEL, GROUP_HEAD_CONTENT), ELEM(header, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT), ELEM(hgroup, true, false, GROUP_BLOCK, GROUP_HEADING), ELEM(hr, false, false, GROUP_BLOCK, GROUP_NONE), ELEM(html, true, false, GROUP_TOPLEVEL, GROUP_TOPLEVEL), ELEM(i, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT), - ELEM(iframe, true, true, GROUP_SPECIAL | GROUP_BLOCK, - GROUP_FLOW_ELEMENT), + ELEM(iframe, true, true, GROUP_SPECIAL | GROUP_BLOCK, GROUP_FLOW_ELEMENT), ELEM(image, false, false, GROUP_NONE, GROUP_NONE), ELEM(img, false, false, GROUP_SPECIAL | GROUP_PICTURE_CONTENT, GROUP_NONE), ELEM(input, false, false, GROUP_FORMCONTROL, GROUP_NONE), @@ -699,15 +697,15 @@ static const ElementInfo kElements[eHTMLTag_userdefined] = { ELEM(noembed, false, false, GROUP_NONE, GROUP_NONE), ELEM(noframes, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT), ELEM(noscript, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT), - ELEM(object, true, true, GROUP_SPECIAL | GROUP_BLOCK, + ELEM(object, + true, + true, + GROUP_SPECIAL | GROUP_BLOCK, GROUP_FLOW_ELEMENT | GROUP_OBJECT_CONTENT), // XXX Can contain self and ul because editor does sublists illegally. - ELEM(ol, true, true, GROUP_BLOCK | GROUP_OL_UL, - GROUP_LI | GROUP_OL_UL), - ELEM(optgroup, true, false, GROUP_SELECT_CONTENT, - GROUP_OPTIONS), - ELEM(option, true, false, - GROUP_SELECT_CONTENT | GROUP_OPTIONS, GROUP_LEAF), + ELEM(ol, true, true, GROUP_BLOCK | GROUP_OL_UL, GROUP_LI | GROUP_OL_UL), + ELEM(optgroup, true, false, GROUP_SELECT_CONTENT, GROUP_OPTIONS), + ELEM(option, true, false, GROUP_SELECT_CONTENT | GROUP_OPTIONS, GROUP_LEAF), ELEM(output, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT), ELEM(p, true, false, GROUP_BLOCK | GROUP_P, GROUP_INLINE_ELEMENT), ELEM(param, false, false, GROUP_OBJECT_CONTENT, GROUP_NONE), @@ -723,12 +721,11 @@ static const ElementInfo kElements[eHTMLTag_userdefined] = { ELEM(ruby, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT), ELEM(s, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT), ELEM(samp, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT), - ELEM(script, true, false, GROUP_HEAD_CONTENT | GROUP_SPECIAL, - GROUP_LEAF), + ELEM(script, true, false, GROUP_HEAD_CONTENT | GROUP_SPECIAL, GROUP_LEAF), ELEM(section, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT), ELEM(select, true, false, GROUP_FORMCONTROL, GROUP_SELECT_CONTENT), - ELEM(shadow, true, false, GROUP_NONE, GROUP_INLINE_ELEMENT), ELEM(small, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT), + ELEM(slot, true, false, GROUP_NONE, GROUP_FLOW_ELEMENT), ELEM(source, false, false, GROUP_PICTURE_CONTENT, GROUP_NONE), ELEM(span, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT), ELEM(strike, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT), @@ -752,8 +749,7 @@ static const ElementInfo kElements[eHTMLTag_userdefined] = { ELEM(tt, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT), ELEM(u, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT), // XXX Can contain self and ol because editor does sublists illegally. - ELEM(ul, true, true, GROUP_BLOCK | GROUP_OL_UL, - GROUP_LI | GROUP_OL_UL), + ELEM(ul, true, true, GROUP_BLOCK | GROUP_OL_UL, GROUP_LI | GROUP_OL_UL), ELEM(var, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT), ELEM(video, false, false, GROUP_NONE, GROUP_NONE), ELEM(wbr, false, false, GROUP_NONE, GROUP_NONE), @@ -794,7 +790,7 @@ HTMLEditUtils::CanContain(int32_t aParent, int32_t aChild) // Special-case button. if (aParent == eHTMLTag_button) { - static const eHTMLTags kButtonExcludeKids[] = { + static const nsHTMLTag kButtonExcludeKids[] = { eHTMLTag_a, eHTMLTag_fieldset, eHTMLTag_form, diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index 532da7a15..c2f0bdc6d 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -63,13 +63,13 @@ #include "nsIWidget.h" #include "nsIFrame.h" -#include "nsIParserService.h" #include "mozilla/dom/Selection.h" #include "mozilla/dom/DocumentFragment.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/Event.h" #include "mozilla/dom/EventTarget.h" #include "mozilla/dom/HTMLBodyElement.h" +#include "nsElementTable.h" #include "nsTextFragment.h" #include "nsContentList.h" #include "mozilla/StyleSheet.h" @@ -165,7 +165,7 @@ HTMLEditor::~HTMLEditor() // free any default style propItems RemoveAllDefaultProperties(); - if (mLinkHandler && mDocWeak) { + if (mLinkHandler && IsInitialized()) { nsCOMPtr<nsIPresShell> ps = GetPresShell(); if (ps && ps->GetPresContext()) { @@ -287,7 +287,7 @@ HTMLEditor::Init(nsIDOMDocument* aDoc, } // Init the HTML-CSS utils - mCSSEditUtils = new CSSEditUtils(this); + mCSSEditUtils = MakeUnique<CSSEditUtils>(this); // disable links nsCOMPtr<nsIPresShell> presShell = GetPresShell(); @@ -335,7 +335,7 @@ HTMLEditor::PreDestroy(bool aDestroyingFrames) return NS_OK; } - nsCOMPtr<nsINode> document = do_QueryReferent(mDocWeak); + nsCOMPtr<nsIDocument> document = GetDocument(); if (document) { document->RemoveMutationObserver(this); } @@ -365,7 +365,7 @@ HTMLEditor::UpdateRootElement() } else { // If there is no HTML body element, // we should use the document root element instead. - nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak); + nsCOMPtr<nsIDOMDocument> doc = GetDOMDocument(); if (doc) { doc->GetDocumentElement(getter_AddRefs(rootElement)); } @@ -430,8 +430,9 @@ HTMLEditor::CreateEventListeners() nsresult HTMLEditor::InstallEventListeners() { - NS_ENSURE_TRUE(mDocWeak && mEventListener, - NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!IsInitialized()) || NS_WARN_IF(!mEventListener)) { + return NS_ERROR_NOT_INITIALIZED; + } // NOTE: HTMLEditor doesn't need to initialize mEventTarget here because // the target must be document node and it must be referenced as weak pointer. @@ -444,7 +445,7 @@ HTMLEditor::InstallEventListeners() void HTMLEditor::RemoveEventListeners() { - if (!mDocWeak) { + if (!IsInitialized()) { return; } @@ -506,7 +507,8 @@ HTMLEditor::InitRules() NS_IMETHODIMP HTMLEditor::BeginningOfDocument() { - if (!mDocWeak) { + // XXX Why doesn't this check if the document is alive? + if (!IsInitialized()) { return NS_ERROR_NOT_INITIALIZED; } @@ -688,49 +690,6 @@ HTMLEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent) return TypedText(str, eTypedText); } -static void -AssertParserServiceIsCorrect(nsIAtom* aTag, bool aIsBlock) -{ -#ifdef DEBUG - // Check this against what we would have said with the old code: - if (aTag == nsGkAtoms::p || - aTag == nsGkAtoms::div || - aTag == nsGkAtoms::blockquote || - aTag == nsGkAtoms::h1 || - aTag == nsGkAtoms::h2 || - aTag == nsGkAtoms::h3 || - aTag == nsGkAtoms::h4 || - aTag == nsGkAtoms::h5 || - aTag == nsGkAtoms::h6 || - aTag == nsGkAtoms::ul || - aTag == nsGkAtoms::ol || - aTag == nsGkAtoms::dl || - aTag == nsGkAtoms::noscript || - aTag == nsGkAtoms::form || - aTag == nsGkAtoms::hr || - aTag == nsGkAtoms::table || - aTag == nsGkAtoms::fieldset || - aTag == nsGkAtoms::address || - aTag == nsGkAtoms::col || - aTag == nsGkAtoms::colgroup || - aTag == nsGkAtoms::li || - aTag == nsGkAtoms::dt || - aTag == nsGkAtoms::dd || - aTag == nsGkAtoms::legend) { - if (!aIsBlock) { - nsAutoString assertmsg (NS_LITERAL_STRING("Parser and editor disagree on blockness: ")); - - nsAutoString tagName; - aTag->ToString(tagName); - assertmsg.Append(tagName); - char* assertstr = ToNewCString(assertmsg); - NS_ASSERTION(aIsBlock, assertstr); - free(assertstr); - } - } -#endif // DEBUG -} - /** * Returns true if the id represents an element of block type. * Can be used to determine if a new paragraph should be started. @@ -740,8 +699,8 @@ HTMLEditor::NodeIsBlockStatic(const nsINode* aElement) { MOZ_ASSERT(aElement); - // Nodes we know we want to treat as block - // even though the parser says they're not: + // We want to treat these as block nodes even though nsHTMLElement says + // they're not. if (aElement->IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::head, nsGkAtoms::tbody, @@ -750,27 +709,13 @@ HTMLEditor::NodeIsBlockStatic(const nsINode* aElement) nsGkAtoms::tr, nsGkAtoms::th, nsGkAtoms::td, - nsGkAtoms::li, nsGkAtoms::dt, - nsGkAtoms::dd, - nsGkAtoms::pre)) { + nsGkAtoms::dd)) { return true; } - bool isBlock; -#ifdef DEBUG - // XXX we can't use DebugOnly here because VC++ is stupid (bug 802884) - nsresult rv = -#endif - nsContentUtils::GetParserService()-> - IsBlock(nsContentUtils::GetParserService()->HTMLAtomTagToId( - aElement->NodeInfo()->NameAtom()), - isBlock); - MOZ_ASSERT(rv == NS_OK); - - AssertParserServiceIsCorrect(aElement->NodeInfo()->NameAtom(), isBlock); - - return isBlock; + return nsHTMLElement::IsBlock( + nsHTMLTags::AtomTagToId(aElement->NodeInfo()->NameAtom())); } nsresult @@ -1183,11 +1128,13 @@ HTMLEditor::ReplaceHeadContentsWithHTML(const nsAString& aSourceToInsert) // Do not use AutoRules -- rules code won't let us insert in <head>. Use // the head node as a parent and delete/insert directly. - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return NS_ERROR_NOT_INITIALIZED; + } RefPtr<nsContentList> nodeList = - doc->GetElementsByTagName(NS_LITERAL_STRING("head")); + document->GetElementsByTagName(NS_LITERAL_STRING("head")); NS_ENSURE_TRUE(nodeList, NS_ERROR_NULL_POINTER); nsCOMPtr<nsIContent> headNode = nodeList->Item(0); @@ -2401,21 +2348,19 @@ HTMLEditor::GetSelectedElement(const nsAString& aTagName, NS_ENSURE_STATE(range); nsCOMPtr<nsIDOMNode> startParent; - int32_t startOffset, endOffset; nsresult rv = range->GetStartContainer(getter_AddRefs(startParent)); NS_ENSURE_SUCCESS(rv, rv); - rv = range->GetStartOffset(&startOffset); - NS_ENSURE_SUCCESS(rv, rv); + uint32_t startOffset = range->StartOffset(); nsCOMPtr<nsIDOMNode> endParent; rv = range->GetEndContainer(getter_AddRefs(endParent)); NS_ENSURE_SUCCESS(rv, rv); - rv = range->GetEndOffset(&endOffset); - NS_ENSURE_SUCCESS(rv, rv); + uint32_t endOffset = range->EndOffset(); // Optimization for a single selected element if (startParent && startParent == endParent && endOffset - startOffset == 1) { - nsCOMPtr<nsIDOMNode> selectedNode = GetChildAt(startParent, startOffset); + nsCOMPtr<nsIDOMNode> selectedNode = + GetChildAt(startParent, static_cast<int32_t>(startOffset)); NS_ENSURE_SUCCESS(rv, NS_OK); if (selectedNode) { selectedNode->GetNodeName(domTagName); @@ -2705,7 +2650,7 @@ HTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement) nsresult HTMLEditor::SetHTMLBackgroundColor(const nsAString& aColor) { - NS_PRECONDITION(mDocWeak, "Missing Editor DOM Document"); + MOZ_ASSERT(IsInitialized(), "The HTMLEditor hasn't been initialized yet"); // Find a selected or enclosing table element to set background on nsCOMPtr<nsIDOMElement> element; @@ -2753,7 +2698,7 @@ HTMLEditor::SetBodyAttribute(const nsAString& aAttribute, { // TODO: Check selection for Cell, Row, Column or table and do color on appropriate level - NS_ASSERTION(mDocWeak, "Missing Editor DOM Document"); + MOZ_ASSERT(IsInitialized(), "The HTMLEditor hasn't been initialized yet"); // Set the background color attribute on the body tag nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(GetRoot()); @@ -2832,7 +2777,9 @@ HTMLEditor::ReplaceStyleSheet(const nsAString& aURL) } // Make sure the pres shell doesn't disappear during the load. - NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!IsInitialized())) { + return NS_ERROR_NOT_INITIALIZED; + } nsCOMPtr<nsIPresShell> ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); @@ -2941,7 +2888,9 @@ HTMLEditor::RemoveOverrideStyleSheet(const nsAString& aURL) NS_ENSURE_TRUE(sheet, NS_OK); /// Don't fail if sheet not found - NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!IsInitialized())) { + return NS_ERROR_NOT_INITIALIZED; + } nsCOMPtr<nsIPresShell> ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); @@ -2960,8 +2909,8 @@ HTMLEditor::EnableStyleSheet(const nsAString& aURL, NS_ENSURE_TRUE(sheet, NS_OK); // Don't fail if sheet not found // Ensure the style sheet is owned by our document. - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - sheet->SetOwningDocument(doc); + nsCOMPtr<nsIDocument> document = GetDocument(); + sheet->SetAssociatedDocument(document, StyleSheet::NotOwnedByDocument); if (sheet->IsServo()) { // XXXheycam ServoStyleSheets don't support being enabled/disabled yet. @@ -2982,8 +2931,8 @@ HTMLEditor::EnableExistingStyleSheet(const nsAString& aURL) } // Ensure the style sheet is owned by our document. - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - sheet->SetOwningDocument(doc); + nsCOMPtr<nsIDocument> document = GetDocument(); + sheet->SetAssociatedDocument(document, StyleSheet::NotOwnedByDocument); if (sheet->IsServo()) { // XXXheycam ServoStyleSheets don't support being enabled/disabled yet. @@ -3284,8 +3233,8 @@ HTMLEditor::DoContentInserted(nsIDocument* aDocument, sibling = sibling->GetNextSibling(); } } - nsresult rv = range->Set(aContainer, aIndexInContainer, - aContainer, endIndex); + nsresult rv = range->SetStartAndEnd(aContainer, aIndexInContainer, + aContainer, endIndex); if (NS_SUCCEEDED(rv)) { mInlineSpellChecker->SpellCheckRange(range); } @@ -3374,13 +3323,12 @@ HTMLEditor::GetIsSelectionEditable(bool* aIsSelectionEditable) static nsresult SetSelectionAroundHeadChildren(Selection* aSelection, - nsIWeakReference* aDocWeak) + nsCOMPtr<nsIDocument>& aDocument) { - // Set selection around <head> node - nsCOMPtr<nsIDocument> doc = do_QueryReferent(aDocWeak); - NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED); + MOZ_ASSERT(aDocument); - dom::Element* headNode = doc->GetHeadElement(); + // Set selection around <head> node + dom::Element* headNode = aDocument->GetHeadElement(); NS_ENSURE_STATE(headNode); // Collapse selection to before first child of the head, @@ -3401,7 +3349,11 @@ HTMLEditor::GetHeadContentsAsHTML(nsAString& aOutputString) // Save current selection AutoSelectionRestorer selectionRestorer(selection, this); - nsresult rv = SetSelectionAroundHeadChildren(selection, mDocWeak); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return NS_ERROR_NOT_INITIALIZED; + } + nsresult rv = SetSelectionAroundHeadChildren(selection, document); NS_ENSURE_SUCCESS(rv, rv); rv = OutputToString(NS_LITERAL_STRING("text/html"), @@ -3529,17 +3481,15 @@ bool HTMLEditor::TagCanContainTag(nsIAtom& aParentTag, nsIAtom& aChildTag) { - nsIParserService* parserService = nsContentUtils::GetParserService(); - int32_t childTagEnum; // XXX Should this handle #cdata-section too? if (&aChildTag == nsGkAtoms::textTagName) { childTagEnum = eHTMLTag_text; } else { - childTagEnum = parserService->HTMLAtomTagToId(&aChildTag); + childTagEnum = nsHTMLTags::AtomTagToId(&aChildTag); } - int32_t parentTagEnum = parserService->HTMLAtomTagToId(&aParentTag); + int32_t parentTagEnum = nsHTMLTags::AtomTagToId(&aParentTag); return HTMLEditUtils::CanContain(parentTagEnum, childTagEnum); } @@ -3553,8 +3503,7 @@ HTMLEditor::IsContainer(nsINode* aNode) if (aNode->IsNodeOfType(nsINode::eTEXT)) { tagEnum = eHTMLTag_text; } else { - tagEnum = - nsContentUtils::GetParserService()->HTMLStringTagToId(aNode->NodeName()); + tagEnum = nsHTMLTags::StringTagToId(aNode->NodeName()); } return HTMLEditUtils::IsContainer(tagEnum); @@ -3581,15 +3530,11 @@ HTMLEditor::SelectEntireDocument(Selection* aSelection) // Protect the edit rules object from dying nsCOMPtr<nsIEditRules> rules(mRules); - // get editor root node - nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot()); - // is doc empty? - bool bDocIsEmpty; - nsresult rv = rules->DocumentIsEmpty(&bDocIsEmpty); - NS_ENSURE_SUCCESS(rv, rv); + if (rules->DocumentIsEmpty()) { + // get editor root node + Element* rootElement = GetRoot(); - if (bDocIsEmpty) { // if its empty dont select entire doc - that would select the bogus node return aSelection->Collapse(rootElement, 0); } @@ -4275,10 +4220,11 @@ HTMLEditor::IsVisTextNode(nsIContent* aNode, uint32_t length = aNode->TextLength(); if (aSafeToAskFrames) { - nsCOMPtr<nsISelectionController> selCon; - nsresult rv = GetSelectionController(getter_AddRefs(selCon)); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE); + nsCOMPtr<nsISelectionController> selectionController = + GetSelectionController(); + if (NS_WARN_IF(!selectionController)) { + return NS_ERROR_FAILURE; + } bool isVisible = false; // ask the selection controller for information about whether any // of the data in the node is really rendered. This is really @@ -4286,7 +4232,8 @@ HTMLEditor::IsVisTextNode(nsIContent* aNode, // So we put a call in the selection controller interface, since it's already // in bed with frames anyway. (this is a fix for bug 22227, and a // partial fix for bug 46209) - rv = selCon->CheckVisibilityContent(aNode, 0, length, &isVisible); + nsresult rv = selectionController->CheckVisibilityContent(aNode, 0, length, + &isVisible); NS_ENSURE_SUCCESS(rv, rv); if (isVisible) { *outIsEmptyNode = false; @@ -4802,7 +4749,9 @@ HTMLEditor::GetElementOrigin(nsIDOMElement* aElement, aX = 0; aY = 0; - NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!IsInitialized())) { + return NS_ERROR_NOT_INITIALIZED; + } nsCOMPtr<nsIPresShell> ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); @@ -4944,28 +4893,29 @@ HTMLEditor::GetReturnInParagraphCreatesNewParagraph(bool* aCreatesNewParagraph) already_AddRefed<nsIContent> HTMLEditor::GetFocusedContent() { - NS_ENSURE_TRUE(mDocWeak, nullptr); - nsFocusManager* fm = nsFocusManager::GetFocusManager(); NS_ENSURE_TRUE(fm, nullptr); nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedContent(); - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - bool inDesignMode = doc->HasFlag(NODE_IS_EDITABLE); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return nullptr; + } + bool inDesignMode = document->HasFlag(NODE_IS_EDITABLE); if (!focusedContent) { // in designMode, nobody gets focus in most cases. if (inDesignMode && OurWindowHasFocus()) { - nsCOMPtr<nsIContent> docRoot = doc->GetRootElement(); - return docRoot.forget(); + nsCOMPtr<nsIContent> rootContent = document->GetRootElement(); + return rootContent.forget(); } return nullptr; } if (inDesignMode) { return OurWindowHasFocus() && - nsContentUtils::ContentIsDescendantOf(focusedContent, doc) ? - focusedContent.forget() : nullptr; + nsContentUtils::ContentIsDescendantOf(focusedContent, document) ? + focusedContent.forget() : nullptr; } // We're HTML editor for contenteditable @@ -4988,28 +4938,32 @@ HTMLEditor::GetFocusedContentForIME() return nullptr; } - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, nullptr); - return doc->HasFlag(NODE_IS_EDITABLE) ? nullptr : focusedContent.forget(); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return nullptr; + } + return document->HasFlag(NODE_IS_EDITABLE) ? nullptr : + focusedContent.forget(); } bool HTMLEditor::IsActiveInDOMWindow() { - NS_ENSURE_TRUE(mDocWeak, false); - nsFocusManager* fm = nsFocusManager::GetFocusManager(); NS_ENSURE_TRUE(fm, false); - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - bool inDesignMode = doc->HasFlag(NODE_IS_EDITABLE); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return false; + } + bool inDesignMode = document->HasFlag(NODE_IS_EDITABLE); // If we're in designMode, we're always active in the DOM window. if (inDesignMode) { return true; } - nsPIDOMWindowOuter* ourWindow = doc->GetWindow(); + nsPIDOMWindowOuter* ourWindow = document->GetWindow(); nsCOMPtr<nsPIDOMWindowOuter> win; nsIContent* content = nsFocusManager::GetFocusedDescendant(ourWindow, false, @@ -5032,12 +4986,12 @@ HTMLEditor::IsActiveInDOMWindow() Element* HTMLEditor::GetActiveEditingHost() { - NS_ENSURE_TRUE(mDocWeak, nullptr); - - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, nullptr); - if (doc->HasFlag(NODE_IS_EDITABLE)) { - return doc->GetBodyElement(); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return nullptr; + } + if (document->HasFlag(NODE_IS_EDITABLE)) { + return document->GetBodyElement(); } // We're HTML editor for contenteditable @@ -5066,8 +5020,8 @@ HTMLEditor::GetDOMEventTarget() // Don't use getDocument here, because we have no way of knowing // whether Init() was ever called. So we need to get the document // ourselves, if it exists. - NS_PRECONDITION(mDocWeak, "This editor has not been initialized yet"); - nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryReferent(mDocWeak); + MOZ_ASSERT(IsInitialized(), "The HTMLEditor has not been initialized yet"); + nsCOMPtr<mozilla::dom::EventTarget> target = GetDocument(); return target.forget(); } @@ -5121,12 +5075,16 @@ HTMLEditor::NotifyRootChanged() nsresult HTMLEditor::GetBodyElement(nsIDOMHTMLElement** aBody) { - NS_PRECONDITION(mDocWeak, "bad state, null mDocWeak"); - nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryReferent(mDocWeak); - if (!htmlDoc) { + MOZ_ASSERT(IsInitialized(), "The HTMLEditor hasn't been initialized yet"); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return NS_ERROR_NOT_INITIALIZED; + } + nsCOMPtr<nsIDOMHTMLDocument> domHTMLDocument = do_QueryInterface(document); + if (!domHTMLDocument) { return NS_ERROR_NOT_INITIALIZED; } - return htmlDoc->GetBody(aBody); + return domHTMLDocument->GetBody(aBody); } already_AddRefed<nsINode> @@ -5146,14 +5104,13 @@ HTMLEditor::GetFocusedNode() return node.forget(); } - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - return doc.forget(); + nsCOMPtr<nsIDocument> document = GetDocument(); + return document.forget(); } bool HTMLEditor::OurWindowHasFocus() { - NS_ENSURE_TRUE(mDocWeak, false); nsIFocusManager* fm = nsFocusManager::GetFocusManager(); NS_ENSURE_TRUE(fm, false); nsCOMPtr<mozIDOMWindowProxy> focusedWindow; @@ -5161,8 +5118,11 @@ HTMLEditor::OurWindowHasFocus() if (!focusedWindow) { return false; } - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - nsPIDOMWindowOuter* ourWindow = doc->GetWindow(); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return false; + } + nsPIDOMWindowOuter* ourWindow = document->GetWindow(); return ourWindow == focusedWindow; } @@ -5180,12 +5140,14 @@ HTMLEditor::IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent) return true; } - NS_ENSURE_TRUE(mDocWeak, false); - nsCOMPtr<nsIDOMEventTarget> target = aGUIEvent->GetDOMEventTarget(); NS_ENSURE_TRUE(target, false); - nsCOMPtr<nsIDocument> document = do_QueryReferent(mDocWeak); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return false; + } + if (document->HasFlag(NODE_IS_EDITABLE)) { // If this editor is in designMode and the event target is the document, // the event is for this editor. diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h index dfcdd8d6b..dc1a41b70 100644 --- a/editor/libeditor/HTMLEditor.h +++ b/editor/libeditor/HTMLEditor.h @@ -10,11 +10,11 @@ #include "mozilla/CSSEditUtils.h" #include "mozilla/StyleSheet.h" #include "mozilla/TextEditor.h" +#include "mozilla/UniquePtr.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/File.h" #include "nsAttrName.h" -#include "nsAutoPtr.h" #include "nsCOMPtr.h" #include "nsIContentFilter.h" #include "nsICSSLoaderObserver.h" @@ -896,7 +896,7 @@ protected: bool mCRInParagraphCreatesParagraph; bool mCSSAware; - nsAutoPtr<CSSEditUtils> mCSSEditUtils; + UniquePtr<CSSEditUtils> mCSSEditUtils; // Used by GetFirstSelectedCell and GetNextSelectedCell int32_t mSelectedCellIndex; diff --git a/editor/libeditor/HTMLEditorDataTransfer.cpp b/editor/libeditor/HTMLEditorDataTransfer.cpp index c56fbead7..0c01bdd1c 100644 --- a/editor/libeditor/HTMLEditorDataTransfer.cpp +++ b/editor/libeditor/HTMLEditorDataTransfer.cpp @@ -145,14 +145,13 @@ HTMLEditor::LoadHTML(const nsAString& aInputString) rv = range->GetStartContainer(getter_AddRefs(parent)); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER); - int32_t childOffset; - rv = range->GetStartOffset(&childOffset); - NS_ENSURE_SUCCESS(rv, rv); + uint32_t childOffset = range->StartOffset(); nsCOMPtr<nsIDOMNode> nodeToInsert; docfrag->GetFirstChild(getter_AddRefs(nodeToInsert)); while (nodeToInsert) { - rv = InsertNode(nodeToInsert, parent, childOffset++); + rv = InsertNode(nodeToInsert, parent, + static_cast<int32_t>(childOffset++)); NS_ENSURE_SUCCESS(rv, rv); docfrag->GetFirstChild(getter_AddRefs(nodeToInsert)); } diff --git a/editor/libeditor/HTMLStyleEditor.cpp b/editor/libeditor/HTMLStyleEditor.cpp index 6a1ffe8b4..7d1217069 100644 --- a/editor/libeditor/HTMLStyleEditor.cpp +++ b/editor/libeditor/HTMLStyleEditor.cpp @@ -541,9 +541,11 @@ HTMLEditor::SplitStyleAboveRange(nsRange* inRange, NS_ENSURE_SUCCESS(rv, rv); // reset the range - rv = inRange->SetStart(startNode, startOffset); - NS_ENSURE_SUCCESS(rv, rv); - return inRange->SetEnd(endNode, endOffset); + rv = inRange->SetStartAndEnd(startNode, startOffset, endNode, endOffset); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + return NS_OK; } nsresult @@ -885,10 +887,11 @@ HTMLEditor::PromoteRangeIfStartsOrEndsInNamedAnchor(nsRange& aRange) endOffset = endNode ? endNode->IndexOf(parent) + 1 : 0; } - nsresult rv = aRange.SetStart(startNode, startOffset); - NS_ENSURE_SUCCESS(rv, rv); - rv = aRange.SetEnd(endNode, endOffset); - NS_ENSURE_SUCCESS(rv, rv); + nsresult rv = aRange.SetStartAndEnd(startNode, startOffset, + endNode, endOffset); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } return NS_OK; } @@ -918,10 +921,11 @@ HTMLEditor::PromoteInlineRange(nsRange& aRange) endNode = parent; } - nsresult rv = aRange.SetStart(startNode, startOffset); - NS_ENSURE_SUCCESS(rv, rv); - rv = aRange.SetEnd(endNode, endOffset); - NS_ENSURE_SUCCESS(rv, rv); + nsresult rv = aRange.SetStartAndEnd(startNode, startOffset, + endNode, endOffset); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } return NS_OK; } @@ -1074,7 +1078,7 @@ HTMLEditor::GetInlinePropertyBase(nsIAtom& aProperty, if (content->GetAsText()) { if (!isCollapsed && first && firstNodeInRange) { firstNodeInRange = false; - if (range->StartOffset() == (int32_t)content->Length()) { + if (range->StartOffset() == content->Length()) { continue; } } else if (content == endNode && !endOffset) { diff --git a/editor/libeditor/HTMLTableEditor.cpp b/editor/libeditor/HTMLTableEditor.cpp index 778bf1d2d..b26466179 100644 --- a/editor/libeditor/HTMLTableEditor.cpp +++ b/editor/libeditor/HTMLTableEditor.cpp @@ -2594,7 +2594,6 @@ HTMLEditor::GetCellIndexes(nsIDOMElement* aCell, aCell = cell; } - NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); nsCOMPtr<nsIPresShell> ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); @@ -2933,11 +2932,10 @@ HTMLEditor::GetCellFromRange(nsRange* aRange, NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(startParent, NS_ERROR_FAILURE); - int32_t startOffset; - rv = aRange->GetStartOffset(&startOffset); - NS_ENSURE_SUCCESS(rv, rv); + uint32_t startOffset = aRange->StartOffset(); - nsCOMPtr<nsIDOMNode> childNode = GetChildAt(startParent, startOffset); + nsCOMPtr<nsIDOMNode> childNode = + GetChildAt(startParent, static_cast<int32_t>(startOffset)); // This means selection is probably at a text node (or end of doc?) if (!childNode) { return NS_ERROR_FAILURE; @@ -2948,15 +2946,11 @@ HTMLEditor::GetCellFromRange(nsRange* aRange, NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(startParent, NS_ERROR_FAILURE); - int32_t endOffset; - rv = aRange->GetEndOffset(&endOffset); - NS_ENSURE_SUCCESS(rv, rv); - // If a cell is deleted, the range is collapse - // (startOffset == endOffset) + // (startOffset == aRange->EndOffset()) // so tell caller the cell wasn't found if (startParent == endParent && - endOffset == startOffset+1 && + aRange->EndOffset() == startOffset+1 && HTMLEditUtils::IsTableCell(childNode)) { // Should we also test if frame is selected? (Use GetCellDataAt()) // (Let's not for now -- more efficient) diff --git a/editor/libeditor/PlaceholderTransaction.cpp b/editor/libeditor/PlaceholderTransaction.cpp index fa808afad..142a85075 100644 --- a/editor/libeditor/PlaceholderTransaction.cpp +++ b/editor/libeditor/PlaceholderTransaction.cpp @@ -8,6 +8,7 @@ #include "CompositionTransaction.h" #include "mozilla/EditorBase.h" #include "mozilla/dom/Selection.h" +#include "mozilla/Move.h" #include "nsGkAtoms.h" #include "nsQueryObject.h" @@ -15,13 +16,18 @@ namespace mozilla { using namespace dom; -PlaceholderTransaction::PlaceholderTransaction() +PlaceholderTransaction::PlaceholderTransaction( + EditorBase& aEditorBase, + nsIAtom* aName, + UniquePtr<SelectionState> aSelState) : mAbsorb(true) , mForwarding(nullptr) , mCompositionTransaction(nullptr) , mCommitted(false) - , mEditorBase(nullptr) + , mStartSel(Move(aSelState)) + , mEditorBase(&aEditorBase) { + mName = aName; } PlaceholderTransaction::~PlaceholderTransaction() @@ -50,26 +56,12 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PlaceholderTransaction) NS_INTERFACE_MAP_ENTRY(nsIAbsorbingTransaction) - NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_END_INHERITING(EditAggregateTransaction) NS_IMPL_ADDREF_INHERITED(PlaceholderTransaction, EditAggregateTransaction) NS_IMPL_RELEASE_INHERITED(PlaceholderTransaction, EditAggregateTransaction) NS_IMETHODIMP -PlaceholderTransaction::Init(nsIAtom* aName, - SelectionState* aSelState, - EditorBase* aEditorBase) -{ - NS_ENSURE_TRUE(aEditorBase && aSelState, NS_ERROR_NULL_POINTER); - - mName = aName; - mStartSel = aSelState; - mEditorBase = aEditorBase; - return NS_OK; -} - -NS_IMETHODIMP PlaceholderTransaction::DoTransaction() { return NS_OK; diff --git a/editor/libeditor/PlaceholderTransaction.h b/editor/libeditor/PlaceholderTransaction.h index 8193239be..5fa58a1e9 100644 --- a/editor/libeditor/PlaceholderTransaction.h +++ b/editor/libeditor/PlaceholderTransaction.h @@ -8,12 +8,13 @@ #include "EditAggregateTransaction.h" #include "mozilla/EditorUtils.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/WeakPtr.h" #include "nsIAbsorbingTransaction.h" #include "nsIDOMNode.h" #include "nsCOMPtr.h" #include "nsWeakPtr.h" #include "nsWeakReference.h" -#include "nsAutoPtr.h" namespace mozilla { @@ -26,14 +27,18 @@ class CompositionTransaction; * transactions it has absorbed. */ -class PlaceholderTransaction final : public EditAggregateTransaction, - public nsIAbsorbingTransaction, - public nsSupportsWeakReference +class PlaceholderTransaction final + : public EditAggregateTransaction + , public nsIAbsorbingTransaction + , public SupportsWeakPtr<PlaceholderTransaction> { public: + MOZ_DECLARE_WEAKREFERENCE_TYPENAME(PlaceholderTransaction) + NS_DECL_ISUPPORTS_INHERITED - PlaceholderTransaction(); + PlaceholderTransaction(EditorBase& aEditorBase, nsIAtom* aName, + UniquePtr<SelectionState> aSelState); NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PlaceholderTransaction, EditAggregateTransaction) @@ -46,9 +51,6 @@ public: // ------------ nsIAbsorbingTransaction ----------------------- - NS_IMETHOD Init(nsIAtom* aName, SelectionState* aSelState, - EditorBase* aEditorBase) override; - NS_IMETHOD GetTxnName(nsIAtom** aName) override; NS_IMETHOD StartSelectionEquals(SelectionState* aSelState, @@ -61,6 +63,11 @@ public: NS_IMETHOD Commit() override; + NS_IMETHOD_(PlaceholderTransaction*) AsPlaceholderTransaction() override + { + return this; + } + nsresult RememberEndingSelection(); protected: @@ -80,7 +87,7 @@ protected: // restore the selection properly. // Use a pointer because this is constructed before we exist. - nsAutoPtr<SelectionState> mStartSel; + UniquePtr<SelectionState> mStartSel; SelectionState mEndSel; // The editor for this transaction. diff --git a/editor/libeditor/SelectionState.cpp b/editor/libeditor/SelectionState.cpp index f9ad5947a..057e04875 100644 --- a/editor/libeditor/SelectionState.cpp +++ b/editor/libeditor/SelectionState.cpp @@ -686,7 +686,8 @@ already_AddRefed<nsRange> RangeItem::GetRange() { RefPtr<nsRange> range = new nsRange(startNode); - if (NS_FAILED(range->Set(startNode, startOffset, endNode, endOffset))) { + if (NS_FAILED(range->SetStartAndEnd(startNode, startOffset, + endNode, endOffset))) { return nullptr; } return range.forget(); diff --git a/editor/libeditor/TextEditRules.cpp b/editor/libeditor/TextEditRules.cpp index 8f8f34e8b..35d4a2f3d 100644 --- a/editor/libeditor/TextEditRules.cpp +++ b/editor/libeditor/TextEditRules.cpp @@ -329,13 +329,10 @@ TextEditRules::DidDoAction(Selection* aSelection, } } -NS_IMETHODIMP -TextEditRules::DocumentIsEmpty(bool* aDocumentIsEmpty) +NS_IMETHODIMP_(bool) +TextEditRules::DocumentIsEmpty() { - NS_ENSURE_TRUE(aDocumentIsEmpty, NS_ERROR_NULL_POINTER); - - *aDocumentIsEmpty = (mBogusNode != nullptr); - return NS_OK; + return (mBogusNode != nullptr); } void diff --git a/editor/libeditor/TextEditRules.h b/editor/libeditor/TextEditRules.h index 6d4915f15..208e14d23 100644 --- a/editor/libeditor/TextEditRules.h +++ b/editor/libeditor/TextEditRules.h @@ -66,7 +66,7 @@ public: bool* aCancel, bool* aHandled) override; NS_IMETHOD DidDoAction(Selection* aSelection, RulesInfo* aInfo, nsresult aResult) override; - NS_IMETHOD DocumentIsEmpty(bool* aDocumentIsEmpty) override; + NS_IMETHOD_(bool) DocumentIsEmpty() override; NS_IMETHOD DocumentModified() override; protected: diff --git a/editor/libeditor/TextEditor.cpp b/editor/libeditor/TextEditor.cpp index 1e855d769..c3cfa4a72 100644 --- a/editor/libeditor/TextEditor.cpp +++ b/editor/libeditor/TextEditor.cpp @@ -864,7 +864,7 @@ TextEditor::UpdateIMEComposition(WidgetCompositionEvent* aCompositionChangeEvent // of NotifiyEditorObservers(eNotifyEditorObserversOfEnd) or // NotifiyEditorObservers(eNotifyEditorObserversOfCancel) which notifies // TextComposition of a selection change. - MOZ_ASSERT(!mPlaceHolderBatch, + MOZ_ASSERT(!mPlaceholderBatch, "UpdateIMEComposition() must be called without place holder batch"); TextComposition::CompositionChangeEventHandlingMarker compositionChangeEventHandlingMarker(mComposition, aCompositionChangeEvent); @@ -913,7 +913,8 @@ TextEditor::GetDocumentIsEmpty(bool* aDocumentIsEmpty) // Protect the edit rules object from dying nsCOMPtr<nsIEditRules> rules(mRules); - return rules->DocumentIsEmpty(aDocumentIsEmpty); + *aDocumentIsEmpty = rules->DocumentIsEmpty(); + return NS_OK; } NS_IMETHODIMP @@ -1237,7 +1238,7 @@ TextEditor::GetAndInitDocEncoder(const nsAString& aFormatType, nsCOMPtr<nsIDocumentEncoder> docEncoder (do_CreateInstance(formatType.get(), &rv)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr<nsIDOMDocument> domDoc = do_QueryReferent(mDocWeak); + nsCOMPtr<nsIDOMDocument> domDoc = GetDOMDocument(); NS_ASSERTION(domDoc, "Need a document"); rv = docEncoder->Init(domDoc, aFormatType, aFlags); @@ -1580,8 +1581,7 @@ TextEditor::SelectEntireDocument(Selection* aSelection) nsCOMPtr<nsIEditRules> rules(mRules); // is doc empty? - bool bDocIsEmpty; - if (NS_SUCCEEDED(rules->DocumentIsEmpty(&bDocIsEmpty)) && bDocIsEmpty) { + if (rules->DocumentIsEmpty()) { // get root node nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot()); NS_ENSURE_TRUE(rootElement, NS_ERROR_FAILURE); diff --git a/editor/libeditor/TypeInState.cpp b/editor/libeditor/TypeInState.cpp index ce43e5e4d..840139fee 100644 --- a/editor/libeditor/TypeInState.cpp +++ b/editor/libeditor/TypeInState.cpp @@ -193,7 +193,7 @@ TypeInState::ClearProp(nsIAtom* aProp, * TakeClearProperty() hands back next property item on the clear list. * Caller assumes ownership of PropItem and must delete it. */ -PropItem* +UniquePtr<PropItem> TypeInState::TakeClearProperty() { size_t count = mClearedArray.Length(); @@ -204,14 +204,14 @@ TypeInState::TakeClearProperty() --count; // indices are zero based PropItem* propItem = mClearedArray[count]; mClearedArray.RemoveElementAt(count); - return propItem; + return UniquePtr<PropItem>(propItem); } /** * TakeSetProperty() hands back next poroperty item on the set list. * Caller assumes ownership of PropItem and must delete it. */ -PropItem* +UniquePtr<PropItem> TypeInState::TakeSetProperty() { size_t count = mSetArray.Length(); @@ -221,7 +221,7 @@ TypeInState::TakeSetProperty() count--; // indices are zero based PropItem* propItem = mSetArray[count]; mSetArray.RemoveElementAt(count); - return propItem; + return UniquePtr<PropItem>(propItem); } /** diff --git a/editor/libeditor/TypeInState.h b/editor/libeditor/TypeInState.h index 540b2d9c1..e1b949508 100644 --- a/editor/libeditor/TypeInState.h +++ b/editor/libeditor/TypeInState.h @@ -6,6 +6,7 @@ #ifndef TypeInState_h #define TypeInState_h +#include "mozilla/UniquePtr.h" #include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" #include "nsISelectionListener.h" @@ -63,13 +64,13 @@ public: * TakeClearProperty() hands back next property item on the clear list. * Caller assumes ownership of PropItem and must delete it. */ - PropItem* TakeClearProperty(); + UniquePtr<PropItem> TakeClearProperty(); /** * TakeSetProperty() hands back next property item on the set list. * Caller assumes ownership of PropItem and must delete it. */ - PropItem* TakeSetProperty(); + UniquePtr<PropItem> TakeSetProperty(); /** * TakeRelativeFontSize() hands back relative font value, which is then diff --git a/editor/libeditor/WSRunObject.cpp b/editor/libeditor/WSRunObject.cpp index 39ac3fee8..0748f09e5 100644 --- a/editor/libeditor/WSRunObject.cpp +++ b/editor/libeditor/WSRunObject.cpp @@ -1315,7 +1315,7 @@ WSRunObject::DeleteChars(nsINode* aStartNode, if (!range) { range = new nsRange(aStartNode); nsresult rv = - range->Set(aStartNode, aStartOffset, aEndNode, aEndOffset); + range->SetStartAndEnd(aStartNode, aStartOffset, aEndNode, aEndOffset); NS_ENSURE_SUCCESS(rv, rv); } bool nodeBefore, nodeAfter; diff --git a/editor/libeditor/crashtests/1348851.html b/editor/libeditor/crashtests/1348851.html new file mode 100644 index 000000000..d618f049e --- /dev/null +++ b/editor/libeditor/crashtests/1348851.html @@ -0,0 +1,19 @@ +<!DOCTYPE> +<html> +<head> +<meta charset="UTF-8"> +<script> +function boom(){ + document.designMode = "on"; + document.execCommand("insertlinebreak"); + document.designMode = "off"; + document.designMode = "on"; + document.execCommand("insertunorderedlist"); +} +addEventListener("DOMContentLoaded", boom); +</script> +</head> +<body style="display:flex;"> +<!--comment--> +</body> +</html> diff --git a/editor/libeditor/crashtests/crashtests.list b/editor/libeditor/crashtests/crashtests.list index 3fbc6b196..7b1c57dbf 100644 --- a/editor/libeditor/crashtests/crashtests.list +++ b/editor/libeditor/crashtests/crashtests.list @@ -68,4 +68,5 @@ load 1158452.html load 1158651.html load 1244894.xhtml load 1272490.html +load 1348851.html load 1317704.html diff --git a/editor/libeditor/nsIAbsorbingTransaction.h b/editor/libeditor/nsIAbsorbingTransaction.h index e22caed4a..06329f3d4 100644 --- a/editor/libeditor/nsIAbsorbingTransaction.h +++ b/editor/libeditor/nsIAbsorbingTransaction.h @@ -23,6 +23,7 @@ class nsIAtom; namespace mozilla { class EditorBase; +class PlaceholderTransaction; class SelectionState; } // namespace mozilla @@ -35,9 +36,6 @@ public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_IABSORBINGTRANSACTION_IID) - NS_IMETHOD Init(nsIAtom* aName, mozilla::SelectionState* aSelState, - mozilla::EditorBase* aEditorBase) = 0; - NS_IMETHOD EndPlaceHolderBatch()=0; NS_IMETHOD GetTxnName(nsIAtom **aName)=0; @@ -48,6 +46,9 @@ public: NS_IMETHOD ForwardEndBatchTo(nsIAbsorbingTransaction *aForwardingAddress)=0; NS_IMETHOD Commit()=0; + + NS_IMETHOD_(mozilla::PlaceholderTransaction*) + AsPlaceholderTransaction() = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIAbsorbingTransaction, diff --git a/editor/libeditor/nsIEditRules.h b/editor/libeditor/nsIEditRules.h index b186895ae..a493145cc 100644 --- a/editor/libeditor/nsIEditRules.h +++ b/editor/libeditor/nsIEditRules.h @@ -59,7 +59,7 @@ public: bool* aHandled) = 0; NS_IMETHOD DidDoAction(mozilla::dom::Selection* aSelection, mozilla::RulesInfo* aInfo, nsresult aResult) = 0; - NS_IMETHOD DocumentIsEmpty(bool* aDocumentIsEmpty) = 0; + NS_IMETHOD_(bool) DocumentIsEmpty() = 0; NS_IMETHOD DocumentModified() = 0; }; diff --git a/editor/txtsvc/nsFilteredContentIterator.cpp b/editor/txtsvc/nsFilteredContentIterator.cpp index c8ea734c4..cccfb90ad 100644 --- a/editor/txtsvc/nsFilteredContentIterator.cpp +++ b/editor/txtsvc/nsFilteredContentIterator.cpp @@ -240,13 +240,15 @@ ContentIsInTraversalRange(nsRange* aRange, nsIDOMNode* aNextNode, bool aIsPreMod nsCOMPtr<nsIDOMNode> sNode; nsCOMPtr<nsIDOMNode> eNode; - int32_t sOffset; - int32_t eOffset; + uint32_t sOffset; + uint32_t eOffset; aRange->GetStartContainer(getter_AddRefs(sNode)); aRange->GetStartOffset(&sOffset); aRange->GetEndContainer(getter_AddRefs(eNode)); aRange->GetEndOffset(&eOffset); - return ContentIsInTraversalRange(content, aIsPreMode, sNode, sOffset, eNode, eOffset); + return ContentIsInTraversalRange(content, aIsPreMode, + sNode, static_cast<int32_t>(sOffset), + eNode, static_cast<int32_t>(eOffset)); } //------------------------------------------------------------ diff --git a/editor/txtsvc/nsTextServicesDocument.cpp b/editor/txtsvc/nsTextServicesDocument.cpp index e0c779683..23a1bec3f 100644 --- a/editor/txtsvc/nsTextServicesDocument.cpp +++ b/editor/txtsvc/nsTextServicesDocument.cpp @@ -406,11 +406,13 @@ nsTextServicesDocument::ExpandRangeToWordBoundaries(nsIDOMRange *aRange) // Now adjust the range so that it uses our new // end points. - - rv = range->SetEnd(rngEndNode, rngEndOffset); - NS_ENSURE_SUCCESS(rv, rv); - - return range->SetStart(rngStartNode, rngStartOffset); + nsCOMPtr<nsINode> startNode = do_QueryInterface(rngStartNode); + nsCOMPtr<nsINode> endNode = do_QueryInterface(rngEndNode); + rv = range->SetStartAndEnd(startNode, rngStartOffset, endNode, rngEndOffset); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + return NS_OK; } NS_IMETHODIMP @@ -508,7 +510,6 @@ nsTextServicesDocument::LastSelectedBlock(TSDBlockSelectionStatus *aSelStatus, nsCOMPtr<nsIContentIterator> iter; RefPtr<nsRange> range; nsCOMPtr<nsIDOMNode> parent; - int32_t rangeCount, offset; if (isCollapsed) { // We have a caret. Check if the caret is in a text node. @@ -535,6 +536,7 @@ nsTextServicesDocument::LastSelectedBlock(TSDBlockSelectionStatus *aSelStatus, return NS_ERROR_FAILURE; } + uint32_t offset; rv = range->GetStartOffset(&offset); if (NS_FAILED(rv)) { @@ -594,8 +596,9 @@ nsTextServicesDocument::LastSelectedBlock(TSDBlockSelectionStatus *aSelStatus, // position to the end of the document, then walk forwards // till you find a text node, then find the beginning of it's block. - rv = CreateDocumentContentRootToNodeOffsetRange(parent, offset, false, - getter_AddRefs(range)); + rv = CreateDocumentContentRootToNodeOffsetRange( + parent, static_cast<int32_t>(offset), false, + getter_AddRefs(range)); if (NS_FAILED(rv)) { UNLOCK_DOC(this); @@ -688,6 +691,7 @@ nsTextServicesDocument::LastSelectedBlock(TSDBlockSelectionStatus *aSelStatus, // beginning of its text block, and make it the current // block. + int32_t rangeCount; rv = selection->GetRangeCount(&rangeCount); if (NS_FAILED(rv)) { @@ -795,6 +799,7 @@ nsTextServicesDocument::LastSelectedBlock(TSDBlockSelectionStatus *aSelStatus, return NS_ERROR_FAILURE; } + uint32_t offset; rv = range->GetEndOffset(&offset); if (NS_FAILED(rv)) { @@ -802,8 +807,8 @@ nsTextServicesDocument::LastSelectedBlock(TSDBlockSelectionStatus *aSelStatus, return rv; } - rv = CreateDocumentContentRootToNodeOffsetRange(parent, offset, false, - getter_AddRefs(range)); + rv = CreateDocumentContentRootToNodeOffsetRange( + parent, static_cast<int32_t>(offset), false, getter_AddRefs(range)); if (NS_FAILED(rv)) { UNLOCK_DOC(this); @@ -2375,14 +2380,16 @@ nsTextServicesDocument::GetCollapsedSelection(nsITextServicesDocument::TSDBlockS nsCOMPtr<nsINode> parent = do_QueryInterface(domParent); MOZ_ASSERT(parent); - int32_t offset; + uint32_t offset; rv = range->GetStartOffset(&offset); NS_ENSURE_SUCCESS(rv, rv); int32_t e1s1 = nsContentUtils::ComparePoints(eStart->mNode, eStartOffset, - domParent, offset); + domParent, + static_cast<int32_t>(offset)); int32_t e2s1 = nsContentUtils::ComparePoints(eEnd->mNode, eEndOffset, - domParent, offset); + domParent, + static_cast<int32_t>(offset)); if (e1s1 > 0 || e2s1 < 0) { // We're done if the caret is outside the current text block. @@ -2399,8 +2406,8 @@ nsTextServicesDocument::GetCollapsedSelection(nsITextServicesDocument::TSDBlockS NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE); if (entry->mNode == domParent.get() && - entry->mNodeOffset <= offset && - offset <= entry->mNodeOffset + entry->mLength) { + entry->mNodeOffset <= static_cast<int32_t>(offset) && + static_cast<int32_t>(offset) <= entry->mNodeOffset + entry->mLength) { *aSelStatus = nsITextServicesDocument::eBlockContains; *aSelOffset = entry->mStrOffset + (offset - entry->mNodeOffset); *aSelLength = 0; @@ -2438,7 +2445,7 @@ nsTextServicesDocument::GetCollapsedSelection(nsITextServicesDocument::TSDBlockS // If the parent has children, position the iterator // on the child that is to the left of the offset. - uint32_t childIndex = (uint32_t)offset; + uint32_t childIndex = offset; if (childIndex > 0) { uint32_t numChildren = parent->GetChildCount(); @@ -2524,8 +2531,8 @@ nsTextServicesDocument::GetCollapsedSelection(nsITextServicesDocument::TSDBlockS NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE); if (entry->mNode == node->AsDOMNode() && - entry->mNodeOffset <= offset && - offset <= entry->mNodeOffset + entry->mLength) { + entry->mNodeOffset <= static_cast<int32_t>(offset) && + static_cast<int32_t>(offset) <= entry->mNodeOffset + entry->mLength) { *aSelStatus = nsITextServicesDocument::eBlockContains; *aSelOffset = entry->mStrOffset + (offset - entry->mNodeOffset); *aSelLength = 0; @@ -2815,9 +2822,12 @@ nsTextServicesDocument::GetRangeEndPoints(nsRange* aRange, NS_ENSURE_TRUE(aStartParent, NS_ERROR_FAILURE); - rv = aRange->GetStartOffset(aStartOffset); - - NS_ENSURE_SUCCESS(rv, rv); + uint32_t offset; + rv = aRange->GetStartOffset(&offset); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + *aStartOffset = static_cast<int32_t>(offset); rv = aRange->GetEndContainer(aEndParent); @@ -2825,7 +2835,12 @@ nsTextServicesDocument::GetRangeEndPoints(nsRange* aRange, NS_ENSURE_TRUE(aEndParent, NS_ERROR_FAILURE); - return aRange->GetEndOffset(aEndOffset); + rv = aRange->GetEndOffset(&offset); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + *aEndOffset = static_cast<int32_t>(offset); + return NS_OK; } nsresult |