tdf#121388 : Disable threading and dep evaluation for IF...

IFS/SWITCH if the call did not originate from
ScDocShell::DoRecalc()/ScDocShell::DoHardRecalc()

Change-Id: Ifdb3a496276dc841fc42a1bad1876cfb1057baf6
Reviewed-on: https://gerrit.libreoffice.org/67414
Tested-by: Jenkins
Reviewed-by: Dennis Francis <dennis.francis@collabora.com>
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index ddf92b9..646e2b4 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -543,6 +543,8 @@ private:

    bool                mbTrackFormulasPending  : 1;
    bool                mbFinalTrackFormulas    : 1;
    // This indicates if a ScDocShell::DoRecalc() or ScDocShell::DoHardRecalc() is in progress.
    bool                mbDocShellRecalc        : 1;

    size_t              mnMutationGuardFlags;

@@ -2469,6 +2471,9 @@ public:

    SC_DLLPUBLIC ScColumnsRange GetColumnsRange(SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd) const;

    bool IsInDocShellRecalc() const   { return mbDocShellRecalc; }
    void SetDocShellRecalc(bool bSet) { mbDocShellRecalc = bSet; }

private:

    /**
@@ -2591,6 +2596,25 @@ struct ScMutationGuard
    size_t mnFlags;
    ScDocument* mpDocument;
#endif

};

class ScDocShellRecalcGuard
{
    ScDocument& mrDoc;

public:
    ScDocShellRecalcGuard(ScDocument& rDoc)
        : mrDoc(rDoc)
    {
        assert(!mrDoc.IsInDocShellRecalc());
        mrDoc.SetDocShellRecalc(true);
    }

    ~ScDocShellRecalcGuard()
    {
        mrDoc.SetDocShellRecalc(false);
    }
};

#endif
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 50ccf97..a97dbc3 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -159,6 +159,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
        mbEmbedFontScriptComplex(true),
        mbTrackFormulasPending(false),
        mbFinalTrackFormulas(false),
        mbDocShellRecalc(false),
        mnMutationGuardFlags(0)
{
    SetStorageGrammar( formula::FormulaGrammar::GRAM_STORAGE_DEFAULT);
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 52c0cf5..1af4729 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -4381,9 +4381,26 @@ struct ScDependantsCalculator

        // Self references should be checked by considering the entire formula-group not just the provided span.
        bool bHasSelfReferences = false;
        bool bInDocShellRecalc = mrDoc.IsInDocShellRecalc();

        for (auto p: mrCode.RPNTokens())
        FormulaToken** pRPNArray = mrCode.GetCode();
        sal_uInt16 nCodeLen = mrCode.GetCodeLen();
        for (sal_Int32 nTokenIdx = nCodeLen-1; nTokenIdx >= 0; --nTokenIdx)
        {
            auto p = pRPNArray[nTokenIdx];
            if (!bInDocShellRecalc)
            {
                // The dependency evaluator evaluates all arguments of IF/IFS/SWITCH irrespective
                // of the result of the condition expression.
                // This is a perf problem if we *don't* intent on recalc'ing all dirty cells
                // in the document. So lets disable threading and stop dependency evaluation if
                // the call did not originate from ScDocShell::DoRecalc()/ScDocShell::DoHardRecalc()
                // for formulae with IF/IFS/SWITCH
                OpCode nOpCode = p->GetOpCode();
                if (nOpCode == ocIf || nOpCode == ocIfs_MS || nOpCode == ocSwitch_MS)
                    return false;
            }

            switch (p->GetType())
            {
            case svSingleRef:
diff --git a/sc/source/ui/docshell/docsh4.cxx b/sc/source/ui/docshell/docsh4.cxx
index 83ccac2..4fba156 100644
--- a/sc/source/ui/docshell/docsh4.cxx
+++ b/sc/source/ui/docshell/docsh4.cxx
@@ -1329,6 +1329,7 @@ bool ScDocShell::ExecuteChangeProtectionDialog( bool bJustQueryIfProtected )

void ScDocShell::DoRecalc( bool bApi )
{
    ScDocShellRecalcGuard aGuard(m_aDocument);
    bool bDone = false;
    ScTabViewShell* pSh = GetBestViewShell();
    ScInputHandler* pHdl = ( pSh ? SC_MOD()->GetInputHdl( pSh ) : nullptr );
@@ -1375,6 +1376,7 @@ void ScDocShell::DoRecalc( bool bApi )
void ScDocShell::DoHardRecalc()
{
    auto start = std::chrono::steady_clock::now();
    ScDocShellRecalcGuard aGuard(m_aDocument);
    WaitObject aWaitObj( GetActiveDialogParent() );
    ScTabViewShell* pSh = GetBestViewShell();
    if ( pSh )