[Libreoffice-commits] core.git: sc/inc sc/source

Dennis Francis (via logerrit) logerrit at kemper.freedesktop.org
Wed Oct 28 07:40:10 UTC 2020


 sc/inc/editutil.hxx                     |    4 
 sc/inc/scmod.hxx                        |    2 
 sc/inc/spellcheckcontext.hxx            |   71 +++---
 sc/source/ui/app/scmod.cxx              |   37 ---
 sc/source/ui/inc/gridwin.hxx            |    4 
 sc/source/ui/inc/output.hxx             |    2 
 sc/source/ui/inc/tabview.hxx            |    2 
 sc/source/ui/view/dbfunc.cxx            |    2 
 sc/source/ui/view/gridwin.cxx           |  200 -----------------
 sc/source/ui/view/gridwin2.cxx          |    6 
 sc/source/ui/view/spellcheckcontext.cxx |  360 ++++++++++++++++++++++++++++----
 sc/source/ui/view/tabview.cxx           |   18 -
 sc/source/ui/view/viewfun2.cxx          |   32 ++
 sc/source/ui/view/viewfun3.cxx          |   15 -
 sc/source/ui/view/viewfunc.cxx          |    7 
 15 files changed, 426 insertions(+), 336 deletions(-)

New commits:
commit bdd149b1ff3d43b94cadc0d43365100c287c7639
Author:     Dennis Francis <dennis.francis at collabora.com>
AuthorDate: Sun Oct 4 12:47:46 2020 +0530
Commit:     Noel Grandin <noel.grandin at collabora.co.uk>
CommitDate: Wed Oct 28 08:39:25 2020 +0100

    Improve spell checking performance and impl. in several ways:
    
    * do synchronous spell checking, avoiding an idle handler
    * avoid continuous invalidations caused per-cell by spell-checking
    * cache spell-checking information for a given SharedString to
      avoid repeated checking of frequently recurring strings.
    
    Change-Id: Ie251f263a8932465297dd8bd66dfc4aa10984947
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104705
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>

diff --git a/sc/inc/editutil.hxx b/sc/inc/editutil.hxx
index f28249145c06..d760faf5c53e 100644
--- a/sc/inc/editutil.hxx
+++ b/sc/inc/editutil.hxx
@@ -117,10 +117,8 @@ protected:
 
 class SC_DLLPUBLIC ScEditEngineDefaulter : public ScEnginePoolHelper, public EditEngine
 {
-private:
-    using EditEngine::SetText;
-
 public:
+    using EditEngine::SetText;
                     /// bDeleteEnginePool: Engine becomes the owner of the pool
                     /// and deletes it on destruction
                     ScEditEngineDefaulter( SfxItemPool* pEnginePool,
diff --git a/sc/inc/scmod.hxx b/sc/inc/scmod.hxx
index c8af1d424d9b..20dc94e9e9e8 100644
--- a/sc/inc/scmod.hxx
+++ b/sc/inc/scmod.hxx
@@ -81,7 +81,6 @@ class SfxDialogController;
 class SAL_DLLPUBLIC_RTTI ScModule final : public SfxModule, public SfxListener, public utl::ConfigurationListener
 {
     Timer               m_aIdleTimer;
-    Idle                m_aSpellIdle;
     std::unique_ptr<ScDragData> m_pDragData;
     ScSelectionTransferObj* m_pSelTransfer;
     ScMessagePool*      m_pMessagePool;
@@ -131,7 +130,6 @@ public:
                         // moved by the application
 
     DECL_LINK( IdleHandler, Timer*, void ); // Timer instead of idle
-    DECL_LINK( SpellTimerHdl, Timer*, void );
     DECL_LINK( CalcFieldValueHdl, EditFieldInfo*, void );
 
     void                Execute( SfxRequest& rReq );
diff --git a/sc/inc/spellcheckcontext.hxx b/sc/inc/spellcheckcontext.hxx
index 42ec80389af2..684b2ceb9edc 100644
--- a/sc/inc/spellcheckcontext.hxx
+++ b/sc/inc/spellcheckcontext.hxx
@@ -10,50 +10,53 @@
 #ifndef INCLUDED_SC_INC_SPELLCHECKCONTEXT_HXX
 #define INCLUDED_SC_INC_SPELLCHECKCONTEXT_HXX
 
+#include <i18nlangtag/lang.h>
 #include <editeng/misspellrange.hxx>
 #include "types.hxx"
 
-#include <unordered_map>
+#include <memory>
 #include <vector>
 
-namespace sc {
+class ScDocument;
+class ScTabEditEngine;
 
-struct SpellCheckContext
+namespace sc
 {
-    struct CellPos
-    {
-        struct Hash
-        {
-            size_t operator() (const CellPos& rPos) const;
-        };
-
-        SCCOL mnCol;
-        SCROW mnRow;
-
-        CellPos();
-        CellPos(SCCOL nCol, SCROW nRow);
-
-        void setInvalid();
-        bool isValid() const;
-        void reset();
-
-        bool operator== (const CellPos& r) const;
-    };
-
-    typedef std::unordered_map<CellPos, std::vector<editeng::MisspellRanges>, CellPos::Hash> CellMapType;
-
-    CellPos maPos;
-    CellMapType maMisspellCells;
-
-    SpellCheckContext();
-
-    bool isMisspelled( SCCOL nCol, SCROW nRow ) const;
-    const std::vector<editeng::MisspellRanges>* getMisspellRanges( SCCOL nCol, SCROW nRow ) const;
-    void setMisspellRanges( SCCOL nCol, SCROW nRow, const std::vector<editeng::MisspellRanges>* pRanges );
+/**
+ * Class shared between grid windows to cache
+ * spelling results.
+ */
+class SpellCheckContext
+{
+    class SpellCheckCache;
+    struct SpellCheckStatus;
+    struct SpellCheckResult;
+
+    std::unique_ptr<SpellCheckCache> mpCache;
+    std::unique_ptr<SpellCheckResult> mpResult;
+    ScDocument* pDoc;
+    std::unique_ptr<ScTabEditEngine> mpEngine;
+    std::unique_ptr<SpellCheckStatus> mpStatus;
+    SCTAB mnTab;
+    LanguageType meLanguage;
+
+public:
+    SpellCheckContext(ScDocument* pDocument, SCTAB nTab);
+    ~SpellCheckContext();
+
+    bool isMisspelled(SCCOL nCol, SCROW nRow) const;
+    const std::vector<editeng::MisspellRanges>* getMisspellRanges(SCCOL nCol, SCROW nRow) const;
+    void setMisspellRanges(SCCOL nCol, SCROW nRow,
+                           const std::vector<editeng::MisspellRanges>* pRanges);
 
     void reset();
-};
+    void resetForContentChange();
 
+private:
+    void ensureResults(SCCOL nCol, SCROW nRow);
+    void resetCache(bool bContentChangeOnly = false);
+    void setup();
+};
 }
 
 #endif
diff --git a/sc/source/ui/app/scmod.cxx b/sc/source/ui/app/scmod.cxx
index 3115b27126c1..d39c9df9a683 100644
--- a/sc/source/ui/app/scmod.cxx
+++ b/sc/source/ui/app/scmod.cxx
@@ -117,7 +117,6 @@ void ScModule::InitInterface_Impl()
 ScModule::ScModule( SfxObjectFactory* pFact ) :
     SfxModule("sc", {pFact}),
     m_aIdleTimer("sc ScModule IdleTimer"),
-    m_aSpellIdle("sc ScModule SpellIdle"),
     m_pDragData(new ScDragData),
     m_pSelTransfer( nullptr ),
     m_pMessagePool( nullptr ),
@@ -144,8 +143,6 @@ ScModule::ScModule( SfxObjectFactory* pFact ) :
                                        ErrCodeArea::Sc,
                                        GetResLocale()) );
 
-    m_aSpellIdle.SetInvokeHandler( LINK( this, ScModule, SpellTimerHdl ) );
-
     m_aIdleTimer.SetTimeout(SC_IDLE_MIN);
     m_aIdleTimer.SetInvokeHandler( LINK( this, ScModule, IdleHandler ) );
     m_aIdleTimer.Start();
@@ -1815,16 +1812,11 @@ IMPL_LINK_NOARG(ScModule, IdleHandler, Timer *, void)
     }
 
     bool bMore = false;
-    bool bAutoSpell = false;
     ScDocShell* pDocSh = dynamic_cast<ScDocShell*>(SfxObjectShell::Current());
 
     if ( pDocSh )
     {
         ScDocument& rDoc = pDocSh->GetDocument();
-        bAutoSpell = rDoc.GetDocOptions().IsAutoSpell();
-        if (pDocSh->IsReadOnly())
-            bAutoSpell = false;
-
         sc::DocumentLinkManager& rLinkMgr = rDoc.GetDocLinkManager();
         bool bLinks = rLinkMgr.idleCheckLinks();
         bool bWidth = rDoc.IdleCalcTextWidth();
@@ -1837,19 +1829,6 @@ IMPL_LINK_NOARG(ScModule, IdleHandler, Timer *, void)
             lcl_CheckNeedsRepaint( pDocSh );
     }
 
-    if (bAutoSpell)
-    {
-        ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
-        if (pViewSh)
-        {
-            bool bSpell = pViewSh->ContinueOnlineSpelling();
-            if (bSpell)
-            {
-                m_aSpellIdle.Start();
-                bMore = true;
-            }
-        }
-    }
 
     sal_uInt64 nOldTime = m_aIdleTimer.GetTimeout();
     sal_uInt64 nNewTime = nOldTime;
@@ -1877,22 +1856,6 @@ IMPL_LINK_NOARG(ScModule, IdleHandler, Timer *, void)
     m_aIdleTimer.Start();
 }
 
-IMPL_LINK_NOARG(ScModule, SpellTimerHdl, Timer *, void)
-{
-    if ( Application::AnyInput( VclInputFlags::KEYBOARD ) )
-    {
-        m_aSpellIdle.Start();
-        return; // Later again ...
-    }
-
-    ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
-    if (pViewSh)
-    {
-        if (pViewSh->ContinueOnlineSpelling())
-            m_aSpellIdle.Start();
-    }
-}
-
 /**
  * Virtual methods for the OptionsDialog
  */
diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx
index 74b335653c54..d9c0606b2dd2 100644
--- a/sc/source/ui/inc/gridwin.hxx
+++ b/sc/source/ui/inc/gridwin.hxx
@@ -37,7 +37,7 @@ namespace editeng {
 }
 
 namespace sc {
-    struct SpellCheckContext;
+    class SpellCheckContext;
 }
 
 namespace sdr::overlay { class OverlayManager; }
@@ -433,9 +433,9 @@ public:
 
     void CursorChanged();
     void DrawLayerCreated();
-    bool ContinueOnlineSpelling();
     void EnableAutoSpell( bool bEnable );
     void ResetAutoSpell();
+    void ResetAutoSpellForContentChange();
     void SetAutoSpellData( SCCOL nPosX, SCROW nPosY, const std::vector<editeng::MisspellRanges>* pRanges );
     const std::vector<editeng::MisspellRanges>* GetAutoSpellData( SCCOL nPosX, SCROW nPosY );
     bool InsideVisibleRange( SCCOL nPosX, SCROW nPosY );
diff --git a/sc/source/ui/inc/output.hxx b/sc/source/ui/inc/output.hxx
index a1e5d6661135..528b4ef770f4 100644
--- a/sc/source/ui/inc/output.hxx
+++ b/sc/source/ui/inc/output.hxx
@@ -31,7 +31,7 @@
 #include <optional>
 
 namespace sc {
-    struct SpellCheckContext;
+    class SpellCheckContext;
 }
 
 namespace editeng {
diff --git a/sc/source/ui/inc/tabview.hxx b/sc/source/ui/inc/tabview.hxx
index 97a1edc276b7..a716763f1d73 100644
--- a/sc/source/ui/inc/tabview.hxx
+++ b/sc/source/ui/inc/tabview.hxx
@@ -589,9 +589,9 @@ public:
     void            SetDrawBrushSet( std::unique_ptr<SfxItemSet> pNew, bool bLock );
     void            ResetBrushDocument();
 
-    bool ContinueOnlineSpelling();
     void EnableAutoSpell( bool bEnable );
     void ResetAutoSpell();
+    void ResetAutoSpellForContentChange();
     void SetAutoSpellData( SCCOL nPosX, SCROW nPosY, const std::vector<editeng::MisspellRanges>* pRanges );
     /// @see ScModelObj::getRowColumnHeaders().
     void getRowColumnHeaders(const tools::Rectangle& rRectangle, tools::JsonWriter& rJsonWriter);
diff --git a/sc/source/ui/view/dbfunc.cxx b/sc/source/ui/view/dbfunc.cxx
index 9698af40aa53..8f9f8e3a52a2 100644
--- a/sc/source/ui/view/dbfunc.cxx
+++ b/sc/source/ui/view/dbfunc.cxx
@@ -225,7 +225,7 @@ void ScDBFunc::Sort( const ScSortParam& rSortParam, bool bRecord, bool bPaint )
         MarkRange( aDestRange );
     }
 
-    ResetAutoSpell();
+    ResetAutoSpellForContentChange();
 }
 
 //  filters
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
index 5c45e2ef53bb..07a4a8317bac 100644
--- a/sc/source/ui/view/gridwin.cxx
+++ b/sc/source/ui/view/gridwin.cxx
@@ -466,6 +466,10 @@ void ScGridWindow::dispose()
     mpDPFieldPopup.disposeAndClear();
     aComboButton.SetOutputDevice(nullptr);
 
+    if (mpSpellCheckCxt)
+        mpSpellCheckCxt->reset();
+    mpSpellCheckCxt.reset();
+
     vcl::Window::dispose();
 }
 
@@ -5497,191 +5501,10 @@ void ScGridWindow::DrawLayerCreated()
     ImpCreateOverlayObjects();
 }
 
-namespace {
-
-struct SpellCheckStatus
-{
-    bool mbModified;
-
-    SpellCheckStatus() : mbModified(false) {};
-
-    DECL_LINK( EventHdl, EditStatus&, void );
-};
-
-IMPL_LINK(SpellCheckStatus, EventHdl, EditStatus&, rStatus, void)
-{
-    EditStatusFlags nStatus = rStatus.GetStatusWord();
-    if (nStatus & EditStatusFlags::WRONGWORDCHANGED)
-        mbModified = true;
-}
-
-}
-
-bool ScGridWindow::ContinueOnlineSpelling()
-{
-    if (!mpSpellCheckCxt)
-        return false;
-
-    if (!mpSpellCheckCxt->maPos.isValid())
-        return false;
-
-    ScDocument& rDoc = mrViewData.GetDocument();
-    ScDPCollection* pDPs = nullptr;
-    if (rDoc.HasPivotTable())
-        pDPs = rDoc.GetDPCollection();
-
-    SCTAB nTab = mrViewData.GetTabNo();
-    SpellCheckStatus aStatus;
-
-    ScHorizontalCellIterator aIter(
-        rDoc, nTab, maVisibleRange.mnCol1, mpSpellCheckCxt->maPos.mnRow, maVisibleRange.mnCol2, maVisibleRange.mnRow2);
-
-    ScRangeList aPivotRanges = pDPs ? pDPs->GetAllTableRanges(nTab) : ScRangeList();
-
-    SCCOL nCol;
-    SCROW nRow;
-    ScRefCellValue* pCell = aIter.GetNext(nCol, nRow);
-    SCROW nEndRow = 0;
-    bool bHidden = pCell && rDoc.RowHidden(nRow, nTab, nullptr, &nEndRow);
-    bool bSkip = pCell && (nRow < mpSpellCheckCxt->maPos.mnRow || bHidden);
-    while (bSkip)
-    {
-        pCell = aIter.GetNext(nCol, nRow);
-        if (pCell && nRow > nEndRow)
-        {
-            bHidden = rDoc.RowHidden(nRow, nTab, nullptr, &nEndRow);
-        }
-        bSkip = pCell && (nRow < mpSpellCheckCxt->maPos.mnRow || bHidden);
-    }
-
-    SCCOL nEndCol = 0;
-    bHidden = pCell && rDoc.ColHidden(nCol, nTab, nullptr, &nEndCol);
-    bSkip = pCell && (nCol < mpSpellCheckCxt->maPos.mnCol || bHidden);
-    while (bSkip)
-    {
-        pCell = aIter.GetNext(nCol, nRow);
-        if (pCell && nCol > nEndCol)
-        {
-            bHidden = rDoc.ColHidden(nCol, nTab, nullptr, &nEndCol);
-        }
-        bSkip = pCell && (nCol < mpSpellCheckCxt->maPos.mnCol || bHidden);
-    }
-
-    std::unique_ptr<ScTabEditEngine> pEngine;
-
-    // Check only up to 256 cells at a time.
-    size_t nTotalCellCount = 0;
-    size_t nTextCellCount = 0;
-    bool bSpellCheckPerformed = false;
-
-    while (pCell)
-    {
-        ++nTotalCellCount;
-
-        if (aPivotRanges.In(ScAddress(nCol, nRow, nTab)))
-        {
-            // Don't spell check within pivot tables.
-            if (nTotalCellCount >= 255)
-                break;
-
-            pCell = aIter.GetNext(nCol, nRow);
-            continue;
-        }
-
-        CellType eType = pCell->meType;
-        if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT)
-        {
-            ++nTextCellCount;
-
-            // NB: For spell-checking, we currently only use the primary
-            // language; not CJK nor CTL.
-            const ScPatternAttr* pPattern = rDoc.GetPattern(nCol, nRow, nTab);
-            LanguageType nCellLang = pPattern->GetItem(ATTR_FONT_LANGUAGE).GetValue();
-
-            if (nCellLang == LANGUAGE_SYSTEM)
-                nCellLang = Application::GetSettings().GetLanguageTag().getLanguageType();   // never use SYSTEM for spelling
-
-            if (nCellLang == LANGUAGE_NONE)
-            {
-                // No need to spell check this cell.
-                pCell = aIter.GetNext(nCol, nRow);
-                continue;
-            }
-
-            if (!pEngine)
-            {
-                //  ScTabEditEngine is needed
-                //  because MapMode must be set for some old documents
-                pEngine.reset(new ScTabEditEngine(&rDoc));
-                pEngine->SetControlWord(
-                    pEngine->GetControlWord() | (EEControlBits::ONLINESPELLING | EEControlBits::ALLOWBIGOBJS));
-                pEngine->SetStatusEventHdl(LINK(&aStatus, SpellCheckStatus, EventHdl));
-                //  Delimiters here like in inputhdl.cxx !!!
-                pEngine->SetWordDelimiters(
-                            ScEditUtil::ModifyDelimiters(pEngine->GetWordDelimiters()));
-
-                uno::Reference<linguistic2::XSpellChecker1> xXSpellChecker1(LinguMgr::GetSpellChecker());
-                pEngine->SetSpeller(xXSpellChecker1);
-                pEngine->SetDefaultLanguage(ScGlobal::GetEditDefaultLanguage());
-            }
-
-            pEngine->SetDefaultItem(SvxLanguageItem(nCellLang, EE_CHAR_LANGUAGE));
-
-            if (eType == CELLTYPE_STRING)
-                pEngine->SetTextCurrentDefaults(pCell->mpString->getString());
-            else
-                pEngine->SetTextCurrentDefaults(*pCell->mpEditText);
-
-            aStatus.mbModified = false;
-            pEngine->CompleteOnlineSpelling();
-            if (aStatus.mbModified)
-            {
-                std::vector<editeng::MisspellRanges> aRanges;
-                pEngine->GetAllMisspellRanges(aRanges);
-                if (!aRanges.empty())
-                {
-                    sc::SpellCheckContext::CellPos aPos(nCol, nRow);
-                    mpSpellCheckCxt->maMisspellCells.emplace(aPos, aRanges);
-                }
-
-                // Broadcast for re-paint.
-                ScPaintHint aHint(ScRange(nCol, nRow, nTab), PaintPartFlags::Grid);
-                aHint.SetPrintFlag(false);
-                rDoc.GetDocumentShell()->Broadcast(aHint);
-            }
-
-            bSpellCheckPerformed = true;
-        }
-
-        if (nTotalCellCount >= 255 || nTextCellCount >= 1)
-            break;
-
-        pCell = aIter.GetNext(nCol, nRow);
-    }
-
-    if (pCell)
-        // Move to the next cell position for the next iteration.
-        pCell = aIter.GetNext(nCol, nRow);
-
-    if (pCell)
-    {
-        // This will become the first cell position for the next time.
-        mpSpellCheckCxt->maPos.mnCol = nCol;
-        mpSpellCheckCxt->maPos.mnRow = nRow;
-    }
-    else
-    {
-        // No more cells to spell check.
-        mpSpellCheckCxt->maPos.setInvalid();
-    }
-
-    return bSpellCheckPerformed;
-}
-
 void ScGridWindow::EnableAutoSpell( bool bEnable )
 {
     if (bEnable)
-        mpSpellCheckCxt.reset(new sc::SpellCheckContext);
+        mpSpellCheckCxt.reset(new sc::SpellCheckContext(&mrViewData.GetDocument(), mrViewData.GetTabNo()));
     else
         mpSpellCheckCxt.reset();
 }
@@ -5689,11 +5512,13 @@ void ScGridWindow::EnableAutoSpell( bool bEnable )
 void ScGridWindow::ResetAutoSpell()
 {
     if (mpSpellCheckCxt)
-    {
         mpSpellCheckCxt->reset();
-        mpSpellCheckCxt->maPos.mnCol = maVisibleRange.mnCol1;
-        mpSpellCheckCxt->maPos.mnRow = maVisibleRange.mnRow1;
-    }
+}
+
+void ScGridWindow::ResetAutoSpellForContentChange()
+{
+    if (mpSpellCheckCxt)
+        mpSpellCheckCxt->resetForContentChange();
 }
 
 void ScGridWindow::SetAutoSpellData( SCCOL nPosX, SCROW nPosY, const std::vector<editeng::MisspellRanges>* pRanges )
@@ -5701,9 +5526,6 @@ void ScGridWindow::SetAutoSpellData( SCCOL nPosX, SCROW nPosY, const std::vector
     if (!mpSpellCheckCxt)
         return;
 
-    if (!maVisibleRange.isInside(nPosX, nPosY))
-        return;
-
     mpSpellCheckCxt->setMisspellRanges(nPosX, nPosY, pRanges);
 }
 
diff --git a/sc/source/ui/view/gridwin2.cxx b/sc/source/ui/view/gridwin2.cxx
index 0d1ef7ea71c9..efb952dc7721 100644
--- a/sc/source/ui/view/gridwin2.cxx
+++ b/sc/source/ui/view/gridwin2.cxx
@@ -638,11 +638,7 @@ bool ScGridWindow::UpdateVisibleRange()
     }
 
     // Store the current visible range.
-    bool bChanged = maVisibleRange.set(nPosX, nPosY, nXRight, nYBottom);
-    if (bChanged)
-        ResetAutoSpell();
-
-    return bChanged;
+    return maVisibleRange.set(nPosX, nPosY, nXRight, nYBottom);
 }
 
 void ScGridWindow::DPMouseMove( const MouseEvent& rMEvt )
diff --git a/sc/source/ui/view/spellcheckcontext.cxx b/sc/source/ui/view/spellcheckcontext.cxx
index 867dc26f5738..6ff81468c5b1 100644
--- a/sc/source/ui/view/spellcheckcontext.cxx
+++ b/sc/source/ui/view/spellcheckcontext.cxx
@@ -8,88 +8,366 @@
  */
 
 #include <spellcheckcontext.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <svl/sharedstring.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/unolingu.hxx>
+
+#include <scitems.hxx>
+#include <attarray.hxx>
+#include <document.hxx>
+#include <cellvalue.hxx>
+#include <editutil.hxx>
+#include <dpobject.hxx>
+
+#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
+
 #include <boost/functional/hash.hpp>
 
-namespace sc {
+#include <unordered_map>
+
+using namespace css;
 
-size_t SpellCheckContext::CellPos::Hash::operator() (const CellPos& rPos) const
+using sc::SpellCheckContext;
+
+class SpellCheckContext::SpellCheckCache
 {
-    std::size_t seed = 0;
-    boost::hash_combine(seed, rPos.mnCol);
-    boost::hash_combine(seed, rPos.mnRow);
-    return seed;
-}
+    struct CellPos
+    {
+        struct Hash
+        {
+            size_t operator() (const CellPos& rPos) const
+            {
+                std::size_t seed = 0;
+                boost::hash_combine(seed, rPos.mnCol);
+                boost::hash_combine(seed, rPos.mnRow);
+                return seed;
+            }
+        };
+
+        SCCOL mnCol;
+        SCROW mnRow;
+
+        CellPos(SCCOL nCol, SCROW nRow) : mnCol(nCol), mnRow(nRow) {}
+
+        bool operator== (const CellPos& r) const
+        {
+            return mnCol == r.mnCol && mnRow == r.mnRow;
+        }
+
+    };
+
+    typedef std::vector<editeng::MisspellRanges> MisspellType;
+    typedef std::unordered_map<CellPos, std::unique_ptr<MisspellType>, CellPos::Hash> CellMapType;
+    typedef std::unordered_map<const rtl_uString*, std::unique_ptr<MisspellType>> SharedStringMapType;
+    typedef std::unordered_map<CellPos, LanguageType, CellPos::Hash> CellLangMapType;
+
+    SharedStringMapType  maStringMisspells;
+    CellMapType          maEditTextMisspells;
+    CellLangMapType      maCellLanguages;
+    LanguageType         meDefCellLanguage;
+
+public:
+
+    SpellCheckCache(LanguageType eDefaultCellLanguage) : meDefCellLanguage(eDefaultCellLanguage)
+    {
+    }
+
+    bool query(SCCOL nCol, SCROW nRow, const ScRefCellValue& rCell, MisspellType*& rpRanges) const
+    {
+        CellType eType = rCell.meType;
+        if (eType == CELLTYPE_STRING)
+        {
+            SharedStringMapType::const_iterator it = maStringMisspells.find(rCell.mpString->getData());
+            if (it == maStringMisspells.end())
+                return false; // Not available
+
+            rpRanges = it->second.get();
+            return true;
+        }
+
+        if (eType == CELLTYPE_EDIT)
+        {
+            CellMapType::const_iterator it = maEditTextMisspells.find(CellPos(nCol, nRow));
+            if (it == maEditTextMisspells.end())
+                return false; // Not available
+
+            rpRanges = it->second.get();
+            return true;
+        }
+
+        rpRanges = nullptr;
+        return true;
+    }
+
+    void set(SCCOL nCol, SCROW nRow, const ScRefCellValue& rCell, std::unique_ptr<MisspellType> pRanges)
+    {
+        CellType eType = rCell.meType;
+        if (eType == CELLTYPE_STRING)
+            maStringMisspells.insert_or_assign(rCell.mpString->getData(), std::move(pRanges));
+        else if (eType == CELLTYPE_EDIT)
+            maEditTextMisspells.insert_or_assign(CellPos(nCol, nRow), std::move(pRanges));
+    }
 
-SpellCheckContext::CellPos::CellPos() : mnCol(0), mnRow(0) {}
-SpellCheckContext::CellPos::CellPos(SCCOL nCol, SCROW nRow) : mnCol(nCol), mnRow(nRow) {}
+    LanguageType getLanguage(SCCOL nCol, SCROW nRow) const
+    {
+        CellLangMapType::const_iterator it = maCellLanguages.find(CellPos(nCol, nRow));
+        if (it == maCellLanguages.end())
+            return meDefCellLanguage;
 
-void SpellCheckContext::CellPos::setInvalid()
+        return it->second;
+    }
+
+    void setLanguage(LanguageType eCellLang, SCCOL nCol, SCROW nRow)
+    {
+        if (eCellLang == meDefCellLanguage)
+            maCellLanguages.erase(CellPos(nCol, nRow));
+        else
+            maCellLanguages.insert_or_assign(CellPos(nCol, nRow), eCellLang);
+    }
+
+    void clear(LanguageType eDefaultCellLanguage)
+    {
+        maStringMisspells.clear();
+        maEditTextMisspells.clear();
+        maCellLanguages.clear();
+        meDefCellLanguage = eDefaultCellLanguage;
+    }
+
+    void clearEditTextMap()
+    {
+        maEditTextMisspells.clear();
+    }
+};
+
+struct SpellCheckContext::SpellCheckStatus
 {
-    mnCol = -1;
-    mnRow = -1;
-}
+    bool mbModified;
 
-bool SpellCheckContext::CellPos::isValid() const
+    SpellCheckStatus() : mbModified(false) {};
+
+    DECL_LINK( EventHdl, EditStatus&, void );
+};
+
+IMPL_LINK(SpellCheckContext::SpellCheckStatus, EventHdl, EditStatus&, rStatus, void)
 {
-    return mnCol >= 0 && mnRow >= 0;
+    EditStatusFlags nStatus = rStatus.GetStatusWord();
+    if (nStatus & EditStatusFlags::WRONGWORDCHANGED)
+        mbModified = true;
 }
 
-void SpellCheckContext::CellPos::reset()
+struct SpellCheckContext::SpellCheckResult
 {
-    mnCol = 0;
-    mnRow = 0;
-}
+    SCCOL mnCol;
+    SCROW mnRow;
+    const std::vector<editeng::MisspellRanges>* pRanges;
+
+    SpellCheckResult() : mnCol(-1), mnRow(-1), pRanges(nullptr) {}
+
+    void set(SCCOL nCol, SCROW nRow, const std::vector<editeng::MisspellRanges>* pMisspells)
+    {
+        mnCol = nCol;
+        mnRow = nRow;
+        pRanges = pMisspells;
+    }
+
+    const std::vector<editeng::MisspellRanges>* query(SCCOL nCol, SCROW nRow) const
+    {
+        assert(mnCol == nCol);
+        assert(mnRow == nRow);
+        (void)nCol;
+        (void)nRow;
+        return pRanges;
+    }
+
+    void clear()
+    {
+        mnCol = -1;
+        mnRow = -1;
+        pRanges = nullptr;
+    }
+};
 
-bool SpellCheckContext::CellPos::operator== (const CellPos& r) const
+SpellCheckContext::SpellCheckContext(ScDocument* pDocument, SCTAB nTab) :
+    pDoc(pDocument),
+    mnTab(nTab),
+    meLanguage(ScGlobal::GetEditDefaultLanguage())
 {
-    return mnCol == r.mnCol && mnRow == r.mnRow;
+    // defer init of engine and cache till the first query/set
 }
 
-SpellCheckContext::SpellCheckContext()
+SpellCheckContext::~SpellCheckContext()
 {
 }
 
-bool SpellCheckContext::isMisspelled( SCCOL nCol, SCROW nRow ) const
+bool SpellCheckContext::isMisspelled(SCCOL nCol, SCROW nRow) const
 {
-    return maMisspellCells.count(CellPos(nCol, nRow)) > 0;
+    const_cast<SpellCheckContext*>(this)->ensureResults(nCol, nRow);
+    return mpResult->query(nCol, nRow);
 }
 
 const std::vector<editeng::MisspellRanges>* SpellCheckContext::getMisspellRanges(
     SCCOL nCol, SCROW nRow ) const
 {
-    CellMapType::const_iterator it = maMisspellCells.find(CellPos(nCol,nRow));
-    if (it == maMisspellCells.end())
-        return nullptr;
-
-    return &it->second;
+    const_cast<SpellCheckContext*>(this)->ensureResults(nCol, nRow);
+    return mpResult->query(nCol, nRow);
 }
 
 void SpellCheckContext::setMisspellRanges(
     SCCOL nCol, SCROW nRow, const std::vector<editeng::MisspellRanges>* pRanges )
 {
-    CellPos aPos(nCol, nRow);
-    CellMapType::iterator it = maMisspellCells.find(aPos);
+    if (!mpEngine || !mpCache)
+        reset();
+
+    ScRefCellValue aCell(*pDoc, ScAddress(nCol, nRow, mnTab));
+    CellType eType = aCell.meType;
+
+    if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
+        return;
+
+    typedef std::vector<editeng::MisspellRanges> MisspellType;
+    std::unique_ptr<MisspellType> pMisspells(pRanges ? new MisspellType(*pRanges) : nullptr);
+    mpCache->set(nCol, nRow, aCell, std::move(pMisspells));
+}
+
+void SpellCheckContext::reset()
+{
+    meLanguage = ScGlobal::GetEditDefaultLanguage();
+    resetCache();
+    mpEngine.reset();
+    mpStatus.reset();
+}
 
-    if (pRanges)
+void SpellCheckContext::resetForContentChange()
+{
+    resetCache(true /* bContentChangeOnly */);
+}
+
+void SpellCheckContext::ensureResults(SCCOL nCol, SCROW nRow)
+{
+    if (!mpEngine || !mpCache ||
+        ScGlobal::GetEditDefaultLanguage() != meLanguage)
     {
-        if (it == maMisspellCells.end())
-            maMisspellCells.emplace(aPos, *pRanges);
-        else
-            it->second = *pRanges;
+        reset();
+        setup();
+    }
+
+    // perhaps compute the pivot rangelist once in some pivot-table change handler ?
+    if (pDoc->HasPivotTable())
+    {
+        if (ScDPCollection* pDPs = pDoc->GetDPCollection())
+        {
+            ScRangeList aPivotRanges = pDPs->GetAllTableRanges(mnTab);
+            if (aPivotRanges.In(ScAddress(nCol, nRow, mnTab))) // Don't spell check within pivot tables
+            {
+                mpResult->set(nCol, nRow, nullptr);
+                return;
+            }
+        }
+    }
+
+    ScRefCellValue aCell(*pDoc, ScAddress(nCol, nRow, mnTab));
+    CellType eType = aCell.meType;
+
+    if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
+    {
+        // No spell-check required.
+        mpResult->set(nCol, nRow, nullptr);
+        return;
     }
+
+
+    // Cell content is either shared-string or EditTextObject
+
+    // For spell-checking, we currently only use the primary
+    // language; not CJK nor CTL.
+    const ScPatternAttr* pPattern = pDoc->GetPattern(nCol, nRow, mnTab);
+    LanguageType eCellLang = pPattern->GetItem(ATTR_FONT_LANGUAGE).GetValue();
+
+    if (eCellLang == LANGUAGE_SYSTEM)
+        eCellLang = meLanguage;   // never use SYSTEM for spelling
+
+    if (eCellLang == LANGUAGE_NONE)
+    {
+        mpResult->set(nCol, nRow, nullptr); // No need to spell check this cell.
+        return;
+    }
+
+    typedef std::vector<editeng::MisspellRanges> MisspellType;
+
+    LanguageType eCachedCellLang = mpCache->getLanguage(nCol, nRow);
+
+    if (eCellLang != eCachedCellLang)
+        mpCache->setLanguage(eCellLang, nCol, nRow);
+
     else
     {
-        if (it != maMisspellCells.end())
-            maMisspellCells.erase(it);
+        MisspellType* pRanges = nullptr;
+        bool bFound = mpCache->query(nCol, nRow, aCell, pRanges);
+        if (bFound)
+        {
+            // Cache hit.
+            mpResult->set(nCol, nRow, pRanges);
+            return;
+        }
     }
+
+    // Cache miss, the cell needs spell-check..
+    mpEngine->SetDefaultItem(SvxLanguageItem(eCellLang, EE_CHAR_LANGUAGE));
+    if (eType == CELLTYPE_STRING)
+        mpEngine->SetText(aCell.mpString->getString());
+    else
+        mpEngine->SetText(*aCell.mpEditText);
+
+    mpStatus->mbModified = false;
+    mpEngine->CompleteOnlineSpelling();
+    std::unique_ptr<MisspellType> pRanges;
+    if (mpStatus->mbModified)
+    {
+        pRanges.reset(new MisspellType);
+        mpEngine->GetAllMisspellRanges(*pRanges);
+
+        if (pRanges->empty())
+            pRanges.reset(nullptr);
+    }
+    // else : No change in status for EditStatusFlags::WRONGWORDCHANGED => no spell errors (which is the default status).
+
+    mpResult->set(nCol, nRow, pRanges.get());
+    mpCache->set(nCol, nRow, aCell, std::move(pRanges));
 }
 
-void SpellCheckContext::reset()
+void SpellCheckContext::resetCache(bool bContentChangeOnly)
 {
-    maPos.reset();
-    maMisspellCells.clear();
+    if (!mpResult)
+        mpResult.reset(new SpellCheckResult());
+    else
+        mpResult->clear();
+
+    if (!mpCache)
+        mpCache.reset(new SpellCheckCache(meLanguage));
+    else if (bContentChangeOnly)
+        mpCache->clearEditTextMap();
+    else
+        mpCache->clear(meLanguage);
 }
 
+void SpellCheckContext::setup()
+{
+    mpEngine.reset(new ScTabEditEngine(pDoc));
+    mpStatus.reset(new SpellCheckStatus());
+
+    mpEngine->SetControlWord(
+        mpEngine->GetControlWord() | (EEControlBits::ONLINESPELLING | EEControlBits::ALLOWBIGOBJS));
+    mpEngine->SetStatusEventHdl(LINK(mpStatus.get(), SpellCheckStatus, EventHdl));
+    //  Delimiters here like in inputhdl.cxx !!!
+    mpEngine->SetWordDelimiters(
+                ScEditUtil::ModifyDelimiters(mpEngine->GetWordDelimiters()));
+
+    uno::Reference<linguistic2::XSpellChecker1> xXSpellChecker1(LinguMgr::GetSpellChecker());
+    mpEngine->SetSpeller(xXSpellChecker1);
+    mpEngine->SetDefaultLanguage(meLanguage);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabview.cxx b/sc/source/ui/view/tabview.cxx
index bcf2831995c0..2f4a407aca5c 100644
--- a/sc/source/ui/view/tabview.cxx
+++ b/sc/source/ui/view/tabview.cxx
@@ -2232,40 +2232,36 @@ void ScTabView::EnableRefInput(bool bFlag)
             p->EnableInput(bFlag, false);
 }
 
-bool ScTabView::ContinueOnlineSpelling()
+void ScTabView::EnableAutoSpell( bool bEnable )
 {
-    bool bChanged = false;
     for (VclPtr<ScGridWindow> & pWin : pGridWin)
     {
-        if (!pWin || !pWin->IsVisible())
+        if (!pWin)
             continue;
 
-        if (pWin->ContinueOnlineSpelling())
-            bChanged = true;
+        pWin->EnableAutoSpell(bEnable);
     }
-
-    return bChanged;
 }
 
-void ScTabView::EnableAutoSpell( bool bEnable )
+void ScTabView::ResetAutoSpell()
 {
     for (VclPtr<ScGridWindow> & pWin : pGridWin)
     {
         if (!pWin)
             continue;
 
-        pWin->EnableAutoSpell(bEnable);
+        pWin->ResetAutoSpell();
     }
 }
 
-void ScTabView::ResetAutoSpell()
+void ScTabView::ResetAutoSpellForContentChange()
 {
     for (VclPtr<ScGridWindow> & pWin : pGridWin)
     {
         if (!pWin)
             continue;
 
-        pWin->ResetAutoSpell();
+        pWin->ResetAutoSpellForContentChange();
     }
 }
 
diff --git a/sc/source/ui/view/viewfun2.cxx b/sc/source/ui/view/viewfun2.cxx
index 572b62cf4036..9bad80bb01d0 100644
--- a/sc/source/ui/view/viewfun2.cxx
+++ b/sc/source/ui/view/viewfun2.cxx
@@ -1477,6 +1477,10 @@ void ScViewFunc::FillAuto( FillDir eDir, SCCOL nStartCol, SCROW nStartRow,
 void ScViewFunc::CopyAutoSpellData( FillDir eDir, SCCOL nStartCol, SCROW nStartRow,
                                    SCCOL nEndCol, SCROW nEndRow, sal_uLong nCount )
 {
+    const ScDocument* pDoc = &GetViewData().GetDocument();
+    SCTAB nTab = GetViewData().GetTabNo();
+    CellType eCellType;
+
     ScGridWindow* pWin = GetActiveWin();
     if ( pWin->InsideVisibleRange(nStartCol, nStartRow) && pWin->InsideVisibleRange(nEndCol, nEndRow) )
     {
@@ -1487,6 +1491,10 @@ void ScViewFunc::CopyAutoSpellData( FillDir eDir, SCCOL nStartCol, SCROW nStartR
                 case FILL_TO_BOTTOM:
                     for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
                     {
+                        pDoc->GetCellType(nColItr, nStartRow, nTab, eCellType); // We need this optimization only for EditTextObject source cells
+                        if (eCellType != CELLTYPE_EDIT)
+                            continue;
+
                         const std::vector<editeng::MisspellRanges>* pRanges = pWin->GetAutoSpellData(nColItr, nStartRow);
                         if ( !pRanges )
                             continue;
@@ -1497,6 +1505,10 @@ void ScViewFunc::CopyAutoSpellData( FillDir eDir, SCCOL nStartCol, SCROW nStartR
                 case FILL_TO_TOP:
                     for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
                     {
+                        pDoc->GetCellType(nColItr, nEndRow, nTab, eCellType); // We need this optimization only for EditTextObject source cells
+                        if (eCellType != CELLTYPE_EDIT)
+                            continue;
+
                         const std::vector<editeng::MisspellRanges>* pRanges = pWin->GetAutoSpellData(nColItr, nEndRow);
                         if ( !pRanges )
                             continue;
@@ -1507,6 +1519,10 @@ void ScViewFunc::CopyAutoSpellData( FillDir eDir, SCCOL nStartCol, SCROW nStartR
                 case FILL_TO_RIGHT:
                     for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
                     {
+                        pDoc->GetCellType(nStartCol, nRowItr, nTab, eCellType); // We need this optimization only for EditTextObject source cells
+                        if (eCellType != CELLTYPE_EDIT)
+                            continue;
+
                         const std::vector<editeng::MisspellRanges>* pRanges = pWin->GetAutoSpellData(nStartCol, nRowItr);
                         if ( !pRanges )
                             continue;
@@ -1517,6 +1533,10 @@ void ScViewFunc::CopyAutoSpellData( FillDir eDir, SCCOL nStartCol, SCROW nStartR
                 case FILL_TO_LEFT:
                     for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
                     {
+                        pDoc->GetCellType(nEndCol, nRowItr, nTab, eCellType); // We need this optimization only for EditTextObject source cells
+                        if (eCellType != CELLTYPE_EDIT)
+                            continue;
+
                         const std::vector<editeng::MisspellRanges>* pRanges = pWin->GetAutoSpellData(nEndCol, nRowItr);
                         if ( !pRanges )
                             continue;
@@ -1533,11 +1553,19 @@ void ScViewFunc::CopyAutoSpellData( FillDir eDir, SCCOL nStartCol, SCROW nStartR
         SCCOL nColRepeatSize = nEndCol - nStartCol + 1;
         SCROW nTillRow = 0;
         SCCOL nTillCol = 0;
-        std::vector<std::vector<MisspellRangesType>> aSourceSpellRanges(nRowRepeatSize, std::vector<MisspellRangesType>(nColRepeatSize));
+        std::vector<std::vector<MisspellRangesType>> aSourceSpellRanges(nRowRepeatSize, std::vector<MisspellRangesType>(nColRepeatSize, nullptr));
 
         for ( SCROW nRowIdx = 0; nRowIdx < nRowRepeatSize; ++nRowIdx )
+        {
             for ( SCCOL nColIdx = 0; nColIdx < nColRepeatSize; ++nColIdx )
+            {
+                pDoc->GetCellType(nStartCol + nColIdx, nStartRow + nRowIdx, nTab, eCellType); // We need this optimization only for EditTextObject source cells
+                if (eCellType != CELLTYPE_EDIT)
+                    continue;
+
                 aSourceSpellRanges[nRowIdx][nColIdx] = pWin->GetAutoSpellData( nStartCol + nColIdx, nStartRow + nRowIdx );
+            }
+        }
 
         switch( eDir )
         {
@@ -1603,7 +1631,7 @@ void ScViewFunc::CopyAutoSpellData( FillDir eDir, SCCOL nStartCol, SCROW nStartR
         }
     }
     else
-        pWin->ResetAutoSpell();
+        pWin->ResetAutoSpellForContentChange();
 
 }
 
diff --git a/sc/source/ui/view/viewfun3.cxx b/sc/source/ui/view/viewfun3.cxx
index 50b73566b1a7..5354391fcaa1 100644
--- a/sc/source/ui/view/viewfun3.cxx
+++ b/sc/source/ui/view/viewfun3.cxx
@@ -955,6 +955,9 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
         ScDrawLayer::SetGlobalDrawPersist(nullptr);
     }
 
+    // TODO: position this call better for performance.
+    ResetAutoSpellForContentChange();
+
     SCCOL nStartCol;
     SCROW nStartRow;
     SCTAB nStartTab;
@@ -1446,7 +1449,6 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
         nPaint, nExtFlags);
     // AdjustBlockHeight has already been called above
 
-    ResetAutoSpell();
     aModificator.SetDocumentModified();
     PostPasteFromClip(aUserRange, rMark);
 
@@ -1544,6 +1546,9 @@ bool ScViewFunc::PasteMultiRangesFromClip(
             return false;
     }
 
+    // TODO: position this call better for performance.
+    ResetAutoSpellForContentChange();
+
     bool bRowInfo = ( aMarkedRange.aStart.Col()==0 && aMarkedRange.aEnd.Col()==pClipDoc->MaxCol() );
     ScDocumentUniquePtr pUndoDoc;
     if (rDoc.IsUndoEnabled())
@@ -1624,7 +1629,6 @@ bool ScViewFunc::PasteMultiRangesFromClip(
         pUndoMgr->LeaveListAction();
     }
 
-    ResetAutoSpell();
     aModificator.SetDocumentModified();
     PostPasteFromClip(aMarkedRange, aMark);
     return true;
@@ -1696,6 +1700,9 @@ bool ScViewFunc::PasteFromClipToMultiRanges(
             return false;
     }
 
+    // TODO: position this call better for performance.
+    ResetAutoSpellForContentChange();
+
     ScDocumentUniquePtr pUndoDoc;
     if (rDoc.IsUndoEnabled())
     {
@@ -1784,7 +1791,6 @@ bool ScViewFunc::PasteFromClipToMultiRanges(
         pUndoMgr->LeaveListAction();
     }
 
-    ResetAutoSpell();
     aModificator.SetDocumentModified();
     PostPasteFromClip(aRanges, aMark);
 
@@ -1828,6 +1834,8 @@ bool ScViewFunc::MoveBlockTo( const ScRange& rSource, const ScAddress& rDestPos,
     ScDocShell* pDocSh = GetViewData().GetDocShell();
     HideAllCursors();
 
+    ResetAutoSpellForContentChange();
+
     bool bSuccess = true;
     SCTAB nDestTab = rDestPos.Tab();
     const ScMarkData& rMark = GetViewData().GetMarkData();
@@ -1899,7 +1907,6 @@ bool ScViewFunc::MoveBlockTo( const ScRange& rSource, const ScAddress& rDestPos,
 
         pDocSh->UpdateOle(GetViewData());
         SelectionChanged();
-        ResetAutoSpell();
     }
     return bSuccess;
 }
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
index c22effdaa37f..d0484beb37c9 100644
--- a/sc/source/ui/view/viewfunc.cxx
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -1607,12 +1607,12 @@ bool ScViewFunc::InsertCells( InsCellCmd eCmd, bool bRecord, bool bPartOfPaste )
         bool bSuccess = pDocSh->GetDocFunc().InsertCells( aRange, &rMark, eCmd, bRecord, false, bPartOfPaste );
         if (bSuccess)
         {
+            ResetAutoSpellForContentChange();
             bool bInsertCols = ( eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER);
             bool bInsertRows = ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER );
 
             pDocSh->UpdateOle(GetViewData());
             CellContentChanged();
-            ResetAutoSpell();
 
             if ( bInsertCols || bInsertRows )
             {
@@ -1684,9 +1684,9 @@ void ScViewFunc::DeleteCells( DelCellCmd eCmd )
             pDocSh->GetDocFunc().DeleteCells( aRange, &rMark, eCmd, false );
         }
 
+        ResetAutoSpellForContentChange();
         pDocSh->UpdateOle(GetViewData());
         CellContentChanged();
-        ResetAutoSpell();
 
         if ( eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::Cols )
         {
@@ -1831,6 +1831,8 @@ void ScViewFunc::DeleteMulti( bool bRows )
 
     WaitObject aWait( GetFrameWin() );      // important for TrackFormulas in UpdateReference
 
+    ResetAutoSpellForContentChange();
+
     ScDocumentUniquePtr pUndoDoc;
     std::unique_ptr<ScRefUndoData> pUndoData;
     if (bRecord)
@@ -1914,7 +1916,6 @@ void ScViewFunc::DeleteMulti( bool bRows )
         }
     }
 
-    ResetAutoSpell();
     aModificator.SetDocumentModified();
 
     CellContentChanged();


More information about the Libreoffice-commits mailing list