[Libreoffice-commits] core.git: Branch 'feature/formula-core-rework' - 16 commits - configure.ac sc/inc sc/source sfx2/source starmath/source svgio/source vcl/inc vcl/unx

Kohei Yoshida kohei.yoshida at gmail.com
Tue Jul 2 20:34:03 PDT 2013


Rebased ref, commits from common ancestor:
commit 8c56ee1f1013c6be4c980ed17945c92b7370c4c8
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jul 2 23:32:11 2013 -0400

    Not to forget this header...
    
    Change-Id: I3f05923787ec87d5231433e4fad562326becae49

diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index b4fd646..221a768 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -22,6 +22,10 @@
 
 #define USE_DUMMY_INTERPRETER 1
 
+#if USE_DUMMY_INTERPRETER
+#include <cstdio>
+#endif
+
 namespace sc {
 
 ScMatrixRef FormulaGroupInterpreterSoftware::inverseMatrix(const ScMatrix& /*rMat*/)
commit b81d130626c20b806fc8a28524b38756eebc6c46
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Tue Jul 2 22:01:01 2013 +0100

    Dummy formula group interpreter for testing.

diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
index 1c573c4..e645968 100644
--- a/sc/inc/formulagroup.hxx
+++ b/sc/inc/formulagroup.hxx
@@ -30,9 +30,8 @@ struct FormulaGroupContext : boost::noncopyable
 };
 
 /**
- * All the vectorized formula calculation code should be collected here.
- *
- * Abstract base class for formula group interpreters, and a factory.
+ * Abstract base class for vectorised formula group interpreters,
+ * plus a global instance factory.
  */
 class SC_DLLPUBLIC FormulaGroupInterpreter
 {
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index b20b437..b4fd646 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -20,6 +20,8 @@
 
 #include <vector>
 
+#define USE_DUMMY_INTERPRETER 1
+
 namespace sc {
 
 ScMatrixRef FormulaGroupInterpreterSoftware::inverseMatrix(const ScMatrix& /*rMat*/)
@@ -108,14 +110,61 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
 namespace opencl {
     extern sc::FormulaGroupInterpreter *createFormulaGroupInterpreter();
 }
-
 FormulaGroupInterpreter *FormulaGroupInterpreter::msInstance = NULL;
 
+#if USE_DUMMY_INTERPRETER
+class FormulaGroupInterpreterDummy : public FormulaGroupInterpreter
+{
+    enum Mode {
+        WRITE_OUTPUT = 0
+    };
+    Mode meMode;
+public:
+    FormulaGroupInterpreterDummy()
+    {
+        const char *pValue = getenv("FORMULA_GROUP_DUMMY");
+        meMode = static_cast<Mode>(OString(pValue, strlen(pValue)).toInt32());
+        fprintf(stderr, "Using Dummy Formula Group interpreter mode %d\n", (int)meMode);
+    }
+
+    virtual ScMatrixRef inverseMatrix(const ScMatrix& /*rMat*/)
+    {
+        return ScMatrixRef();
+    }
+
+    virtual bool interpret(ScDocument& rDoc, const ScAddress& rTopPos,
+                           const ScFormulaCellGroupRef& xGroup,
+                           ScTokenArray& rCode)
+    {
+        (void)rCode;
+
+        // Write simple data back into the sheet
+        if (meMode == WRITE_OUTPUT)
+        {
+            double *pDoubles = new double[xGroup->mnLength];
+            for (sal_Int32 i = 0; i < xGroup->mnLength; i++)
+                pDoubles[i] = 42.0 + i;
+            rDoc.SetFormulaResults(rTopPos, pDoubles, xGroup->mnLength);
+            delete [] pDoubles;
+        }
+        return true;
+    }
+};
+#endif
+
 /// load and/or configure the correct formula group interpreter
 FormulaGroupInterpreter *FormulaGroupInterpreter::getStatic()
 {
     static bool bOpenCLEnabled = false;
 
+#if USE_DUMMY_INTERPRETER
+    if (getenv("FORMULA_GROUP_DUMMY"))
+    {
+        delete msInstance;
+        return msInstance = new sc::FormulaGroupInterpreterDummy();
+    }
+#endif
+
     if ( msInstance &&
          bOpenCLEnabled != ScInterpreter::GetGlobalConfig().mbOpenCLEnabled )
     {
commit 1eb0aac39f366caf497534de00fb30b84ac1ba62
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jul 2 22:23:56 2013 -0400

    Forgot to remove these debug statements.
    
    Change-Id: I680750c43dce4b6e7f9b9ed0a6b8550bdf485a8c

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 132ed5c..f8928e5 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3115,12 +3115,8 @@ bool ScFormulaCell::InterpretFormulaGroup()
     if (!xGroup || !pCode)
         return false;
 
-    fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup:   calc state = %d\n", xGroup->meCalcState);
     if (xGroup->meCalcState == sc::GroupCalcDisabled)
-    {
-        fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup:   group calc disabled.\n");
         return false;
-    }
 
     switch (pCode->GetVectorState())
     {
@@ -3145,7 +3141,6 @@ bool ScFormulaCell::InterpretFormulaGroup()
     GroupTokenConverter aConverter(aCxt, aCode, *pDocument, *this, aTopPos);
     if (!aConverter.convert(*pCode))
     {
-        fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup:   disabling group calc due to failed conversion\n");
         xGroup->meCalcState = sc::GroupCalcDisabled;
         return false;
     }
@@ -3153,7 +3148,6 @@ bool ScFormulaCell::InterpretFormulaGroup()
     xGroup->meCalcState = sc::GroupCalcRunning;
     if (!sc::FormulaGroupInterpreter::getStatic()->interpret(*pDocument, aTopPos, xGroup, aCode))
     {
-        fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup:   disabling group calc due to failed calculation\n");
         xGroup->meCalcState = sc::GroupCalcDisabled;
         return false;
     }
commit ce7a2d39efc66ae682873a96030332b38ba3a4d6
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jul 2 22:10:25 2013 -0400

    Detect circular dependency in formula groups to fallback to cell-based.
    
    Change-Id: Icfb4fd4be4e0c1f6f450fb8ddce57c7b79568e6f

diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 52a1474..07b726a 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -24,6 +24,7 @@
 
 #include "formula/tokenarray.hxx"
 #include "svl/listener.hxx"
+#include "types.hxx"
 
 #include <set>
 
@@ -40,19 +41,23 @@ struct ScSimilarFormulaDelta;
 
 struct SC_DLLPUBLIC ScFormulaCellGroup
 {
-    sal_Int32 mnRefCount;
+    mutable size_t mnRefCount;
+
     SCROW mnStart;  // Start offset of that cell
     SCROW mnLength; // How many of these do we have ?
     bool mbInvariant;
+    sc::GroupCalcState meCalcState;
 
     ScFormulaCellGroup();
     ~ScFormulaCellGroup();
 };
-inline void intrusive_ptr_add_ref(ScFormulaCellGroup *p)
+
+inline void intrusive_ptr_add_ref(const ScFormulaCellGroup *p)
 {
     p->mnRefCount++;
 }
-inline void intrusive_ptr_release(ScFormulaCellGroup *p)
+
+inline void intrusive_ptr_release(const ScFormulaCellGroup *p)
 {
     if( --p->mnRefCount == 0 )
         delete p;
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 445311e..5c11da5 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -56,6 +56,13 @@ const sal_uInt16 MatrixEdgeTop     = 8;
 const sal_uInt16 MatrixEdgeRight   = 16;
 const sal_uInt16 MatrixEdgeOpen    = 32;
 
+enum GroupCalcState
+{
+    GroupCalcEnabled,
+    GroupCalcRunning,
+    GroupCalcDisabled
+};
+
 }
 
 #endif
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 4becbb7..82daadf 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2166,10 +2166,15 @@ bool appendDouble(
                     nLenRemain = 0;
                 }
 
+                sal_uInt16 nErr;
+                double fVal;
                 for (; itData != itDataEnd; ++itData)
                 {
                     ScFormulaCell& rFC = **itData;
-                    rArray.push_back(rFC.GetValue());
+                    if (!rFC.GetErrorOrValue(nErr, fVal) || nErr)
+                        return false;
+
+                    rArray.push_back(fVal);
                 }
             }
             break;
@@ -2238,6 +2243,9 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
         break;
         case sc::element_type_formula:
         {
+            sal_uInt16 nErr;
+            double fVal;
+
             rCxt.maArrays.push_back(new sc::FormulaGroupContext::DoubleArrayType);
             sc::FormulaGroupContext::DoubleArrayType& rArray = rCxt.maArrays.back();
             rArray.reserve(nLenRequested);
@@ -2252,7 +2260,10 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
                 for (; it != itEnd; ++it)
                 {
                     ScFormulaCell& rCell = **it;
-                    rArray.push_back(rCell.GetValue()); // the cell may be interpreted.
+                    if (!rCell.GetErrorOrValue(nErr, fVal) || nErr)
+                        return NULL;
+
+                    rArray.push_back(fVal);
                 }
 
                 return &rArray[0];
@@ -2264,7 +2275,10 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
             for (; it != itEnd; ++it)
             {
                 ScFormulaCell& rCell = **it;
-                rArray.push_back(rCell.GetValue()); // the cell may be interpreted.
+                if (!rCell.GetErrorOrValue(nErr, fVal) || nErr)
+                    return NULL;
+
+                rArray.push_back(fVal);
             }
 
             // Fill the remaining array with values from the following blocks.
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index a129726..132ed5c 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -382,7 +382,11 @@ void adjustDBRange(ScToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldD
 }
 
 ScFormulaCellGroup::ScFormulaCellGroup() :
-    mnRefCount(0), mnStart(0), mnLength(0), mbInvariant(false)
+    mnRefCount(0),
+    mnStart(0),
+    mnLength(0),
+    mbInvariant(false),
+    meCalcState(sc::GroupCalcEnabled)
 {
 }
 
@@ -1547,6 +1551,9 @@ void ScFormulaCell::SetDirty( bool bDirtyFlag )
 void ScFormulaCell::SetDirtyVar()
 {
     bDirty = true;
+    if (xGroup)
+        xGroup->meCalcState = sc::GroupCalcEnabled;
+
     // mark the sheet of this cell to be calculated
     //#FIXME do we need to revert this remnant of old fake vba events? pDocument->AddCalculateTable( aPos.Tab() );
 }
@@ -1611,7 +1618,7 @@ void ScFormulaCell::SetErrCode( sal_uInt16 n )
 void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits )
 {
     if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL )
-        bDirty = true;
+        SetDirtyVar();
     if ( nBits & RECALCMODE_ONLOAD_ONCE )
     {   // OnLoadOnce nur zum Dirty setzen nach Filter-Import
         nBits = (nBits & ~RECALCMODE_EMASK) | RECALCMODE_NORMAL;
@@ -2959,9 +2966,10 @@ class GroupTokenConverter
     ScTokenArray& mrGroupTokens;
     ScDocument& mrDoc;
     ScFormulaCell& mrCell;
+    const ScAddress& mrPos;
 public:
-    GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell) :
-        mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell) {}
+    GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) :
+        mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos) {}
 
     bool convert(ScTokenArray& rCode)
     {
@@ -2979,8 +2987,7 @@ public:
                 case svSingleRef:
                 {
                     ScSingleRefData aRef = pToken->GetSingleRef();
-                    aRef.CalcAbsIfRel(mrCell.aPos);
-                    ScAddress aRefPos(aRef.nCol, aRef.nRow, aRef.nTab);
+                    ScAddress aRefPos = aRef.toAbs(mrPos);
                     if (aRef.IsRowRel())
                     {
                         // Fetch double array guarantees that the length of the
@@ -3108,6 +3115,13 @@ bool ScFormulaCell::InterpretFormulaGroup()
     if (!xGroup || !pCode)
         return false;
 
+    fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup:   calc state = %d\n", xGroup->meCalcState);
+    if (xGroup->meCalcState == sc::GroupCalcDisabled)
+    {
+        fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup:   group calc disabled.\n");
+        return false;
+    }
+
     switch (pCode->GetVectorState())
     {
         case FormulaVectorEnabled:
@@ -3126,10 +3140,26 @@ bool ScFormulaCell::InterpretFormulaGroup()
 
     sc::FormulaGroupContext aCxt;
     ScTokenArray aCode;
-    GroupTokenConverter aConverter(aCxt, aCode, *pDocument, *this);
+    ScAddress aTopPos = aPos;
+    aTopPos.SetRow(xGroup->mnStart);
+    GroupTokenConverter aConverter(aCxt, aCode, *pDocument, *this, aTopPos);
     if (!aConverter.convert(*pCode))
+    {
+        fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup:   disabling group calc due to failed conversion\n");
+        xGroup->meCalcState = sc::GroupCalcDisabled;
+        return false;
+    }
+
+    xGroup->meCalcState = sc::GroupCalcRunning;
+    if (!sc::FormulaGroupInterpreter::getStatic()->interpret(*pDocument, aTopPos, xGroup, aCode))
+    {
+        fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup:   disabling group calc due to failed calculation\n");
+        xGroup->meCalcState = sc::GroupCalcDisabled;
         return false;
-    return sc::FormulaGroupInterpreter::getStatic()->interpret(*pDocument, aPos, xGroup, aCode);
+    }
+
+    xGroup->meCalcState = sc::GroupCalcEnabled;
+    return true;
 }
 
 bool ScFormulaCell::InterpretInvariantFormulaGroup()
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 79621ea..b20b437 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -33,18 +33,14 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
 {
     // Decompose the group into individual cells and calculate them individually.
 
-    // Always set the top row to be the top of the group.  Grouped formula
-    // cells are to be calculated for its full segment at all times.
-
-    ScAddress aTopPos = rTopPos;
-    aTopPos.SetRow(xGroup->mnStart);
-    ScAddress aTmpPos = aTopPos;
+    // The caller must ensure that the top position is the start position of
+    // the group.
 
+    ScAddress aTmpPos = rTopPos;
     std::vector<double> aResults;
     aResults.reserve(xGroup->mnLength);
-    for (SCROW i = 0; i < xGroup->mnLength; ++i)
+    for (SCROW i = 0; i < xGroup->mnLength; ++i, aTmpPos.IncRow())
     {
-        aTmpPos.SetRow(aTopPos.Row() + i);
         ScTokenArray aCode2;
         for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
         {
@@ -103,7 +99,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
     } // for loop end (xGroup->mnLength)
 
     if (!aResults.empty())
-        rDoc.SetFormulaResults(aTopPos, &aResults[0], aResults.size());
+        rDoc.SetFormulaResults(rTopPos, &aResults[0], aResults.size());
 
     return true;
 }
commit 041e7dce8097fe2a4fe1cc853cab463dd5ea72e5
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jul 2 18:55:29 2013 -0400

    Actually we need to reset the top row to be the top of the group.
    
    To ensure that a group of formula cells are either all clean or all
    dirty at any given time. We'll fallback to non-grouped calculation
    mode if that's not possible.
    
    Change-Id: I8a5d4740571ca149d32a4630555e3c213c222ef3

diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 3dd43e3..79621ea 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -33,14 +33,18 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
 {
     // Decompose the group into individual cells and calculate them individually.
 
-    ScAddress aTmpPos = rTopPos;
-    SCROW nOffset = rTopPos.Row() - xGroup->mnStart;
-    SCROW nLength = xGroup->mnLength - nOffset;
+    // Always set the top row to be the top of the group.  Grouped formula
+    // cells are to be calculated for its full segment at all times.
+
+    ScAddress aTopPos = rTopPos;
+    aTopPos.SetRow(xGroup->mnStart);
+    ScAddress aTmpPos = aTopPos;
+
     std::vector<double> aResults;
-    aResults.reserve(nLength);
-    for (SCROW i = 0; i < nLength; ++i)
+    aResults.reserve(xGroup->mnLength);
+    for (SCROW i = 0; i < xGroup->mnLength; ++i)
     {
-        aTmpPos.SetRow(rTopPos.Row() + i);
+        aTmpPos.SetRow(aTopPos.Row() + i);
         ScTokenArray aCode2;
         for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
         {
@@ -99,7 +103,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
     } // for loop end (xGroup->mnLength)
 
     if (!aResults.empty())
-        rDoc.SetFormulaResults(rTopPos, &aResults[0], aResults.size());
+        rDoc.SetFormulaResults(aTopPos, &aResults[0], aResults.size());
 
     return true;
 }
commit 75cfc9a332b224597872960df22091ca76747058
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jul 2 16:47:31 2013 -0400

    Be aware that the top row may not always be the top of the group.
    
    Adjust the length and the starting row position for accordingly.
    
    Change-Id: I2f9c5a515887b98334bad51c5409461d5dd1505d

diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 4754bd0..3dd43e3 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -18,6 +18,8 @@
 
 #include "formula/vectortoken.hxx"
 
+#include <vector>
+
 namespace sc {
 
 ScMatrixRef FormulaGroupInterpreterSoftware::inverseMatrix(const ScMatrix& /*rMat*/)
@@ -29,12 +31,16 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
                                                 const ScFormulaCellGroupRef& xGroup,
                                                 ScTokenArray& rCode)
 {
-    // Until we implement group calculation for real, decompose the group into
-    // individual formula token arrays for individual calculation.
+    // Decompose the group into individual cells and calculate them individually.
+
     ScAddress aTmpPos = rTopPos;
-    for (sal_Int32 i = 0; i < xGroup->mnLength; ++i)
+    SCROW nOffset = rTopPos.Row() - xGroup->mnStart;
+    SCROW nLength = xGroup->mnLength - nOffset;
+    std::vector<double> aResults;
+    aResults.reserve(nLength);
+    for (SCROW i = 0; i < nLength; ++i)
     {
-        aTmpPos.SetRow(xGroup->mnStart + i);
+        aTmpPos.SetRow(rTopPos.Row() + i);
         ScTokenArray aCode2;
         for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
         {
@@ -89,11 +95,12 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
         aComp.CompileTokenArray(); // Create RPN token array.
         ScInterpreter aInterpreter(pDest, &rDoc, aTmpPos, aCode2);
         aInterpreter.Interpret();
-        pDest->SetResultToken(aInterpreter.GetResultToken().get());
-        pDest->ResetDirty();
-        pDest->SetChanged(true);
+        aResults.push_back(aInterpreter.GetResultToken()->GetDouble());
     } // for loop end (xGroup->mnLength)
 
+    if (!aResults.empty())
+        rDoc.SetFormulaResults(rTopPos, &aResults[0], aResults.size());
+
     return true;
 }
 
commit d61233a388284383a939e2f26a0e25b9ad243898
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jul 2 16:02:59 2013 -0400

    Move this code from the column code back into the interpreter code.
    
    Change-Id: I7830cdf3f09ed7b6ae6221212bfb84abcdeac523

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 359b8ac..62e1ddf 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -409,9 +409,6 @@ public:
     void        ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark );
     void        ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark );
 
-    double SumNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const;
-    size_t CountNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const;
-
     long GetNeededSize(
         SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY,
         const Fraction& rZoomX, const Fraction& rZoomY,
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 61f57ab..6a2dbd3 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -466,80 +466,6 @@ void ScColumn::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
     }
 }
 
-namespace {
-
-class NumericCellAccumulator
-{
-    double mfSum;
-public:
-    NumericCellAccumulator() : mfSum(0.0) {}
-
-    void operator() (size_t, double fVal)
-    {
-        mfSum += fVal;
-    }
-
-    void operator() (size_t, const ScFormulaCell* pCell)
-    {
-        ScFormulaCell& rCell = const_cast<ScFormulaCell&>(*pCell);
-        if (rCell.IsValue())
-            mfSum += rCell.GetValue();
-    }
-
-    double getSum() const { return mfSum; }
-};
-
-class NumericCellCounter
-{
-    size_t mnCount;
-public:
-    NumericCellCounter() : mnCount(0) {}
-
-    void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize)
-    {
-        switch (rNode.type)
-        {
-            case sc::element_type_numeric:
-                mnCount += nDataSize;
-            break;
-            case sc::element_type_formula:
-            {
-                sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
-                std::advance(it, nOffset);
-                sc::formula_block::const_iterator itEnd = it;
-                std::advance(itEnd, nDataSize);
-                for (; it != itEnd; ++it)
-                {
-                    ScFormulaCell& rCell = const_cast<ScFormulaCell&>(**it);
-                    if (rCell.IsValueNoError())
-                        ++mnCount;
-                }
-            }
-            break;
-            default:
-                ;
-        }
-    }
-
-    size_t getCount() const { return mnCount; }
-};
-
-}
-
-double ScColumn::SumNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const
-{
-    NumericCellAccumulator aFunc;
-    rPos.miCellPos = sc::ParseFormulaNumeric(rPos.miCellPos, maCells, nRow1, nRow2, aFunc);
-    return aFunc.getSum();
-}
-
-size_t ScColumn::CountNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const
-{
-    NumericCellCounter aFunc;
-    rPos.miCellPos = sc::ParseBlock(rPos.miCellPos, maCells, aFunc, nRow1, nRow2);
-    return aFunc.getCount();
-}
-
 void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark )
 {
     SCROW nTop;
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index e31a062..03d87a9 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -24,6 +24,7 @@
 #include "document.hxx"
 #include "cellvalue.hxx"
 #include "dociter.hxx"
+#include "mtvcellfunc.hxx"
 
 #include "formula/token.hxx"
 #include <rtl/logfile.hxx>
@@ -213,6 +214,62 @@ double ScInterpreter::GetGammaDist( double fX, double fAlpha, double fLambda )
 
 namespace {
 
+class NumericCellAccumulator
+{
+    double mfSum;
+public:
+    NumericCellAccumulator() : mfSum(0.0) {}
+
+    void operator() (size_t, double fVal)
+    {
+        mfSum += fVal;
+    }
+
+    void operator() (size_t, const ScFormulaCell* pCell)
+    {
+        ScFormulaCell& rCell = const_cast<ScFormulaCell&>(*pCell);
+        if (rCell.IsValue())
+            mfSum += rCell.GetValue();
+    }
+
+    double getSum() const { return mfSum; }
+};
+
+class NumericCellCounter
+{
+    size_t mnCount;
+public:
+    NumericCellCounter() : mnCount(0) {}
+
+    void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize)
+    {
+        switch (rNode.type)
+        {
+            case sc::element_type_numeric:
+                mnCount += nDataSize;
+            break;
+            case sc::element_type_formula:
+            {
+                sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
+                std::advance(it, nOffset);
+                sc::formula_block::const_iterator itEnd = it;
+                std::advance(itEnd, nDataSize);
+                for (; it != itEnd; ++it)
+                {
+                    ScFormulaCell& rCell = const_cast<ScFormulaCell&>(**it);
+                    if (rCell.IsValueNoError())
+                        ++mnCount;
+                }
+            }
+            break;
+            default:
+                ;
+        }
+    }
+
+    size_t getCount() const { return mnCount; }
+};
+
 class FuncCount : public sc::ColumnSpanSet::ColumnAction
 {
     sc::ColumnBlockConstPosition maPos;
@@ -234,7 +291,9 @@ public:
         if (!bVal)
             return;
 
-        mnCount += mpCol->CountNumericCells(maPos, nRow1, nRow2);
+        NumericCellCounter aFunc;
+        maPos.miCellPos = sc::ParseBlock(maPos.miCellPos, mpCol->GetCellStore(), aFunc, nRow1, nRow2);
+        mnCount += aFunc.getCount();
         mnNumFmt = mpCol->GetNumberFormat(nRow2);
     };
 
@@ -263,7 +322,9 @@ public:
         if (!bVal)
             return;
 
-        mfSum += mpCol->SumNumericCells(maPos, nRow1, nRow2);
+        NumericCellAccumulator aFunc;
+        maPos.miCellPos = sc::ParseFormulaNumeric(maPos.miCellPos, mpCol->GetCellStore(), nRow1, nRow2, aFunc);
+        mfSum += aFunc.getSum();
         mnNumFmt = mpCol->GetNumberFormat(nRow2);
     };
 
commit 4277d968eb4407e22a3d4b467340a347e43e7ea9
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jul 2 15:43:57 2013 -0400

    Move this to another file to distribute the compiler load.
    
    interpr1.cxx is getting way too big....
    
    Change-Id: Ic3e4879daebd09c8dcb86a42b305864dcc1c67c4

diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 93bcfef..8b738fa 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -58,8 +58,6 @@
 #include "queryparam.hxx"
 #include "queryentry.hxx"
 #include "tokenarray.hxx"
-#include "columnspanset.hxx"
-#include "column.hxx"
 
 #include <comphelper/processfactory.hxx>
 #include <comphelper/string.hxx>
@@ -3852,771 +3850,6 @@ void ScInterpreter::ScMax( bool bTextAsZero )
         PushDouble(nMax);
 }
 
-namespace {
-
-class FuncCount : public sc::ColumnSpanSet::ColumnAction
-{
-    sc::ColumnBlockConstPosition maPos;
-    ScColumn* mpCol;
-    size_t mnCount;
-    sal_uInt32 mnNumFmt;
-
-public:
-    FuncCount() : mnCount(0), mnNumFmt(0) {}
-
-    virtual void startColumn(ScColumn* pCol)
-    {
-        mpCol = pCol;
-        mpCol->InitBlockPosition(maPos);
-    }
-
-    virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal)
-    {
-        if (!bVal)
-            return;
-
-        mnCount += mpCol->CountNumericCells(maPos, nRow1, nRow2);
-        mnNumFmt = mpCol->GetNumberFormat(nRow2);
-    };
-
-    size_t getCount() const { return mnCount; }
-    sal_uInt32 getNumberFormat() const { return mnNumFmt; }
-};
-
-class FuncSum : public sc::ColumnSpanSet::ColumnAction
-{
-    sc::ColumnBlockConstPosition maPos;
-    ScColumn* mpCol;
-    double mfSum;
-    sal_uInt32 mnNumFmt;
-
-public:
-    FuncSum() : mfSum(0.0), mnNumFmt(0) {}
-
-    virtual void startColumn(ScColumn* pCol)
-    {
-        mpCol = pCol;
-        mpCol->InitBlockPosition(maPos);
-    }
-
-    virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal)
-    {
-        if (!bVal)
-            return;
-
-        mfSum += mpCol->SumNumericCells(maPos, nRow1, nRow2);
-        mnNumFmt = mpCol->GetNumberFormat(nRow2);
-    };
-
-    double getSum() const { return mfSum; }
-    sal_uInt32 getNumberFormat() const { return mnNumFmt; }
-};
-
-void IterateMatrix(
-    const ScMatrixRef& pMat, ScIterFunc eFunc, bool bTextAsZero,
-    sal_uLong& rCount, short& rFuncFmtType, double& fRes, double& fMem, bool& bNull)
-{
-    if (!pMat)
-        return;
-
-    rFuncFmtType = NUMBERFORMAT_NUMBER;
-    switch (eFunc)
-    {
-        case ifAVERAGE:
-        case ifSUM:
-        {
-            ScMatrix::IterateResult aRes = pMat->Sum(bTextAsZero);
-            if (bNull)
-            {
-                bNull = false;
-                fMem = aRes.mfFirst;
-                fRes += aRes.mfRest;
-            }
-            else
-                fRes += aRes.mfFirst + aRes.mfRest;
-            rCount += aRes.mnCount;
-        }
-        break;
-        case ifCOUNT:
-            rCount += pMat->Count(bTextAsZero);
-        break;
-        case ifCOUNT2:
-            rCount += pMat->Count(true);
-        break;
-        case ifPRODUCT:
-        {
-            ScMatrix::IterateResult aRes = pMat->Product(bTextAsZero);
-            fRes *= aRes.mfRest;
-            rCount += aRes.mnCount;
-        }
-        break;
-        case ifSUMSQ:
-        {
-            ScMatrix::IterateResult aRes = pMat->SumSquare(bTextAsZero);
-            fRes += aRes.mfRest;
-            rCount += aRes.mnCount;
-        }
-        break;
-        default:
-            ;
-    }
-}
-
-}
-
-double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
-{
-    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IterateParameters" );
-    short nParamCount = GetByte();
-    double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
-    double fVal = 0.0;
-    double fMem = 0.0; // first numeric value.
-    bool bNull = true;
-    sal_uLong nCount = 0;
-    ScAddress aAdr;
-    ScRange aRange;
-    size_t nRefInList = 0;
-    if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
-        nGlobalError = 0;
-    while (nParamCount-- > 0)
-    {
-        switch (GetStackType())
-        {
-            case svString:
-            {
-                if( eFunc == ifCOUNT )
-                {
-                    String aStr( PopString() );
-                    sal_uInt32 nFIndex = 0;                 // damit default Land/Spr.
-                    if ( bTextAsZero || pFormatter->IsNumberFormat(aStr, nFIndex, fVal))
-                        nCount++;
-                }
-                else
-                {
-                    switch ( eFunc )
-                    {
-                        case ifAVERAGE:
-                        case ifSUM:
-                        case ifSUMSQ:
-                        case ifPRODUCT:
-                        {
-                            if ( bTextAsZero )
-                            {
-                                Pop();
-                                nCount++;
-                                if ( eFunc == ifPRODUCT )
-                                    fRes = 0.0;
-                            }
-                            else
-                            {
-                                while (nParamCount-- > 0)
-                                    Pop();
-                                SetError( errNoValue );
-                            }
-                        }
-                        break;
-                        default:
-                            Pop();
-                            nCount++;
-                    }
-                }
-            }
-            break;
-            case svDouble    :
-                fVal = GetDouble();
-                nCount++;
-                switch( eFunc )
-                {
-                    case ifAVERAGE:
-                    case ifSUM:
-                        if ( bNull && fVal != 0.0 )
-                        {
-                            bNull = false;
-                            fMem = fVal;
-                        }
-                        else
-                            fRes += fVal;
-                        break;
-                    case ifSUMSQ:   fRes += fVal * fVal; break;
-                    case ifPRODUCT: fRes *= fVal; break;
-                    default: ; // nothing
-                }
-                nFuncFmtType = NUMBERFORMAT_NUMBER;
-                break;
-            case svExternalSingleRef:
-            {
-                ScExternalRefCache::TokenRef pToken;
-                ScExternalRefCache::CellFormat aFmt;
-                PopExternalSingleRef(pToken, &aFmt);
-                if (nGlobalError && (eFunc == ifCOUNT2 || eFunc == ifCOUNT))
-                {
-                    nGlobalError = 0;
-                    if ( eFunc == ifCOUNT2 )
-                        ++nCount;
-                    break;
-                }
-
-                if (!pToken)
-                    break;
-
-                StackVar eType = pToken->GetType();
-                if (eFunc == ifCOUNT2)
-                {
-                    if (eType != formula::svEmptyCell)
-                        nCount++;
-                    if (nGlobalError)
-                        nGlobalError = 0;
-                }
-                else if (eType == formula::svDouble)
-                {
-                    nCount++;
-                    fVal = pToken->GetDouble();
-                    if (aFmt.mbIsSet)
-                    {
-                        nFuncFmtType = aFmt.mnType;
-                        nFuncFmtIndex = aFmt.mnIndex;
-                    }
-                    switch( eFunc )
-                    {
-                        case ifAVERAGE:
-                        case ifSUM:
-                            if ( bNull && fVal != 0.0 )
-                            {
-                                bNull = false;
-                                fMem = fVal;
-                            }
-                            else
-                                fRes += fVal;
-                            break;
-                        case ifSUMSQ:   fRes += fVal * fVal; break;
-                        case ifPRODUCT: fRes *= fVal; break;
-                        case ifCOUNT:
-                            if ( nGlobalError )
-                            {
-                                nGlobalError = 0;
-                                nCount--;
-                            }
-                            break;
-                        default: ; // nothing
-                    }
-                }
-                else if (bTextAsZero && eType == formula::svString)
-                {
-                    nCount++;
-                    if ( eFunc == ifPRODUCT )
-                        fRes = 0.0;
-                }
-            }
-            break;
-            case svSingleRef :
-            {
-                PopSingleRef( aAdr );
-                if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
-                {
-                    nGlobalError = 0;
-                    if ( eFunc == ifCOUNT2 )
-                        ++nCount;
-                    break;
-                }
-                if (glSubTotal && pDok->RowFiltered( aAdr.Row(), aAdr.Tab()))
-                {
-                    break;
-                }
-                ScRefCellValue aCell;
-                aCell.assign(*pDok, aAdr);
-                if (!aCell.isEmpty())
-                {
-                    if( eFunc == ifCOUNT2 )
-                    {
-                        CellType eCellType = aCell.meType;
-                        if (eCellType != CELLTYPE_NONE)
-                            nCount++;
-                        if ( nGlobalError )
-                            nGlobalError = 0;
-                    }
-                    else if (aCell.hasNumeric())
-                    {
-                        nCount++;
-                        fVal = GetCellValue(aAdr, aCell);
-                        CurFmtToFuncFmt();
-                        switch( eFunc )
-                        {
-                            case ifAVERAGE:
-                            case ifSUM:
-                                if ( bNull && fVal != 0.0 )
-                                {
-                                    bNull = false;
-                                    fMem = fVal;
-                                }
-                                else
-                                    fRes += fVal;
-                                break;
-                            case ifSUMSQ:   fRes += fVal * fVal; break;
-                            case ifPRODUCT: fRes *= fVal; break;
-                            case ifCOUNT:
-                                if ( nGlobalError )
-                                {
-                                    nGlobalError = 0;
-                                    nCount--;
-                                }
-                                break;
-                            default: ; // nothing
-                        }
-                    }
-                    else if (bTextAsZero && aCell.hasString())
-                    {
-                        nCount++;
-                        if ( eFunc == ifPRODUCT )
-                            fRes = 0.0;
-                    }
-                }
-            }
-            break;
-            case svDoubleRef :
-            case svRefList :
-            {
-                PopDoubleRef( aRange, nParamCount, nRefInList);
-                if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
-                {
-                    nGlobalError = 0;
-                    if ( eFunc == ifCOUNT2 )
-                        ++nCount;
-                    break;
-                }
-                if( eFunc == ifCOUNT2 )
-                {
-                    ScCellIterator aIter( pDok, aRange, glSubTotal );
-                    for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
-                    {
-                        if (!aIter.hasEmptyData())
-                            ++nCount;
-                    }
-
-                    if ( nGlobalError )
-                        nGlobalError = 0;
-                }
-                else
-                {
-                    ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
-                    sal_uInt16 nErr = 0;
-                    if (aValIter.GetFirst(fVal, nErr))
-                    {
-                        // placed the loop on the inside for performance reasons:
-                        aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
-                        switch( eFunc )
-                        {
-                            case ifAVERAGE:
-                            case ifSUM:
-                                    do
-                                    {
-                                        SetError(nErr);
-                                        if ( bNull && fVal != 0.0 )
-                                        {
-                                            bNull = false;
-                                            fMem = fVal;
-                                        }
-                                        else
-                                            fRes += fVal;
-                                        nCount++;
-                                    }
-                                    while (aValIter.GetNext(fVal, nErr));
-                                    break;
-                            case ifSUMSQ:
-                                    do
-                                    {
-                                        SetError(nErr);
-                                        fRes += fVal * fVal;
-                                        nCount++;
-                                    }
-                                    while (aValIter.GetNext(fVal, nErr));
-                                    break;
-                            case ifPRODUCT:
-                                    do
-                                    {
-                                        SetError(nErr);
-                                        fRes *= fVal;
-                                        nCount++;
-                                    }
-                                    while (aValIter.GetNext(fVal, nErr));
-                                    break;
-                            case ifCOUNT:
-                                    do
-                                    {
-                                        if ( !nErr )
-                                            nCount++;
-                                    }
-                                    while (aValIter.GetNext(fVal, nErr));
-                                    break;
-                            default: ;  // nothing
-                        }
-                        SetError( nErr );
-                    }
-                }
-            }
-            break;
-            case svExternalDoubleRef:
-            {
-                ScMatrixRef pMat;
-                PopExternalDoubleRef(pMat);
-                if (nGlobalError)
-                    break;
-
-                IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fRes, fMem, bNull);
-            }
-            break;
-            case svMatrix :
-            {
-                ScMatrixRef pMat = PopMatrix();
-                IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fRes, fMem, bNull);
-            }
-            break;
-            case svError:
-            {
-                PopError();
-                if ( eFunc == ifCOUNT )
-                {
-                    nGlobalError = 0;
-                }
-                else if ( eFunc == ifCOUNT2 )
-                {
-                    nCount++;
-                    nGlobalError = 0;
-                }
-            }
-            break;
-            default :
-                while (nParamCount-- > 0)
-                    PopError();
-                SetError(errIllegalParameter);
-        }
-    }
-    switch( eFunc )
-    {
-        case ifSUM:     fRes = ::rtl::math::approxAdd( fRes, fMem ); break;
-        case ifAVERAGE: fRes = div(::rtl::math::approxAdd( fRes, fMem ), nCount); break;
-        case ifCOUNT2:
-        case ifCOUNT:   fRes  = nCount; break;
-        case ifPRODUCT: if ( !nCount ) fRes = 0.0; break;
-        default: ; // nothing
-    }
-    // Bei Summen etc. macht ein bool-Ergebnis keinen Sinn
-    // und Anzahl ist immer Number (#38345#)
-    if( eFunc == ifCOUNT || nFuncFmtType == NUMBERFORMAT_LOGICAL )
-        nFuncFmtType = NUMBERFORMAT_NUMBER;
-    return fRes;
-}
-
-
-void ScInterpreter::ScSumSQ()
-{
-    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumSQ" );
-    PushDouble( IterateParameters( ifSUMSQ ) );
-}
-
-
-void ScInterpreter::ScSum()
-{
-    short nParamCount = GetByte();
-    double fRes = 0.0;
-    double fVal = 0.0;
-    ScAddress aAdr;
-    ScRange aRange;
-    size_t nRefInList = 0;
-    while (nParamCount-- > 0)
-    {
-        switch (GetStackType())
-        {
-            case svString:
-            {
-                while (nParamCount-- > 0)
-                    Pop();
-                SetError( errNoValue );
-            }
-            break;
-            case svDouble    :
-                fVal = GetDouble();
-                fRes += fVal;
-                nFuncFmtType = NUMBERFORMAT_NUMBER;
-                break;
-            case svExternalSingleRef:
-            {
-                ScExternalRefCache::TokenRef pToken;
-                ScExternalRefCache::CellFormat aFmt;
-                PopExternalSingleRef(pToken, &aFmt);
-
-                if (!pToken)
-                    break;
-
-                StackVar eType = pToken->GetType();
-                if (eType == formula::svDouble)
-                {
-                    fVal = pToken->GetDouble();
-                    if (aFmt.mbIsSet)
-                    {
-                        nFuncFmtType = aFmt.mnType;
-                        nFuncFmtIndex = aFmt.mnIndex;
-                    }
-
-                    fRes += fVal;
-                }
-            }
-            break;
-            case svSingleRef :
-            {
-                PopSingleRef( aAdr );
-
-                if (glSubTotal && pDok->RowFiltered( aAdr.Row(), aAdr.Tab()))
-                {
-                    break;
-                }
-                ScRefCellValue aCell;
-                aCell.assign(*pDok, aAdr);
-                if (!aCell.isEmpty())
-                {
-                    if (aCell.hasNumeric())
-                    {
-                        fVal = GetCellValue(aAdr, aCell);
-                        CurFmtToFuncFmt();
-                        fRes += fVal;
-                    }
-                }
-            }
-            break;
-            case svDoubleRef :
-            case svRefList :
-            {
-                PopDoubleRef( aRange, nParamCount, nRefInList);
-
-                sc::ColumnSpanSet aSet(false);
-                aSet.set(aRange, true);
-                if (glSubTotal)
-                    // Skip all filtered rows and subtotal formula cells.
-                    pDok->MarkSubTotalCells(aSet, aRange, false);
-
-                FuncSum aAction;
-                aSet.executeColumnAction(*pDok, aAction);
-                fRes = aAction.getSum();
-
-                // Get the number format of the last iterated cell.
-                nFuncFmtIndex = aAction.getNumberFormat();
-                nFuncFmtType = pDok->GetFormatTable()->GetType(nFuncFmtIndex);
-            }
-            break;
-            case svExternalDoubleRef:
-            {
-                ScMatrixRef pMat;
-                PopExternalDoubleRef(pMat);
-                if (nGlobalError)
-                    break;
-
-                sal_uLong nCount = 0;
-                double fMem = 0.0;
-                bool bNull = true;
-                IterateMatrix(pMat, ifSUM, false, nCount, nFuncFmtType, fRes, fMem, bNull);
-                fRes += fMem;
-            }
-            break;
-            case svMatrix :
-            {
-                ScMatrixRef pMat = PopMatrix();
-                sal_uLong nCount = 0;
-                double fMem = 0.0;
-                bool bNull = true;
-                IterateMatrix(pMat, ifSUM, false, nCount, nFuncFmtType, fRes, fMem, bNull);
-                fRes += fMem;
-            }
-            break;
-            case svError:
-            {
-                PopError();
-            }
-            break;
-            default :
-                while (nParamCount-- > 0)
-                    PopError();
-                SetError(errIllegalParameter);
-        }
-    }
-
-    if (nFuncFmtType == NUMBERFORMAT_LOGICAL)
-        nFuncFmtType = NUMBERFORMAT_NUMBER;
-
-    PushDouble(fRes);
-}
-
-
-void ScInterpreter::ScProduct()
-{
-    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScProduct" );
-    PushDouble( IterateParameters( ifPRODUCT ) );
-}
-
-
-void ScInterpreter::ScAverage( bool bTextAsZero )
-{
-    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAverage" );
-    PushDouble( IterateParameters( ifAVERAGE, bTextAsZero ) );
-}
-
-void ScInterpreter::ScCount()
-{
-    short nParamCount = GetByte();
-    double fVal = 0.0;
-    sal_uLong nCount = 0;
-    ScAddress aAdr;
-    ScRange aRange;
-    size_t nRefInList = 0;
-    if (nGlobalError)
-        nGlobalError = 0;
-
-    while (nParamCount-- > 0)
-    {
-        switch (GetStackType())
-        {
-            case svString:
-            {
-                String aStr( PopString() );
-                sal_uInt32 nFIndex = 0;                 // damit default Land/Spr.
-                if (pFormatter->IsNumberFormat(aStr, nFIndex, fVal))
-                    nCount++;
-            }
-            break;
-            case svDouble    :
-                nCount++;
-                nFuncFmtType = NUMBERFORMAT_NUMBER;
-                break;
-            case svExternalSingleRef:
-            {
-                ScExternalRefCache::TokenRef pToken;
-                ScExternalRefCache::CellFormat aFmt;
-                PopExternalSingleRef(pToken, &aFmt);
-                if (nGlobalError)
-                {
-                    nGlobalError = 0;
-                    break;
-                }
-
-                if (!pToken)
-                    break;
-
-                StackVar eType = pToken->GetType();
-                if (eType == formula::svDouble)
-                {
-                    nCount++;
-                    if (aFmt.mbIsSet)
-                    {
-                        nFuncFmtType = aFmt.mnType;
-                        nFuncFmtIndex = aFmt.mnIndex;
-                    }
-
-                    if (nGlobalError)
-                    {
-                        nGlobalError = 0;
-                        nCount--;
-                    }
-                }
-            }
-            break;
-            case svSingleRef :
-            {
-                PopSingleRef( aAdr );
-                if (nGlobalError)
-                {
-                    nGlobalError = 0;
-                    break;
-                }
-                if (glSubTotal && pDok->RowFiltered( aAdr.Row(), aAdr.Tab()))
-                {
-                    break;
-                }
-                ScRefCellValue aCell;
-                aCell.assign(*pDok, aAdr);
-                if (!aCell.isEmpty())
-                {
-                    if (aCell.hasNumeric())
-                    {
-                        nCount++;
-                        CurFmtToFuncFmt();
-                        if (nGlobalError)
-                        {
-                            nGlobalError = 0;
-                            nCount--;
-                        }
-                    }
-                }
-            }
-            break;
-            case svDoubleRef :
-            case svRefList :
-            {
-                PopDoubleRef( aRange, nParamCount, nRefInList);
-                if (nGlobalError)
-                {
-                    nGlobalError = 0;
-                    break;
-                }
-
-                sc::ColumnSpanSet aSet(false);
-                aSet.set(aRange, true);
-                if (glSubTotal)
-                    // Skip all filtered rows and subtotal formula cells.
-                    pDok->MarkSubTotalCells(aSet, aRange, false);
-
-                FuncCount aAction;
-                aSet.executeColumnAction(*pDok, aAction);
-                nCount = aAction.getCount();
-
-                // Get the number format of the last iterated cell.
-                nFuncFmtIndex = aAction.getNumberFormat();
-                nFuncFmtType = pDok->GetFormatTable()->GetType(nFuncFmtIndex);
-            }
-            break;
-            case svExternalDoubleRef:
-            {
-                ScMatrixRef pMat;
-                PopExternalDoubleRef(pMat);
-                if (nGlobalError)
-                    break;
-
-                double fMem = 0.0, fRes = 0.0;
-                bool bNull = true;
-                IterateMatrix(pMat, ifCOUNT, false, nCount, nFuncFmtType, fRes, fMem, bNull);
-            }
-            break;
-            case svMatrix :
-            {
-                ScMatrixRef pMat = PopMatrix();
-                double fMem = 0.0, fRes = 0.0;
-                bool bNull = true;
-                IterateMatrix(pMat, ifCOUNT, false, nCount, nFuncFmtType, fRes, fMem, bNull);
-            }
-            break;
-            case svError:
-            {
-                PopError();
-                nGlobalError = 0;
-            }
-            break;
-            default :
-                while (nParamCount-- > 0)
-                    PopError();
-                SetError(errIllegalParameter);
-        }
-    }
-
-    nFuncFmtType = NUMBERFORMAT_NUMBER;
-
-    PushDouble(nCount);
-}
-
-
-void ScInterpreter::ScCount2()
-{
-    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCount2" );
-    PushDouble( IterateParameters( ifCOUNT2 ) );
-}
-
-
 void ScInterpreter::GetStVarParams( double& rVal, double& rValCount,
                 bool bTextAsZero )
 {
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index 7f712e3..e31a062 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -18,8 +18,17 @@
  */
 
 
-#include <rtl/logfile.hxx>
 #include "interpre.hxx"
+#include "columnspanset.hxx"
+#include "column.hxx"
+#include "document.hxx"
+#include "cellvalue.hxx"
+#include "dociter.hxx"
+
+#include "formula/token.hxx"
+#include <rtl/logfile.hxx>
+
+using namespace formula;
 
 double const fHalfMachEps = 0.5 * ::std::numeric_limits<double>::epsilon();
 
@@ -202,4 +211,768 @@ double ScInterpreter::GetGammaDist( double fX, double fAlpha, double fLambda )
         return GetLowRegIGamma( fAlpha, fX / fLambda);
 }
 
+namespace {
+
+class FuncCount : public sc::ColumnSpanSet::ColumnAction
+{
+    sc::ColumnBlockConstPosition maPos;
+    ScColumn* mpCol;
+    size_t mnCount;
+    sal_uInt32 mnNumFmt;
+
+public:
+    FuncCount() : mnCount(0), mnNumFmt(0) {}
+
+    virtual void startColumn(ScColumn* pCol)
+    {
+        mpCol = pCol;
+        mpCol->InitBlockPosition(maPos);
+    }
+
+    virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal)
+    {
+        if (!bVal)
+            return;
+
+        mnCount += mpCol->CountNumericCells(maPos, nRow1, nRow2);
+        mnNumFmt = mpCol->GetNumberFormat(nRow2);
+    };
+
+    size_t getCount() const { return mnCount; }
+    sal_uInt32 getNumberFormat() const { return mnNumFmt; }
+};
+
+class FuncSum : public sc::ColumnSpanSet::ColumnAction
+{
+    sc::ColumnBlockConstPosition maPos;
+    ScColumn* mpCol;
+    double mfSum;
+    sal_uInt32 mnNumFmt;
+
+public:
+    FuncSum() : mfSum(0.0), mnNumFmt(0) {}
+
+    virtual void startColumn(ScColumn* pCol)
+    {
+        mpCol = pCol;
+        mpCol->InitBlockPosition(maPos);
+    }
+
+    virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal)
+    {
+        if (!bVal)
+            return;
+
+        mfSum += mpCol->SumNumericCells(maPos, nRow1, nRow2);
+        mnNumFmt = mpCol->GetNumberFormat(nRow2);
+    };
+
+    double getSum() const { return mfSum; }
+    sal_uInt32 getNumberFormat() const { return mnNumFmt; }
+};
+
+void IterateMatrix(
+    const ScMatrixRef& pMat, ScIterFunc eFunc, bool bTextAsZero,
+    sal_uLong& rCount, short& rFuncFmtType, double& fRes, double& fMem, bool& bNull)
+{
+    if (!pMat)
+        return;
+
+    rFuncFmtType = NUMBERFORMAT_NUMBER;
+    switch (eFunc)
+    {
+        case ifAVERAGE:
+        case ifSUM:
+        {
+            ScMatrix::IterateResult aRes = pMat->Sum(bTextAsZero);
+            if (bNull)
+            {
+                bNull = false;
+                fMem = aRes.mfFirst;
+                fRes += aRes.mfRest;
+            }
+            else
+                fRes += aRes.mfFirst + aRes.mfRest;
+            rCount += aRes.mnCount;
+        }
+        break;
+        case ifCOUNT:
+            rCount += pMat->Count(bTextAsZero);
+        break;
+        case ifCOUNT2:
+            rCount += pMat->Count(true);
+        break;
+        case ifPRODUCT:
+        {
+            ScMatrix::IterateResult aRes = pMat->Product(bTextAsZero);
+            fRes *= aRes.mfRest;
+            rCount += aRes.mnCount;
+        }
+        break;
+        case ifSUMSQ:
+        {
+            ScMatrix::IterateResult aRes = pMat->SumSquare(bTextAsZero);
+            fRes += aRes.mfRest;
+            rCount += aRes.mnCount;
+        }
+        break;
+        default:
+            ;
+    }
+}
+
+}
+
+double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
+{
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IterateParameters" );
+    short nParamCount = GetByte();
+    double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
+    double fVal = 0.0;
+    double fMem = 0.0; // first numeric value.
+    bool bNull = true;
+    sal_uLong nCount = 0;
+    ScAddress aAdr;
+    ScRange aRange;
+    size_t nRefInList = 0;
+    if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
+        nGlobalError = 0;
+    while (nParamCount-- > 0)
+    {
+        switch (GetStackType())
+        {
+            case svString:
+            {
+                if( eFunc == ifCOUNT )
+                {
+                    String aStr( PopString() );
+                    sal_uInt32 nFIndex = 0;                 // damit default Land/Spr.
+                    if ( bTextAsZero || pFormatter->IsNumberFormat(aStr, nFIndex, fVal))
+                        nCount++;
+                }
+                else
+                {
+                    switch ( eFunc )
+                    {
+                        case ifAVERAGE:
+                        case ifSUM:
+                        case ifSUMSQ:
+                        case ifPRODUCT:
+                        {
+                            if ( bTextAsZero )
+                            {
+                                Pop();
+                                nCount++;
+                                if ( eFunc == ifPRODUCT )
+                                    fRes = 0.0;
+                            }
+                            else
+                            {
+                                while (nParamCount-- > 0)
+                                    Pop();
+                                SetError( errNoValue );
+                            }
+                        }
+                        break;
+                        default:
+                            Pop();
+                            nCount++;
+                    }
+                }
+            }
+            break;
+            case svDouble    :
+                fVal = GetDouble();
+                nCount++;
+                switch( eFunc )
+                {
+                    case ifAVERAGE:
+                    case ifSUM:
+                        if ( bNull && fVal != 0.0 )
+                        {
+                            bNull = false;
+                            fMem = fVal;
+                        }
+                        else
+                            fRes += fVal;
+                        break;
+                    case ifSUMSQ:   fRes += fVal * fVal; break;
+                    case ifPRODUCT: fRes *= fVal; break;
+                    default: ; // nothing
+                }
+                nFuncFmtType = NUMBERFORMAT_NUMBER;
+                break;
+            case svExternalSingleRef:
+            {
+                ScExternalRefCache::TokenRef pToken;
+                ScExternalRefCache::CellFormat aFmt;
+                PopExternalSingleRef(pToken, &aFmt);
+                if (nGlobalError && (eFunc == ifCOUNT2 || eFunc == ifCOUNT))
+                {
+                    nGlobalError = 0;
+                    if ( eFunc == ifCOUNT2 )
+                        ++nCount;
+                    break;
+                }
+
+                if (!pToken)
+                    break;
+
+                StackVar eType = pToken->GetType();
+                if (eFunc == ifCOUNT2)
+                {
+                    if (eType != formula::svEmptyCell)
+                        nCount++;
+                    if (nGlobalError)
+                        nGlobalError = 0;
+                }
+                else if (eType == formula::svDouble)
+                {
+                    nCount++;
+                    fVal = pToken->GetDouble();
+                    if (aFmt.mbIsSet)
+                    {
+                        nFuncFmtType = aFmt.mnType;
+                        nFuncFmtIndex = aFmt.mnIndex;
+                    }
+                    switch( eFunc )
+                    {
+                        case ifAVERAGE:
+                        case ifSUM:
+                            if ( bNull && fVal != 0.0 )
+                            {
+                                bNull = false;
+                                fMem = fVal;
+                            }
+                            else
+                                fRes += fVal;
+                            break;
+                        case ifSUMSQ:   fRes += fVal * fVal; break;
+                        case ifPRODUCT: fRes *= fVal; break;
+                        case ifCOUNT:
+                            if ( nGlobalError )
+                            {
+                                nGlobalError = 0;
+                                nCount--;
+                            }
+                            break;
+                        default: ; // nothing
+                    }
+                }
+                else if (bTextAsZero && eType == formula::svString)
+                {
+                    nCount++;
+                    if ( eFunc == ifPRODUCT )
+                        fRes = 0.0;
+                }
+            }
+            break;
+            case svSingleRef :
+            {
+                PopSingleRef( aAdr );
+                if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
+                {
+                    nGlobalError = 0;
+                    if ( eFunc == ifCOUNT2 )
+                        ++nCount;
+                    break;
+                }
+                if (glSubTotal && pDok->RowFiltered( aAdr.Row(), aAdr.Tab()))
+                {
+                    break;
+                }
+                ScRefCellValue aCell;
+                aCell.assign(*pDok, aAdr);
+                if (!aCell.isEmpty())
+                {
+                    if( eFunc == ifCOUNT2 )
+                    {
+                        CellType eCellType = aCell.meType;
+                        if (eCellType != CELLTYPE_NONE)
+                            nCount++;
+                        if ( nGlobalError )
+                            nGlobalError = 0;
+                    }
+                    else if (aCell.hasNumeric())
+                    {
+                        nCount++;
+                        fVal = GetCellValue(aAdr, aCell);
+                        CurFmtToFuncFmt();
+                        switch( eFunc )
+                        {
+                            case ifAVERAGE:
+                            case ifSUM:
+                                if ( bNull && fVal != 0.0 )
+                                {
+                                    bNull = false;
+                                    fMem = fVal;
+                                }
+                                else
+                                    fRes += fVal;
+                                break;
+                            case ifSUMSQ:   fRes += fVal * fVal; break;
+                            case ifPRODUCT: fRes *= fVal; break;
+                            case ifCOUNT:
+                                if ( nGlobalError )
+                                {
+                                    nGlobalError = 0;
+                                    nCount--;
+                                }
+                                break;
+                            default: ; // nothing
+                        }
+                    }
+                    else if (bTextAsZero && aCell.hasString())
+                    {
+                        nCount++;
+                        if ( eFunc == ifPRODUCT )
+                            fRes = 0.0;
+                    }
+                }
+            }
+            break;
+            case svDoubleRef :
+            case svRefList :
+            {
+                PopDoubleRef( aRange, nParamCount, nRefInList);
+                if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
+                {
+                    nGlobalError = 0;
+                    if ( eFunc == ifCOUNT2 )
+                        ++nCount;
+                    break;
+                }
+                if( eFunc == ifCOUNT2 )
+                {
+                    ScCellIterator aIter( pDok, aRange, glSubTotal );
+                    for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
+                    {
+                        if (!aIter.hasEmptyData())
+                            ++nCount;
+                    }
+
+                    if ( nGlobalError )
+                        nGlobalError = 0;
+                }
+                else
+                {
+                    ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
+                    sal_uInt16 nErr = 0;
+                    if (aValIter.GetFirst(fVal, nErr))
+                    {
+                        // placed the loop on the inside for performance reasons:
+                        aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
+                        switch( eFunc )
+                        {
+                            case ifAVERAGE:
+                            case ifSUM:
+                                    do
+                                    {
+                                        SetError(nErr);
+                                        if ( bNull && fVal != 0.0 )
+                                        {
+                                            bNull = false;
+                                            fMem = fVal;
+                                        }
+                                        else
+                                            fRes += fVal;
+                                        nCount++;
+                                    }
+                                    while (aValIter.GetNext(fVal, nErr));
+                                    break;
+                            case ifSUMSQ:
+                                    do
+                                    {
+                                        SetError(nErr);
+                                        fRes += fVal * fVal;
+                                        nCount++;
+                                    }
+                                    while (aValIter.GetNext(fVal, nErr));
+                                    break;
+                            case ifPRODUCT:
+                                    do
+                                    {
+                                        SetError(nErr);
+                                        fRes *= fVal;
+                                        nCount++;
+                                    }
+                                    while (aValIter.GetNext(fVal, nErr));
+                                    break;
+                            case ifCOUNT:
+                                    do
+                                    {
+                                        if ( !nErr )
+                                            nCount++;
+                                    }
+                                    while (aValIter.GetNext(fVal, nErr));
+                                    break;
+                            default: ;  // nothing
+                        }
+                        SetError( nErr );
+                    }
+                }
+            }
+            break;
+            case svExternalDoubleRef:
+            {
+                ScMatrixRef pMat;
+                PopExternalDoubleRef(pMat);
+                if (nGlobalError)
+                    break;
+
+                IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fRes, fMem, bNull);
+            }
+            break;
+            case svMatrix :
+            {
+                ScMatrixRef pMat = PopMatrix();
+                IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fRes, fMem, bNull);
+            }
+            break;
+            case svError:
+            {
+                PopError();
+                if ( eFunc == ifCOUNT )
+                {
+                    nGlobalError = 0;
+                }
+                else if ( eFunc == ifCOUNT2 )
+                {
+                    nCount++;
+                    nGlobalError = 0;
+                }
+            }
+            break;
+            default :
+                while (nParamCount-- > 0)
+                    PopError();
+                SetError(errIllegalParameter);
+        }
+    }
+    switch( eFunc )
+    {
+        case ifSUM:     fRes = ::rtl::math::approxAdd( fRes, fMem ); break;
+        case ifAVERAGE: fRes = div(::rtl::math::approxAdd( fRes, fMem ), nCount); break;
+        case ifCOUNT2:
+        case ifCOUNT:   fRes  = nCount; break;
+        case ifPRODUCT: if ( !nCount ) fRes = 0.0; break;
+        default: ; // nothing
+    }
+    // Bei Summen etc. macht ein bool-Ergebnis keinen Sinn
+    // und Anzahl ist immer Number (#38345#)
+    if( eFunc == ifCOUNT || nFuncFmtType == NUMBERFORMAT_LOGICAL )
+        nFuncFmtType = NUMBERFORMAT_NUMBER;
+    return fRes;
+}
+
+
+void ScInterpreter::ScSumSQ()
+{
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumSQ" );
+    PushDouble( IterateParameters( ifSUMSQ ) );
+}
+
+
+void ScInterpreter::ScSum()
+{
+    short nParamCount = GetByte();
+    double fRes = 0.0;
+    double fVal = 0.0;
+    ScAddress aAdr;
+    ScRange aRange;
+    size_t nRefInList = 0;
+    while (nParamCount-- > 0)
+    {
+        switch (GetStackType())
+        {
+            case svString:
+            {
+                while (nParamCount-- > 0)
+                    Pop();
+                SetError( errNoValue );
+            }
+            break;
+            case svDouble    :
+                fVal = GetDouble();
+                fRes += fVal;
+                nFuncFmtType = NUMBERFORMAT_NUMBER;
+                break;
+            case svExternalSingleRef:
+            {
+                ScExternalRefCache::TokenRef pToken;
+                ScExternalRefCache::CellFormat aFmt;
+                PopExternalSingleRef(pToken, &aFmt);
+
+                if (!pToken)
+                    break;
+
+                StackVar eType = pToken->GetType();
+                if (eType == formula::svDouble)
+                {
+                    fVal = pToken->GetDouble();
+                    if (aFmt.mbIsSet)
+                    {
+                        nFuncFmtType = aFmt.mnType;
+                        nFuncFmtIndex = aFmt.mnIndex;
+                    }
+
+                    fRes += fVal;
+                }
+            }
+            break;
+            case svSingleRef :
+            {
+                PopSingleRef( aAdr );
+
+                if (glSubTotal && pDok->RowFiltered( aAdr.Row(), aAdr.Tab()))
+                {
+                    break;
+                }
+                ScRefCellValue aCell;
+                aCell.assign(*pDok, aAdr);
+                if (!aCell.isEmpty())
+                {
+                    if (aCell.hasNumeric())
+                    {
+                        fVal = GetCellValue(aAdr, aCell);
+                        CurFmtToFuncFmt();
+                        fRes += fVal;
+                    }
+                }
+            }
+            break;
+            case svDoubleRef :
+            case svRefList :
+            {
+                PopDoubleRef( aRange, nParamCount, nRefInList);
+
+                sc::ColumnSpanSet aSet(false);
+                aSet.set(aRange, true);
+                if (glSubTotal)
+                    // Skip all filtered rows and subtotal formula cells.
+                    pDok->MarkSubTotalCells(aSet, aRange, false);
+
+                FuncSum aAction;
+                aSet.executeColumnAction(*pDok, aAction);
+                fRes = aAction.getSum();
+
+                // Get the number format of the last iterated cell.
+                nFuncFmtIndex = aAction.getNumberFormat();
+                nFuncFmtType = pDok->GetFormatTable()->GetType(nFuncFmtIndex);
+            }
+            break;
+            case svExternalDoubleRef:
+            {
+                ScMatrixRef pMat;
+                PopExternalDoubleRef(pMat);
+                if (nGlobalError)
+                    break;
+
+                sal_uLong nCount = 0;
+                double fMem = 0.0;
+                bool bNull = true;
+                IterateMatrix(pMat, ifSUM, false, nCount, nFuncFmtType, fRes, fMem, bNull);
+                fRes += fMem;
+            }
+            break;
+            case svMatrix :
+            {
+                ScMatrixRef pMat = PopMatrix();
+                sal_uLong nCount = 0;
+                double fMem = 0.0;
+                bool bNull = true;
+                IterateMatrix(pMat, ifSUM, false, nCount, nFuncFmtType, fRes, fMem, bNull);
+                fRes += fMem;
+            }
+            break;
+            case svError:
+            {
+                PopError();
+            }
+            break;
+            default :
+                while (nParamCount-- > 0)
+                    PopError();
+                SetError(errIllegalParameter);
+        }
+    }
+
+    if (nFuncFmtType == NUMBERFORMAT_LOGICAL)
+        nFuncFmtType = NUMBERFORMAT_NUMBER;
+
+    PushDouble(fRes);
+}
+
+
+void ScInterpreter::ScProduct()
+{
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScProduct" );
+    PushDouble( IterateParameters( ifPRODUCT ) );
+}
+
+
+void ScInterpreter::ScAverage( bool bTextAsZero )
+{
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAverage" );
+    PushDouble( IterateParameters( ifAVERAGE, bTextAsZero ) );
+}
+
+void ScInterpreter::ScCount()
+{
+    short nParamCount = GetByte();
+    double fVal = 0.0;
+    sal_uLong nCount = 0;
+    ScAddress aAdr;
+    ScRange aRange;
+    size_t nRefInList = 0;
+    if (nGlobalError)
+        nGlobalError = 0;
+
+    while (nParamCount-- > 0)
+    {
+        switch (GetStackType())
+        {
+            case svString:
+            {
+                String aStr( PopString() );
+                sal_uInt32 nFIndex = 0;                 // damit default Land/Spr.
+                if (pFormatter->IsNumberFormat(aStr, nFIndex, fVal))
+                    nCount++;
+            }
+            break;
+            case svDouble    :
+                nCount++;
+                nFuncFmtType = NUMBERFORMAT_NUMBER;
+                break;
+            case svExternalSingleRef:
+            {
+                ScExternalRefCache::TokenRef pToken;
+                ScExternalRefCache::CellFormat aFmt;
+                PopExternalSingleRef(pToken, &aFmt);
+                if (nGlobalError)
+                {
+                    nGlobalError = 0;
+                    break;
+                }
+
+                if (!pToken)
+                    break;
+
+                StackVar eType = pToken->GetType();
+                if (eType == formula::svDouble)
+                {
+                    nCount++;
+                    if (aFmt.mbIsSet)
+                    {
+                        nFuncFmtType = aFmt.mnType;
+                        nFuncFmtIndex = aFmt.mnIndex;
+                    }
+
+                    if (nGlobalError)
+                    {
+                        nGlobalError = 0;
+                        nCount--;
+                    }
+                }
+            }
+            break;
+            case svSingleRef :
+            {
+                PopSingleRef( aAdr );
+                if (nGlobalError)
+                {
+                    nGlobalError = 0;
+                    break;
+                }
+                if (glSubTotal && pDok->RowFiltered( aAdr.Row(), aAdr.Tab()))
+                {
+                    break;
+                }
+                ScRefCellValue aCell;
+                aCell.assign(*pDok, aAdr);
+                if (!aCell.isEmpty())
+                {
+                    if (aCell.hasNumeric())
+                    {
+                        nCount++;
+                        CurFmtToFuncFmt();
+                        if (nGlobalError)
+                        {
+                            nGlobalError = 0;
+                            nCount--;
+                        }
+                    }
+                }
+            }
+            break;
+            case svDoubleRef :
+            case svRefList :
+            {
+                PopDoubleRef( aRange, nParamCount, nRefInList);
+                if (nGlobalError)
+                {
+                    nGlobalError = 0;
+                    break;
+                }
+
+                sc::ColumnSpanSet aSet(false);
+                aSet.set(aRange, true);
+                if (glSubTotal)
+                    // Skip all filtered rows and subtotal formula cells.
+                    pDok->MarkSubTotalCells(aSet, aRange, false);
+
+                FuncCount aAction;
+                aSet.executeColumnAction(*pDok, aAction);
+                nCount = aAction.getCount();
+
+                // Get the number format of the last iterated cell.
+                nFuncFmtIndex = aAction.getNumberFormat();
+                nFuncFmtType = pDok->GetFormatTable()->GetType(nFuncFmtIndex);
+            }
+            break;
+            case svExternalDoubleRef:
+            {
+                ScMatrixRef pMat;
+                PopExternalDoubleRef(pMat);
+                if (nGlobalError)
+                    break;
+
+                double fMem = 0.0, fRes = 0.0;
+                bool bNull = true;
+                IterateMatrix(pMat, ifCOUNT, false, nCount, nFuncFmtType, fRes, fMem, bNull);
+            }
+            break;
+            case svMatrix :
+            {
+                ScMatrixRef pMat = PopMatrix();
+                double fMem = 0.0, fRes = 0.0;
+                bool bNull = true;
+                IterateMatrix(pMat, ifCOUNT, false, nCount, nFuncFmtType, fRes, fMem, bNull);
+            }
+            break;
+            case svError:
+            {
+                PopError();
+                nGlobalError = 0;
+            }
+            break;
+            default :
+                while (nParamCount-- > 0)
+                    PopError();
+                SetError(errIllegalParameter);
+        }
+    }
+
+    nFuncFmtType = NUMBERFORMAT_NUMBER;
+
+    PushDouble(nCount);
+}
+
+
+void ScInterpreter::ScCount2()
+{
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCount2" );
+    PushDouble( IterateParameters( ifCOUNT2 ) );
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 6f86d931b4266d00fec75c0124ac9fc3026a4f1b
Author: Frédéric Wang <fred.wang at free.fr>
Date:   Sun Jun 30 17:34:40 2013 +0200

     fdo#66283 - MathML export: remove useless mrow/mstyle with font commands
    
    Change-Id: I57870a22ef915950fe177dcb75ab31a25f2520c8
    Reviewed-on: https://gerrit.libreoffice.org/4634
    Reviewed-by: Khaled Hosny <khaledhosny at eglug.org>
    Tested-by: Khaled Hosny <khaledhosny at eglug.org>

diff --git a/starmath/source/mathmlexport.cxx b/starmath/source/mathmlexport.cxx
index a10765e..a523693 100644
--- a/starmath/source/mathmlexport.cxx
+++ b/starmath/source/mathmlexport.cxx
@@ -780,13 +780,15 @@ void SmXMLExport::ExportUnaryHorizontal(const SmNode *pNode, int nLevel)
     ExportExpression(pNode, nLevel);
 }
 
-void SmXMLExport::ExportExpression(const SmNode *pNode, int nLevel)
+void SmXMLExport::ExportExpression(const SmNode *pNode, int nLevel,
+                                   bool bNoMrowContainer /*=false*/)
 {
     SvXMLElementExport *pRow=0;
     sal_uLong  nSize = pNode->GetNumSubNodes();
 
     // #i115443: nodes of type expression always need to be grouped with mrow statement
-    if (nSize > 1 || (pNode && pNode->GetType() == NEXPRESSION))
+    if (!bNoMrowContainer &&
+        (nSize > 1 || (pNode && pNode->GetType() == NEXPRESSION)))
         pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW, sal_True, sal_True);
 
     for (sal_uInt16 i = 0; i < nSize; i++)
@@ -1290,8 +1292,6 @@ static bool lcl_HasEffectOnMathvariant( const SmTokenType eType )
 
 void SmXMLExport::ExportFont(const SmNode *pNode, int nLevel)
 {
-    SvXMLElementExport *pElement = 0;
-
     //
     // gather the mathvariant attribut relevant data from all
     // successively following SmFontNodes...
@@ -1328,10 +1328,8 @@ void SmXMLExport::ExportFont(const SmNode *pNode, int nLevel)
 
     switch (pNode->GetToken().eType)
     {
-        //wrap a phantom element around everything*/
         case TPHANTOM:
-            pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
-                XML_MPHANTOM, sal_True,sal_True);
+            // No attribute needed. An <mphantom> element will be used below.
             break;
         case TBLACK:
             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_BLACK);
@@ -1455,15 +1453,15 @@ void SmXMLExport::ExportFont(const SmNode *pNode, int nLevel)
             break;
 
     }
-    //for now we will just always export with a style and not worry about
-    //anyone else for the moment.
     {
-        //wrap a style around it
-        SvXMLElementExport aStyle(*this, XML_NAMESPACE_MATH, XML_MSTYLE, sal_True,sal_True);
-        ExportExpression(pNode, nLevel);
+        // Wrap everything in an <mphantom> or <mstyle> element. These elements
+        // are mrow-like, so ExportExpression doesn't need to add an explicit
+        // <mrow> element. See #fdo 66283.
+        SvXMLElementExport aElement(*this, XML_NAMESPACE_MATH,
+            pNode->GetToken().eType == TPHANTOM ? XML_MPHANTOM : XML_MSTYLE,
+            sal_True, sal_True);
+        ExportExpression(pNode, nLevel, true);
     }
-
-    delete pElement;
 }
 
 
diff --git a/starmath/source/mathmlexport.hxx b/starmath/source/mathmlexport.hxx
index 3cbaaae..d7ca75a 100644
--- a/starmath/source/mathmlexport.hxx
+++ b/starmath/source/mathmlexport.hxx
@@ -84,7 +84,8 @@ protected:
     void ExportNodes(const SmNode *pNode, int nLevel);
     void ExportTable(const SmNode *pNode, int nLevel);
     void ExportLine(const SmNode *pNode, int nLevel);
-    void ExportExpression(const SmNode *pNode, int nLevel);
+    void ExportExpression(const SmNode *pNode, int nLevel,
+                          bool bNoMrowContainer = false);
     void ExportText(const SmNode *pNode, int nLevel);
     void ExportMath(const SmNode *pNode, int nLevel);
     void ExportPolygon(const SmNode *pNode, int nLevel);
commit d2a71b952850cdf1a7efc5c0f86df9864201a950
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Tue Jul 2 21:58:12 2013 +0100

    fdo#46990 - re-work new desktop checks, guard against NULL DESKTOP_SESSION.
    
    Change-Id: Ia3e408b372989b757f7dde080849e38d315d53cd

diff --git a/vcl/unx/generic/desktopdetect/desktopdetector.cxx b/vcl/unx/generic/desktopdetect/desktopdetector.cxx
index a133449..d2d91de 100644
--- a/vcl/unx/generic/desktopdetect/desktopdetector.cxx
+++ b/vcl/unx/generic/desktopdetect/desktopdetector.cxx
@@ -42,11 +42,8 @@ static bool is_gnome_desktop( Display* pDisplay )
 
     // warning: these checks are coincidental, GNOME does not
     // explicitly advertise itself
-
-    if ( "gnome" == getenv( "DESKTOP_SESSION" ) || NULL != getenv( "GNOME_DESKTOP_SESSION_ID" ) )
-    {
+    if ( NULL != getenv( "GNOME_DESKTOP_SESSION_ID" ) )
         ret = true;
-    }
 
     if( ! ret )
     {
@@ -121,24 +118,6 @@ static bool is_gnome_desktop( Display* pDisplay )
     return ret;
 }
 
-static bool is_xfce_desktop( Display* pDisplay )
-{
-    if ( "xfce" == getenv( "DESKTOP_SESSION" ) )
-    {
-        return true;
-    }
-    return false;
-}
-
-static bool is_mate_desktop( Display* pDisplay )
-{
-    if ( "mate" == getenv( "DESKTOP_SESSION" ) )
-    {
-        return true;
-    }
-    return false;
-}
-
 static bool bWasXError = false;
 
 static inline bool WasXError()
@@ -369,18 +348,30 @@ DESKTOP_DETECTOR_PUBLIC DesktopType get_desktop_environment()
 
     XErrorHandler pOldHdl = XSetErrorHandler( autodect_error_handler );
 
-    if ( is_tde_desktop( pDisplay ) )
-        ret = DESKTOP_TDE;
+    const char *pSession;
+    OString aDesktopSession;
+
+    if ( ( pSession = getenv( "DESKTOP_SESSION" ) ) )
+        aDesktopSession = OString( pSession, strlen( pSession ) );
+
+    // fast environment variable checks
+    if ( aDesktopSession.equalsIgnoreAsciiCase( "gnome" ) )
+        ret = DESKTOP_GNOME;
+    else if ( aDesktopSession.equalsIgnoreAsciiCase( "mate" ) )
+        ret = DESKTOP_MATE;
+    else if ( aDesktopSession.equalsIgnoreAsciiCase( "xfce" ) )
+        ret = DESKTOP_XFCE;
+
+    // these guys can be slower, with X property fetches,
+    // round-trips etc. and so are done later.
     else if ( is_kde4_desktop( pDisplay ) )
         ret = DESKTOP_KDE4;
     else if ( is_gnome_desktop( pDisplay ) )
         ret = DESKTOP_GNOME;
-    else if ( is_xfce_desktop( pDisplay ) )
-        ret = DESKTOP_XFCE;
-    else if ( is_mate_desktop( pDisplay ) )
-        ret = DESKTOP_MATE;
     else if ( is_kde_desktop( pDisplay ) )
         ret = DESKTOP_KDE;
+    else if ( is_tde_desktop( pDisplay ) )
+        ret = DESKTOP_TDE;
     else
         ret = DESKTOP_UNKNOWN;
 
diff --git a/vcl/unx/generic/plugadapt/salplug.cxx b/vcl/unx/generic/plugadapt/salplug.cxx
index fba45f1..4cb49f9 100644
--- a/vcl/unx/generic/plugadapt/salplug.cxx
+++ b/vcl/unx/generic/plugadapt/salplug.cxx
@@ -188,7 +188,9 @@ static SalInstance* autodetect_plugin()
     // no server at all: dummy plugin
     if ( desktop == DESKTOP_NONE )
         pList = pHeadlessFallbackList;
-    else if ( desktop == DESKTOP_GNOME || desktop == DESKTOP_XFCE || desktop == DESKTOP_MATE )
+    else if ( desktop == DESKTOP_GNOME ||
+              desktop == DESKTOP_XFCE  ||
+              desktop == DESKTOP_MATE )
         pList = pStandardFallbackList;
     else if( desktop == DESKTOP_TDE )
         pList = pTDEFallbackList;
@@ -287,7 +289,11 @@ void SalAbort( const OUString& rErrorText, bool bDumpCore )
         _exit(1);
 }
 
-static const char * desktop_strings[] = { "none", "unknown", "GNOME", "XFCE", "MATE", "TDE", "KDE", "KDE4" };
+// Order to match desktops.hxx' DesktopType
+static const char * desktop_strings[] = {
+    "none", "unknown", "GNOME",
+    "XFCE", "MATE", "TDE",
+    "KDE", "KDE4" };
 
 const OUString& SalGetDesktopEnvironment()
 {
commit f31fad32005c6709eaae71b49af31264e585478a
Author: Pader Rezso <rezso at rezso.net>
Date:   Tue Jul 2 21:23:56 2013 +0100

    fdo#46990 - detect MATE and XFCE desktops.
    
    Change-Id: Id72860fc2e7d6b40f4fcb96b8f504a4f86a335b1

diff --git a/vcl/inc/unx/desktops.hxx b/vcl/inc/unx/desktops.hxx
index c97d708..e41add4 100644
--- a/vcl/inc/unx/desktops.hxx
+++ b/vcl/inc/unx/desktops.hxx
@@ -24,6 +24,8 @@ enum DesktopType {
     DESKTOP_NONE, // headless, i.e. no X connection at all
     DESKTOP_UNKNOWN, // unknown desktop, simple WM, etc.
     DESKTOP_GNOME,
+    DESKTOP_XFCE,
+    DESKTOP_MATE,
     DESKTOP_KDE,
     DESKTOP_KDE4,
     DESKTOP_TDE
diff --git a/vcl/unx/generic/desktopdetect/desktopdetector.cxx b/vcl/unx/generic/desktopdetect/desktopdetector.cxx
index f1d6c26..a133449 100644
--- a/vcl/unx/generic/desktopdetect/desktopdetector.cxx
+++ b/vcl/unx/generic/desktopdetect/desktopdetector.cxx
@@ -43,8 +43,10 @@ static bool is_gnome_desktop( Display* pDisplay )
     // warning: these checks are coincidental, GNOME does not
     // explicitly advertise itself
 
-    if ( NULL != getenv( "GNOME_DESKTOP_SESSION_ID" ) )
+    if ( "gnome" == getenv( "DESKTOP_SESSION" ) || NULL != getenv( "GNOME_DESKTOP_SESSION_ID" ) )
+    {
         ret = true;
+    }
 
     if( ! ret )
     {
@@ -119,6 +121,24 @@ static bool is_gnome_desktop( Display* pDisplay )
     return ret;
 }
 
+static bool is_xfce_desktop( Display* pDisplay )
+{
+    if ( "xfce" == getenv( "DESKTOP_SESSION" ) )
+    {
+        return true;
+    }
+    return false;
+}
+
+static bool is_mate_desktop( Display* pDisplay )
+{
+    if ( "mate" == getenv( "DESKTOP_SESSION" ) )
+    {
+        return true;
+    }
+    return false;
+}
+
 static bool bWasXError = false;
 
 static inline bool WasXError()
@@ -291,6 +311,10 @@ DESKTOP_DETECTOR_PUBLIC DesktopType get_desktop_environment()
             return DESKTOP_KDE4;
         if ( aOver.equalsIgnoreAsciiCase( "gnome" ) )
             return DESKTOP_GNOME;
+        if ( aOver.equalsIgnoreAsciiCase( "xfce" ) )
+            return DESKTOP_XFCE;
+        if ( aOver.equalsIgnoreAsciiCase( "mate" ) )
+            return DESKTOP_MATE;
         if ( aOver.equalsIgnoreAsciiCase( "kde" ) )
             return DESKTOP_KDE;
         if ( aOver.equalsIgnoreAsciiCase( "none" ) )
@@ -351,6 +375,10 @@ DESKTOP_DETECTOR_PUBLIC DesktopType get_desktop_environment()
         ret = DESKTOP_KDE4;
     else if ( is_gnome_desktop( pDisplay ) )
         ret = DESKTOP_GNOME;
+    else if ( is_xfce_desktop( pDisplay ) )
+        ret = DESKTOP_XFCE;
+    else if ( is_mate_desktop( pDisplay ) )
+        ret = DESKTOP_MATE;
     else if ( is_kde_desktop( pDisplay ) )
         ret = DESKTOP_KDE;
     else
diff --git a/vcl/unx/generic/plugadapt/salplug.cxx b/vcl/unx/generic/plugadapt/salplug.cxx
index 2eec717..fba45f1 100644
--- a/vcl/unx/generic/plugadapt/salplug.cxx
+++ b/vcl/unx/generic/plugadapt/salplug.cxx
@@ -188,7 +188,7 @@ static SalInstance* autodetect_plugin()
     // no server at all: dummy plugin
     if ( desktop == DESKTOP_NONE )
         pList = pHeadlessFallbackList;
-    else if ( desktop == DESKTOP_GNOME )
+    else if ( desktop == DESKTOP_GNOME || desktop == DESKTOP_XFCE || desktop == DESKTOP_MATE )
         pList = pStandardFallbackList;
     else if( desktop == DESKTOP_TDE )
         pList = pTDEFallbackList;
@@ -287,7 +287,7 @@ void SalAbort( const OUString& rErrorText, bool bDumpCore )
         _exit(1);
 }
 
-static const char * desktop_strings[] = { "none", "unknown", "GNOME", "TDE", "KDE", "KDE4" };
+static const char * desktop_strings[] = { "none", "unknown", "GNOME", "XFCE", "MATE", "TDE", "KDE", "KDE4" };
 
 const OUString& SalGetDesktopEnvironment()
 {
commit 3887ba5677b1902fcf45f076d7a8e3ac96322dff
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Tue Jul 2 17:57:36 2013 +0100

    Fix opencl path and linking issues on windows.
    
    Change-Id: Ie39a3c02d6021ae200d6e3939ec9a14ed7f34d21

diff --git a/configure.ac b/configure.ac
index 66733ea..fdca180 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9840,8 +9840,14 @@ elif test "z$with_opencl_sdk" = "z"; then
 else
     if test -d "$with_opencl_sdk/include"; then
         ENABLE_OPENCL=TRUE
-        OPENCL_CFLAGS="-I$with_opencl_sdk/include"
-        OPENCL_LIBS="-L$with_opencl_sdk/lib/x86 -lOpenCL"
+        if test "$_os" = "WINNT"; then
+            PathFormat "$with_opencl_sdk"
+            OPENCL_CFLAGS="-I$formatted_path/include"
+            OPENCL_LIBS="-LIBPATH:$formatted_path/lib/x86 OpenCL.lib"
+        else
+            OPENCL_CFLAGS="-I$with_opencl_sdk/include"
+            OPENCL_LIBS="-L$with_opencl_sdk/lib/x86 -lOpenCL"
+        fi
         AC_MSG_RESULT([found at path $with_opencl_sdk])
         AC_DEFINE(HAVE_FEATURE_OPENCL)
     else
commit 74b5f592dbbd499ef4c50601e92e393623244c4c
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Jul 2 15:26:28 2013 -0400

    Some feeble attempt to reduce dependency on token.hxx header.
    
    But I didn't go far.
    
    Change-Id: Iaf9cbac99812c1bf7d7f2db2ad5bb6231ea5e292

diff --git a/sc/inc/chart2uno.hxx b/sc/inc/chart2uno.hxx
index 6d53073..333a2db 100644
--- a/sc/inc/chart2uno.hxx
+++ b/sc/inc/chart2uno.hxx
@@ -23,7 +23,7 @@
 #include "cellsuno.hxx"     // for XModifyListenerArr_Impl / ScLinkListener
 #include "rangelst.hxx"
 #include "externalrefmgr.hxx"
-#include "token.hxx"
+#include "types.hxx"
 #include "chartlis.hxx"
 
 #include <svl/lstner.hxx>
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 487afcd..445311e 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -10,6 +10,8 @@
 #ifndef SC_TYPES_HXX
 #define SC_TYPES_HXX
 
+#include "sal/types.h"
+
 #include <boost/intrusive_ptr.hpp>
 
 class ScMatrix;
diff --git a/sc/source/filter/inc/xichart.hxx b/sc/source/filter/inc/xichart.hxx
index c1a2cbc..308ca4c 100644
--- a/sc/source/filter/inc/xichart.hxx
+++ b/sc/source/filter/inc/xichart.hxx
@@ -28,7 +28,7 @@
 #include <svl/itemset.hxx>
 
 #include "rangelst.hxx"
-#include "token.hxx"
+#include "types.hxx"
 #include "xlchart.hxx"
 #include "xlstyle.hxx"
 #include "xiescher.hxx"
commit 76f20ffd2f5aafe284fc52baac4b304d7e8edaca
Author: Armin Le Grand <alg at apache.org>
Date:   Tue Jul 2 16:36:07 2013 +0000

    Related: #i122594# Added same handling for outer SVG element
    
    (cherry picked from commit d6dd461da975a4fcd7d58a1f03d0add9e5defa8b)
    
    Conflicts:
    	svgio/source/svgreader/svgsvgnode.cxx
    
    Change-Id: I99f5ce54a70d064ae83e56c0a23b77122dcc838c

diff --git a/svgio/source/svgreader/svgsvgnode.cxx b/svgio/source/svgreader/svgsvgnode.cxx
index 4aff559..0eb04dd 100644
--- a/svgio/source/svgreader/svgsvgnode.cxx
+++ b/svgio/source/svgreader/svgsvgnode.cxx
@@ -168,6 +168,64 @@ namespace svgio
             {
                 if(getParent())
                 {
+                    const bool bWidthIsRelative(!getWidth().isSet() || Unit_percent == getWidth().getUnit());
+                    const bool bHeightIsRelative(!getWidth().isSet() || Unit_percent == getWidth().getUnit());
+                    const SvgSvgNode* pParentSvgSvgNode = 0;
+                    double fW(0.0);
+                    double fH(0.0);
+
+                    // #i122594# if width/height is not given, it's 100% (see 5.1.2 The ‘svg’ element in SVG1.1 spec).
+                    // If it is relative, the question is to what. The previous implementatin assumed relative to the
+                    // local ViewBox which is implied by (4.2 Basic data types):
+                    //
+                    // "Note that the non-property <length> definition also allows a percentage unit identifier.
+                    // The meaning of a percentage length value depends on the attribute for which the percentage
+                    // length value has been specified. Two common cases are: (a) when a percentage length value
+                    // represents a percentage of the viewport width or height (refer to the section that discusses
+                    // units in general), and (b) when a percentage length value represents a percentage of the
+                    // bounding box width or height on a given object (refer to the section that describes object
+                    // bounding box units)."
+                    //
+                    // This is not closer specified for the SVG element itself as non-outmost element, but comparisons
+                    // with common browsers shows that it's mostly interpreted relative to the viewBox of the parent.
+                    // Adding code to search the parent SVG element and calculating width/height relative to it's
+                    // viewBox width/height (and no longer to the local viewBox).
+                    if(bWidthIsRelative || bHeightIsRelative)
+                    {
+                        for(const SvgNode* pParent = getParent(); pParent && !pParentSvgSvgNode; pParent = pParent->getParent())
+                        {
+                            pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent);
+                        }
+                    }
+
+                    if(bWidthIsRelative)
+                    {
+                        fW = getWidth().isSet() ? getWidth().getNumber() * 0.01 : 1.0;
+
+                        if(pParentSvgSvgNode)
+                        {
+                            fW *= pParentSvgSvgNode->getViewBox()->getWidth();
+                        }
+                    }
+                    else
+                    {
+                        fW = getWidth().solve(*this, xcoordinate);
+                    }
+
+                    if(bHeightIsRelative)
+                    {
+                        fH = getHeight().isSet() ? getHeight().getNumber() * 0.01 : 1.0;
+
+                        if(pParentSvgSvgNode)
+                        {
+                            fH *= pParentSvgSvgNode->getViewBox()->getHeight();
+                        }
+                    }
+                    else
+                    {
+                        fH = getHeight().solve(*this, ycoordinate);
+                    }
+
                     if(getViewBox())
                     {
                         // Svg defines that with no width or no height the viewBox content is empty,
@@ -177,64 +235,6 @@ namespace svgio
                             // create target range homing x,y, width and height as given
                             const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0);
                             const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0);
-                            const bool bWidthIsRelative(!getWidth().isSet() || Unit_percent == getWidth().getUnit());
-                            const bool bHeightIsRelative(!getWidth().isSet() || Unit_percent == getWidth().getUnit());
-                            const SvgSvgNode* pParentSvgSvgNode = 0;
-                            double fW(0.0);
-                            double fH(0.0);
-
-                            // #i122594# if width/height is not given, it's 100% (see 5.1.2 The ‘svg’ element in SVG1.1 spec).
-                            // If it is relative, the question is to what. The previous implementatin assumed relative to the
-                            // local ViewBox which is implied by (4.2 Basic data types):
-                            //
-                            // "Note that the non-property <length> definition also allows a percentage unit identifier.
-                            // The meaning of a percentage length value depends on the attribute for which the percentage
-                            // length value has been specified. Two common cases are: (a) when a percentage length value
-                            // represents a percentage of the viewport width or height (refer to the section that discusses
-                            // units in general), and (b) when a percentage length value represents a percentage of the
-                            // bounding box width or height on a given object (refer to the section that describes object
-                            // bounding box units)."
-                            //
-                            // This is not closer specified for the SVG element itself as non-outmost element, but comparisons
-                            // with common browsers shows that it's mostly interpreted relative to the viewBox of the parent.
-                            // Adding code to search the parent SVG element and calculating width/height relative to it's
-                            // viewBox width/height (and no longer to the local viewBox).
-                            if(bWidthIsRelative || bHeightIsRelative)
-                            {
-                                for(const SvgNode* pParent = getParent(); pParent && !pParentSvgSvgNode; pParent = pParent->getParent())
-                                {
-                                    pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent);
-                                }
-                            }
-
-                            if(bWidthIsRelative)
-                            {
-                                fW = getWidth().isSet() ? getWidth().getNumber() * 0.01 : 1.0;
-
-                                if(pParentSvgSvgNode)
-                                {
-                                    fW *= pParentSvgSvgNode->getViewBox()->getWidth();
-                                }
-                            }
-                            else
-                            {
-                                fW = getWidth().solve(*this, xcoordinate);
-                            }
-
-                            if(bHeightIsRelative)
-                            {
-                                fH = getHeight().isSet() ? getHeight().getNumber() * 0.01 : 1.0;
-
-                                if(pParentSvgSvgNode)

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list