[Libreoffice-commits] core.git: 18 commits - formula/source include/formula offapi/com sc/inc sc/qa sc/source svl/source vbahelper/source

Kohei Yoshida kohei.yoshida at collabora.com
Mon Nov 11 13:16:33 PST 2013


 formula/source/core/api/FormulaCompiler.cxx           |    2 
 formula/source/core/api/token.cxx                     |   27 +
 formula/source/core/inc/core_resource.hrc             |    5 
 formula/source/core/resource/core_resource.src        |  356 ++++++++++++++++++
 include/formula/token.hxx                             |    5 
 include/formula/tokenarray.hxx                        |    2 
 offapi/com/sun/star/script/vba/XVBAEventProcessor.idl |    5 
 sc/inc/externalrefmgr.hxx                             |    6 
 sc/inc/mtvelements.hxx                                |    2 
 sc/qa/unit/data/xlsx/functions-excel-2010.xlsx        |binary
 sc/qa/unit/helper/qahelper.cxx                        |    9 
 sc/qa/unit/helper/qahelper.hxx                        |    6 
 sc/qa/unit/subsequent_filters-test.cxx                |   23 +
 sc/source/core/data/column.cxx                        |    2 
 sc/source/core/data/mtvelements.cxx                   |    2 
 sc/source/core/tool/rangenam.cxx                      |    3 
 sc/source/filter/inc/formulabuffer.hxx                |   14 
 sc/source/filter/oox/formulabuffer.cxx                |  158 ++++++-
 sc/source/ui/docshell/externalrefmgr.cxx              |   26 -
 svl/source/numbers/zforlist.cxx                       |   64 ++-
 vbahelper/source/vbahelper/vbaeventshelperbase.cxx    |   19 
 21 files changed, 621 insertions(+), 115 deletions(-)

New commits:
commit c40cbf189750f623e065b6ed9596d90977a2f631
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Nov 11 11:26:30 2013 -0500

    Add test for importing some of those functions new in Excel 2010.
    
    Change-Id: Ic3577b3ef0edcfa417ae0065499171bf770c2a32

diff --git a/sc/qa/unit/data/xlsx/functions-excel-2010.xlsx b/sc/qa/unit/data/xlsx/functions-excel-2010.xlsx
new file mode 100755
index 0000000..03e570e
Binary files /dev/null and b/sc/qa/unit/data/xlsx/functions-excel-2010.xlsx differ
diff --git a/sc/qa/unit/helper/qahelper.cxx b/sc/qa/unit/helper/qahelper.cxx
index 905abef..23b45c8 100644
--- a/sc/qa/unit/helper/qahelper.cxx
+++ b/sc/qa/unit/helper/qahelper.cxx
@@ -430,6 +430,15 @@ bool checkFormula(ScDocument& rDoc, const ScAddress& rPos, const char* pExpected
     return true;
 }
 
+bool isFormulaWithoutError(ScDocument& rDoc, const ScAddress& rPos)
+{
+    ScFormulaCell* pFC = rDoc.GetFormulaCell(rPos);
+    if (!pFC)
+        return false;
+
+    return pFC->GetErrCode() == 0;
+}
+
 OUString toString(
     ScDocument& rDoc, const ScAddress& rPos, ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram)
 {
diff --git a/sc/qa/unit/helper/qahelper.hxx b/sc/qa/unit/helper/qahelper.hxx
index a6d5a02..657f66b 100644
--- a/sc/qa/unit/helper/qahelper.hxx
+++ b/sc/qa/unit/helper/qahelper.hxx
@@ -121,6 +121,12 @@ SCQAHELPER_DLLPUBLIC ScRangeList getChartRanges(ScDocument& rDoc, const SdrOle2O
 SCQAHELPER_DLLPUBLIC bool checkFormula(ScDocument& rDoc, const ScAddress& rPos, const char* pExpected);
 
 /**
+ * Check if the cell at specified position is a formula cell that doesn't
+ * have an error value.
+ */
+SCQAHELPER_DLLPUBLIC bool isFormulaWithoutError(ScDocument& rDoc, const ScAddress& rPos);
+
+/**
  * Convert formula token array to a formula string.
  */
 SCQAHELPER_DLLPUBLIC OUString toString(
diff --git a/sc/qa/unit/subsequent_filters-test.cxx b/sc/qa/unit/subsequent_filters-test.cxx
index 4f7d702..b2dc2b6 100644
--- a/sc/qa/unit/subsequent_filters-test.cxx
+++ b/sc/qa/unit/subsequent_filters-test.cxx
@@ -87,6 +87,7 @@ public:
     void testRangeNameXLSX();
     void testHardRecalcODS();
     void testFunctionsODS();
+    void testFunctionsExcel2010();
     void testCachedFormulaResultsODS();
     void testCachedMatrixFormulaResultsODS();
     void testDatabaseRangesODS();
@@ -155,6 +156,7 @@ public:
     CPPUNIT_TEST(testRangeNameXLSX);
     CPPUNIT_TEST(testHardRecalcODS);
     CPPUNIT_TEST(testFunctionsODS);
+    CPPUNIT_TEST(testFunctionsExcel2010);
     CPPUNIT_TEST(testCachedFormulaResultsODS);
     CPPUNIT_TEST(testCachedMatrixFormulaResultsODS);
     CPPUNIT_TEST(testDatabaseRangesODS);
@@ -371,6 +373,27 @@ void ScFiltersTest::testFunctionsODS()
     xDocSh->DoClose();
 }
 
+void ScFiltersTest::testFunctionsExcel2010()
+{
+    ScDocShellRef xDocSh = loadDoc("functions-excel-2010.", XLSX);
+    CPPUNIT_ASSERT_MESSAGE("Failed to load the document.", xDocSh.Is());
+    ScDocument* pDoc = xDocSh->GetDocument();
+    pDoc->CalcAll(); // perform hard re-calculation.
+
+    // B2:B6 and B8 should all be formula cells, and shouldn't have errors.
+    CPPUNIT_ASSERT_MESSAGE("Expected a formula cell without errro.", isFormulaWithoutError(*pDoc, ScAddress(1,1,0)));
+    CPPUNIT_ASSERT_MESSAGE("Expected a formula cell without errro.", isFormulaWithoutError(*pDoc, ScAddress(1,2,0)));
+    CPPUNIT_ASSERT_MESSAGE("Expected a formula cell without errro.", isFormulaWithoutError(*pDoc, ScAddress(1,3,0)));
+    CPPUNIT_ASSERT_MESSAGE("Expected a formula cell without errro.", isFormulaWithoutError(*pDoc, ScAddress(1,4,0)));
+#if 0 // CHISQ.TEST and F.DIST.RT are not yet supported in the core.
+    CPPUNIT_ASSERT_MESSAGE("Expected a formula cell without errro.", isFormulaWithoutError(*pDoc, ScAddress(1,5,0)));
+    // Skip B7.
+    CPPUNIT_ASSERT_MESSAGE("Expected a formula cell without errro.", isFormulaWithoutError(*pDoc, ScAddress(1,7,0)));
+#endif
+
+    xDocSh->DoClose();
+}
+
 void ScFiltersTest::testCachedFormulaResultsODS()
 {
     {
commit 7e2677c02997ad7bf38641b46fd1e7ac2c643cd2
Author: Michael Meeks <michael.meeks at collabora.com>
Date:   Mon Nov 11 17:07:35 2013 +0000

    Accelerate checking for VBA macros that are not there.

diff --git a/offapi/com/sun/star/script/vba/XVBAEventProcessor.idl b/offapi/com/sun/star/script/vba/XVBAEventProcessor.idl
index 750cc4d..1fbf75d 100644
--- a/offapi/com/sun/star/script/vba/XVBAEventProcessor.idl
+++ b/offapi/com/sun/star/script/vba/XVBAEventProcessor.idl
@@ -44,10 +44,7 @@ interface XVBAEventProcessor
 
         @return
             `TRUE`, if the VBA event handler exists.
-
-        @throws ::com::sun::star::lang::IllegalArgumentException
-            if the passed event identifier is not supported, or if the passed
-            specifier is required but invalid.
+            `FALSE`, for all other cases.
     **/
     boolean hasVbaEventHandler( [in] long nEventId, [in] sequence< any > aArgs )
         raises (::com::sun::star::lang::IllegalArgumentException);
diff --git a/vbahelper/source/vbahelper/vbaeventshelperbase.cxx b/vbahelper/source/vbahelper/vbaeventshelperbase.cxx
index b6a7e7a..69b5584 100644
--- a/vbahelper/source/vbahelper/vbaeventshelperbase.cxx
+++ b/vbahelper/source/vbahelper/vbaeventshelperbase.cxx
@@ -51,15 +51,6 @@ VbaEventsHelperBase::~VbaEventsHelperBase()
     SAL_WARN_IF( !mbDisposed, "vbahelper", "VbaEventsHelperBase::~VbaEventsHelperBase - missing disposing notification" );
 }
 
-sal_Bool SAL_CALL VbaEventsHelperBase::hasVbaEventHandler( sal_Int32 nEventId, const uno::Sequence< uno::Any >& rArgs )
-        throw (lang::IllegalArgumentException, uno::RuntimeException)
-{
-    // getEventHandlerInfo() throws, if unknown event dentifier has been passed
-    const EventHandlerInfo& rInfo = getEventHandlerInfo( nEventId );
-    // getEventHandlerPath() searches for the macro in the document
-    return !getEventHandlerPath( rInfo, rArgs ).isEmpty();
-}
-
 sal_Bool SAL_CALL VbaEventsHelperBase::processVbaEvent( sal_Int32 nEventId, const uno::Sequence< uno::Any >& rArgs )
         throw (lang::IllegalArgumentException, util::VetoException, uno::RuntimeException)
 {
@@ -241,6 +232,16 @@ void VbaEventsHelperBase::stopListening()
     mbDisposed = true;
 }
 
+sal_Bool SAL_CALL VbaEventsHelperBase::hasVbaEventHandler( sal_Int32 nEventId, const uno::Sequence< uno::Any >& rArgs )
+        throw (lang::IllegalArgumentException, uno::RuntimeException)
+{
+    EventHandlerInfoMap::const_iterator aIt = maEventInfos.find( nEventId );
+    if( aIt == maEventInfos.end() )
+        return sal_False; // throwing a lot of exceptions is slow.
+    else // getEventHandlerPath() searches for the macro in the document
+        return !getEventHandlerPath( aIt->second, rArgs ).isEmpty();
+}
+
 const VbaEventsHelperBase::EventHandlerInfo& VbaEventsHelperBase::getEventHandlerInfo(
         sal_Int32 nEventId ) const throw (lang::IllegalArgumentException)
 {
commit 01ea75c0f08e07c8243aafc8628612a9210add26
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Sat Nov 9 00:01:49 2013 -0500

    Add separate list of function names for OOXML import.
    
    Change-Id: Id6bb9ed65f94a56e82c0c4a6fee241dec4eb9138

diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx
index f54d00b..1d84757 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -703,7 +703,7 @@ void FormulaCompiler::InitSymbolsEnglishXL() const
     static OpCodeMapData aMap;
     osl::MutexGuard aGuard(&aMap.maMtx);
     if (!aMap.mxSymbolMap)
-        loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
+        loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
     mxSymbolsEnglishXL = aMap.mxSymbolMap;
 
     // TODO: For now, just replace the separators to the Excel English
diff --git a/formula/source/core/inc/core_resource.hrc b/formula/source/core/inc/core_resource.hrc
index 3594989..5253e65 100644
--- a/formula/source/core/inc/core_resource.hrc
+++ b/formula/source/core/inc/core_resource.hrc
@@ -29,8 +29,9 @@
 //------------------------------------------------------------------------------
 //- String-IDs
 #define RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF     (RID_CORE_OTHER_START + 0)
-#define RID_STRLIST_FUNCTION_NAMES_ENGLISH          (RID_CORE_OTHER_START + 1)
-#define RID_STRLIST_FUNCTION_NAMES                  (RID_CORE_OTHER_START + 2)
+#define RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML    (RID_CORE_OTHER_START + 1)
+#define RID_STRLIST_FUNCTION_NAMES_ENGLISH          (RID_CORE_OTHER_START + 2)
+#define RID_STRLIST_FUNCTION_NAMES                  (RID_CORE_OTHER_START + 3)
 
 
 #endif // _FORMULA_CORE_RESOURCE_HRC_
diff --git a/formula/source/core/resource/core_resource.src b/formula/source/core/resource/core_resource.src
index f67ac77..06e39e7 100644
--- a/formula/source/core/resource/core_resource.src
+++ b/formula/source/core/resource/core_resource.src
@@ -382,6 +382,362 @@ Resource RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF
     String SC_OPCODE_WEBSERVICE    { Text = "COM.MICROSOFT.WEBSERVICE"; };
 };
 
+Resource RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML
+{
+    String SC_OPCODE_IF { Text = "IF" ; };
+    String SC_OPCODE_IF_ERROR { Text = "IFERROR" ; };
+    String SC_OPCODE_IF_NA { Text = "IFNA" ; };
+    String SC_OPCODE_CHOSE { Text = "CHOOSE" ; };
+    String SC_OPCODE_OPEN { Text = "(" ; };
+    String SC_OPCODE_CLOSE { Text = ")" ; };
+    String SC_OPCODE_ARRAY_OPEN { Text = "{" ; };
+    String SC_OPCODE_ARRAY_CLOSE { Text = "}" ; };
+    String SC_OPCODE_ARRAY_ROW_SEP { Text = ";" ; };
+    String SC_OPCODE_ARRAY_COL_SEP { Text = "," ; };
+    String SC_OPCODE_SEP { Text = "," ; };
+    String SC_OPCODE_PERCENT_SIGN { Text = "%" ; };
+    String SC_OPCODE_ADD { Text = "+" ; };
+    String SC_OPCODE_SUB { Text = "-" ; };
+    String SC_OPCODE_MUL { Text = "*" ; };
+    String SC_OPCODE_DIV { Text = "/" ; };
+    String SC_OPCODE_AMPERSAND { Text = "&" ; };
+    String SC_OPCODE_POW { Text = "^" ; };
+    String SC_OPCODE_EQUAL { Text = "=" ; };
+    String SC_OPCODE_NOT_EQUAL { Text = "<>" ; };
+    String SC_OPCODE_LESS { Text = "<" ; };
+    String SC_OPCODE_GREATER { Text = ">" ; };
+    String SC_OPCODE_LESS_EQUAL { Text = "<=" ; };
+    String SC_OPCODE_GREATER_EQUAL { Text = ">=" ; };
+    String SC_OPCODE_AND { Text = "AND" ; };
+    String SC_OPCODE_OR { Text = "OR" ; };
+    String SC_OPCODE_XOR { Text = "XOR" ; };
+    String SC_OPCODE_INTERSECT { Text = "!" ; };
+    String SC_OPCODE_UNION { Text = "~" ; };
+    String SC_OPCODE_RANGE { Text = ":" ; };
+    String SC_OPCODE_NOT { Text = "NOT" ; };
+    String SC_OPCODE_NEG { Text = "NEG" ; };
+    String SC_OPCODE_NEG_SUB { Text = "-" ; };
+    String SC_OPCODE_PI { Text = "PI" ; };
+    String SC_OPCODE_RANDOM { Text = "RAND" ; };
+    String SC_OPCODE_TRUE { Text = "TRUE" ; };
+    String SC_OPCODE_FALSE { Text = "FALSE" ; };
+    String SC_OPCODE_GET_ACT_DATE { Text = "TODAY" ; };
+    String SC_OPCODE_GET_ACT_TIME { Text = "NOW" ; };
+    String SC_OPCODE_NO_VALUE { Text = "NA" ; };
+    String SC_OPCODE_CURRENT { Text = "CURRENT" ; };
+    String SC_OPCODE_DEG { Text = "DEGREES" ; };
+    String SC_OPCODE_RAD { Text = "RADIANS" ; };
+    String SC_OPCODE_SIN { Text = "SIN" ; };
+    String SC_OPCODE_COS { Text = "COS" ; };
+    String SC_OPCODE_TAN { Text = "TAN" ; };
+    String SC_OPCODE_COT { Text = "COT" ; };
+    String SC_OPCODE_ARC_SIN { Text = "ASIN" ; };
+    String SC_OPCODE_ARC_COS { Text = "ACOS" ; };
+    String SC_OPCODE_ARC_TAN { Text = "ATAN" ; };
+    String SC_OPCODE_ARC_COT { Text = "ACOT" ; };
+    String SC_OPCODE_SIN_HYP { Text = "SINH" ; };
+    String SC_OPCODE_COS_HYP { Text = "COSH" ; };
+    String SC_OPCODE_TAN_HYP { Text = "TANH" ; };
+    String SC_OPCODE_COT_HYP { Text = "COTH" ; };
+    String SC_OPCODE_ARC_SIN_HYP { Text = "ASINH" ; };
+    String SC_OPCODE_ARC_COS_HYP { Text = "ACOSH" ; };
+    String SC_OPCODE_ARC_TAN_HYP { Text = "ATANH" ; };
+    String SC_OPCODE_ARC_COT_HYP { Text = "ACOTH" ; };
+    String SC_OPCODE_COSECANT { Text = "CSC" ; };
+    String SC_OPCODE_SECANT { Text = "SEC" ; };
+    String SC_OPCODE_COSECANT_HYP { Text = "CSCH" ; };
+    String SC_OPCODE_SECANT_HYP { Text = "SECH" ; };
+    String SC_OPCODE_EXP { Text = "EXP" ; };
+    String SC_OPCODE_LN { Text = "LN" ; };
+    String SC_OPCODE_SQRT { Text = "SQRT" ; };
+    String SC_OPCODE_FACT { Text = "FACT" ; };
+    String SC_OPCODE_GET_YEAR { Text = "YEAR" ; };
+    String SC_OPCODE_GET_MONTH { Text = "MONTH" ; };
+    String SC_OPCODE_GET_DAY { Text = "DAY" ; };
+    String SC_OPCODE_GET_HOUR { Text = "HOUR" ; };
+    String SC_OPCODE_GET_MIN { Text = "MINUTE" ; };
+    String SC_OPCODE_GET_SEC { Text = "SECOND" ; };
+    String SC_OPCODE_PLUS_MINUS { Text = "SIGN" ; };
+    String SC_OPCODE_ABS { Text = "ABS" ; };
+    String SC_OPCODE_INT { Text = "INT" ; };
+    String SC_OPCODE_PHI { Text = "PHI" ; };
+    String SC_OPCODE_GAUSS { Text = "GAUSS" ; };
+    String SC_OPCODE_IS_EMPTY { Text = "ISBLANK" ; };
+    String SC_OPCODE_IS_STRING { Text = "ISTEXT" ; };
+    String SC_OPCODE_IS_NON_STRING { Text = "ISNONTEXT" ; };
+    String SC_OPCODE_IS_LOGICAL { Text = "ISLOGICAL" ; };
+    String SC_OPCODE_TYPE { Text = "TYPE" ; };
+    String SC_OPCODE_CELL { Text = "CELL" ; };
+    String SC_OPCODE_IS_REF { Text = "ISREF" ; };
+    String SC_OPCODE_IS_VALUE { Text = "ISNUMBER" ; };
+    String SC_OPCODE_IS_FORMULA { Text = "ISFORMULA" ; };
+    String SC_OPCODE_IS_NV { Text = "ISNA" ; };
+    String SC_OPCODE_IS_ERR { Text = "ISERR" ; };
+    String SC_OPCODE_IS_ERROR { Text = "ISERROR" ; };
+    String SC_OPCODE_IS_EVEN { Text = "ISEVEN" ; };
+    String SC_OPCODE_IS_ODD { Text = "ISODD" ; };
+    String SC_OPCODE_N { Text = "N" ; };
+    String SC_OPCODE_GET_DATE_VALUE { Text = "DATEVALUE" ; };
+    String SC_OPCODE_GET_TIME_VALUE { Text = "TIMEVALUE" ; };
+    String SC_OPCODE_CODE { Text = "CODE" ; };
+    String SC_OPCODE_TRIM { Text = "TRIM" ; };
+    String SC_OPCODE_UPPER { Text = "UPPER" ; };
+    String SC_OPCODE_PROPPER { Text = "PROPER" ; };
+    String SC_OPCODE_LOWER { Text = "LOWER" ; };
+    String SC_OPCODE_LEN { Text = "LEN" ; };
+    String SC_OPCODE_T { Text = "T" ; };
+    String SC_OPCODE_VALUE { Text = "VALUE" ; };
+    String SC_OPCODE_CLEAN { Text = "CLEAN" ; };
+    String SC_OPCODE_CHAR { Text = "CHAR" ; };
+    String SC_OPCODE_JIS { Text = "JIS" ; };
+    String SC_OPCODE_ASC { Text = "ASC" ; };
+    String SC_OPCODE_UNICODE { Text = "UNICODE" ; };
+    String SC_OPCODE_UNICHAR { Text = "UNICHAR" ; };
+    String SC_OPCODE_LOG10 { Text = "LOG10" ; };
+    String SC_OPCODE_EVEN { Text = "EVEN" ; };
+    String SC_OPCODE_ODD { Text = "ODD" ; };
+    String SC_OPCODE_STD_NORM_DIST { Text = "NORMSDIST" ; };
+    String SC_OPCODE_FISHER { Text = "FISHER" ; };
+    String SC_OPCODE_FISHER_INV { Text = "FISHERINV" ; };
+    String SC_OPCODE_S_NORM_INV { Text = "NORMSINV" ; };
+    String SC_OPCODE_GAMMA_LN { Text = "GAMMALN" ; };
+    String SC_OPCODE_ERROR_TYPE { Text = "ERRORTYPE" ; };
+    String SC_OPCODE_ERR_CELL { Text = "ZellError" ; };  // TODO: ancient legacy only, remove?
+    String SC_OPCODE_FORMULA { Text = "FORMULA"; };
+    String SC_OPCODE_ARC_TAN_2 { Text = "ATAN2" ; };
+    String SC_OPCODE_CEIL { Text = "CEILING" ; };
+    String SC_OPCODE_FLOOR { Text = "FLOOR" ; };
+    String SC_OPCODE_ROUND { Text = "ROUND" ; };
+    String SC_OPCODE_ROUND_UP { Text = "ROUNDUP" ; };
+    String SC_OPCODE_ROUND_DOWN { Text = "ROUNDDOWN" ; };
+    String SC_OPCODE_TRUNC { Text = "TRUNC" ; };
+    String SC_OPCODE_LOG { Text = "LOG" ; };
+    String SC_OPCODE_POWER { Text = "POWER" ; };
+    String SC_OPCODE_GGT { Text = "GCD" ; };
+    String SC_OPCODE_KGV { Text = "LCM" ; };
+    String SC_OPCODE_MOD { Text = "MOD" ; };
+    String SC_OPCODE_SUM_PRODUCT { Text = "SUMPRODUCT" ; };
+    String SC_OPCODE_SUM_SQ { Text = "SUMSQ" ; };
+    String SC_OPCODE_SUM_X2MY2 { Text = "SUMX2MY2" ; };
+    String SC_OPCODE_SUM_X2DY2 { Text = "SUMX2PY2" ; };
+    String SC_OPCODE_SUM_XMY2 { Text = "SUMXMY2" ; };
+    String SC_OPCODE_GET_DATE { Text = "DATE" ; };
+    String SC_OPCODE_GET_TIME { Text = "TIME" ; };
+    String SC_OPCODE_GET_DIFF_DATE { Text = "DAYS" ; };
+    String SC_OPCODE_GET_DIFF_DATE_360 { Text = "DAYS360" ; };
+    String SC_OPCODE_GET_DATEDIF { Text = "DATEDIF" ; };
+    String SC_OPCODE_MIN { Text = "MIN" ; };
+    String SC_OPCODE_MIN_A { Text = "MINA" ; };
+    String SC_OPCODE_MAX { Text = "MAX" ; };
+    String SC_OPCODE_MAX_A { Text = "MAXA" ; };
+    String SC_OPCODE_SUM { Text = "SUM" ; };
+    String SC_OPCODE_PRODUCT { Text = "PRODUCT" ; };
+    String SC_OPCODE_AVERAGE { Text = "AVERAGE" ; };
+    String SC_OPCODE_AVERAGE_A { Text = "AVERAGEA" ; };
+    String SC_OPCODE_COUNT { Text = "COUNT" ; };
+    String SC_OPCODE_COUNT_2 { Text = "COUNTA" ; };
+    String SC_OPCODE_NBW { Text = "NPV" ; };
+    String SC_OPCODE_IKV { Text = "IRR" ; };
+    String SC_OPCODE_MIRR { Text = "MIRR" ; };
+    String SC_OPCODE_ISPMT { Text = "ISPMT" ; };
+    String SC_OPCODE_VAR { Text = "VAR" ; };
+    String SC_OPCODE_VAR_A { Text = "VARA" ; };
+    String SC_OPCODE_VAR_P { Text = "VARP" ; };
+    String SC_OPCODE_VAR_P_A { Text = "VARPA" ; };
+    String SC_OPCODE_VAR_P_MS { Text = "VAR.P" ; };
+    String SC_OPCODE_VAR_S { Text = "VAR.S" ; };
+    String SC_OPCODE_ST_DEV { Text = "STDEV" ; };
+    String SC_OPCODE_ST_DEV_A { Text = "STDEVA" ; };
+    String SC_OPCODE_ST_DEV_P { Text = "STDEVP" ; };
+    String SC_OPCODE_ST_DEV_P_A { Text = "STDEVPA" ; };
+    String SC_OPCODE_ST_DEV_P_MS { Text = "STDEV.P" ; };
+    String SC_OPCODE_ST_DEV_S { Text = "STDEV.S" ; };
+    String SC_OPCODE_B { Text = "B" ; };
+    String SC_OPCODE_NORM_DIST { Text = "NORMDIST" ; };
+    String SC_OPCODE_EXP_DIST { Text = "EXPONDIST" ; };
+    String SC_OPCODE_BINOM_DIST { Text = "BINOMDIST" ; };
+    String SC_OPCODE_BINOM_DIST_MS { Text = "_xlfn.BINOM.DIST" ; };
+    String SC_OPCODE_POISSON_DIST { Text = "POISSON" ; };
+    String SC_OPCODE_KOMBIN { Text = "COMBIN" ; };
+    String SC_OPCODE_KOMBIN_2 { Text = "COMBINA" ; };
+    String SC_OPCODE_VARIATIONEN { Text = "PERMUT" ; };
+    String SC_OPCODE_VARIATIONEN_2 { Text = "PERMUTATIONA" ; };
+    String SC_OPCODE_BW { Text = "PV" ; };
+    String SC_OPCODE_DIA { Text = "SYD" ; };
+    String SC_OPCODE_GDA { Text = "DDB" ; };
+    String SC_OPCODE_GDA_2 { Text = "DB" ; };
+    String SC_OPCODE_VBD { Text = "VDB" ; };
+    String SC_OPCODE_LAUFZ { Text = "DURATION" ; };
+    String SC_OPCODE_LIA { Text = "SLN" ; };
+    String SC_OPCODE_RMZ { Text = "PMT" ; };
+    String SC_OPCODE_COLUMNS { Text = "COLUMNS" ; };
+    String SC_OPCODE_ROWS { Text = "ROWS" ; };
+    String SC_OPCODE_TABLES { Text = "SHEETS" ; };
+    String SC_OPCODE_COLUMN { Text = "COLUMN" ; };
+    String SC_OPCODE_ROW { Text = "ROW" ; };
+    String SC_OPCODE_TABLE { Text = "SHEET" ; };
+    String SC_OPCODE_ZGZ { Text = "ZGZ" ; };
+    String SC_OPCODE_ZW { Text = "FV" ; };
+    String SC_OPCODE_ZZR { Text = "NPER" ; };
+    String SC_OPCODE_ZINS { Text = "RATE" ; };
+    String SC_OPCODE_ZINS_Z { Text = "IPMT" ; };
+    String SC_OPCODE_KAPZ { Text = "PPMT" ; };
+    String SC_OPCODE_KUM_ZINS_Z { Text = "CUMIPMT" ; };
+    String SC_OPCODE_KUM_KAP_Z { Text = "CUMPRINC" ; };
+    String SC_OPCODE_EFFEKTIV { Text = "EFFECTIVE" ; };
+    String SC_OPCODE_NOMINAL { Text = "NOMINAL" ; };
+    String SC_OPCODE_SUB_TOTAL { Text = "SUBTOTAL" ; };
+    String SC_OPCODE_DB_SUM { Text = "DSUM" ; };
+    String SC_OPCODE_DB_COUNT { Text = "DCOUNT" ; };
+    String SC_OPCODE_DB_COUNT_2 { Text = "DCOUNTA" ; };
+    String SC_OPCODE_DB_AVERAGE { Text = "DAVERAGE" ; };
+    String SC_OPCODE_DB_GET { Text = "DGET" ; };
+    String SC_OPCODE_DB_MAX { Text = "DMAX" ; };
+    String SC_OPCODE_DB_MIN { Text = "DMIN" ; };
+    String SC_OPCODE_DB_PRODUCT { Text = "DPRODUCT" ; };
+    String SC_OPCODE_DB_STD_DEV { Text = "DSTDEV" ; };
+    String SC_OPCODE_DB_STD_DEV_P { Text = "DSTDEVP" ; };
+    String SC_OPCODE_DB_VAR { Text = "DVAR" ; };
+    String SC_OPCODE_DB_VAR_P { Text = "DVARP" ; };
+    String SC_OPCODE_INDIRECT { Text = "INDIRECT" ; };
+    String SC_OPCODE_ADDRESS { Text = "ADDRESS" ; };
+    String SC_OPCODE_MATCH { Text = "MATCH" ; };
+    String SC_OPCODE_COUNT_EMPTY_CELLS { Text = "COUNTBLANK" ; };
+    String SC_OPCODE_COUNT_IF { Text = "COUNTIF" ; };
+    String SC_OPCODE_SUM_IF { Text = "SUMIF" ; };
+    String SC_OPCODE_AVERAGE_IF { Text = "AVERAGEIF" ; };
+    String SC_OPCODE_SUM_IFS { Text = "SUMIFS" ; };
+    String SC_OPCODE_AVERAGE_IFS { Text = "AVERAGEIFS" ; };
+    String SC_OPCODE_COUNT_IFS { Text = "COUNTIFS" ; };
+    String SC_OPCODE_LOOKUP { Text = "LOOKUP" ; };
+    String SC_OPCODE_V_LOOKUP { Text = "VLOOKUP" ; };
+    String SC_OPCODE_H_LOOKUP { Text = "HLOOKUP" ; };
+    String SC_OPCODE_MULTI_AREA { Text = "MULTIRANGE" ; };      // legacy for range list (union)
+    String SC_OPCODE_OFFSET { Text = "OFFSET" ; };
+    String SC_OPCODE_INDEX { Text = "INDEX" ; };
+    String SC_OPCODE_AREAS { Text = "AREAS" ; };
+    String SC_OPCODE_CURRENCY { Text = "DOLLAR" ; };
+    String SC_OPCODE_REPLACE { Text = "REPLACE" ; };
+    String SC_OPCODE_FIXED { Text = "FIXED" ; };
+    String SC_OPCODE_FIND { Text = "FIND" ; };
+    String SC_OPCODE_EXACT { Text = "EXACT" ; };
+    String SC_OPCODE_LEFT { Text = "LEFT" ; };
+    String SC_OPCODE_RIGHT { Text = "RIGHT" ; };
+    String SC_OPCODE_SEARCH { Text = "SEARCH" ; };
+    String SC_OPCODE_MID { Text = "MID" ; };
+    String SC_OPCODE_LENB { Text = "LENB" ; };
+    String SC_OPCODE_RIGHTB { Text = "RIGHTB" ; };
+    String SC_OPCODE_LEFTB { Text = "LEFTB" ; };
+    String SC_OPCODE_MIDB { Text = "MIDB" ; };
+    String SC_OPCODE_TEXT { Text = "TEXT" ; };
+    String SC_OPCODE_SUBSTITUTE { Text = "SUBSTITUTE" ; };
+    String SC_OPCODE_REPT { Text = "REPT" ; };
+    String SC_OPCODE_CONCAT { Text = "CONCATENATE" ; };
+    String SC_OPCODE_MAT_VALUE { Text = "MVALUE" ; };
+    String SC_OPCODE_MAT_DET { Text = "MDETERM" ; };
+    String SC_OPCODE_MAT_INV { Text = "MINVERSE" ; };
+    String SC_OPCODE_MAT_MULT { Text = "MMULT" ; };
+    String SC_OPCODE_MAT_TRANS { Text = "TRANSPOSE" ; };
+    String SC_OPCODE_MATRIX_UNIT { Text = "MUNIT" ; };
+    String SC_OPCODE_BACK_SOLVER { Text = "GOALSEEK" ; };
+    String SC_OPCODE_HYP_GEOM_DIST { Text = "HYPGEOMDIST" ; };
+    String SC_OPCODE_LOG_NORM_DIST { Text = "LOGNORMDIST" ; };
+    String SC_OPCODE_T_DIST { Text = "TDIST" ; };
+    String SC_OPCODE_F_DIST { Text = "FDIST" ; };
+    String SC_OPCODE_CHI_DIST { Text = "CHIDIST" ; };
+    String SC_OPCODE_WEIBULL { Text = "WEIBULL" ; };
+    String SC_OPCODE_NEG_BINOM_VERT { Text = "NEGBINOMDIST" ; };
+    String SC_OPCODE_KRIT_BINOM { Text = "CRITBINOM" ; };
+    String SC_OPCODE_BINOM_INV { Text = "_xlfn.BINOM.INV" ; };
+    String SC_OPCODE_KURT { Text = "KURT" ; };
+    String SC_OPCODE_HAR_MEAN { Text = "HARMEAN" ; };
+    String SC_OPCODE_GEO_MEAN { Text = "GEOMEAN" ; };
+    String SC_OPCODE_STANDARD { Text = "STANDARDIZE" ; };
+    String SC_OPCODE_AVE_DEV { Text = "AVEDEV" ; };
+    String SC_OPCODE_SCHIEFE { Text = "SKEW" ; };
+    String SC_OPCODE_SKEWP   { Text = "SKEWP" ; };
+    String SC_OPCODE_DEV_SQ { Text = "DEVSQ" ; };
+    String SC_OPCODE_MEDIAN { Text = "MEDIAN" ; };
+    String SC_OPCODE_MODAL_VALUE { Text = "MODE" ; };
+    String SC_OPCODE_Z_TEST { Text = "ZTEST" ; };
+    String SC_OPCODE_T_TEST { Text = "TTEST" ; };
+    String SC_OPCODE_RANK { Text = "RANK" ; };
+    String SC_OPCODE_PERCENTILE { Text = "PERCENTILE" ; };
+    String SC_OPCODE_PERCENT_RANK { Text = "PERCENTRANK" ; };
+    String SC_OPCODE_LARGE { Text = "LARGE" ; };
+    String SC_OPCODE_SMALL { Text = "SMALL" ; };
+    String SC_OPCODE_FREQUENCY { Text = "FREQUENCY" ; };
+    String SC_OPCODE_QUARTILE { Text = "QUARTILE" ; };
+    String SC_OPCODE_NORM_INV { Text = "NORMINV" ; };
+    String SC_OPCODE_CONFIDENCE { Text = "CONFIDENCE" ; };
+    String SC_OPCODE_F_TEST { Text = "FTEST" ; };
+    String SC_OPCODE_TRIM_MEAN { Text = "TRIMMEAN" ; };
+    String SC_OPCODE_PROB { Text = "PROB" ; };
+    String SC_OPCODE_CORREL { Text = "CORREL" ; };
+    String SC_OPCODE_COVAR { Text = "COVAR" ; };
+    String SC_OPCODE_COVARIANCE_P { Text = "COVARIANCE.P" ; };
+    String SC_OPCODE_COVARIANCE_S { Text = "COVARIANCE.S" ; };
+    String SC_OPCODE_PEARSON { Text = "PEARSON" ; };
+    String SC_OPCODE_RSQ { Text = "RSQ" ; };
+    String SC_OPCODE_STEYX { Text = "STEYX" ; };
+    String SC_OPCODE_SLOPE { Text = "SLOPE" ; };
+    String SC_OPCODE_INTERCEPT { Text = "INTERCEPT" ; };
+    String SC_OPCODE_TREND { Text = "TREND" ; };
+    String SC_OPCODE_GROWTH { Text = "GROWTH" ; };
+    String SC_OPCODE_RGP { Text = "LINEST" ; };
+    String SC_OPCODE_RKP { Text = "LOGEST" ; };
+    String SC_OPCODE_FORECAST { Text = "FORECAST" ; };
+    String SC_OPCODE_CHI_INV { Text = "CHIINV" ; };
+    String SC_OPCODE_GAMMA_DIST { Text = "GAMMADIST" ; };
+    String SC_OPCODE_GAMMA_INV { Text = "GAMMAINV" ; };
+    String SC_OPCODE_T_INV { Text = "TINV" ; };
+    String SC_OPCODE_F_INV { Text = "FINV" ; };
+    String SC_OPCODE_CHI_TEST { Text = "CHITEST" ; };
+    String SC_OPCODE_CHI_TEST_MS { Text = "_xlfn.CHISQ.TEST" ; };
+    String SC_OPCODE_LOG_INV { Text = "LOGINV" ; };
+    String SC_OPCODE_TABLE_OP { Text = "TABLE" ; };
+    String SC_OPCODE_BETA_DIST { Text = "BETADIST" ; };
+    String SC_OPCODE_BETA_INV { Text = "BETAINV" ; };
+    String SC_OPCODE_BETA_DIST_MS { Text = "_xlfn.BETA.DIST" ; };
+    String SC_OPCODE_BETA_INV_MS { Text = "_xlfn.BETA.INV" ; };
+    String SC_OPCODE_WEEK { Text = "WEEKNUM" ; };
+    String SC_OPCODE_EASTERSUNDAY { Text = "EASTERSUNDAY" ; };
+    String SC_OPCODE_GET_DAY_OF_WEEK { Text = "WEEKDAY" ; };
+    String SC_OPCODE_NO_NAME { Text = "#NAME!" ; };
+    String SC_OPCODE_STYLE { Text = "STYLE" ; };
+    String SC_OPCODE_DDE { Text = "DDE" ; };
+    String SC_OPCODE_BASE { Text = "BASE" ; };
+    String SC_OPCODE_DECIMAL { Text = "DECIMAL" ; };
+    String SC_OPCODE_CONVERT { Text = "CONVERT" ; };
+    String SC_OPCODE_ROMAN { Text = "ROMAN" ; };
+    String SC_OPCODE_ARABIC { Text = "ARABIC" ; };
+    String SC_OPCODE_HYPERLINK { Text = "HYPERLINK" ; };
+    String SC_OPCODE_INFO { Text = "INFO" ; };
+    String SC_OPCODE_BAHTTEXT { Text = "BAHTTEXT" ; };
+    String SC_OPCODE_GET_PIVOT_DATA { Text = "GETPIVOTDATA" ; };
+    String SC_OPCODE_EUROCONVERT { Text = "EUROCONVERT" ; };
+    String SC_OPCODE_NUMBERVALUE { Text = "NUMBERVALUE" ; };
+    String SC_OPCODE_GAMMA { Text = "GAMMA" ; };
+    String SC_OPCODE_CHISQ_DIST { Text = "CHISQDIST" ; };
+    String SC_OPCODE_CHISQ_INV { Text = "CHISQINV" ;};
+    String SC_OPCODE_BITAND    { Text = "BITAND" ;};
+    String SC_OPCODE_BITOR    { Text = "BITOR" ;};
+    String SC_OPCODE_BITXOR    { Text = "BITXOR" ;};
+    String SC_OPCODE_BITRSHIFT    { Text = "BITRSHIFT" ;};
+    String SC_OPCODE_BITLSHIFT    { Text = "BITLSHIFT" ;};
+    /* BEGIN defined ERROR.TYPE() values. */
+    String SC_OPCODE_ERROR_NULL    { Text = "#NULL!"  ; };
+    String SC_OPCODE_ERROR_DIVZERO { Text = "#DIV/0!" ; };
+    String SC_OPCODE_ERROR_VALUE   { Text = "#VALUE!" ; };
+    String SC_OPCODE_ERROR_REF     { Text = "#REF!"   ; };
+    String SC_OPCODE_ERROR_NAME    { Text = "#NAME?"  ; };
+    String SC_OPCODE_ERROR_NUM     { Text = "#NUM!"   ; };
+    String SC_OPCODE_ERROR_NA      { Text = "#N/A"    ; };
+    /* END defined ERROR.TYPE() values. */
+    String SC_OPCODE_FILTERXML     { Text = "FILTERXML";};
+    String SC_OPCODE_WEBSERVICE    { Text = "WEBSERVICE"; };
+};
+
 // DO NOT CHANGE NAMES! Only add functions.
 // These English names are used internally to store/load ODF v1.0/v1.1 and for
 // API XFunctionAccess.
commit a1ff0b3c1125d715e216efccf114efb46b31c587
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Nov 8 14:49:44 2013 -0500

    Group formula cells if we can, to avoid cloning of token array instances.
    
    Change-Id: I584e6d0c34f972c1ae5105a80d201f32dd8590d9

diff --git a/sc/source/filter/oox/formulabuffer.cxx b/sc/source/filter/oox/formulabuffer.cxx
index eb1892b..4bdb6ae 100644
--- a/sc/source/filter/oox/formulabuffer.cxx
+++ b/sc/source/filter/oox/formulabuffer.cxx
@@ -189,7 +189,24 @@ void applyCellFormulas(
         if (p)
         {
             // Use the cached version to avoid re-compilation.
-            ScFormulaCell* pCell = new ScFormulaCell(&rDoc.getDoc(), aPos, p->mpCell->GetCode()->Clone());
+
+            ScFormulaCell* pCell = NULL;
+            if (p->mnRow + 1 == aPos.Row())
+            {
+                // Put them in the same formula group.
+                ScFormulaCell& rPrev = *p->mpCell;
+                ScFormulaCellGroupRef xGroup = rPrev.GetCellGroup();
+                if (!xGroup)
+                    // Last cell is not grouped yet. Start a new group.
+                    xGroup = rPrev.CreateCellGroup(p->mnRow, 1, false);
+
+                ++xGroup->mnLength;
+
+                pCell = new ScFormulaCell(&rDoc.getDoc(), aPos, xGroup);
+            }
+            else
+                pCell = new ScFormulaCell(&rDoc.getDoc(), aPos, p->mpCell->GetCode()->Clone());
+
             rDoc.setFormulaCell(aPos, pCell);
 
             // Update the cache.
commit fbdd02dd6655914930b60b175328324bb53dc650
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Nov 8 14:36:40 2013 -0500

    This is clearly a mistake.
    
    Change-Id: Id87e120d80b823db9be989db7a7b2ac383304f77

diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 12fc80a..0b7f0c3 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -1284,7 +1284,7 @@ class CopyToClipHandler
         for (++it; it != itEnd; ++it, pPrev = pCur)
         {
             pCur = *it;
-            ScFormulaCell::CompareState eState = pPrev->CompareByTokenArray(*pPrev);
+            ScFormulaCell::CompareState eState = pPrev->CompareByTokenArray(*pCur);
             if (eState == ScFormulaCell::NotEqual)
                 continue;
 
commit a70c324daf1f4ef8562dd283b84e72eeee60a585
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Nov 8 14:30:03 2013 -0500

    Store the formula cell instance in cache rather than the token array.
    
    Change-Id: I1c4a0897c46458d6ee086e7f72ab8a03aa54c9e0

diff --git a/sc/source/filter/oox/formulabuffer.cxx b/sc/source/filter/oox/formulabuffer.cxx
index d9c164a..eb1892b 100644
--- a/sc/source/filter/oox/formulabuffer.cxx
+++ b/sc/source/filter/oox/formulabuffer.cxx
@@ -51,10 +51,11 @@ public:
     struct Item : boost::noncopyable
     {
         SCROW mnRow;
-        boost::scoped_ptr<ScTokenArray> mpCode;
+        ScFormulaCell* mpCell;
 
-        Item() : mnRow(-1), mpCode(NULL) {}
-        Item( SCROW nRow, ScTokenArray* p ) : mnRow(nRow), mpCode(p) {}
+        Item() : mnRow(-1), mpCell(NULL) {}
+        Item( SCROW nRow, ScFormulaCell* pCell ) :
+            mnRow(nRow), mpCell(pCell) {}
     };
 
     CachedTokenArray( ScDocument& rDoc ) : mrDoc(rDoc) {}
@@ -74,7 +75,7 @@ public:
             return NULL;
 
         Item& rCached = *it->second;
-        ScCompiler aComp(&mrDoc, rPos, *rCached.mpCode);
+        ScCompiler aComp(&mrDoc, rPos, *rCached.mpCell->GetCode());
         aComp.SetGrammar(formula::FormulaGrammar::GRAM_ENGLISH_XL_OOX);
         OUStringBuffer aBuf;
         aComp.CreateStringFromTokenArray(aBuf);
@@ -85,7 +86,7 @@ public:
         return NULL;
     }
 
-    void store( const ScAddress& rPos, const ScTokenArray& rArray )
+    void store( const ScAddress& rPos, ScFormulaCell* pCell )
     {
         ColCacheType::iterator it = maCache.find(rPos.Col());
         if (it == maCache.end())
@@ -100,8 +101,9 @@ public:
             it = r.first;
         }
 
-        it->second->mnRow = rPos.Row();
-        it->second->mpCode.reset(rArray.Clone());
+        Item& rItem = *it->second;
+        rItem.mnRow = rPos.Row();
+        rItem.mpCell = pCell;
     }
 
 private:
@@ -187,8 +189,12 @@ void applyCellFormulas(
         if (p)
         {
             // Use the cached version to avoid re-compilation.
-            ScFormulaCell* pCell = new ScFormulaCell(&rDoc.getDoc(), aPos, p->mpCode->Clone());
+            ScFormulaCell* pCell = new ScFormulaCell(&rDoc.getDoc(), aPos, p->mpCell->GetCode()->Clone());
             rDoc.setFormulaCell(aPos, pCell);
+
+            // Update the cache.
+            p->mnRow = aPos.Row();
+            p->mpCell = pCell;
             continue;
         }
 
@@ -201,7 +207,7 @@ void applyCellFormulas(
 
         ScFormulaCell* pCell = new ScFormulaCell(&rDoc.getDoc(), aPos, pCode);
         rDoc.setFormulaCell(aPos, pCell);
-        rCache.store(aPos, *pCode);
+        rCache.store(aPos, pCell);
     }
 }
 
commit 454ea7a80b14707df8164de6e09c3f8ec9893e71
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Nov 8 14:19:19 2013 -0500

    Create formula cells there...
    
    Change-Id: Idfd4081245905cdc88ad0da195b81be7e34ebf21

diff --git a/sc/source/filter/oox/formulabuffer.cxx b/sc/source/filter/oox/formulabuffer.cxx
index 86c9e6c..d9c164a 100644
--- a/sc/source/filter/oox/formulabuffer.cxx
+++ b/sc/source/filter/oox/formulabuffer.cxx
@@ -46,6 +46,8 @@ namespace {
  */
 class CachedTokenArray : boost::noncopyable
 {
+public:
+
     struct Item : boost::noncopyable
     {
         SCROW mnRow;
@@ -55,11 +57,6 @@ class CachedTokenArray : boost::noncopyable
         Item( SCROW nRow, ScTokenArray* p ) : mnRow(nRow), mpCode(p) {}
     };
 
-    typedef boost::unordered_map<SCCOL, Item*> ColCacheType;
-    ColCacheType maCache;
-    ScDocument& mrDoc;
-
-public:
     CachedTokenArray( ScDocument& rDoc ) : mrDoc(rDoc) {}
 
     ~CachedTokenArray()
@@ -69,21 +66,21 @@ public:
             delete it->second;
     }
 
-    const ScTokenArray* get( const ScAddress& rPos, const OUString& rFormula ) const
+    Item* get( const ScAddress& rPos, const OUString& rFormula )
     {
         // Check if a token array is cached for this column.
-        ColCacheType::const_iterator it = maCache.find(rPos.Col());
+        ColCacheType::iterator it = maCache.find(rPos.Col());
         if (it == maCache.end())
             return NULL;
 
-        const Item& rCached = *it->second;
+        Item& rCached = *it->second;
         ScCompiler aComp(&mrDoc, rPos, *rCached.mpCode);
         aComp.SetGrammar(formula::FormulaGrammar::GRAM_ENGLISH_XL_OOX);
         OUStringBuffer aBuf;
         aComp.CreateStringFromTokenArray(aBuf);
         OUString aPredicted = aBuf.makeStringAndClear();
         if (rFormula == aPredicted)
-            return rCached.mpCode.get();
+            return &rCached;
 
         return NULL;
     }
@@ -106,6 +103,11 @@ public:
         it->second->mnRow = rPos.Row();
         it->second->mpCode.reset(rArray.Clone());
     }
+
+private:
+    typedef boost::unordered_map<SCCOL, Item*> ColCacheType;
+    ColCacheType maCache;
+    ScDocument& mrDoc;
 };
 
 void applySharedFormulas(
@@ -181,11 +183,12 @@ void applyCellFormulas(
     {
         ScAddress aPos;
         ScUnoConversion::FillScAddress(aPos, it->maCellAddress);
-        const ScTokenArray* p = rCache.get(aPos, it->maTokenStr);
+        CachedTokenArray::Item* p = rCache.get(aPos, it->maTokenStr);
         if (p)
         {
             // Use the cached version to avoid re-compilation.
-            rDoc.setFormulaCell(aPos, p->Clone());
+            ScFormulaCell* pCell = new ScFormulaCell(&rDoc.getDoc(), aPos, p->mpCode->Clone());
+            rDoc.setFormulaCell(aPos, pCell);
             continue;
         }
 
@@ -196,7 +199,8 @@ void applyCellFormulas(
         if (!pCode)
             continue;
 
-        rDoc.setFormulaCell(aPos, pCode);
+        ScFormulaCell* pCell = new ScFormulaCell(&rDoc.getDoc(), aPos, pCode);
+        rDoc.setFormulaCell(aPos, pCell);
         rCache.store(aPos, *pCode);
     }
 }
commit 6ad8f2618ae153281ccd2f78c676452db7d1b25a
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Nov 8 12:33:57 2013 -0500

    Cache previous formula tokens to avoid formula re-compilations.
    
    Change-Id: If20e0ebf5410af0b7655f36f7e4fc06f53d8b14b

diff --git a/sc/source/filter/oox/formulabuffer.cxx b/sc/source/filter/oox/formulabuffer.cxx
index fa8e06a..86c9e6c 100644
--- a/sc/source/filter/oox/formulabuffer.cxx
+++ b/sc/source/filter/oox/formulabuffer.cxx
@@ -34,11 +34,80 @@ using namespace ::com::sun::star::sheet;
 using namespace ::com::sun::star::container;
 
 #include <boost/scoped_ptr.hpp>
+#include <boost/noncopyable.hpp>
 
 namespace oox { namespace xls {
 
 namespace {
 
+/**
+ * Cache the token array for the last cell position in each column. We use
+ * one cache per sheet.
+ */
+class CachedTokenArray : boost::noncopyable
+{
+    struct Item : boost::noncopyable
+    {
+        SCROW mnRow;
+        boost::scoped_ptr<ScTokenArray> mpCode;
+
+        Item() : mnRow(-1), mpCode(NULL) {}
+        Item( SCROW nRow, ScTokenArray* p ) : mnRow(nRow), mpCode(p) {}
+    };
+
+    typedef boost::unordered_map<SCCOL, Item*> ColCacheType;
+    ColCacheType maCache;
+    ScDocument& mrDoc;
+
+public:
+    CachedTokenArray( ScDocument& rDoc ) : mrDoc(rDoc) {}
+
+    ~CachedTokenArray()
+    {
+        ColCacheType::const_iterator it = maCache.begin(), itEnd = maCache.end();
+        for (; it != itEnd; ++it)
+            delete it->second;
+    }
+
+    const ScTokenArray* get( const ScAddress& rPos, const OUString& rFormula ) const
+    {
+        // Check if a token array is cached for this column.
+        ColCacheType::const_iterator it = maCache.find(rPos.Col());
+        if (it == maCache.end())
+            return NULL;
+
+        const Item& rCached = *it->second;
+        ScCompiler aComp(&mrDoc, rPos, *rCached.mpCode);
+        aComp.SetGrammar(formula::FormulaGrammar::GRAM_ENGLISH_XL_OOX);
+        OUStringBuffer aBuf;
+        aComp.CreateStringFromTokenArray(aBuf);
+        OUString aPredicted = aBuf.makeStringAndClear();
+        if (rFormula == aPredicted)
+            return rCached.mpCode.get();
+
+        return NULL;
+    }
+
+    void store( const ScAddress& rPos, const ScTokenArray& rArray )
+    {
+        ColCacheType::iterator it = maCache.find(rPos.Col());
+        if (it == maCache.end())
+        {
+            // Create an entry for this column.
+            std::pair<ColCacheType::iterator,bool> r =
+                maCache.insert(ColCacheType::value_type(rPos.Col(), new Item));
+            if (!r.second)
+                // Insertion failed.
+                return;
+
+            it = r.first;
+        }
+
+        it->second->mnRow = rPos.Row();
+        it->second->mpCode.reset(rArray.Clone());
+    }
+};
+
 void applySharedFormulas(
     ScDocumentImport& rDoc,
     SvNumberFormatter& rFormatter,
@@ -104,7 +173,7 @@ void applySharedFormulas(
 }
 
 void applyCellFormulas(
-    ScDocumentImport& rDoc, SvNumberFormatter& rFormatter,
+    ScDocumentImport& rDoc, CachedTokenArray& rCache, SvNumberFormatter& rFormatter,
     const std::vector<FormulaBuffer::TokenAddressItem>& rCells )
 {
     std::vector<FormulaBuffer::TokenAddressItem>::const_iterator it = rCells.begin(), itEnd = rCells.end();
@@ -112,6 +181,14 @@ void applyCellFormulas(
     {
         ScAddress aPos;
         ScUnoConversion::FillScAddress(aPos, it->maCellAddress);
+        const ScTokenArray* p = rCache.get(aPos, it->maTokenStr);
+        if (p)
+        {
+            // Use the cached version to avoid re-compilation.
+            rDoc.setFormulaCell(aPos, p->Clone());
+            continue;
+        }
+
         ScCompiler aCompiler(&rDoc.getDoc(), aPos);
         aCompiler.SetNumberFormatter(&rFormatter);
         aCompiler.SetGrammar(formula::FormulaGrammar::GRAM_ENGLISH_XL_OOX);
@@ -120,6 +197,7 @@ void applyCellFormulas(
             continue;
 
         rDoc.setFormulaCell(aPos, pCode);
+        rCache.store(aPos, *pCode);
     }
 }
 
@@ -185,7 +263,10 @@ protected:
             applySharedFormulas(mrDoc, *mpFormatter, *mrItem.mpSharedFormulaEntries, *mrItem.mpSharedFormulaIDs);
 
         if (mrItem.mpCellFormulas)
-            applyCellFormulas(mrDoc, *mpFormatter, *mrItem.mpCellFormulas);
+        {
+            CachedTokenArray aCache(mrDoc.getDoc());
+            applyCellFormulas(mrDoc, aCache, *mpFormatter, *mrItem.mpCellFormulas);
+        }
 
         if (mrItem.mpArrayFormulas)
             applyArrayFormulas(mrDoc, *mpFormatter, *mrItem.mpArrayFormulas);
commit d8fe172ea08f57675b6b1f69331c19502ec02119
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Nov 8 10:26:47 2013 -0500

    Remove mutexes from external ref manager.
    
    Change-Id: I4857bb3a1804d4cd53c3e25a7586bd68ab95a202

diff --git a/sc/inc/externalrefmgr.hxx b/sc/inc/externalrefmgr.hxx
index e7a5e79..c072cfd 100644
--- a/sc/inc/externalrefmgr.hxx
+++ b/sc/inc/externalrefmgr.hxx
@@ -768,12 +768,6 @@ private:
 private:
     ScDocument* mpDoc;
 
-    /** Mutex for accessing cached data and/or source document shells. */
-    mutable osl::Mutex maMtxCacheAccess;
-
-    /** Mutex for source document meta-data access. */
-    mutable osl::Mutex maMtxSrcFiles;
-
     /** cache of referenced ranges and names from source documents. */
     ScExternalRefCache maRefCache;
 
diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx
index 9c07fd7..c06490e 100644
--- a/sc/source/ui/docshell/externalrefmgr.cxx
+++ b/sc/source/ui/docshell/externalrefmgr.cxx
@@ -1606,7 +1606,6 @@ void ScExternalRefManager::getAllCachedNumberFormats(vector<sal_uInt32>& rNumFmt
 
 sal_uInt16 ScExternalRefManager::getExternalFileCount() const
 {
-    osl::MutexGuard aGuard(&maMtxSrcFiles);
     return static_cast< sal_uInt16 >( maSrcFiles.size() );
 }
 
@@ -1759,8 +1758,6 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
     sal_uInt16 nFileId, const OUString& rTabName, const ScAddress& rCell,
     const ScAddress* pCurPos, SCTAB* pTab, ScExternalRefCache::CellFormat* pFmt)
 {
-    osl::MutexGuard aGuard(&maMtxCacheAccess);
-
     if (pCurPos)
         insertRefCell(nFileId, *pCurPos);
 
@@ -1853,8 +1850,6 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
 ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
     sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange, const ScAddress* pCurPos)
 {
-    osl::MutexGuard aGuard(&maMtxCacheAccess);
-
     if (pCurPos)
         insertRefCell(nFileId, *pCurPos);
 
@@ -1901,8 +1896,6 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
 ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(
     sal_uInt16 nFileId, const OUString& rName, const ScAddress* pCurPos)
 {
-    osl::MutexGuard aGuard(&maMtxCacheAccess);
-
     if (pCurPos)
         insertRefCell(nFileId, *pCurPos);
 
@@ -1956,8 +1949,6 @@ bool hasRangeName(ScDocument& rDoc, const OUString& rName)
 
 bool ScExternalRefManager::isValidRangeName(sal_uInt16 nFileId, const OUString& rName)
 {
-    osl::MutexGuard aGuard(&maMtxCacheAccess);
-
     maybeLinkExternalFile(nFileId);
     ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
     if (pSrcDoc)
@@ -2415,7 +2406,6 @@ void ScExternalRefManager::SrcFileData::maybeCreateRealFileName(const OUString&
 
 void ScExternalRefManager::maybeCreateRealFileName(sal_uInt16 nFileId)
 {
-    osl::MutexGuard aGuard(&maMtxSrcFiles);
     if (nFileId >= maSrcFiles.size())
         return;
 
@@ -2460,8 +2450,6 @@ void ScExternalRefManager::convertToAbsName(OUString& rFile) const
 
 sal_uInt16 ScExternalRefManager::getExternalFileId(const OUString& rFile)
 {
-    osl::MutexGuard aGuard(&maMtxSrcFiles);
-
     vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
     vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
     if (itr != itrEnd)
@@ -2478,8 +2466,6 @@ sal_uInt16 ScExternalRefManager::getExternalFileId(const OUString& rFile)
 
 const OUString* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId, bool bForceOriginal)
 {
-    osl::MutexGuard aGuard(&maMtxSrcFiles);
-
     if (nFileId >= maSrcFiles.size())
         return NULL;
 
@@ -2496,14 +2482,11 @@ const OUString* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId, bo
 
 bool ScExternalRefManager::hasExternalFile(sal_uInt16 nFileId) const
 {
-    osl::MutexGuard aGuard(&maMtxSrcFiles);
     return nFileId < maSrcFiles.size();
 }
 
 bool ScExternalRefManager::hasExternalFile(const OUString& rFile) const
 {
-    osl::MutexGuard aGuard(&maMtxSrcFiles);
-
     vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
     vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
     return itr != itrEnd;
@@ -2602,8 +2585,6 @@ void ScExternalRefManager::breakLink(sal_uInt16 nFileId)
 
 void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const OUString& rNewFile, const OUString& rNewFilter)
 {
-    osl::MutexGuard aGuard(&maMtxSrcFiles);
-
     maSrcFiles[nFileId].maFileName = rNewFile;
     maSrcFiles[nFileId].maRelativeName = OUString();
     maSrcFiles[nFileId].maRealFileName = OUString();
@@ -2618,8 +2599,6 @@ void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const OUString& rNe
 
 void ScExternalRefManager::setRelativeFileName(sal_uInt16 nFileId, const OUString& rRelUrl)
 {
-    osl::MutexGuard aGuard(&maMtxSrcFiles);
-
     if (nFileId >= maSrcFiles.size())
         return;
     maSrcFiles[nFileId].maRelativeName = rRelUrl;
@@ -2627,8 +2606,6 @@ void ScExternalRefManager::setRelativeFileName(sal_uInt16 nFileId, const OUStrin
 
 void ScExternalRefManager::setFilterData(sal_uInt16 nFileId, const OUString& rFilterName, const OUString& rOptions)
 {
-    osl::MutexGuard aGuard(&maMtxSrcFiles);
-
     if (nFileId >= maSrcFiles.size())
         return;
     maSrcFiles[nFileId].maFilterName = rFilterName;
@@ -2647,13 +2624,11 @@ void ScExternalRefManager::clear()
 
 bool ScExternalRefManager::hasExternalData() const
 {
-    osl::MutexGuard aGuard(&maMtxSrcFiles);
     return !maSrcFiles.empty();
 }
 
 void ScExternalRefManager::resetSrcFileData(const OUString& rBaseFileUrl)
 {
-    osl::MutexGuard aGuard(&maMtxSrcFiles);
     for (vector<SrcFileData>::iterator itr = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
           itr != itrEnd; ++itr)
     {
@@ -2669,7 +2644,6 @@ void ScExternalRefManager::resetSrcFileData(const OUString& rBaseFileUrl)
 
 void ScExternalRefManager::updateAbsAfterLoad()
 {
-    osl::MutexGuard aGuard(&maMtxSrcFiles);
     OUString aOwn( getOwnDocumentName() );
     for (vector<SrcFileData>::iterator itr = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
           itr != itrEnd; ++itr)
commit afb9817b583c01ca80ac4e182c6ffde62f6316a8
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Nov 8 10:06:51 2013 -0500

    Revert "Guard access to external ref manager instance."
    
    This reverts commit 7cf9ea71ad1364d00eaca95b309cc6c0f35cf6cb.

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 08ba3a2..09f1466 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -39,7 +39,6 @@
 #include "calcmacros.hxx"
 #include <tools/fract.hxx>
 #include <tools/gen.hxx>
-#include "osl/mutex.hxx"
 
 #include <memory>
 #include <map>
@@ -299,9 +298,7 @@ private:
     ::std::auto_ptr<ScDocProtection> pDocProtection;
     ::std::auto_ptr<ScClipParam>     mpClipParam;
 
-    boost::scoped_ptr<ScExternalRefManager> mpExternalRefMgr;
-    mutable osl::Mutex maMtxExternalRefMgr;
-
+    ::std::auto_ptr<ScExternalRefManager> pExternalRefMgr;
     ::std::auto_ptr<ScMacroManager> mpMacroMgr;
 
 
@@ -664,7 +661,7 @@ public:
                                     const OUString& aFileName,
                                     const OUString& aTabName );
 
-    SC_DLLPUBLIC bool HasExternalRefManager() const;
+    bool            HasExternalRefManager() const { return pExternalRefMgr.get(); }
     SC_DLLPUBLIC ScExternalRefManager* GetExternalRefManager() const;
     bool            IsInExternalReferenceMarking() const;
     void            MarkUsedExternalReferences();
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 846b5c8..23a4bcf 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -150,7 +150,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
         pCacheFieldEditEngine( NULL ),
         pDocProtection( NULL ),
         mpClipParam( NULL),
-        mpExternalRefMgr( NULL ),
+        pExternalRefMgr( NULL ),
         mpMacroMgr( NULL ),
         pViewOptions( NULL ),
         pDocOptions( NULL ),
@@ -384,7 +384,7 @@ ScDocument::~ScDocument()
     mxFormulaParserPool.reset();
     // Destroy the external ref mgr instance here because it has a timer
     // which needs to be stopped before the app closes.
-    mpExternalRefMgr.reset();
+    pExternalRefMgr.reset();
 
     ScAddInAsync::RemoveDocument( this );
     ScAddInListener::RemoveDocument( this );
diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
index 67fda15..73f8d71 100644
--- a/sc/source/core/data/documen3.cxx
+++ b/sc/source/core/data/documen3.cxx
@@ -582,41 +582,30 @@ bool ScDocument::LinkExternalTab( SCTAB& rTab, const OUString& aDocTab,
     return true;
 }
 
-bool ScDocument::HasExternalRefManager() const
-{
-    osl::MutexGuard aGuard(&maMtxExternalRefMgr);
-    return mpExternalRefMgr.get();
-}
-
 ScExternalRefManager* ScDocument::GetExternalRefManager() const
 {
-    osl::MutexGuard aGuard(&maMtxExternalRefMgr);
-
     ScDocument* pThis = const_cast<ScDocument*>(this);
-    if (!mpExternalRefMgr.get())
-        pThis->mpExternalRefMgr.reset( new ScExternalRefManager( pThis));
+    if (!pExternalRefMgr.get())
+        pThis->pExternalRefMgr.reset( new ScExternalRefManager( pThis));
 
-    return mpExternalRefMgr.get();
+    return pExternalRefMgr.get();
 }
 
 bool ScDocument::IsInExternalReferenceMarking() const
 {
-    osl::MutexGuard aGuard(&maMtxExternalRefMgr);
-    return mpExternalRefMgr.get() && mpExternalRefMgr->isInReferenceMarking();
+    return pExternalRefMgr.get() && pExternalRefMgr->isInReferenceMarking();
 }
 
 void ScDocument::MarkUsedExternalReferences()
 {
-    osl::MutexGuard aGuard(&maMtxExternalRefMgr);
-
-    if (!mpExternalRefMgr.get())
+    if (!pExternalRefMgr.get())
         return;
-    if (!mpExternalRefMgr->hasExternalData())
+    if (!pExternalRefMgr->hasExternalData())
         return;
     // Charts.
-    mpExternalRefMgr->markUsedByLinkListeners();
+    pExternalRefMgr->markUsedByLinkListeners();
     // Formula cells.
-    mpExternalRefMgr->markUsedExternalRefCells();
+    pExternalRefMgr->markUsedExternalRefCells();
 
     /* NOTE: Conditional formats and validation objects are marked when
      * collecting them during export. */
commit 9575edc8ae21e4dd060a7d228cad98e54b490458
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Nov 8 09:51:23 2013 -0500

    We don't need to put this in a separate thread.
    
    We can do this on the main thread.
    
    Change-Id: I58a32d9e0ce2599c5822903393a5b698233599df

diff --git a/sc/source/filter/inc/formulabuffer.hxx b/sc/source/filter/inc/formulabuffer.hxx
index 7e881ee..2411466 100644
--- a/sc/source/filter/inc/formulabuffer.hxx
+++ b/sc/source/filter/inc/formulabuffer.hxx
@@ -31,20 +31,6 @@ namespace oox { namespace xls {
 
 class FormulaBuffer : public WorkbookHelper
 {
-    class FinalizeThread : public salhelper::Thread
-    {
-        FormulaBuffer& mrParent;
-        size_t mnThreadCount;
-    public:
-        FinalizeThread( FormulaBuffer& rParent, size_t nThreadCount );
-        virtual ~FinalizeThread();
-
-    protected:
-        virtual void execute();
-    };
-
-    friend class FinalizeThread;
-
 public:
     /**
      * Represents a shared formula definition.
diff --git a/sc/source/filter/oox/formulabuffer.cxx b/sc/source/filter/oox/formulabuffer.cxx
index f58e9f7..fa8e06a 100644
--- a/sc/source/filter/oox/formulabuffer.cxx
+++ b/sc/source/filter/oox/formulabuffer.cxx
@@ -214,15 +214,16 @@ FormulaBuffer::SheetItem::SheetItem() :
     mpSharedFormulaEntries(NULL),
     mpSharedFormulaIDs(NULL) {}
 
-FormulaBuffer::FinalizeThread::FinalizeThread( FormulaBuffer& rParent, size_t nThreadCount ) :
-    salhelper::Thread("xlsx-import-formula-buffer-finalize-thread"),
-    mrParent(rParent), mnThreadCount(nThreadCount) {}
-
-FormulaBuffer::FinalizeThread::~FinalizeThread() {}
+FormulaBuffer::FormulaBuffer( const WorkbookHelper& rHelper ) : WorkbookHelper( rHelper )
+{
+}
 
-void FormulaBuffer::FinalizeThread::execute()
+void FormulaBuffer::finalizeImport()
 {
-    ScDocumentImport& rDoc = mrParent.getDocImport();
+    ISegmentProgressBarRef xFormulaBar = getProgressBar().createSegment( getProgressBar().getFreeLength() );
+
+    const size_t nThreadCount = 1;
+    ScDocumentImport& rDoc = getDocImport();
     rDoc.getDoc().SetAutoNameCache(new ScAutoNameCache(&rDoc.getDoc()));
     ScExternalRefManager::ApiGuard aExtRefGuard(&rDoc.getDoc());
 
@@ -232,11 +233,11 @@ void FormulaBuffer::FinalizeThread::execute()
     std::vector<SheetItem> aSheetItems;
     aSheetItems.reserve(nTabCount);
     for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
-        aSheetItems.push_back(mrParent.getSheetItem(nTab));
+        aSheetItems.push_back(getSheetItem(nTab));
 
     typedef rtl::Reference<WorkerThread> WorkerThreadRef;
     std::vector<WorkerThreadRef> aThreads;
-    aThreads.reserve(mnThreadCount);
+    aThreads.reserve(nThreadCount);
 
     std::vector<SheetItem>::iterator it = aSheetItems.begin(), itEnd = aSheetItems.end();
 
@@ -246,7 +247,7 @@ void FormulaBuffer::FinalizeThread::execute()
     // lack.
     while (it != itEnd)
     {
-        for (size_t i = 0; i < mnThreadCount; ++i)
+        for (size_t i = 0; i < nThreadCount; ++i)
         {
             if (it == itEnd)
                 break;
@@ -267,21 +268,6 @@ void FormulaBuffer::FinalizeThread::execute()
     }
 
     rDoc.getDoc().SetAutoNameCache(NULL);
-}
-
-FormulaBuffer::FormulaBuffer( const WorkbookHelper& rHelper ) : WorkbookHelper( rHelper )
-{
-}
-
-void FormulaBuffer::finalizeImport()
-{
-    ISegmentProgressBarRef xFormulaBar = getProgressBar().createSegment( getProgressBar().getFreeLength() );
-
-    rtl::Reference<FinalizeThread> xThreadMgr(new FinalizeThread(*this, 1));
-    xThreadMgr->launch();
-
-    if (xThreadMgr.is())
-        xThreadMgr->join();
 
     xFormulaBar->setPosition( 1.0 );
 }
commit a4a60b677cd31ecaf040abce20da256fed06523c
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Nov 8 09:40:25 2013 -0500

    Revert "Guard CharacterClassificationImpl with mutex."
    
    This reverts commit fc04b55f7f96a4f70f31c145dafd44c1d9276a41.

diff --git a/i18npool/inc/characterclassificationImpl.hxx b/i18npool/inc/characterclassificationImpl.hxx
index 24221d1..e220968 100644
--- a/i18npool/inc/characterclassificationImpl.hxx
+++ b/i18npool/inc/characterclassificationImpl.hxx
@@ -26,8 +26,6 @@
 #include <com/sun/star/lang/XServiceInfo.hpp>
 #include <com/sun/star/uno/XComponentContext.hpp>
 
-#include "osl/mutex.hxx"
-
 namespace com { namespace sun { namespace star { namespace i18n {
 
 class CharacterClassificationImpl : public cppu::WeakImplHelper2
@@ -95,19 +93,17 @@ private:
             aLocale.Variant == rLocale.Variant;
         };
     };
+    std::vector<lookupTableItem*> lookupTable;
+    lookupTableItem *cachedItem;
+
+    com::sun::star::uno::Reference < com::sun::star::uno::XComponentContext > m_xContext;
+    com::sun::star::uno::Reference < XCharacterClassification > xUCI;
 
     com::sun::star::uno::Reference < XCharacterClassification > SAL_CALL
     getLocaleSpecificCharacterClassification(const com::sun::star::lang::Locale& rLocale) throw(com::sun::star::uno::RuntimeException);
     sal_Bool SAL_CALL
     createLocaleSpecificCharacterClassification(const OUString& serviceName, const com::sun::star::lang::Locale& rLocale);
 
-private:
-    std::vector<lookupTableItem*> lookupTable;
-    lookupTableItem *cachedItem;
-
-    com::sun::star::uno::Reference < com::sun::star::uno::XComponentContext > m_xContext;
-    com::sun::star::uno::Reference < XCharacterClassification > xUCI;
-    osl::Mutex maMtx;
 };
 
 } } } }
diff --git a/i18npool/source/characterclassification/characterclassificationImpl.cxx b/i18npool/source/characterclassification/characterclassificationImpl.cxx
index edcf9db..d65b5a5 100644
--- a/i18npool/source/characterclassification/characterclassificationImpl.cxx
+++ b/i18npool/source/characterclassification/characterclassificationImpl.cxx
@@ -47,7 +47,6 @@ OUString SAL_CALL
 CharacterClassificationImpl::toUpper( const OUString& Text, sal_Int32 nPos,
         sal_Int32 nCount, const Locale& rLocale ) throw(RuntimeException)
 {
-    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->toUpper(Text, nPos, nCount, rLocale);
 }
 
@@ -55,7 +54,6 @@ OUString SAL_CALL
 CharacterClassificationImpl::toLower( const OUString& Text, sal_Int32 nPos,
         sal_Int32 nCount, const Locale& rLocale ) throw(RuntimeException)
 {
-    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->toLower(Text, nPos, nCount, rLocale);
 }
 
@@ -63,7 +61,6 @@ OUString SAL_CALL
 CharacterClassificationImpl::toTitle( const OUString& Text, sal_Int32 nPos,
         sal_Int32 nCount, const Locale& rLocale ) throw(RuntimeException)
 {
-    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->toTitle(Text, nPos, nCount, rLocale);
 }
 
@@ -71,7 +68,6 @@ sal_Int16 SAL_CALL
 CharacterClassificationImpl::getType( const OUString& Text, sal_Int32 nPos )
         throw(RuntimeException)
 {
-    osl::MutexGuard aGuard(&maMtx);
     if (xUCI.is())
         return xUCI->getType(Text, nPos);
     throw RuntimeException();
@@ -81,7 +77,6 @@ sal_Int16 SAL_CALL
 CharacterClassificationImpl::getCharacterDirection( const OUString& Text, sal_Int32 nPos )
         throw(RuntimeException)
 {
-    osl::MutexGuard aGuard(&maMtx);
     if (xUCI.is())
         return xUCI->getCharacterDirection(Text, nPos);
     throw RuntimeException();
@@ -91,7 +86,6 @@ sal_Int16 SAL_CALL
 CharacterClassificationImpl::getScript( const OUString& Text, sal_Int32 nPos )
         throw(RuntimeException)
 {
-    osl::MutexGuard aGuard(&maMtx);
     if (xUCI.is())
         return xUCI->getScript(Text, nPos);
     throw RuntimeException();
@@ -101,7 +95,6 @@ sal_Int32 SAL_CALL
 CharacterClassificationImpl::getCharacterType( const OUString& Text, sal_Int32 nPos,
         const Locale& rLocale ) throw(RuntimeException)
 {
-    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->getCharacterType(Text, nPos, rLocale);
 }
 
@@ -109,7 +102,6 @@ sal_Int32 SAL_CALL
 CharacterClassificationImpl::getStringType( const OUString& Text, sal_Int32 nPos,
         sal_Int32 nCount, const Locale& rLocale ) throw(RuntimeException)
 {
-    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->getStringType(Text, nPos, nCount, rLocale);
 }
 
@@ -119,7 +111,6 @@ ParseResult SAL_CALL CharacterClassificationImpl::parseAnyToken(
         sal_Int32 contCharTokenType, const OUString& userDefinedCharactersCont )
         throw(RuntimeException)
 {
-    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->parseAnyToken(Text, nPos, rLocale,
             startCharTokenType,userDefinedCharactersStart,
             contCharTokenType, userDefinedCharactersCont);
@@ -132,7 +123,6 @@ ParseResult SAL_CALL CharacterClassificationImpl::parsePredefinedToken(
         const OUString& userDefinedCharactersStart, sal_Int32 contCharTokenType,
         const OUString& userDefinedCharactersCont ) throw(RuntimeException)
 {
-    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->parsePredefinedToken(
             nTokenType, Text, nPos, rLocale, startCharTokenType, userDefinedCharactersStart,
             contCharTokenType, userDefinedCharactersCont);
commit 677cefa3db2507fbe5ccca131451620272f7d8b5
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Nov 7 14:46:53 2013 -0500

    Mutex access to the global theIndexTable.
    
    Change-Id: I31e2cf3a479e385aa0fca4678a3a2c7fa6cc4b5f

diff --git a/svl/source/numbers/zforlist.cxx b/svl/source/numbers/zforlist.cxx
index 2117041..accc557 100644
--- a/svl/source/numbers/zforlist.cxx
+++ b/svl/source/numbers/zforlist.cxx
@@ -71,9 +71,16 @@ using namespace ::std;
  * (old currency) is recognized as a date (#53155#). */
 #define UNKNOWN_SUBSTITUTE      LANGUAGE_ENGLISH_US
 
-static bool bIndexTableInitialized = false;
-static sal_uInt32 theIndexTable[NF_INDEX_TABLE_ENTRIES];
+struct IndexTable
+{
+    bool mbInitialized;
+    sal_uInt32 maData[NF_INDEX_TABLE_ENTRIES];
+    osl::Mutex maMtx;
+
+    IndexTable() : mbInitialized(false) {}
+};
 
+static IndexTable theIndexTable;
 
 // ====================================================================
 
@@ -2001,11 +2008,13 @@ sal_uInt32 SvNumberFormatter::GetFormatSpecialInfo( const OUString& rFormatStrin
 
 inline sal_uInt32 SetIndexTable( NfIndexTableOffset nTabOff, sal_uInt32 nIndOff )
 {
-    if ( !bIndexTableInitialized )
+    osl::MutexGuard aGuard(&theIndexTable.maMtx);
+
+    if (!theIndexTable.mbInitialized)
     {
-        DBG_ASSERT( theIndexTable[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND,
+        DBG_ASSERT(theIndexTable.maData[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND,
             "SetIndexTable: theIndexTable[nTabOff] already occupied" );
-        theIndexTable[nTabOff] = nIndOff;
+        theIndexTable.maData[nTabOff] = nIndOff;
     }
     return nIndOff;
 }
@@ -2196,13 +2205,17 @@ void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset, bool bNoAdditio
 {
     using namespace ::com::sun::star;
 
-    if ( !bIndexTableInitialized )
     {
-        for ( sal_uInt16 j=0; j<NF_INDEX_TABLE_ENTRIES; j++ )
+        osl::MutexGuard aGuard(&theIndexTable.maMtx);
+        if (!theIndexTable.mbInitialized)
         {
-            theIndexTable[j] = NUMBERFORMAT_ENTRY_NOT_FOUND;
+            for ( sal_uInt16 j=0; j<NF_INDEX_TABLE_ENTRIES; j++ )
+            {
+                theIndexTable.maData[j] = NUMBERFORMAT_ENTRY_NOT_FOUND;
+            }
         }
     }
+
     bool bOldConvertMode = pFormatScanner->GetConvertMode();
     if (bOldConvertMode)
     {
@@ -2631,8 +2644,10 @@ void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset, bool bNoAdditio
                                 CLOffset + SetIndexTable( NF_DATE_WW, nNewExtended++ ),
                                 SV_NUMBERFORMATTER_VERSION_NF_DATE_WW );
 
-
-    bIndexTableInitialized = true;
+    {
+        osl::MutexGuard aGuard(&theIndexTable.maMtx);
+        theIndexTable.mbInitialized = true;
+    }
     SAL_WARN_IF( nNewExtended > ZF_STANDARD_NEWEXTENDEDMAX, "svl.numbers",
         "ImpGenerateFormats: overflow of nNewExtended standard formats" );
 
@@ -3092,17 +3107,24 @@ sal_uInt32 SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat,
 sal_uInt32 SvNumberFormatter::GetFormatIndex( NfIndexTableOffset nTabOff,
                                               LanguageType eLnge )
 {
-    if ( nTabOff >= NF_INDEX_TABLE_ENTRIES ||
-         theIndexTable[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND )
-    {
+    if (nTabOff >= NF_INDEX_TABLE_ENTRIES)
         return NUMBERFORMAT_ENTRY_NOT_FOUND;
-    }
-    if ( eLnge == LANGUAGE_DONTKNOW )
-    {
+
+    if (eLnge == LANGUAGE_DONTKNOW)
         eLnge = IniLnge;
+
+    {
+        osl::MutexGuard aGuard(&theIndexTable.maMtx);
+        if (theIndexTable.maData[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND)
+            return NUMBERFORMAT_ENTRY_NOT_FOUND;
     }
+
     sal_uInt32 nCLOffset = ImpGenerateCL(eLnge);    // create new standard formats if necessary
-    return nCLOffset + theIndexTable[nTabOff];
+
+    {
+        osl::MutexGuard aGuard(&theIndexTable.maMtx);
+        return nCLOffset + theIndexTable.maData[nTabOff];
+    }
 }
 
 
@@ -3113,11 +3135,13 @@ NfIndexTableOffset SvNumberFormatter::GetIndexTableOffset( sal_uInt32 nFormat )
     {
         return NF_INDEX_TABLE_ENTRIES;      // not a built-in format
     }
-    for ( sal_uInt16 j = 0; j < NF_INDEX_TABLE_ENTRIES; j++ )
+
     {
-        if ( theIndexTable[j] == nOffset )
+        osl::MutexGuard aGuard(&theIndexTable.maMtx);
+        for ( sal_uInt16 j = 0; j < NF_INDEX_TABLE_ENTRIES; j++ )
         {
-            return (NfIndexTableOffset) j;
+            if (theIndexTable.maData[j] == nOffset)
+                return (NfIndexTableOffset) j;
         }
     }
     return NF_INDEX_TABLE_ENTRIES;      // bad luck
commit 3ac4277ba1ad8925329bbe8a1c5ed3684b9b8ee7
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Nov 7 14:16:48 2013 -0500

    Thread-safe way to check for presence of references in formula tokens.
    
    Change-Id: I995668d1e183dc0dae4f354889bc13053e858723

diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx
index 8f0cfa8..ae1655e 100644
--- a/formula/source/core/api/token.cxx
+++ b/formula/source/core/api/token.cxx
@@ -130,6 +130,22 @@ bool FormulaToken::IsExternalRef() const
     return bRet;
 }
 
+bool FormulaToken::IsRef() const
+{
+    switch (eType)
+    {
+        case svSingleRef:
+        case svDoubleRef:
+        case svExternalSingleRef:
+        case svExternalDoubleRef:
+            return true;
+        default:
+            ;
+    }
+
+    return false;
+}
+
 bool FormulaToken::operator==( const FormulaToken& rToken ) const
 {
     // don't compare reference count!
@@ -538,6 +554,17 @@ FormulaToken* FormulaTokenArray::PeekPrevNoSpaces()
         return NULL;
 }
 
+bool FormulaTokenArray::HasReferences() const
+{
+    for (sal_uInt16 i = 0; i < nLen; ++i)
+    {
+        if (pCode[i]->IsRef())
+            return true;
+    }
+
+    return false;
+}
+
 bool FormulaTokenArray::HasExternalRef() const
 {
     for ( sal_uInt16 j=0; j < nLen; j++ )
diff --git a/include/formula/token.hxx b/include/formula/token.hxx
index 73f773b..002cefb 100644
--- a/include/formula/token.hxx
+++ b/include/formula/token.hxx
@@ -106,7 +106,10 @@ public:
     inline  void                Delete()                { delete this; }
     inline  StackVar            GetType() const         { return eType; }
             bool                IsFunction() const; // pure functions, no operators
-            bool                IsExternalRef() const;
+
+    bool IsExternalRef() const;
+    bool IsRef() const;
+
             sal_uInt8           GetParamCount() const;
 
     inline void IncRef() const
diff --git a/include/formula/tokenarray.hxx b/include/formula/tokenarray.hxx
index ddd7d81..9f8fed0 100644
--- a/include/formula/tokenarray.hxx
+++ b/include/formula/tokenarray.hxx
@@ -116,6 +116,8 @@ public:
     FormulaToken* LastRPN() { nIndex = nRPN; return PrevRPN(); }
     FormulaToken* PrevRPN();
 
+    bool HasReferences() const;
+
     bool    HasExternalRef() const;
     bool    HasOpCode( OpCode ) const;
     bool    HasOpCodeRPN( OpCode ) const;
diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx
index 6096ecf..c1e2865 100644
--- a/sc/source/core/tool/rangenam.cxx
+++ b/sc/source/core/tool/rangenam.cxx
@@ -518,8 +518,7 @@ sal_uInt16 ScRangeData::GetErrCode() const
 
 bool ScRangeData::HasReferences() const
 {
-    pCode->Reset();
-    return pCode->GetNextReference() != NULL;
+    return pCode->HasReferences();
 }
 
 sal_uInt32 ScRangeData::GetUnoType() const
commit 6122a6c272436f0f1959f160406d2e4ecdd1a733
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Nov 7 13:35:24 2013 -0500

    Guard CharacterClassificationImpl with mutex.
    
    They are accessed from multiple threads frequently.
    
    Change-Id: I3f9720ede076109efe0b7eaa4a05dd50f2e38102

diff --git a/i18npool/inc/characterclassificationImpl.hxx b/i18npool/inc/characterclassificationImpl.hxx
index e220968..24221d1 100644
--- a/i18npool/inc/characterclassificationImpl.hxx
+++ b/i18npool/inc/characterclassificationImpl.hxx
@@ -26,6 +26,8 @@
 #include <com/sun/star/lang/XServiceInfo.hpp>
 #include <com/sun/star/uno/XComponentContext.hpp>
 
+#include "osl/mutex.hxx"
+
 namespace com { namespace sun { namespace star { namespace i18n {
 
 class CharacterClassificationImpl : public cppu::WeakImplHelper2
@@ -93,17 +95,19 @@ private:
             aLocale.Variant == rLocale.Variant;
         };
     };
-    std::vector<lookupTableItem*> lookupTable;
-    lookupTableItem *cachedItem;
-
-    com::sun::star::uno::Reference < com::sun::star::uno::XComponentContext > m_xContext;
-    com::sun::star::uno::Reference < XCharacterClassification > xUCI;
 
     com::sun::star::uno::Reference < XCharacterClassification > SAL_CALL
     getLocaleSpecificCharacterClassification(const com::sun::star::lang::Locale& rLocale) throw(com::sun::star::uno::RuntimeException);
     sal_Bool SAL_CALL
     createLocaleSpecificCharacterClassification(const OUString& serviceName, const com::sun::star::lang::Locale& rLocale);
 
+private:
+    std::vector<lookupTableItem*> lookupTable;
+    lookupTableItem *cachedItem;
+
+    com::sun::star::uno::Reference < com::sun::star::uno::XComponentContext > m_xContext;
+    com::sun::star::uno::Reference < XCharacterClassification > xUCI;
+    osl::Mutex maMtx;
 };
 
 } } } }
diff --git a/i18npool/source/characterclassification/characterclassificationImpl.cxx b/i18npool/source/characterclassification/characterclassificationImpl.cxx
index d65b5a5..edcf9db 100644
--- a/i18npool/source/characterclassification/characterclassificationImpl.cxx
+++ b/i18npool/source/characterclassification/characterclassificationImpl.cxx
@@ -47,6 +47,7 @@ OUString SAL_CALL
 CharacterClassificationImpl::toUpper( const OUString& Text, sal_Int32 nPos,
         sal_Int32 nCount, const Locale& rLocale ) throw(RuntimeException)
 {
+    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->toUpper(Text, nPos, nCount, rLocale);
 }
 
@@ -54,6 +55,7 @@ OUString SAL_CALL
 CharacterClassificationImpl::toLower( const OUString& Text, sal_Int32 nPos,
         sal_Int32 nCount, const Locale& rLocale ) throw(RuntimeException)
 {
+    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->toLower(Text, nPos, nCount, rLocale);
 }
 
@@ -61,6 +63,7 @@ OUString SAL_CALL
 CharacterClassificationImpl::toTitle( const OUString& Text, sal_Int32 nPos,
         sal_Int32 nCount, const Locale& rLocale ) throw(RuntimeException)
 {
+    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->toTitle(Text, nPos, nCount, rLocale);
 }
 
@@ -68,6 +71,7 @@ sal_Int16 SAL_CALL
 CharacterClassificationImpl::getType( const OUString& Text, sal_Int32 nPos )
         throw(RuntimeException)
 {
+    osl::MutexGuard aGuard(&maMtx);
     if (xUCI.is())
         return xUCI->getType(Text, nPos);
     throw RuntimeException();
@@ -77,6 +81,7 @@ sal_Int16 SAL_CALL
 CharacterClassificationImpl::getCharacterDirection( const OUString& Text, sal_Int32 nPos )
         throw(RuntimeException)
 {
+    osl::MutexGuard aGuard(&maMtx);
     if (xUCI.is())
         return xUCI->getCharacterDirection(Text, nPos);
     throw RuntimeException();
@@ -86,6 +91,7 @@ sal_Int16 SAL_CALL
 CharacterClassificationImpl::getScript( const OUString& Text, sal_Int32 nPos )
         throw(RuntimeException)
 {
+    osl::MutexGuard aGuard(&maMtx);
     if (xUCI.is())
         return xUCI->getScript(Text, nPos);
     throw RuntimeException();
@@ -95,6 +101,7 @@ sal_Int32 SAL_CALL
 CharacterClassificationImpl::getCharacterType( const OUString& Text, sal_Int32 nPos,
         const Locale& rLocale ) throw(RuntimeException)
 {
+    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->getCharacterType(Text, nPos, rLocale);
 }
 
@@ -102,6 +109,7 @@ sal_Int32 SAL_CALL
 CharacterClassificationImpl::getStringType( const OUString& Text, sal_Int32 nPos,
         sal_Int32 nCount, const Locale& rLocale ) throw(RuntimeException)
 {
+    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->getStringType(Text, nPos, nCount, rLocale);
 }
 
@@ -111,6 +119,7 @@ ParseResult SAL_CALL CharacterClassificationImpl::parseAnyToken(
         sal_Int32 contCharTokenType, const OUString& userDefinedCharactersCont )
         throw(RuntimeException)
 {
+    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->parseAnyToken(Text, nPos, rLocale,
             startCharTokenType,userDefinedCharactersStart,
             contCharTokenType, userDefinedCharactersCont);
@@ -123,6 +132,7 @@ ParseResult SAL_CALL CharacterClassificationImpl::parsePredefinedToken(
         const OUString& userDefinedCharactersStart, sal_Int32 contCharTokenType,
         const OUString& userDefinedCharactersCont ) throw(RuntimeException)
 {
+    osl::MutexGuard aGuard(&maMtx);
     return getLocaleSpecificCharacterClassification(rLocale)->parsePredefinedToken(
             nTokenType, Text, nPos, rLocale, startCharTokenType, userDefinedCharactersStart,
             contCharTokenType, userDefinedCharactersCont);
commit 94934248e73defcf96d2e58089b0a731b191f015
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Nov 7 13:21:13 2013 -0500

    Make this thread safe too.
    
    Change-Id: Ic8508f693f8a6e9bae513d6b5b6eaaaae618194b

diff --git a/sc/inc/mtvelements.hxx b/sc/inc/mtvelements.hxx
index a1532d4..e5efbf1 100644
--- a/sc/inc/mtvelements.hxx
+++ b/sc/inc/mtvelements.hxx
@@ -17,6 +17,7 @@
 #include "editeng/editobj.hxx"
 #include "calcmacros.hxx"
 #include "postit.hxx"
+#include "osl/mutex.hxx"
 
 #if DEBUG_COLUMN_STORAGE
 #ifdef NDEBUG
@@ -138,6 +139,7 @@ class ColumnBlockPositionSet
 
     ScDocument& mrDoc;
     TablesType maTables;
+    osl::Mutex maMtxTables;
 
 public:
     ColumnBlockPositionSet(ScDocument& rDoc);
diff --git a/sc/source/core/data/mtvelements.cxx b/sc/source/core/data/mtvelements.cxx
index 222aabd..5a94606 100644
--- a/sc/source/core/data/mtvelements.cxx
+++ b/sc/source/core/data/mtvelements.cxx
@@ -30,6 +30,8 @@ ColumnBlockPositionSet::ColumnBlockPositionSet(ScDocument& rDoc) : mrDoc(rDoc) {
 
 ColumnBlockPosition* ColumnBlockPositionSet::getBlockPosition(SCTAB nTab, SCCOL nCol)
 {
+    osl::MutexGuard aGuard(&maMtxTables);
+
     TablesType::iterator itTab = maTables.find(nTab);
     if (itTab == maTables.end())
     {
commit fd50b465b94203e9980368481c579178cf93483a
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Nov 7 13:14:57 2013 -0500

    Guard access to external ref manager instance.
    
    Change-Id: Ie3208844b523463954c482d080f02d726ae749f9

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 09f1466..08ba3a2 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -39,6 +39,7 @@
 #include "calcmacros.hxx"
 #include <tools/fract.hxx>
 #include <tools/gen.hxx>
+#include "osl/mutex.hxx"
 
 #include <memory>
 #include <map>
@@ -298,7 +299,9 @@ private:
     ::std::auto_ptr<ScDocProtection> pDocProtection;
     ::std::auto_ptr<ScClipParam>     mpClipParam;
 
-    ::std::auto_ptr<ScExternalRefManager> pExternalRefMgr;
+    boost::scoped_ptr<ScExternalRefManager> mpExternalRefMgr;
+    mutable osl::Mutex maMtxExternalRefMgr;
+
     ::std::auto_ptr<ScMacroManager> mpMacroMgr;
 
 
@@ -661,7 +664,7 @@ public:
                                     const OUString& aFileName,
                                     const OUString& aTabName );
 
-    bool            HasExternalRefManager() const { return pExternalRefMgr.get(); }
+    SC_DLLPUBLIC bool HasExternalRefManager() const;
     SC_DLLPUBLIC ScExternalRefManager* GetExternalRefManager() const;
     bool            IsInExternalReferenceMarking() const;
     void            MarkUsedExternalReferences();
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 23a4bcf..846b5c8 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -150,7 +150,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
         pCacheFieldEditEngine( NULL ),
         pDocProtection( NULL ),
         mpClipParam( NULL),
-        pExternalRefMgr( NULL ),
+        mpExternalRefMgr( NULL ),
         mpMacroMgr( NULL ),
         pViewOptions( NULL ),
         pDocOptions( NULL ),
@@ -384,7 +384,7 @@ ScDocument::~ScDocument()
     mxFormulaParserPool.reset();
     // Destroy the external ref mgr instance here because it has a timer
     // which needs to be stopped before the app closes.
-    pExternalRefMgr.reset();
+    mpExternalRefMgr.reset();
 
     ScAddInAsync::RemoveDocument( this );
     ScAddInListener::RemoveDocument( this );
diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
index 73f8d71..67fda15 100644
--- a/sc/source/core/data/documen3.cxx
+++ b/sc/source/core/data/documen3.cxx
@@ -582,30 +582,41 @@ bool ScDocument::LinkExternalTab( SCTAB& rTab, const OUString& aDocTab,
     return true;
 }
 
+bool ScDocument::HasExternalRefManager() const
+{
+    osl::MutexGuard aGuard(&maMtxExternalRefMgr);
+    return mpExternalRefMgr.get();
+}
+
 ScExternalRefManager* ScDocument::GetExternalRefManager() const
 {
+    osl::MutexGuard aGuard(&maMtxExternalRefMgr);
+
     ScDocument* pThis = const_cast<ScDocument*>(this);
-    if (!pExternalRefMgr.get())
-        pThis->pExternalRefMgr.reset( new ScExternalRefManager( pThis));
+    if (!mpExternalRefMgr.get())
+        pThis->mpExternalRefMgr.reset( new ScExternalRefManager( pThis));
 
-    return pExternalRefMgr.get();
+    return mpExternalRefMgr.get();
 }
 
 bool ScDocument::IsInExternalReferenceMarking() const
 {
-    return pExternalRefMgr.get() && pExternalRefMgr->isInReferenceMarking();
+    osl::MutexGuard aGuard(&maMtxExternalRefMgr);
+    return mpExternalRefMgr.get() && mpExternalRefMgr->isInReferenceMarking();
 }
 
 void ScDocument::MarkUsedExternalReferences()
 {
-    if (!pExternalRefMgr.get())
+    osl::MutexGuard aGuard(&maMtxExternalRefMgr);
+
+    if (!mpExternalRefMgr.get())
         return;
-    if (!pExternalRefMgr->hasExternalData())
+    if (!mpExternalRefMgr->hasExternalData())
         return;
     // Charts.
-    pExternalRefMgr->markUsedByLinkListeners();
+    mpExternalRefMgr->markUsedByLinkListeners();
     // Formula cells.
-    pExternalRefMgr->markUsedExternalRefCells();
+    mpExternalRefMgr->markUsedExternalRefCells();
 
     /* NOTE: Conditional formats and validation objects are marked when
      * collecting them during export. */
commit 82d6b0c64698e356a950d9b516ca5332817b71a3
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Nov 7 13:01:40 2013 -0500

    Move the API guard out of the worker threads onto the manager thread.
    
    Just set this once before spawning multiple worker threads.
    
    Change-Id: I9cb60721f633f939d4a95f1d80e2ed8e4542a8fa

diff --git a/sc/source/filter/oox/formulabuffer.cxx b/sc/source/filter/oox/formulabuffer.cxx
index c3e1d24..f58e9f7 100644
--- a/sc/source/filter/oox/formulabuffer.cxx
+++ b/sc/source/filter/oox/formulabuffer.cxx
@@ -107,7 +107,6 @@ void applyCellFormulas(
     ScDocumentImport& rDoc, SvNumberFormatter& rFormatter,
     const std::vector<FormulaBuffer::TokenAddressItem>& rCells )
 {
-    ScExternalRefManager::ApiGuard aExtRefGuard(&rDoc.getDoc());
     std::vector<FormulaBuffer::TokenAddressItem>::const_iterator it = rCells.begin(), itEnd = rCells.end();
     for (; it != itEnd; ++it)
     {
@@ -225,8 +224,11 @@ void FormulaBuffer::FinalizeThread::execute()
 {
     ScDocumentImport& rDoc = mrParent.getDocImport();
     rDoc.getDoc().SetAutoNameCache(new ScAutoNameCache(&rDoc.getDoc()));
+    ScExternalRefManager::ApiGuard aExtRefGuard(&rDoc.getDoc());
+
     SCTAB nTabCount = rDoc.getDoc().GetTableCount();
 
+    // Fetch all the formulas to process first.
     std::vector<SheetItem> aSheetItems;
     aSheetItems.reserve(nTabCount);
     for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
@@ -238,6 +240,10 @@ void FormulaBuffer::FinalizeThread::execute()
 
     std::vector<SheetItem>::iterator it = aSheetItems.begin(), itEnd = aSheetItems.end();
 
+    // TODO: Right now we are spawning multiple threads all at once and block
+    // on them all at once.  Any more clever thread management would require
+    // use of condition variables which our own osl thread framework seems to
+    // lack.
     while (it != itEnd)
     {
         for (size_t i = 0; i < mnThreadCount; ++i)


More information about the Libreoffice-commits mailing list