From 21d36249302a0e6fc9e734b9e99b4536047ef0a5 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Thu, 16 Feb 2023 11:48:13 +0000 Subject: [PATCH] Bug 1816312, try to avoid creating Range objects in some common cases when spellchecker is disabled for contentEditable, r=masayuki This is not very optimimal, but tracking spellchecking state in DOM tree is tricky because of multiple contentEditables and possibility to set spellcheck true/false anywhere etc. At least this helps with the testcase quite a bit. Differential Revision: https://phabricator.services.mozilla.com/D169870 --- dom/base/Document.cpp | 23 ++++++++++++----------- dom/base/FragmentOrElement.cpp | 8 ++++++++ dom/base/moz.build | 1 + dom/base/nsIContent.h | 7 +++++++ editor/libeditor/HTMLEditor.cpp | 16 +++++++++++++++- 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index 770f80811a2f..a1499b4b6c74 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -6217,22 +6217,23 @@ void Document::DeferredContentEditableCountChange(Element* aElement) { RefPtr htmlEditor = docshell->GetHTMLEditor(); if (htmlEditor) { - RefPtr range = nsRange::Create(aElement); - IgnoredErrorResult res; - range->SelectNode(*aElement, res); - if (res.Failed()) { - // The node might be detached from the document at this point, - // which would cause this call to fail. In this case, we can - // safely ignore the contenteditable count change. - return; - } - nsCOMPtr spellChecker; rv = htmlEditor->GetInlineSpellChecker(false, getter_AddRefs(spellChecker)); NS_ENSURE_SUCCESS_VOID(rv); - if (spellChecker) { + if (spellChecker && + aElement->InclusiveDescendantMayNeedSpellchecking(htmlEditor)) { + RefPtr range = nsRange::Create(aElement); + IgnoredErrorResult res; + range->SelectNode(*aElement, res); + if (res.Failed()) { + // The node might be detached from the document at this point, + // which would cause this call to fail. In this case, we can + // safely ignore the contenteditable count change. + return; + } + rv = spellChecker->SpellCheckRange(range); NS_ENSURE_SUCCESS_VOID(rv); } diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index eb26a3a67a5e..e6129d24b35d 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -22,6 +22,7 @@ #include "mozilla/EventListenerManager.h" #include "mozilla/ElementAnimationData.h" #include "mozilla/HTMLEditor.h" +#include "mozilla/mozInlineSpellChecker.h" #include "mozilla/PresShell.h" #include "mozilla/RestyleManager.h" #include "mozilla/TextEditor.h" @@ -356,6 +357,13 @@ void nsIContent::ConstructUbiNode(void* storage) { JS::ubi::Concrete::construct(storage, this); } +bool nsIContent::InclusiveDescendantMayNeedSpellchecking(HTMLEditor* aEditor) { + // Return true if the node may have elements as children, since those or their + // descendants may have spellcheck attributes. + return HasFlag(NODE_MAY_HAVE_ELEMENT_CHILDREN) || + mozInlineSpellChecker::ShouldSpellCheckNode(aEditor, this); +} + //---------------------------------------------------------------------- static inline JSObject* GetJSObjectChild(nsWrapperCache* aCache) { diff --git a/dom/base/moz.build b/dom/base/moz.build index e9ee184c3112..534504753c87 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -565,6 +565,7 @@ LOCAL_INCLUDES += [ "/dom/xml", "/dom/xslt/xpath", "/dom/xul", + "/extensions/spellcheck/src", "/gfx/2d", "/image", "/js/xpconnect/loader", diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h index 656ac2cdb28b..6406d02b629a 100644 --- a/dom/base/nsIContent.h +++ b/dom/base/nsIContent.h @@ -17,6 +17,7 @@ class nsIFrame; namespace mozilla { class EventChainPreVisitor; +class HTMLEditor; struct URLExtraData; namespace dom { struct BindContext; @@ -624,6 +625,12 @@ class nsIContent : public nsINode { return rc == 0; } + /** + * Use this method with designMode and contentEditable to check if the + * node may need spellchecking. + */ + bool InclusiveDescendantMayNeedSpellchecking(mozilla::HTMLEditor* aEditor); + protected: /** * Lazily allocated extended slots to avoid diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index f80baa721e33..2c68bcdf7169 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -4423,12 +4423,26 @@ void HTMLEditor::DoContentInserted(nsIContent* aChild, // Update spellcheck for only the newly-inserted node (bug 743819) if (mInlineSpellChecker) { - RefPtr range = nsRange::Create(aChild); nsIContent* endContent = aChild; if (aInsertedOrAppended == eAppended) { + nsIContent* child = nullptr; + for (child = aChild; child; child = child->GetNextSibling()) { + if (child->InclusiveDescendantMayNeedSpellchecking(this)) { + break; + } + } + if (!child) { + // No child needed spellchecking, return. + return; + } + // Maybe more than 1 child was appended. endContent = container->GetLastChild(); + } else if (!aChild->InclusiveDescendantMayNeedSpellchecking(this)) { + return; } + + RefPtr range = nsRange::Create(aChild); range->SelectNodesInContainer(container, aChild, endContent); DebugOnly rvIgnored = mInlineSpellChecker->SpellCheckRange(range);