diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h index 3c8ed5c24430..48ed83682fa7 100644 --- a/editor/libeditor/HTMLEditor.h +++ b/editor/libeditor/HTMLEditor.h @@ -4616,6 +4616,8 @@ class HTMLEditor final : public TextEditor, EditorDOMPoint GetNewCaretPointAfterInsertingHTML( const EditorDOMPoint& lastInsertedPoint) const; + class HTMLWithContextInserter; + /** * This function is used to insert a string of HTML input optionally with some * context information into the editable field. The HTML input either comes diff --git a/editor/libeditor/HTMLEditorDataTransfer.cpp b/editor/libeditor/HTMLEditorDataTransfer.cpp index aabb9d04971e..dc3b34af5110 100644 --- a/editor/libeditor/HTMLEditorDataTransfer.cpp +++ b/editor/libeditor/HTMLEditorDataTransfer.cpp @@ -200,6 +200,26 @@ nsresult HTMLEditor::InsertHTMLAsAction(const nsAString& aInString, return EditorBase::ToGenericNSResult(rv); } +class MOZ_STACK_CLASS HTMLEditor::HTMLWithContextInserter final { + public: + MOZ_CAN_RUN_SCRIPT explicit HTMLWithContextInserter(HTMLEditor& aHTMLEditor) + : mHTMLEditor(aHTMLEditor) {} + + HTMLWithContextInserter() = delete; + HTMLWithContextInserter(const HTMLWithContextInserter&) = delete; + HTMLWithContextInserter(HTMLWithContextInserter&&) = delete; + + MOZ_CAN_RUN_SCRIPT nsresult Run(const nsAString& aInputString, + const nsAString& aContextStr, + const nsAString& aInfoStr, + const EditorDOMPoint& aPointToInsert, + bool aDoDeleteSelection, bool aTrustedInput, + bool aClearStyle); + + private: + HTMLEditor& mHTMLEditor; +}; + EditorDOMPoint HTMLEditor::GetNewCaretPointAfterInsertingHTML( const EditorDOMPoint& aLastInsertedPoint) const { EditorDOMPoint pointToPutCaret; @@ -277,23 +297,36 @@ EditorDOMPoint HTMLEditor::GetNewCaretPointAfterInsertingHTML( return pointToPutCaret; } + nsresult HTMLEditor::DoInsertHTMLWithContext( const nsAString& aInputString, const nsAString& aContextStr, const nsAString& aInfoStr, const nsAString& aFlavor, Document* aSourceDoc, const EditorDOMPoint& aPointToInsert, bool aDoDeleteSelection, bool aTrustedInput, bool aClearStyle) { - MOZ_ASSERT(IsEditActionDataAvailable()); + HTMLWithContextInserter htmlWithContextInserter(*this); - if (NS_WARN_IF(!mInitSucceeded)) { + return htmlWithContextInserter.Run(aInputString, aContextStr, aInfoStr, + aPointToInsert, aDoDeleteSelection, + aTrustedInput, aClearStyle); +} + +nsresult HTMLEditor::HTMLWithContextInserter::Run( + const nsAString& aInputString, const nsAString& aContextStr, + const nsAString& aInfoStr, const EditorDOMPoint& aPointToInsert, + bool aDoDeleteSelection, bool aTrustedInput, bool aClearStyle) { + MOZ_ASSERT(mHTMLEditor.IsEditActionDataAvailable()); + + if (NS_WARN_IF(!mHTMLEditor.mInitSucceeded)) { return NS_ERROR_NOT_INITIALIZED; } // force IME commit; set up rules sniffing and batching - CommitComposition(); - AutoPlaceholderBatch treatAsOneTransaction(*this); + mHTMLEditor.CommitComposition(); + AutoPlaceholderBatch treatAsOneTransaction(mHTMLEditor); IgnoredErrorResult ignoredError; AutoEditSubActionNotifier startToHandleEditSubAction( - *this, EditSubAction::ePasteHTMLContent, nsIEditor::eNext, ignoredError); + MOZ_KnownLive(mHTMLEditor), EditSubAction::ePasteHTMLContent, + nsIEditor::eNext, ignoredError); if (NS_WARN_IF(ignoredError.ErrorCodeIs(NS_ERROR_EDITOR_DESTROYED))) { return ignoredError.StealNSResult(); } @@ -306,7 +339,7 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( nsCOMPtr fragmentAsNode, streamStartParent, streamEndParent; int32_t streamStartOffset = 0, streamEndOffset = 0; - nsresult rv = CreateDOMFragmentFromPaste( + nsresult rv = mHTMLEditor.CreateDOMFragmentFromPaste( aInputString, aContextStr, aInfoStr, address_of(fragmentAsNode), address_of(streamStartParent), address_of(streamEndParent), &streamStartOffset, &streamEndOffset, aTrustedInput); @@ -322,7 +355,8 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( // scenarios where we are dropping in an editor (and may want to delete // the selection before collapsing the selection in the new destination) if (aPointToInsert.IsSet()) { - rv = PrepareToInsertContent(aPointToInsert, aDoDeleteSelection); + rv = MOZ_KnownLive(mHTMLEditor) + .PrepareToInsertContent(aPointToInsert, aDoDeleteSelection); if (NS_FAILED(rv)) { NS_WARNING("HTMLEditor::PrepareToInsertContent() failed"); return rv; @@ -357,7 +391,8 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( // XXX What will this do? We've already called DeleteSelectionAsSubAtion() // above if insertion point is specified. if (aDoDeleteSelection) { - nsresult rv = DeleteSelectionAsSubAction(eNone, eStrip); + nsresult rv = + MOZ_KnownLive(mHTMLEditor).DeleteSelectionAsSubAction(eNone, eStrip); if (NS_FAILED(rv)) { NS_WARNING( "EditorBase::DeleteSelectionAsSubAction(eNone, eStrip) failed"); @@ -370,7 +405,8 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( // Are there any table elements in the list? // check for table cell selection mode bool cellSelectionMode = false; - RefPtr cellElement = GetFirstSelectedTableCellElement(ignoredError); + RefPtr cellElement = + mHTMLEditor.GetFirstSelectedTableCellElement(ignoredError); if (cellElement) { cellSelectionMode = true; } @@ -387,7 +423,7 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( } if (!cellSelectionMode) { - rv = DeleteSelectionAndPrepareToCreateNode(); + rv = MOZ_KnownLive(mHTMLEditor).DeleteSelectionAndPrepareToCreateNode(); if (NS_FAILED(rv)) { NS_WARNING("HTMLEditor::DeleteSelectionAndPrepareToCreateNode() failed"); return rv; @@ -395,8 +431,11 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( if (aClearStyle) { // pasting does not inherit local inline styles - EditResult result = ClearStyleAt( - EditorDOMPoint(SelectionRefPtr()->AnchorRef()), nullptr, nullptr); + EditResult result = + MOZ_KnownLive(mHTMLEditor) + .ClearStyleAt( + EditorDOMPoint(mHTMLEditor.SelectionRefPtr()->AnchorRef()), + nullptr, nullptr); if (result.Failed()) { NS_WARNING("HTMLEditor::ClearStyleAt() failed"); return result.Rv(); @@ -409,8 +448,8 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( // Save current selection since DeleteTableCellWithTransaction() perturbs // it. { - AutoSelectionRestorer restoreSelectionLater(*this); - rv = DeleteTableCellWithTransaction(1); + AutoSelectionRestorer restoreSelectionLater(mHTMLEditor); + rv = MOZ_KnownLive(mHTMLEditor).DeleteTableCellWithTransaction(1); if (NS_FAILED(rv)) { NS_WARNING("HTMLEditor::DeleteTableCellWithTransaction(1) failed"); return rv; @@ -418,26 +457,26 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( } // collapse selection to beginning of deleted table content IgnoredErrorResult ignoredError; - SelectionRefPtr()->CollapseToStart(ignoredError); + mHTMLEditor.SelectionRefPtr()->CollapseToStart(ignoredError); NS_WARNING_ASSERTION(!ignoredError.Failed(), "Selection::Collapse() failed, but ignored"); } // XXX Why don't we test this first? - if (IsReadonly()) { + if (mHTMLEditor.IsReadonly()) { return NS_OK; } - EditActionResult result = CanHandleHTMLEditSubAction(); + EditActionResult result = mHTMLEditor.CanHandleHTMLEditSubAction(); if (result.Failed() || result.Canceled()) { NS_WARNING_ASSERTION(result.Succeeded(), "HTMLEditor::CanHandleHTMLEditSubAction() failed"); return result.Rv(); } - UndefineCaretBidiLevel(); + mHTMLEditor.UndefineCaretBidiLevel(); - rv = EnsureNoPaddingBRElementForEmptyEditor(); + rv = MOZ_KnownLive(mHTMLEditor).EnsureNoPaddingBRElementForEmptyEditor(); if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) { return NS_ERROR_EDITOR_DESTROYED; } @@ -445,8 +484,9 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( "EditorBase::EnsureNoPaddingBRElementForEmptyEditor() " "failed, but ignored"); - if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) { - nsresult rv = EnsureCaretNotAfterPaddingBRElement(); + if (NS_SUCCEEDED(rv) && mHTMLEditor.SelectionRefPtr()->IsCollapsed()) { + nsresult rv = + MOZ_KnownLive(mHTMLEditor).EnsureCaretNotAfterPaddingBRElement(); if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) { return NS_ERROR_EDITOR_DESTROYED; } @@ -454,7 +494,7 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( "HTMLEditor::EnsureCaretNotAfterPaddingBRElement() " "failed, but ignored"); if (NS_SUCCEEDED(rv)) { - nsresult rv = PrepareInlineStylesForCaret(); + nsresult rv = MOZ_KnownLive(mHTMLEditor).PrepareInlineStylesForCaret(); if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) { return NS_ERROR_EDITOR_DESTROYED; } @@ -465,9 +505,9 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( } // Adjust position based on the first node we are going to insert. - EditorDOMPoint pointToInsert = - GetBetterInsertionPointFor(arrayOfTopMostChildContents[0], - EditorBase::GetStartPoint(*SelectionRefPtr())); + EditorDOMPoint pointToInsert = mHTMLEditor.GetBetterInsertionPointFor( + arrayOfTopMostChildContents[0], + EditorBase::GetStartPoint(*mHTMLEditor.SelectionRefPtr())); if (!pointToInsert.IsSet()) { NS_WARNING("HTMLEditor::GetBetterInsertionPointFor() failed"); return NS_ERROR_FAILURE; @@ -476,14 +516,16 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( // Remove invisible `
` element at the point because if there is a `
` // element at end of what we paste, it will make the existing invisible // `
` element visible. - WSRunScanner wsRunScannerAtInsertionPoint(this, pointToInsert); + WSRunScanner wsRunScannerAtInsertionPoint(&mHTMLEditor, pointToInsert); if (wsRunScannerAtInsertionPoint.GetEndReasonContent() && wsRunScannerAtInsertionPoint.GetEndReasonContent()->IsHTMLElement( nsGkAtoms::br) && - !IsVisibleBRElement(wsRunScannerAtInsertionPoint.GetEndReasonContent())) { + !mHTMLEditor.IsVisibleBRElement( + wsRunScannerAtInsertionPoint.GetEndReasonContent())) { AutoEditorDOMPointChildInvalidator lockOffset(pointToInsert); - nsresult rv = DeleteNodeWithTransaction( - MOZ_KnownLive(*wsRunScannerAtInsertionPoint.GetEndReasonContent())); + nsresult rv = MOZ_KnownLive(mHTMLEditor) + .DeleteNodeWithTransaction(MOZ_KnownLive( + *wsRunScannerAtInsertionPoint.GetEndReasonContent())); if (NS_FAILED(rv)) { NS_WARNING("HTMLEditor::DeleteNodeWithTransaction() failed"); return rv; @@ -491,12 +533,14 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( } const bool insertionPointWasInLink = - !!GetLinkElement(pointToInsert.GetContainer()); + !!HTMLEditor::GetLinkElement(pointToInsert.GetContainer()); if (pointToInsert.IsInTextNode()) { - SplitNodeResult splitNodeResult = SplitNodeDeepWithTransaction( - MOZ_KnownLive(*pointToInsert.GetContainerAsContent()), pointToInsert, - SplitAtEdges::eAllowToCreateEmptyContainer); + SplitNodeResult splitNodeResult = + MOZ_KnownLive(mHTMLEditor) + .SplitNodeDeepWithTransaction( + MOZ_KnownLive(*pointToInsert.GetContainerAsContent()), + pointToInsert, SplitAtEdges::eAllowToCreateEmptyContainer); if (splitNodeResult.Failed()) { NS_WARNING("HTMLEditor::SplitNodeDeepWithTransaction() failed"); return splitNodeResult.Rv(); @@ -559,9 +603,10 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( for (nsCOMPtr firstChild = content->GetFirstChild(); firstChild; firstChild = content->GetFirstChild()) { EditorDOMPoint insertedPoint = - InsertNodeIntoProperAncestorWithTransaction( - *firstChild, pointToInsert, - SplitAtEdges::eDoNotCreateEmptyContainer); + MOZ_KnownLive(mHTMLEditor) + .InsertNodeIntoProperAncestorWithTransaction( + *firstChild, pointToInsert, + SplitAtEdges::eDoNotCreateEmptyContainer); if (!insertedPoint.IsSet()) { NS_WARNING( "HTMLEditor::InsertNodeIntoProperAncestorWithTransaction(" @@ -596,24 +641,27 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( // is not proper child of the parent element, or current node // is a list element. if (HTMLEditUtils::IsListItem(pointToInsert.GetContainer()) && - IsEmptyNode(*pointToInsert.GetContainer(), true)) { + mHTMLEditor.IsEmptyNode(*pointToInsert.GetContainer(), true)) { NS_WARNING_ASSERTION(pointToInsert.GetContainerParent(), "Insertion point is out of the DOM tree"); if (pointToInsert.GetContainerParent()) { pointToInsert.Set(pointToInsert.GetContainer()); MOZ_ASSERT(pointToInsert.IsSet()); AutoEditorDOMPointChildInvalidator lockOffset(pointToInsert); - DebugOnly rvIgnored = DeleteNodeWithTransaction( - MOZ_KnownLive(*pointToInsert.GetChild())); + DebugOnly rvIgnored = + MOZ_KnownLive(mHTMLEditor) + .DeleteNodeWithTransaction( + MOZ_KnownLive(*pointToInsert.GetChild())); NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored), "HTMLEditor::DeleteNodeWithTransaction() " "failed, but ignored"); } } EditorDOMPoint insertedPoint = - InsertNodeIntoProperAncestorWithTransaction( - *firstChild, pointToInsert, - SplitAtEdges::eDoNotCreateEmptyContainer); + MOZ_KnownLive(mHTMLEditor) + .InsertNodeIntoProperAncestorWithTransaction( + *firstChild, pointToInsert, + SplitAtEdges::eDoNotCreateEmptyContainer); if (!insertedPoint.IsSet()) { NS_WARNING( "HTMLEditor::InsertNodeIntoProperAncestorWithTransaction(" @@ -649,9 +697,10 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( for (nsCOMPtr firstChild = content->GetFirstChild(); firstChild; firstChild = content->GetFirstChild()) { EditorDOMPoint insertedPoint = - InsertNodeIntoProperAncestorWithTransaction( - *firstChild, pointToInsert, - SplitAtEdges::eDoNotCreateEmptyContainer); + MOZ_KnownLive(mHTMLEditor) + .InsertNodeIntoProperAncestorWithTransaction( + *firstChild, pointToInsert, + SplitAtEdges::eDoNotCreateEmptyContainer); if (!insertedPoint.IsSet()) { NS_WARNING( "HTMLEditor::InsertNodeIntoProperAncestorWithTransaction(" @@ -675,9 +724,10 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( // MOZ_KnownLive because 'arrayOfTopMostChildContents' is guaranteed to // keep it alive. EditorDOMPoint insertedPoint = - InsertNodeIntoProperAncestorWithTransaction( - MOZ_KnownLive(content), pointToInsert, - SplitAtEdges::eDoNotCreateEmptyContainer); + MOZ_KnownLive(mHTMLEditor) + .InsertNodeIntoProperAncestorWithTransaction( + MOZ_KnownLive(content), pointToInsert, + SplitAtEdges::eDoNotCreateEmptyContainer); NS_WARNING_ASSERTION( insertedPoint.IsSet(), "HTMLEditor::InsertNodeIntoProperAncestorWithTransaction(" @@ -703,9 +753,10 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( } OwningNonNull oldParentContent( *childContent->GetParent()); - insertedPoint = InsertNodeIntoProperAncestorWithTransaction( - oldParentContent, pointToInsert, - SplitAtEdges::eDoNotCreateEmptyContainer); + insertedPoint = MOZ_KnownLive(mHTMLEditor) + .InsertNodeIntoProperAncestorWithTransaction( + oldParentContent, pointToInsert, + SplitAtEdges::eDoNotCreateEmptyContainer); NS_WARNING_ASSERTION( insertedPoint.IsSet(), "HTMLEditor::InsertNodeIntoProperAncestorWithTransaction(" @@ -740,9 +791,9 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( } const EditorDOMPoint pointToPutCaret = - GetNewCaretPointAfterInsertingHTML(lastInsertedPoint); + mHTMLEditor.GetNewCaretPointAfterInsertingHTML(lastInsertedPoint); // Now collapse the selection to the end of what we just inserted. - rv = CollapseSelectionTo(pointToPutCaret); + rv = MOZ_KnownLive(mHTMLEditor).CollapseSelectionTo(pointToPutCaret); if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) { return NS_ERROR_EDITOR_DESTROYED; } @@ -763,15 +814,19 @@ nsresult HTMLEditor::DoInsertHTMLWithContext( // above just placed selection inside that. So we need to split it instead. // XXX Sounds like that it's not really expensive comparing with the reason // to use SplitNodeDeepWithTransaction() here. - SplitNodeResult splitLinkResult = SplitNodeDeepWithTransaction( - *linkElement, pointToPutCaret, SplitAtEdges::eDoNotCreateEmptyContainer); + SplitNodeResult splitLinkResult = + MOZ_KnownLive(mHTMLEditor) + .SplitNodeDeepWithTransaction( + *linkElement, pointToPutCaret, + SplitAtEdges::eDoNotCreateEmptyContainer); NS_WARNING_ASSERTION( splitLinkResult.Succeeded(), "HTMLEditor::SplitNodeDeepWithTransaction() failed, but ignored"); if (splitLinkResult.GetPreviousNode()) { EditorRawDOMPoint afterLeftLink(splitLinkResult.GetPreviousNode()); if (afterLeftLink.AdvanceOffset()) { - nsresult rv = CollapseSelectionTo(afterLeftLink); + nsresult rv = + MOZ_KnownLive(mHTMLEditor).CollapseSelectionTo(afterLeftLink); if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) { return NS_ERROR_EDITOR_DESTROYED; }