From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- editor/libeditor/EditorBase.cpp | 7065 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 7065 insertions(+) create mode 100644 editor/libeditor/EditorBase.cpp (limited to 'editor/libeditor/EditorBase.cpp') diff --git a/editor/libeditor/EditorBase.cpp b/editor/libeditor/EditorBase.cpp new file mode 100644 index 0000000000..0f864a4bb2 --- /dev/null +++ b/editor/libeditor/EditorBase.cpp @@ -0,0 +1,7065 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "EditorBase.h" + +#include // for nullptr, stdout +#include // for strcmp + +#include "AutoRangeArray.h" // for AutoRangeArray +#include "ChangeAttributeTransaction.h" +#include "CompositionTransaction.h" +#include "DeleteContentTransactionBase.h" +#include "DeleteMultipleRangesTransaction.h" +#include "DeleteNodeTransaction.h" +#include "DeleteRangeTransaction.h" +#include "DeleteTextTransaction.h" +#include "EditAction.h" // for EditSubAction +#include "EditorDOMPoint.h" // for EditorDOMPoint +#include "EditorUtils.h" // for various helper classes. +#include "EditTransactionBase.h" // for EditTransactionBase +#include "EditorEventListener.h" // for EditorEventListener +#include "HTMLEditor.h" // for HTMLEditor +#include "HTMLEditorInlines.h" +#include "HTMLEditUtils.h" // for HTMLEditUtils +#include "InsertNodeTransaction.h" // for InsertNodeTransaction +#include "InsertTextTransaction.h" // for InsertTextTransaction +#include "JoinNodesTransaction.h" // for JoinNodesTransaction +#include "PlaceholderTransaction.h" // for PlaceholderTransaction +#include "SplitNodeTransaction.h" // for SplitNodeTransaction +#include "TextEditor.h" // for TextEditor + +#include "ErrorList.h" +#include "gfxFontUtils.h" // for gfxFontUtils +#include "mozilla/Assertions.h" +#include "mozilla/intl/BidiEmbeddingLevel.h" +#include "mozilla/BasePrincipal.h" // for BasePrincipal +#include "mozilla/CheckedInt.h" // for CheckedInt +#include "mozilla/ComposerCommandsUpdater.h" // for ComposerCommandsUpdater +#include "mozilla/ContentEvents.h" // for InternalClipboardEvent +#include "mozilla/DebugOnly.h" // for DebugOnly +#include "mozilla/EditorSpellCheck.h" // for EditorSpellCheck +#include "mozilla/Encoding.h" // for Encoding (used in Document::GetDocumentCharacterSet) +#include "mozilla/EventDispatcher.h" // for EventChainPreVisitor, etc. +#include "mozilla/FlushType.h" // for FlushType::Frames +#include "mozilla/IMEContentObserver.h" // for IMEContentObserver +#include "mozilla/IMEStateManager.h" // for IMEStateManager +#include "mozilla/InputEventOptions.h" // for InputEventOptions +#include "mozilla/IntegerRange.h" // for IntegerRange +#include "mozilla/InternalMutationEvent.h" // for NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED +#include "mozilla/mozalloc.h" // for operator new, etc. +#include "mozilla/mozInlineSpellChecker.h" // for mozInlineSpellChecker +#include "mozilla/mozSpellChecker.h" // for mozSpellChecker +#include "mozilla/Preferences.h" // for Preferences +#include "mozilla/PresShell.h" // for PresShell +#include "mozilla/RangeBoundary.h" // for RawRangeBoundary, RangeBoundary +#include "mozilla/Services.h" // for GetObserverService +#include "mozilla/StaticPrefs_bidi.h" // for StaticPrefs::bidi_* +#include "mozilla/StaticPrefs_dom.h" // for StaticPrefs::dom_* +#include "mozilla/StaticPrefs_editor.h" // for StaticPrefs::editor_* +#include "mozilla/StaticPrefs_layout.h" // for StaticPrefs::layout_* +#include "mozilla/TextComposition.h" // for TextComposition +#include "mozilla/TextControlElement.h" // for TextControlElement +#include "mozilla/TextInputListener.h" // for TextInputListener +#include "mozilla/TextServicesDocument.h" // for TextServicesDocument +#include "mozilla/TextEvents.h" +#include "mozilla/TransactionManager.h" // for TransactionManager +#include "mozilla/dom/AbstractRange.h" // for AbstractRange +#include "mozilla/dom/Attr.h" // for Attr +#include "mozilla/dom/BrowsingContext.h" // for BrowsingContext +#include "mozilla/dom/CharacterData.h" // for CharacterData +#include "mozilla/dom/DataTransfer.h" // for DataTransfer +#include "mozilla/dom/Document.h" // for Document +#include "mozilla/dom/DocumentInlines.h" // for GetObservingPresShell +#include "mozilla/dom/DragEvent.h" // for DragEvent +#include "mozilla/dom/Element.h" // for Element, nsINode::AsElement +#include "mozilla/dom/EventTarget.h" // for EventTarget +#include "mozilla/dom/HTMLBodyElement.h" +#include "mozilla/dom/HTMLBRElement.h" +#include "mozilla/dom/Selection.h" // for Selection, etc. +#include "mozilla/dom/StaticRange.h" // for StaticRange +#include "mozilla/dom/Text.h" +#include "mozilla/dom/Event.h" +#include "nsAString.h" // for nsAString::Length, etc. +#include "nsCCUncollectableMarker.h" // for nsCCUncollectableMarker +#include "nsCaret.h" // for nsCaret +#include "nsCaseTreatment.h" +#include "nsCharTraits.h" // for NS_IS_HIGH_SURROGATE, etc. +#include "nsContentUtils.h" // for nsContentUtils +#include "nsCopySupport.h" // for nsCopySupport +#include "nsDOMString.h" // for DOMStringIsNull +#include "nsDebug.h" // for NS_WARNING, etc. +#include "nsError.h" // for NS_OK, etc. +#include "nsFocusManager.h" // for nsFocusManager +#include "nsFrameSelection.h" // for nsFrameSelection +#include "nsGenericHTMLElement.h" // for nsGenericHTMLElement +#include "nsGkAtoms.h" // for nsGkAtoms, nsGkAtoms::dir +#include "nsIClipboard.h" // for nsIClipboard +#include "nsIContent.h" // for nsIContent +#include "nsIContentInlines.h" // for nsINode::IsInDesignMode() +#include "nsIDocumentEncoder.h" // for nsIDocumentEncoder +#include "nsIDocumentStateListener.h" // for nsIDocumentStateListener +#include "nsIDocShell.h" // for nsIDocShell +#include "nsIEditActionListener.h" // for nsIEditActionListener +#include "nsIFrame.h" // for nsIFrame +#include "nsIInlineSpellChecker.h" // for nsIInlineSpellChecker, etc. +#include "nsNameSpaceManager.h" // for kNameSpaceID_None, etc. +#include "nsINode.h" // for nsINode, etc. +#include "nsISelectionController.h" // for nsISelectionController, etc. +#include "nsISelectionDisplay.h" // for nsISelectionDisplay, etc. +#include "nsISupports.h" // for nsISupports +#include "nsISupportsUtils.h" // for NS_ADDREF, NS_IF_ADDREF +#include "nsITransferable.h" // for nsITransferable +#include "nsIWeakReference.h" // for nsISupportsWeakReference +#include "nsIWidget.h" // for nsIWidget, IMEState, etc. +#include "nsPIDOMWindow.h" // for nsPIDOMWindow +#include "nsPresContext.h" // for nsPresContext +#include "nsRange.h" // for nsRange +#include "nsReadableUtils.h" // for EmptyString, ToNewCString +#include "nsString.h" // for nsAutoString, nsString, etc. +#include "nsStringFwd.h" // for nsString +#include "nsStyleConsts.h" // for StyleDirection::Rtl, etc. +#include "nsStyleStruct.h" // for nsStyleDisplay, nsStyleText, etc. +#include "nsStyleStructFwd.h" // for nsIFrame::StyleUIReset, etc. +#include "nsTextNode.h" // for nsTextNode +#include "nsThreadUtils.h" // for nsRunnable +#include "prtime.h" // for PR_Now + +class nsIOutputStream; +class nsITransferable; + +namespace mozilla { + +using namespace dom; +using namespace widget; + +using EmptyCheckOption = HTMLEditUtils::EmptyCheckOption; +using LeafNodeType = HTMLEditUtils::LeafNodeType; +using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes; +using WalkTreeOption = HTMLEditUtils::WalkTreeOption; + +/***************************************************************************** + * mozilla::EditorBase + *****************************************************************************/ +template EditorDOMPoint EditorBase::GetFirstIMESelectionStartPoint() const; +template EditorRawDOMPoint EditorBase::GetFirstIMESelectionStartPoint() const; +template EditorDOMPoint EditorBase::GetLastIMESelectionEndPoint() const; +template EditorRawDOMPoint EditorBase::GetLastIMESelectionEndPoint() const; + +template Result +EditorBase::InsertNodeWithTransaction(nsIContent& aContentToInsert, + const EditorDOMPoint& aPointToInsert); +template Result +EditorBase::InsertNodeWithTransaction(Element& aContentToInsert, + const EditorDOMPoint& aPointToInsert); +template Result +EditorBase::InsertNodeWithTransaction(Text& aContentToInsert, + const EditorDOMPoint& aPointToInsert); + +template EditorDOMPoint EditorBase::GetFirstSelectionStartPoint() const; +template EditorRawDOMPoint EditorBase::GetFirstSelectionStartPoint() const; +template EditorDOMPoint EditorBase::GetFirstSelectionEndPoint() const; +template EditorRawDOMPoint EditorBase::GetFirstSelectionEndPoint() const; + +template EditorDOMPoint EditorBase::FindBetterInsertionPoint( + const EditorDOMPoint& aPoint) const; +template EditorRawDOMPoint EditorBase::FindBetterInsertionPoint( + const EditorRawDOMPoint& aPoint) const; + +template EditorBase::AutoCaretBidiLevelManager::AutoCaretBidiLevelManager( + const EditorBase& aEditorBase, nsIEditor::EDirection aDirectionAndAmount, + const EditorDOMPoint& aPointAtCaret); +template EditorBase::AutoCaretBidiLevelManager::AutoCaretBidiLevelManager( + const EditorBase& aEditorBase, nsIEditor::EDirection aDirectionAndAmount, + const EditorRawDOMPoint& aPointAtCaret); + +EditorBase::EditorBase(EditorType aEditorType) + : mEditActionData(nullptr), + mPlaceholderName(nullptr), + mModCount(0), + mFlags(0), + mUpdateCount(0), + mPlaceholderBatch(0), + mWrapColumn(0), + mNewlineHandling(StaticPrefs::editor_singleLine_pasteNewlines()), + mCaretStyle(StaticPrefs::layout_selection_caret_style()), + mDocDirtyState(-1), + mSpellcheckCheckboxState(eTriUnset), + mInitSucceeded(false), + mAllowsTransactionsToChangeSelection(true), + mDidPreDestroy(false), + mDidPostCreate(false), + mDispatchInputEvent(true), + mIsInEditSubAction(false), + mHidingCaret(false), + mSpellCheckerDictionaryUpdated(true), + mIsHTMLEditorClass(aEditorType == EditorType::HTML) { +#ifdef XP_WIN + if (!mCaretStyle && !IsTextEditor()) { + // Wordpad-like caret behavior. + mCaretStyle = 1; + } +#endif // #ifdef XP_WIN + if (mNewlineHandling < nsIEditor::eNewlinesPasteIntact || + mNewlineHandling > nsIEditor::eNewlinesStripSurroundingWhitespace) { + mNewlineHandling = nsIEditor::eNewlinesPasteToFirst; + } +} + +EditorBase::~EditorBase() { + MOZ_ASSERT(!IsInitialized() || mDidPreDestroy, + "Why PreDestroy hasn't been called?"); + + if (mComposition) { + mComposition->OnEditorDestroyed(); + mComposition = nullptr; + } + // If this editor is still hiding the caret, we need to restore it. + HideCaret(false); + mTransactionManager = nullptr; +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(EditorBase) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(EditorBase) + // Remove event listeners first since EditorEventListener may need + // mDocument, mEventTarget, etc. + if (tmp->mEventListener) { + tmp->mEventListener->Disconnect(); + tmp->mEventListener = nullptr; + } + + NS_IMPL_CYCLE_COLLECTION_UNLINK(mRootElement) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectionController) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mIMEContentObserver) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mInlineSpellChecker) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextServicesDocument) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextInputListener) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransactionManager) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mActionListeners) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocStateListeners) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventTarget) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlaceholderTransaction) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedDocumentEncoder) + NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(EditorBase) + Document* currentDoc = + tmp->mRootElement ? tmp->mRootElement->GetUncomposedDoc() : nullptr; + if (currentDoc && nsCCUncollectableMarker::InGeneration( + cb, currentDoc->GetMarkedCCGeneration())) { + return NS_SUCCESS_INTERRUPTED_TRAVERSE; + } + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRootElement) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectionController) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIMEContentObserver) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInlineSpellChecker) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextServicesDocument) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextInputListener) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransactionManager) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mActionListeners) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocStateListeners) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventTarget) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventListener) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlaceholderTransaction) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedDocumentEncoder) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EditorBase) + NS_INTERFACE_MAP_ENTRY(nsISelectionListener) + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) + NS_INTERFACE_MAP_ENTRY(nsIEditor) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(EditorBase) +NS_IMPL_CYCLE_COLLECTING_RELEASE(EditorBase) + +nsresult EditorBase::InitInternal(Document& aDocument, Element* aRootElement, + nsISelectionController& aSelectionController, + uint32_t aFlags) { + MOZ_ASSERT_IF( + !mEditActionData || + !mEditActionData->HasEditorDestroyedDuringHandlingEditAction(), + GetTopLevelEditSubAction() == EditSubAction::eNone); + + // First only set flags, but other stuff shouldn't be initialized now. + // Note that SetFlags() will be called by PostCreate(). + mFlags = aFlags; + + mDocument = &aDocument; + // nsISelectionController should be stored only when we're a `TextEditor`. + // Otherwise, in `HTMLEditor`, it's `PresShell`, and grabbing it causes + // a circular reference and memory leak. + // XXX Should we move `mSelectionController to `TextEditor`? + MOZ_ASSERT_IF(!IsTextEditor(), &aSelectionController == GetPresShell()); + if (IsTextEditor()) { + MOZ_ASSERT(&aSelectionController != GetPresShell()); + mSelectionController = &aSelectionController; + } + + if (mEditActionData) { + // During edit action, selection is cached. But this selection is invalid + // now since selection controller is updated, so we have to update this + // cache. + Selection* selection = aSelectionController.GetSelection( + nsISelectionController::SELECTION_NORMAL); + NS_WARNING_ASSERTION(selection, + "SelectionController::GetSelection() failed"); + if (selection) { + mEditActionData->UpdateSelectionCache(*selection); + } + } + + // set up root element if we are passed one. + if (aRootElement) { + mRootElement = aRootElement; + } + + // If this is an editor for or