[Libreoffice-commits] core.git: Branch 'private/kohei/calc-shared-string' - 484 commits - accessibility/source android/experimental android/sdremote avmedia/source basctl/source basic/source bin/benchmark-document-loading boost/boost_1_44_0-gcc4.8.patch boost/boost.wdeprecated-auto_ptr.patch.0 boost/UnpackedTarball_boost.mk bridges/source canvas/source chart2/CppunitTest_chart2_export.mk chart2/CppunitTest_chart2_import.mk chart2/source codemaker/source comphelper/source config_host.mk.in configmgr/source configure.ac connectivity/source cppuhelper/source cpputools/source crashrep/source cui/source cui/uiconfig dbaccess/CppunitTest_dbaccess_firebird_test.mk dbaccess/CppunitTest_dbaccess_hsqldb_test.mk dbaccess/CppunitTest_dbaccess_macros_test.mk dbaccess/Module_dbaccess.mk dbaccess/source desktop/source dictionaries drawinglayer/source editeng/source embeddedobj/source extensions/source extensions/test extensions/workben filter/Configuration_filter.mk filter/source fontconfig/ExternalProj ect_fontconfig.mk forms/source formula/source fpicker/source framework/source g helpcontent2 i18nlangtag/source include/avmedia include/canvas include/com include/comphelper include/connectivity include/cppuhelper include/editeng include/filter include/formula include/i18nlangtag include/oox include/osl include/sfx2 include/svl include/svtools include/svx include/toolkit include/tools include/unotools include/vbahelper include/vcl instsetoo_native/CustomTarget_install.mk instsetoo_native/inc_ooohelppack instsetoo_native/inc_openoffice instsetoo_native/inc_sdkoo instsetoo_native/util ios/CustomTarget_LibreOffice_app.mk ios/experimental ios/iosremote io/test jurt/com libxml2/ExternalProject_xml2.mk libxmlsec/ExternalPackage_xmlsec.mk lingucomponent/Module_lingucomponent.mk lingucomponent/Package_config.mk lingucomponent/source linguistic/source lotuswordpro/source m4/ax_boost_base.m4 Makefile.in nss/ExternalPackage_nss.mk odk/Package_odk_headers.mk offapi/com officecfg/Module_ officecfg.mk officecfg/Package_tools.mk officecfg/registry oox/source package/source padmin/source postgresql/ExternalPackage_postgresql.mk postgresql/Module_postgresql.mk postprocess/CustomTarget_registry.mk postprocess/Module_postprocess.mk postprocess/Package_registry_install.mk postprocess/Package_registry.mk pyuno/source qadevOOo/runner reportdesign/source RepositoryExternal.mk Repository.mk sal/Library_sal.mk sal/osl sal/qa sal/rtl sal/textenc sax/source sax/test scaddins/source sc/CppunitTest_sc_annotationobj.mk sc/CppunitTest_sc_annotationshapeobj.mk sc/CppunitTest_sc_annotationsobj.mk sc/CppunitTest_sc_cellrangeobj.mk sc/CppunitTest_sc_chart_regression_test.mk sc/CppunitTest_sc_databaserangeobj.mk sc/CppunitTest_sc_datapilotfieldobj.mk sc/CppunitTest_sc_datapilottableobj.mk sc/CppunitTest_sc_editfieldobj_cell.mk sc/CppunitTest_sc_editfieldobj_header.mk sc/CppunitTest_sc_filters_test.mk sc/CppunitTest_sc_macros_test.mk sc/CppunitTest_sc_modelobj.mk sc/CppunitTest_sc_ namedrangeobj.mk sc/CppunitTest_sc_namedrangesobj.mk sc/CppunitTest_sc_outlineobj.mk sc/CppunitTest_sc_rangelst_test.mk sc/CppunitTest_sc_subsequent_export_test.mk sc/CppunitTest_sc_subsequent_filters_test.mk sc/CppunitTest_sc_tableautoformatfield.mk sc/CppunitTest_sc_tablesheetobj.mk sc/CppunitTest_sc_tablesheetsobj.mk sc/inc scp2/source sc/qa scripting/source sc/source sd/CppunitTest_sd_filters_test.mk sd/CppunitTest_sd_import_tests.mk sdext/Extension_minimizer.mk sdext/Module_sdext.mk sdext/Package_pdfimport_xcu.mk sdext/source sd/source sd/uiconfig sd/UIConfig_simpress.mk sfx2/source slideshow/source solenv/bin solenv/gbuild sot/source starmath/inc starmath/source stoc/source svgio/source svl/Library_svl.mk svl/qa svl/source svtools/source svx/inc svx/README svx/source svx/uiconfig svx/UIConfig_svx.mk sw/CppunitTest_sw_filters_test.mk sw/CppunitTest_sw_htmlexport.mk sw/CppunitTest_sw_layout_test.mk sw/CppunitTest_sw_macros_test.mk sw/CppunitTest_sw_odfexport.mk sw/Cppuni tTest_sw_odfimport.mk sw/CppunitTest_sw_ooxmlexport.mk sw/CppunitTest_sw_ooxmlimport.mk sw/CppunitTest_sw_rtfexport.mk sw/CppunitTest_sw_rtfimport.mk sw/CppunitTest_sw_ww8export.mk sw/CppunitTest_sw_ww8import.mk swext/mediawiki sw/inc sw/qa sw/sdi sw/source sw/uiconfig sysui/CustomTarget_share.mk sysui/desktop test/source toolkit/source tools/source ucb/source udkapi/com UnoControls/source unotools/source unoxml/source uui/source vbahelper/source vcl/generic vcl/source vcl/unx wizards/source writerfilter/source xmlhelp/source xmloff/qa xmloff/source xmlsecurity/Library_xsec_xmlsec.mk xmlsecurity/source

Kohei Yoshida kohei.yoshida at collabora.com
Fri Oct 4 13:02:25 PDT 2013


Rebased ref, commits from common ancestor:
commit 67551f371efb9cfef102172b88d910961499dfd2
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Oct 4 15:21:36 2013 -0400

    Some attempt to store string ID's into query items.
    
    Change-Id: I8db7cd327728be0974405eabb0fd58156ba231d6

diff --git a/sc/inc/queryentry.hxx b/sc/inc/queryentry.hxx
index a3baea6..636372e 100644
--- a/sc/inc/queryentry.hxx
+++ b/sc/inc/queryentry.hxx
@@ -42,8 +42,9 @@ struct SC_DLLPUBLIC ScQueryEntry
         QueryType     meType;
         double        mfVal;
         OUString maString;
+        sal_uIntPtr mnStrId;
 
-        Item() : meType(ByValue), mfVal(0.0) {}
+        Item() : meType(ByValue), mfVal(0.0), mnStrId(0) {}
 
         bool operator== (const Item& r) const;
     };
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index fd2600e..7026a46 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -60,6 +60,7 @@
 
 #include <comphelper/processfactory.hxx>
 #include <comphelper/string.hxx>
+#include "svl/stringpool.hxx"
 
 #include <stdlib.h>
 #include <string.h>
@@ -6448,6 +6449,43 @@ void ScInterpreter::ScHLookup()
     CalculateLookup(true);
 }
 
+namespace {
+
+#if 1
+bool isFilterByEqualString( const ScQueryParam& )
+{
+    return false;
+}
+#else
+bool isFilterByEqualString( const ScQueryParam& rParam )
+{
+    if (rParam.bRegExp)
+        // filter by regular expression.
+        return false;
+
+    if (!rParam.GetEntryCount())
+        // No entries.
+        return false;
+
+    const ScQueryEntry& rEntry = rParam.GetEntry(0);
+    if (rEntry.eOp != SC_EQUAL)
+        return false;
+
+    const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+    if (rItems.size() != 1)
+        // Multi-item query is not supported.
+        return false;
+
+    if (rItems[0].meType != ScQueryEntry::ByString)
+        // Not by string equality.
+        return false;
+
+    return true;
+}
+#endif
+
+}
+
 void ScInterpreter::CalculateLookup(bool bHLookup)
 {
     sal_uInt8 nParamCount = GetByte();
@@ -6684,9 +6722,18 @@ void ScInterpreter::CalculateLookup(bool bHLookup)
         }
         else
         {
-            ScAddress aResultPos( nCol1, nRow1, nTab1);
-            bFound = LookupQueryWithCache( aResultPos, aParam);
-            nRow = aResultPos.Row();
+            if (isFilterByEqualString(aParam))
+            {
+                nRow = nRow1;
+                bFound = true;
+            }
+            else
+            {
+                ScAddress aResultPos( nCol1, nRow1, nTab1);
+                bFound = LookupQueryWithCache( aResultPos, aParam);
+                nRow = aResultPos.Row();
+            }
+
             nCol = nSpIndex;
         }
 
@@ -6716,6 +6763,7 @@ bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
             const OUString& sStr = GetString();
             rItem.meType = ScQueryEntry::ByString;
             rItem.maString = sStr;
+            rItem.mnStrId = pDok->GetCellStringPool().getIdentifierIgnoreCase(rItem.maString);
         }
         break;
         case svDoubleRef :
@@ -6740,6 +6788,7 @@ bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
                 GetCellString(aStr, aCell);
                 rItem.meType = ScQueryEntry::ByString;
                 rItem.maString = aStr;
+                rItem.mnStrId = pDok->GetCellStringPool().getIdentifierIgnoreCase(rItem.maString);
             }
         }
         break;
@@ -6748,6 +6797,7 @@ bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
             OUString aStr;
             const ScMatValType nType = GetDoubleOrStringFromMatrix(rItem.mfVal, aStr);
             rItem.maString = aStr;
+            rItem.mnStrId = pDok->GetCellStringPool().getIdentifierIgnoreCase(rItem.maString);
             rItem.meType = ScMatrix::IsNonValueType(nType) ?
                 ScQueryEntry::ByString : ScQueryEntry::ByValue;
         }
diff --git a/sc/source/core/tool/queryentry.cxx b/sc/source/core/tool/queryentry.cxx
index 1ac1a89..e061d0f 100644
--- a/sc/source/core/tool/queryentry.cxx
+++ b/sc/source/core/tool/queryentry.cxx
@@ -32,7 +32,7 @@
 
 bool ScQueryEntry::Item::operator== (const Item& r) const
 {
-    return meType == r.meType && mfVal == r.mfVal && maString.equals(r.maString);
+    return meType == r.meType && mfVal == r.mfVal && maString.equals(r.maString) && mnStrId == r.mnStrId;
 }
 
 ScQueryEntry::ScQueryEntry() :
commit 67ad01944d8ad3b784bc09b89623789fbfcd7cc8
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Oct 4 13:18:12 2013 -0400

    ScInterpreter::GetString() now returns a ref to OUString.
    
    Making adjustments in some call sites.
    
    Change-Id: I85aca2eeb2aece46be52d90a611a64d85792a05f

diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index c21e113..fd2600e 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -591,7 +591,7 @@ bool ScInterpreter::JumpMatrix( short nStackLevel )
                 break;
                 case svString:
                 {
-                    const String& rStr = GetString();
+                    const OUString& rStr = GetString();
                     if ( nGlobalError )
                     {
                         pResMat->PutDouble( CreateDoubleError( nGlobalError),
@@ -3150,7 +3150,7 @@ void ScInterpreter::ScTrim()
 
 void ScInterpreter::ScUpper()
 {
-    String aString = ScGlobal::pCharClass->uppercase(GetString());
+    OUString aString = ScGlobal::pCharClass->uppercase(GetString());
     PushString(aString);
 }
 
@@ -3182,15 +3182,15 @@ void ScInterpreter::ScPropper()
 
 void ScInterpreter::ScLower()
 {
-    String aString = ScGlobal::pCharClass->lowercase(GetString());
+    OUString aString = ScGlobal::pCharClass->lowercase(GetString());
     PushString(aString);
 }
 
 
 void ScInterpreter::ScLen()
 {
-    String aStr( GetString() );
-    PushDouble( aStr.Len() );
+    const OUString& aStr = GetString();
+    PushDouble( aStr.getLength() );
 }
 
 
@@ -3456,7 +3456,7 @@ void ScInterpreter::ScClean()
 void ScInterpreter::ScCode()
 {
 //2do: make it full range unicode?
-    const String& rStr = GetString();
+    String aStr = GetString();
     //"classic" ByteString conversion flags
     const sal_uInt32 convertFlags =
         RTL_UNICODETOTEXT_FLAGS_NONSPACING_IGNORE |
@@ -3465,7 +3465,7 @@ void ScInterpreter::ScCode()
         RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT |
         RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT |
         RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE;
-    PushInt( (sal_uChar) OUStringToOString(OUString(rStr.GetChar(0)), osl_getThreadTextEncoding(), convertFlags).toChar() );
+    PushInt( (sal_uChar) OUStringToOString(OUString(aStr.GetChar(0)), osl_getThreadTextEncoding(), convertFlags).toChar() );
 }
 
 
@@ -6713,7 +6713,7 @@ bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
         break;
         case svString:
         {
-            const String& sStr = GetString();
+            const OUString& sStr = GetString();
             rItem.meType = ScQueryEntry::ByString;
             rItem.maString = sStr;
         }
@@ -8262,11 +8262,11 @@ void ScInterpreter::ScMid()
     {
         double fAnz    = ::rtl::math::approxFloor(GetDouble());
         double fAnfang = ::rtl::math::approxFloor(GetDouble());
-        const String& rStr = GetString();
+        String aStr = GetString();
         if (fAnfang < 1.0 || fAnz < 0.0 || fAnfang > double(STRING_MAXLEN) || fAnz > double(STRING_MAXLEN))
             PushIllegalArgument();
         else
-            PushString(rStr.Copy( (xub_StrLen) fAnfang - 1, (xub_StrLen) fAnz ));
+            PushString(aStr.Copy( (xub_StrLen) fAnfang - 1, (xub_StrLen) fAnz ));
     }
 }
 
@@ -8275,7 +8275,7 @@ void ScInterpreter::ScText()
 {
     if ( MustHaveParamCount( GetByte(), 2 ) )
     {
-        OUString sFormatString = GetString();
+        const OUString& sFormatString = GetString();
         OUString aStr;
         bool bString = false;
         double fVal = 0.0;
@@ -8432,7 +8432,7 @@ void ScInterpreter::ScConcat()
     String aRes;
     while( nParamCount-- > 0)
     {
-        const String& rStr = GetString();
+        const OUString& rStr = GetString();
         aRes.Insert( rStr, 0 );
     }
     PushString( aRes );
diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx
index 4eb4075..6f08958 100644
--- a/sc/source/core/tool/interpr2.cxx
+++ b/sc/source/core/tool/interpr2.cxx
@@ -162,7 +162,7 @@ void ScInterpreter::ScGetHour()
 
 void ScInterpreter::ScGetDateValue()
 {
-    String aInputString = GetString();
+    const OUString& aInputString = GetString();
     sal_uInt32 nFIndex = 0;                 // damit default Land/Spr.
     double fVal;
     if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
@@ -388,7 +388,7 @@ void ScInterpreter::ScGetDateDif()
 {
     if ( MustHaveParamCount( GetByte(), 3 ) )
     {
-        OUString aInterval = GetString();
+        const OUString& aInterval = GetString();
         double nDate2    = GetDouble();
         double nDate1    = GetDouble();
 
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index ec37683..fedda31 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -2726,7 +2726,7 @@ void ScInterpreter::ScExternal()
                     break;
 
                 case SC_ADDINARG_STRING:
-                    aParam <<= OUString( GetString() );
+                    aParam <<= GetString();
                     break;
 
                 case SC_ADDINARG_INTEGER_ARRAY:
@@ -2806,7 +2806,7 @@ void ScInterpreter::ScExternal()
                         case svString:
                         case svSingleRef:
                             {
-                                OUString aString = OUString( GetString() );
+                                const OUString& aString = GetString();
                                 uno::Sequence<OUString> aInner( &aString, 1 );
                                 uno::Sequence< uno::Sequence<OUString> > aOuter( &aInner, 1 );
                                 aParam <<= aOuter;
@@ -2841,7 +2841,7 @@ void ScInterpreter::ScExternal()
                                 if ( nStackType == svDouble )
                                     aElem <<= (double) GetDouble();
                                 else if ( nStackType == svString )
-                                    aElem <<= OUString( GetString() );
+                                    aElem <<= GetString();
                                 else
                                 {
                                     ScAddress aAdr;
@@ -2891,7 +2891,7 @@ void ScInterpreter::ScExternal()
                             aParam <<= (double) GetDouble();
                             break;
                         case svString:
-                            aParam <<= OUString( GetString() );
+                            aParam <<= GetString();
                             break;
                         case svSingleRef:
                             {
commit 442993417346c4213a5e70e94c2bb67a28a81253
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Oct 3 15:53:18 2013 -0400

    Reduce the amount of indentation by early exit.
    
    Change-Id: Ibcf64f57d84dd90a41421522c8082319f1d5796a

diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index f1988d6..1935c3b 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -688,7 +688,7 @@ bool CalculateTest( bool _bTemplin
                    ,const SCSIZE nC1, const SCSIZE nC2,const SCSIZE nR1,const SCSIZE nR2
                    ,const ScMatrixRef& pMat1,const ScMatrixRef& pMat2
                    ,double& fT,double& fF);
-void CalculateLookup(bool HLookup);
+void CalculateLookup(bool bHLookup);
 bool FillEntry(ScQueryEntry& rEntry);
 void CalculateAddSub(bool _bSub);
 void CalculateTrendGrowth(bool _bGrowth);
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 7025b00..c21e113 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -6447,249 +6447,256 @@ void ScInterpreter::ScHLookup()
 {
     CalculateLookup(true);
 }
-void ScInterpreter::CalculateLookup(bool HLookup)
+
+void ScInterpreter::CalculateLookup(bool bHLookup)
 {
     sal_uInt8 nParamCount = GetByte();
-    if ( MustHaveParamCount( nParamCount, 3, 4 ) )
+    if (!MustHaveParamCount(nParamCount, 3, 4))
+        return;
+
+    // Optional 4th argument to declare whether or not the range is sorted.
+    bool bSorted = true;
+    if (nParamCount == 4)
+        bSorted = GetBool();
+
+    // Index of column to search.
+    double fIndex = ::rtl::math::approxFloor( GetDouble() ) - 1.0;
+
+    ScMatrixRef pMat = NULL;
+    SCSIZE nC = 0, nR = 0;
+    SCCOL nCol1 = 0;
+    SCROW nRow1 = 0;
+    SCTAB nTab1 = 0;
+    SCCOL nCol2 = 0;
+    SCROW nRow2 = 0;
+    SCTAB nTab2;
+    StackVar eType = GetStackType();
+    if (eType == svDoubleRef)
     {
-        bool bSorted;
-        if (nParamCount == 4)
-            bSorted = GetBool();
-        else
-            bSorted = true;
-        double fIndex = ::rtl::math::approxFloor( GetDouble() ) - 1.0;
-        ScMatrixRef pMat = NULL;
-        SCSIZE nC = 0, nR = 0;
-        SCCOL nCol1 = 0;
-        SCROW nRow1 = 0;
-        SCTAB nTab1 = 0;
-        SCCOL nCol2 = 0;
-        SCROW nRow2 = 0;
-        SCTAB nTab2;
-        StackVar eType = GetStackType();
-        if (eType == svDoubleRef)
-        {
-            PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
-            if (nTab1 != nTab2)
-            {
-                PushIllegalParameter();
-                return;
-            }
-        }
-        else if (eType == svSingleRef)
+        PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+        if (nTab1 != nTab2)
         {
-            PopSingleRef(nCol1, nRow1, nTab1);
-            nCol2 = nCol1;
-            nRow2 = nRow1;
+            PushIllegalParameter();
+            return;
         }
-        else if (eType == svMatrix || eType == svExternalDoubleRef || eType == svExternalSingleRef)
-        {
-            pMat = GetMatrix();
+    }
+    else if (eType == svSingleRef)
+    {
+        PopSingleRef(nCol1, nRow1, nTab1);
+        nCol2 = nCol1;
+        nRow2 = nRow1;
+    }
+    else if (eType == svMatrix || eType == svExternalDoubleRef || eType == svExternalSingleRef)
+    {
+        pMat = GetMatrix();
 
-            if (pMat)
-                pMat->GetDimensions(nC, nR);
-            else
-            {
-                PushIllegalParameter();
-                return;
-            }
-        }
+        if (pMat)
+            pMat->GetDimensions(nC, nR);
         else
         {
             PushIllegalParameter();
             return;
         }
-        if ( fIndex < 0.0 || (HLookup ? (pMat ? (fIndex >= nR) : (fIndex+nRow1 > nRow2)) : (pMat ? (fIndex >= nC) : (fIndex+nCol1 > nCol2)) ) )
-        {
-            PushIllegalArgument();
-            return;
-        }
-        SCROW nZIndex = static_cast<SCROW>(fIndex);
-        SCCOL nSpIndex = static_cast<SCCOL>(fIndex);
+    }
+    else
+    {
+        PushIllegalParameter();
+        return;
+    }
 
-        if (!pMat)
-        {
-            nZIndex += nRow1;                       // Wertzeile
-            nSpIndex = sal::static_int_cast<SCCOL>( nSpIndex + nCol1 );     // value column
-        }
+    if ( fIndex < 0.0 || (bHLookup ? (pMat ? (fIndex >= nR) : (fIndex+nRow1 > nRow2)) : (pMat ? (fIndex >= nC) : (fIndex+nCol1 > nCol2)) ) )
+    {
+        PushIllegalArgument();
+        return;
+    }
 
-        if (nGlobalError == 0)
-        {
-            ScQueryParam rParam;
-            rParam.nCol1       = nCol1;
-            rParam.nRow1       = nRow1;
-            if ( HLookup )
-            {
-                rParam.nCol2       = nCol2;
-                rParam.nRow2       = nRow1;     // nur in der ersten Zeile suchen
-                rParam.bByRow      = false;
-            } // if ( HLookup )
-            else
-            {
-                rParam.nCol2       = nCol1;     // nur in der ersten Spalte suchen
-                rParam.nRow2       = nRow2;
-                rParam.nTab        = nTab1;
-            }
+    SCROW nZIndex = static_cast<SCROW>(fIndex);
+    SCCOL nSpIndex = static_cast<SCCOL>(fIndex);
 
-            ScQueryEntry& rEntry = rParam.GetEntry(0);
-            rEntry.bDoQuery = true;
-            if ( bSorted )
-                rEntry.eOp = SC_LESS_EQUAL;
-            if ( !FillEntry(rEntry) )
-                return;
+    if (!pMat)
+    {
+        nZIndex += nRow1;                       // Wertzeile
+        nSpIndex = sal::static_int_cast<SCCOL>( nSpIndex + nCol1 );     // value column
+    }
 
-            ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
-            if (rItem.meType == ScQueryEntry::ByString)
-                rParam.bRegExp = MayBeRegExp(rItem.maString, pDok);
-            if (pMat)
+    if (nGlobalError)
+    {
+        PushIllegalParameter();
+        return;
+    }
+
+    ScQueryParam aParam;
+    aParam.nCol1 = nCol1;
+    aParam.nRow1 = nRow1;
+    if ( bHLookup )
+    {
+        aParam.nCol2 = nCol2;
+        aParam.nRow2 = nRow1;     // nur in der ersten Zeile suchen
+        aParam.bByRow = false;
+    }
+    else
+    {
+        aParam.nCol2 = nCol1;     // nur in der ersten Spalte suchen
+        aParam.nRow2 = nRow2;
+        aParam.nTab  = nTab1;
+    }
+
+    ScQueryEntry& rEntry = aParam.GetEntry(0);
+    rEntry.bDoQuery = true;
+    if ( bSorted )
+        rEntry.eOp = SC_LESS_EQUAL;
+    if ( !FillEntry(rEntry) )
+        return;
+
+    ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
+    if (rItem.meType == ScQueryEntry::ByString)
+        aParam.bRegExp = MayBeRegExp(rItem.maString, pDok);
+    if (pMat)
+    {
+        SCSIZE nMatCount = bHLookup ? nC : nR;
+        SCSIZE nDelta = SCSIZE_MAX;
+        if (rItem.meType == ScQueryEntry::ByString)
+        {
+//!!!!!!!
+//! TODO: enable regex on matrix strings
+//!!!!!!!
+            const OUString& rParamStr = rItem.maString;
+            if ( bSorted )
             {
-                SCSIZE nMatCount = HLookup ? nC : nR;
-                SCSIZE nDelta = SCSIZE_MAX;
-                if (rItem.meType == ScQueryEntry::ByString)
+                static CollatorWrapper* pCollator = ScGlobal::GetCollator();
+                for (SCSIZE i = 0; i < nMatCount; i++)
                 {
-        //!!!!!!!
-        //! TODO: enable regex on matrix strings
-        //!!!!!!!
-                    const OUString& rParamStr = rItem.maString;
-                    if ( bSorted )
+                    if (bHLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
                     {
-                        static CollatorWrapper* pCollator = ScGlobal::GetCollator();
-                        for (SCSIZE i = 0; i < nMatCount; i++)
-                        {
-                            if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
-                            {
-                                sal_Int32 nRes =
-                                    pCollator->compareString( HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), rParamStr);
-                                if (nRes <= 0)
-                                    nDelta = i;
-                                else if (i>0)   // #i2168# ignore first mismatch
-                                    i = nMatCount+1;
-                            }
-                            else
-                                nDelta = i;
-                        }
+                        sal_Int32 nRes =
+                            pCollator->compareString( bHLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), rParamStr);
+                        if (nRes <= 0)
+                            nDelta = i;
+                        else if (i>0)   // #i2168# ignore first mismatch
+                            i = nMatCount+1;
                     }
                     else
+                        nDelta = i;
+                }
+            }
+            else
+            {
+                if (bHLookup)
+                {
+                    for (SCSIZE i = 0; i < nMatCount; i++)
                     {
-                        if (HLookup)
+                        if (pMat->IsString(i, 0))
                         {
-                            for (SCSIZE i = 0; i < nMatCount; i++)
+                            if ( ScGlobal::GetpTransliteration()->isEqual(
+                                pMat->GetString(i,0), rParamStr))
                             {
-                                if (pMat->IsString(i, 0))
-                                {
-                                    if ( ScGlobal::GetpTransliteration()->isEqual(
-                                        pMat->GetString(i,0), rParamStr))
-                                    {
-                                        nDelta = i;
-                                        i = nMatCount + 1;
-                                    }
-                                }
+                                nDelta = i;
+                                i = nMatCount + 1;
                             }
                         }
-                        else
-                        {
-                            nDelta = pMat->MatchStringInColumns(rParamStr, 0, 0);
-                        }
                     }
                 }
                 else
                 {
-                    if ( bSorted )
-                    {
-                        // #i2168# ignore strings
-                        for (SCSIZE i = 0; i < nMatCount; i++)
-                        {
-                            if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
-                            {
-                                if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) <= rItem.mfVal)
-                                    nDelta = i;
-                                else
-                                    i = nMatCount+1;
-                            }
-                        }
-                    }
-                    else
-                    {
-                        if (HLookup)
-                        {
-                            for (SCSIZE i = 0; i < nMatCount; i++)
-                            {
-                                if (! pMat->IsString(i, 0) )
-                                {
-                                    if ( pMat->GetDouble(i,0) == rItem.mfVal)
-                                    {
-                                        nDelta = i;
-                                        i = nMatCount + 1;
-                                    }
-                                }
-                            }
-                        }
-                        else
-                        {
-                            nDelta = pMat->MatchDoubleInColumns(rItem.mfVal, 0, 0);
-                        }
-                    }
+                    nDelta = pMat->MatchStringInColumns(rParamStr, 0, 0);
                 }
-                if ( nDelta != SCSIZE_MAX )
+            }
+        }
+        else
+        {
+            if ( bSorted )
+            {
+                // #i2168# ignore strings
+                for (SCSIZE i = 0; i < nMatCount; i++)
                 {
-                    SCSIZE nX = static_cast<SCSIZE>(nSpIndex);
-                    SCSIZE nY = nDelta;
-                    if ( HLookup )
+                    if (!(bHLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
                     {
-                        nX = nDelta;
-                        nY = static_cast<SCSIZE>(nZIndex);
+                        if ((bHLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) <= rItem.mfVal)
+                            nDelta = i;
+                        else
+                            i = nMatCount+1;
                     }
-                    if ( pMat->IsString( nX, nY) )
-                        PushString(pMat->GetString( nX,nY));
-                    else
-                        PushDouble(pMat->GetDouble( nX,nY));
                 }
-                else
-                    PushNA();
             }
             else
             {
-                rEntry.nField = nCol1;
-                bool bFound = false;
-                SCCOL nCol = 0;
-                SCROW nRow = 0;
-                if ( bSorted )
-                    rEntry.eOp = SC_LESS_EQUAL;
-                if ( HLookup )
+                if (bHLookup)
                 {
-                    ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
-                    // advance Entry.nField in Iterator upon switching columns
-                    aCellIter.SetAdvanceQueryParamEntryField( true );
-                    if ( bSorted )
-                    {
-                        SCROW nRow1_temp;
-                        bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow1_temp );
-                    }
-                    else if ( aCellIter.GetFirst() )
+                    for (SCSIZE i = 0; i < nMatCount; i++)
                     {
-                        bFound = true;
-                        nCol = aCellIter.GetCol();
+                        if (! pMat->IsString(i, 0) )
+                        {
+                            if ( pMat->GetDouble(i,0) == rItem.mfVal)
+                            {
+                                nDelta = i;
+                                i = nMatCount + 1;
+                            }
+                        }
                     }
-                    nRow = nZIndex;
-                } // if ( HLookup )
-                else
-                {
-                    ScAddress aResultPos( nCol1, nRow1, nTab1);
-                    bFound = LookupQueryWithCache( aResultPos, rParam);
-                    nRow = aResultPos.Row();
-                    nCol = nSpIndex;
                 }
-                if ( bFound )
+                else
                 {
-                    ScAddress aAdr( nCol, nRow, nTab1 );
-                    PushCellResultToken( true, aAdr, NULL, NULL);
+                    nDelta = pMat->MatchDoubleInColumns(rItem.mfVal, 0, 0);
                 }
-                else
-                    PushNA();
             }
         }
+        if ( nDelta != SCSIZE_MAX )
+        {
+            SCSIZE nX = static_cast<SCSIZE>(nSpIndex);
+            SCSIZE nY = nDelta;
+            if ( bHLookup )
+            {
+                nX = nDelta;
+                nY = static_cast<SCSIZE>(nZIndex);
+            }
+            if ( pMat->IsString( nX, nY) )
+                PushString(pMat->GetString( nX,nY));
+            else
+                PushDouble(pMat->GetDouble( nX,nY));
+        }
         else
-            PushIllegalParameter();
+            PushNA();
+    }
+    else
+    {
+        rEntry.nField = nCol1;
+        bool bFound = false;
+        SCCOL nCol = 0;
+        SCROW nRow = 0;
+        if ( bSorted )
+            rEntry.eOp = SC_LESS_EQUAL;
+        if ( bHLookup )
+        {
+            ScQueryCellIterator aCellIter(pDok, nTab1, aParam, false);
+            // advance Entry.nField in Iterator upon switching columns
+            aCellIter.SetAdvanceQueryParamEntryField( true );
+            if ( bSorted )
+            {
+                SCROW nRow1_temp;
+                bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow1_temp );
+            }
+            else if ( aCellIter.GetFirst() )
+            {
+                bFound = true;
+                nCol = aCellIter.GetCol();
+            }
+            nRow = nZIndex;
+        }
+        else
+        {
+            ScAddress aResultPos( nCol1, nRow1, nTab1);
+            bFound = LookupQueryWithCache( aResultPos, aParam);
+            nRow = aResultPos.Row();
+            nCol = nSpIndex;
+        }
+
+        if ( bFound )
+        {
+            ScAddress aAdr( nCol, nRow, nTab1 );
+            PushCellResultToken( true, aAdr, NULL, NULL);
+        }
+        else
+            PushNA();
     }
 }
 
commit 40ecff9a6005791ebfb1904a0b48626a43ca1f3b
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Oct 3 14:58:06 2013 -0400

    Test comparison between simple and rich-text string values.
    
    Change-Id: Icdb9a81b1be80b058b71c23b3fcb58a5e8970e21

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index ba9a78e..3e7239e 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -57,6 +57,8 @@
 #include <basegfx/polygon/b2dpolygon.hxx>
 #include <editeng/boxitem.hxx>
 #include <editeng/brushitem.hxx>
+#include "editeng/wghtitem.hxx"
+#include "editeng/postitem.hxx"
 
 #include <svx/svdograf.hxx>
 #include <svx/svdpage.hxx>
@@ -535,6 +537,56 @@ void Test::testCellStringPool()
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCount());
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCountIgnoreCase());
 
+    // Now, compare string and edit text cells.
+    m_pDoc->SetString(ScAddress(0,0,0), "Andy and Bruce"); // A1
+    ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
+    rEE.SetText("Andy and Bruce");
+
+    ESelection aSel;
+    aSel.nStartPara = aSel.nEndPara = 0;
+
+    {
+        // Set 'Andy' bold.
+        SfxItemSet aItemSet = rEE.GetEmptyItemSet();
+        aSel.nStartPos = 0;
+        aSel.nEndPos = 4;
+        SvxWeightItem aWeight(WEIGHT_BOLD, EE_CHAR_WEIGHT);
+        aItemSet.Put(aWeight);
+        rEE.QuickSetAttribs(aItemSet, aSel);
+    }
+
+    {
+        // Set 'Bruce' italic.
+        SfxItemSet aItemSet = rEE.GetEmptyItemSet();
+        SvxPostureItem aItalic(ITALIC_NORMAL, EE_CHAR_ITALIC);
+        aItemSet.Put(aItalic);
+        aSel.nStartPos = 9;
+        aSel.nEndPos = 14;
+        rEE.QuickSetAttribs(aItemSet, aSel);
+    }
+
+    m_pDoc->SetEditText(ScAddress(1,0,0), rEE.CreateTextObject()); // B1
+
+    // These two should be equal.
+    nId1 = m_pDoc->GetCellStringID(ScAddress(0,0,0));
+    nId2 = m_pDoc->GetCellStringID(ScAddress(1,0,0));
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId1);
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId2);
+    CPPUNIT_ASSERT_EQUAL(nId1, nId2);
+
+    rEE.SetText("ANDY and BRUCE");
+    m_pDoc->SetEditText(ScAddress(2,0,0), rEE.CreateTextObject()); // C1
+    nId2 = m_pDoc->GetCellStringID(ScAddress(2,0,0));
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId2);
+    CPPUNIT_ASSERT_MESSAGE("These two should be different when cases are considered.", nId1 != nId2);
+
+    // But they should be considered equal when cases are ignored.
+    nId1 = m_pDoc->GetCellStringIDIgnoreCase(ScAddress(0,0,0));
+    nId2 = m_pDoc->GetCellStringIDIgnoreCase(ScAddress(2,0,0));
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId1);
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId2);
+    CPPUNIT_ASSERT_EQUAL(nId1, nId2);
+
     m_pDoc->DeleteTab(0);
 }
 
commit b68489603e129a013742973e9bcf6f31d90db550
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Oct 3 14:24:28 2013 -0400

    Add methods to turn cell strings into numeric IDs for comparison.
    
    Both in case sensitive and case insensitive comparisons.
    
    Change-Id: I356a655273f0f37157810c86e1cf3f87ea2afa09

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 6d09ad1..2f4d697 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -280,6 +280,9 @@ public:
     ScFormulaCell* SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell );
     bool SetGroupFormulaCell( SCROW nRow, ScFormulaCell* pCell );
 
+    sal_uIntPtr GetCellStringID( SCROW nRow ) const;
+    sal_uIntPtr GetCellStringIDIgnoreCase( SCROW nRow ) const;
+
     void SetRawString( SCROW nRow, const OUString& rStr, bool bBroadcast = true );
     void SetRawString( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const OUString& rStr, bool bBroadcast = true );
     void SetValue( SCROW nRow, double fVal );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 6828d4d..2ef6073 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -436,7 +436,6 @@ public:
     sal_uLong           GetCodeCount() const;       // RPN-Code in formulas
     DECL_LINK( GetUserDefinedColor, sal_uInt16 * );
                                                                 // number formatter
-
 public:
     SC_DLLPUBLIC                ScDocument( ScDocumentMode eMode = SCDOCMODE_DOCUMENT,
                                 SfxObjectShell* pDocShell = NULL );
@@ -860,6 +859,11 @@ public:
      */
     double* GetValueCell( const ScAddress& rPos );
 
+    svl::StringPool& GetCellStringPool();
+    const svl::StringPool& GetCellStringPool() const;
+    sal_uIntPtr GetCellStringID( const ScAddress& rPos ) const;
+    sal_uIntPtr GetCellStringIDIgnoreCase( const ScAddress& rPos ) const;
+
     SC_DLLPUBLIC void GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString );
     SC_DLLPUBLIC void GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rString );
     sal_uInt16 GetStringForFormula( const ScAddress& rPos, OUString& rString );
@@ -2066,8 +2070,6 @@ private: // CLOOK-Impl-methods
 
     ScRefCellValue GetRefCellValue( const ScAddress& rPos );
 
-    svl::StringPool& GetCellStringPool();
-
     std::map< SCTAB, ScSortParam > mSheetSortParams;
 
 };
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 7ae03f2..7d5fa1e 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -343,6 +343,9 @@ public:
     ScFormulaCell* SetFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* pCell );
     bool SetGroupFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* pCell );
 
+    sal_uIntPtr GetCellStringID( SCCOL nCol, SCROW nRow ) const;
+    sal_uIntPtr GetCellStringIDIgnoreCase( SCCOL nCol, SCROW nRow ) const;
+
     void        SetValue( SCCOL nCol, SCROW nRow, const double& rVal );
     void        SetError( SCCOL nCol, SCROW nRow, sal_uInt16 nError);
 
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 8d2266e..ba9a78e 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -63,6 +63,7 @@
 #include <svx/svdocirc.hxx>
 #include <svx/svdopath.hxx>
 #include "svl/srchitem.hxx"
+#include "svl/stringpool.hxx"
 
 #include <sfx2/docfile.hxx>
 
@@ -458,6 +459,85 @@ void Test::testCollator()
     CPPUNIT_ASSERT_MESSAGE("these strings are supposed to be different!", nRes != 0);
 }
 
+void Test::testCellStringPool()
+{
+    m_pDoc->InsertTab(0, "foo");
+
+    // Strings that are identical.
+    m_pDoc->SetString(ScAddress(0,0,0), "Andy");  // A1
+    m_pDoc->SetString(ScAddress(0,1,0), "Andy");  // A2
+    m_pDoc->SetString(ScAddress(0,2,0), "Bruce"); // A3
+    m_pDoc->SetString(ScAddress(0,3,0), "andy");  // A4
+    m_pDoc->SetString(ScAddress(0,4,0), "BRUCE"); // A5
+
+    sal_uIntPtr nId1 = m_pDoc->GetCellStringID(ScAddress(0,0,0));
+    sal_uIntPtr nId2 = m_pDoc->GetCellStringID(ScAddress(0,1,0));
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId1);
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId2);
+    CPPUNIT_ASSERT_EQUAL(nId1, nId2);
+
+    nId2 = m_pDoc->GetCellStringID(ScAddress(0,2,0));
+    CPPUNIT_ASSERT_MESSAGE("They must differ", nId1 != nId2);
+
+    nId2 = m_pDoc->GetCellStringID(ScAddress(0,3,0));
+    CPPUNIT_ASSERT_MESSAGE("They must differ", nId1 != nId2);
+
+    nId2 = m_pDoc->GetCellStringID(ScAddress(0,4,0));
+    CPPUNIT_ASSERT_MESSAGE("They must differ", nId1 != nId2);
+
+    // A3 and A5 should differ but should be equal case-insensitively.
+    nId1 = m_pDoc->GetCellStringID(ScAddress(0,2,0));
+    nId2 = m_pDoc->GetCellStringID(ScAddress(0,4,0));
+    CPPUNIT_ASSERT_MESSAGE("They must differ", nId1 != nId2);
+
+    nId1 = m_pDoc->GetCellStringIDIgnoreCase(ScAddress(0,2,0));
+    nId2 = m_pDoc->GetCellStringIDIgnoreCase(ScAddress(0,4,0));
+    CPPUNIT_ASSERT_MESSAGE("They must be equal when cases are ignored.", nId1 == nId2);
+
+    // A2 and A4 should be equal when ignoring cases.
+    nId1 = m_pDoc->GetCellStringIDIgnoreCase(ScAddress(0,1,0));
+    nId2 = m_pDoc->GetCellStringIDIgnoreCase(ScAddress(0,3,0));
+    CPPUNIT_ASSERT_MESSAGE("They must be equal when cases are ignored.", nId1 == nId2);
+
+    // Check the string counts after purging. Purging shouldn't remove any strings in this case.
+    svl::StringPool& rPool = m_pDoc->GetCellStringPool();
+    rPool.purge();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rPool.getCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
+
+    // Clear A1 and purge again.
+    clearRange(m_pDoc, ScAddress(0,0,0));
+    rPool.purge();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rPool.getCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
+
+    // Clear A2 and purge again.
+    clearRange(m_pDoc, ScAddress(0,1,0));
+    rPool.purge();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), rPool.getCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
+
+    // Clear A3 and purge again.
+    clearRange(m_pDoc, ScAddress(0,2,0));
+    rPool.purge();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
+
+    // Clear A4 and purge again.
+    clearRange(m_pDoc, ScAddress(0,3,0));
+    rPool.purge();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPool.getCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPool.getCountIgnoreCase());
+
+    // Clear A5 and the pool should be completely empty.
+    clearRange(m_pDoc, ScAddress(0,4,0));
+    rPool.purge();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCountIgnoreCase());
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testRangeList()
 {
     m_pDoc->InsertTab(0, "foo");
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index d01714e..d1ba668 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -80,6 +80,7 @@ public:
      */
     void testPerf();
     void testCollator();
+    void testCellStringPool();
     void testRangeList();
     void testInput();
 
@@ -284,6 +285,7 @@ public:
     CPPUNIT_TEST(testPerf);
 #endif
     CPPUNIT_TEST(testCollator);
+    CPPUNIT_TEST(testCellStringPool);
     CPPUNIT_TEST(testRangeList);
     CPPUNIT_TEST(testInput);
     CPPUNIT_TEST(testFormulaHashAndTag);
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index f5eccae..6c964ca 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -1732,6 +1732,64 @@ bool ScColumn::SetGroupFormulaCell( SCROW nRow, ScFormulaCell* pCell )
     return true;
 }
 
+sal_uIntPtr ScColumn::GetCellStringID( SCROW nRow ) const
+{
+    sc::CellStoreType::const_position_type aPos = maCells.position(nRow);
+    switch (aPos.first->type)
+    {
+        case sc::element_type_string:
+        {
+            const OUString& rStr = sc::string_block::at(*aPos.first->data, aPos.second);
+            return pDocument->GetCellStringPool().getIdentifier(rStr);
+        }
+        break;
+        case sc::element_type_edittext:
+        {
+            std::vector<sal_uIntPtr> aIDs;
+            const EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second);
+            pObj->GetStringIDs(pDocument->GetCellStringPool(), aIDs);
+            if (aIDs.size() != 1)
+                // We don't handle multiline content for now.
+                return 0;
+
+            return aIDs[0];
+        }
+        break;
+        default:
+            ;
+    }
+    return 0;
+}
+
+sal_uIntPtr ScColumn::GetCellStringIDIgnoreCase( SCROW nRow ) const
+{
+    sc::CellStoreType::const_position_type aPos = maCells.position(nRow);
+    switch (aPos.first->type)
+    {
+        case sc::element_type_string:
+        {
+            const OUString& rStr = sc::string_block::at(*aPos.first->data, aPos.second);
+            return pDocument->GetCellStringPool().getIdentifierIgnoreCase(rStr);
+        }
+        break;
+        case sc::element_type_edittext:
+        {
+            std::vector<sal_uIntPtr> aIDs;
+            const EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second);
+            pObj->GetStringIDsIgnoreCase(pDocument->GetCellStringPool(), aIDs);
+            if (aIDs.size() != 1)
+                // We don't handle multiline content for now.
+                return 0;
+
+            return aIDs[0];
+        }
+        break;
+        default:
+            ;
+    }
+    return 0;
+}
+
 namespace {
 
 class FilterEntriesHandler
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 9f64090..ea00606 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -605,6 +605,11 @@ svl::StringPool& ScDocument::GetCellStringPool()
     return *mpCellStringPool;
 }
 
+const svl::StringPool& ScDocument::GetCellStringPool() const
+{
+    return *mpCellStringPool;
+}
+
 bool ScDocument::GetPrintArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow,
                                 bool bNotes ) const
 {
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index dc7db44..9b91290 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -3221,6 +3221,22 @@ double* ScDocument::GetValueCell( const ScAddress& rPos )
     return maTabs[rPos.Tab()]->GetValueCell(rPos.Col(), rPos.Row());
 }
 
+sal_uIntPtr ScDocument::GetCellStringID( const ScAddress& rPos ) const
+{
+    if (!TableExists(rPos.Tab()))
+        return 0;
+
+    return maTabs[rPos.Tab()]->GetCellStringID(rPos.Col(), rPos.Row());
+}
+
+sal_uIntPtr ScDocument::GetCellStringIDIgnoreCase( const ScAddress& rPos ) const
+{
+    if (!TableExists(rPos.Tab()))
+        return 0;
+
+    return maTabs[rPos.Tab()]->GetCellStringIDIgnoreCase(rPos.Col(), rPos.Row());
+}
+
 void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rString )
 {
     if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 24fc92b..9ec6977 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1505,6 +1505,22 @@ bool ScTable::SetGroupFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* pCell
     return aCol[nCol].SetGroupFormulaCell(nRow, pCell);
 }
 
+sal_uIntPtr ScTable::GetCellStringID( SCCOL nCol, SCROW nRow ) const
+{
+    if (!ValidColRow(nCol, nRow))
+        return 0;
+
+    return aCol[nCol].GetCellStringID(nRow);
+}
+
+sal_uIntPtr ScTable::GetCellStringIDIgnoreCase( SCCOL nCol, SCROW nRow ) const
+{
+    if (!ValidColRow(nCol, nRow))
+        return 0;
+
+    return aCol[nCol].GetCellStringIDIgnoreCase(nRow);
+}
+
 void ScTable::SetValue( SCCOL nCol, SCROW nRow, const double& rVal )
 {
     if (ValidColRow(nCol, nRow))
commit fc9451faf2c910e052809d7e418c1c3f54ea5423
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Oct 3 12:16:22 2013 -0400

    Add methods to extract string IDs from edit text object.
    
    Note that a single edit text object may have multiple string ID's in case
    it consists of multiple paragraphs.
    
    Change-Id: Ie90541de38a639c30a010817dada389e9445d08c

diff --git a/editeng/source/editeng/editobj.cxx b/editeng/source/editeng/editobj.cxx
index aaf5e5f..4e6af47 100644
--- a/editeng/source/editeng/editobj.cxx
+++ b/editeng/source/editeng/editobj.cxx
@@ -154,6 +154,16 @@ void ContentInfo::NormalizeString( svl::StringPool& rPool )
     aText = OUString(rPool.intern(aText));
 }
 
+sal_uIntPtr ContentInfo::GetStringID( const svl::StringPool& rPool ) const
+{
+    return rPool.getIdentifier(aText);
+}
+
+sal_uIntPtr ContentInfo::GetStringIDIgnoreCase( const svl::StringPool& rPool ) const
+{
+    return rPool.getIdentifierIgnoreCase(aText);
+}
+
 const WrongList* ContentInfo::GetWrongList() const
 {
     return mpWrongs.get();
@@ -327,6 +337,16 @@ void EditTextObject::NormalizeString( svl::StringPool& rPool )
     mpImpl->NormalizeString(rPool);
 }
 
+bool EditTextObject::GetStringIDs( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
+{
+    return mpImpl->GetStringIDs(rPool, rIDs);
+}
+
+bool EditTextObject::GetStringIDsIgnoreCase( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
+{
+    return mpImpl->GetStringIDsIgnoreCase(rPool, rIDs);
+}
+
 const SfxItemPool* EditTextObject::GetPool() const
 {
     return mpImpl->GetPool();
@@ -623,6 +643,44 @@ void EditTextObjectImpl::NormalizeString( svl::StringPool& rPool )
     }
 }
 
+bool EditTextObjectImpl::GetStringIDs( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
+{
+    std::vector<sal_uIntPtr> aIDs;
+    aIDs.reserve(aContents.size());
+    ContentInfosType::const_iterator it = aContents.begin(), itEnd = aContents.end();
+    for (; it != itEnd; ++it)
+    {
+        const ContentInfo& rInfo = *it;
+        sal_uIntPtr nID = rInfo.GetStringID(rPool);
+        if (!nID)
+            return false;
+
+        aIDs.push_back(nID);
+    }
+
+    rIDs.swap(aIDs);
+    return true;
+}
+
+bool EditTextObjectImpl::GetStringIDsIgnoreCase( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
+{
+    std::vector<sal_uIntPtr> aIDs;
+    aIDs.reserve(aContents.size());
+    ContentInfosType::const_iterator it = aContents.begin(), itEnd = aContents.end();
+    for (; it != itEnd; ++it)
+    {
+        const ContentInfo& rInfo = *it;
+        sal_uIntPtr nID = rInfo.GetStringIDIgnoreCase(rPool);
+        if (!nID)
+            return false;
+
+        aIDs.push_back(nID);
+    }
+
+    rIDs.swap(aIDs);
+    return true;
+}
+
 bool EditTextObjectImpl::IsVertical() const
 {
     return bVertical;
diff --git a/editeng/source/editeng/editobj2.hxx b/editeng/source/editeng/editobj2.hxx
index c331134..d2118d7 100644
--- a/editeng/source/editeng/editobj2.hxx
+++ b/editeng/source/editeng/editobj2.hxx
@@ -143,6 +143,8 @@ public:
                         ~ContentInfo();
 
     void NormalizeString( svl::StringPool& rPool );
+    sal_uIntPtr GetStringID( const svl::StringPool& rPool ) const;
+    sal_uIntPtr GetStringIDIgnoreCase( const svl::StringPool& rPool ) const;
 
     const XEditAttributesType& GetAttribs() const { return aAttribs; }
     XEditAttributesType& GetAttribs() { return aAttribs; }
@@ -207,6 +209,8 @@ public:
     void SetUserType( sal_uInt16 n );
 
     void NormalizeString( svl::StringPool& rPool );
+    bool GetStringIDs( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
+    bool GetStringIDsIgnoreCase( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
 
     bool                    IsVertical() const;
     void                    SetVertical( bool b );
diff --git a/include/editeng/editobj.hxx b/include/editeng/editobj.hxx
index 36392e2..4751469 100644
--- a/include/editeng/editobj.hxx
+++ b/include/editeng/editobj.hxx
@@ -85,6 +85,9 @@ public:
      */
     void NormalizeString( svl::StringPool& rPool );
 
+    bool GetStringIDs( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
+    bool GetStringIDsIgnoreCase( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
+
     const SfxItemPool* GetPool() const;
     sal_uInt16 GetUserType() const;    // For OutlinerMode, it can however not save in compatible format
     void SetUserType( sal_uInt16 n );
commit 9a9313367c5f54b4e9c339fa6f26bd86f97e556c
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Oct 3 11:34:24 2013 -0400

    Let's just use sal_uIntPtr straight.
    
    So that the user of this class won't have to include the header just
    to get the string ID type.
    
    Change-Id: I0ccbc18fe02644f69701f57b0b1b9c30fd141d83

diff --git a/include/svl/stringpool.hxx b/include/svl/stringpool.hxx
index cac7637..fbcff1e 100644
--- a/include/svl/stringpool.hxx
+++ b/include/svl/stringpool.hxx
@@ -37,7 +37,6 @@ class SVL_DLLPUBLIC StringPool
     const CharClass* mpCharClass;
 
 public:
-    typedef sal_uIntPtr StrIdType;
 
     StringPool();
     StringPool( const CharClass* pCharClass );
@@ -61,7 +60,7 @@ public:
      *
      * @return unique ID of the string object.
      */
-    StrIdType getIdentifier( const OUString& rStr ) const;
+    sal_uIntPtr getIdentifier( const OUString& rStr ) const;
 
     /**
      * Get a unique ID of string object for case insensitive comparison. The
@@ -72,7 +71,7 @@ public:
      * @return unique ID of the string object usable for case insensitive
      *         comparison.
      */
-    StrIdType getIdentifierIgnoreCase( const OUString& rStr ) const;
+    sal_uIntPtr getIdentifierIgnoreCase( const OUString& rStr ) const;
 
     /**
      * Go through all string objects in the pool, and clear those that are no
diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 11a52e6..a34bb47 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -309,8 +309,8 @@ void Test::testStringPool()
     CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
 
     OUString aAndy("Andy");
-    svl::StringPool::StrIdType si1 = aPool.getIdentifier("Andy");
-    svl::StringPool::StrIdType si2 = aPool.getIdentifier(aAndy);
+    sal_uIntPtr si1 = aPool.getIdentifier("Andy");
+    sal_uIntPtr si2 = aPool.getIdentifier(aAndy);
     CPPUNIT_ASSERT_MESSAGE("Identifier shouldn't be 0.", si1);
     CPPUNIT_ASSERT_MESSAGE("Identifier shouldn't be 0.", si2);
     CPPUNIT_ASSERT_EQUAL(si1, si2);
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index 4760348..7ebc207 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -45,13 +45,13 @@ rtl_uString* StringPool::intern( const OUString& rStr )
     return pOrig;
 }
 
-StringPool::StrIdType StringPool::getIdentifier( const OUString& rStr ) const
+sal_uIntPtr StringPool::getIdentifier( const OUString& rStr ) const
 {
     StrHashType::const_iterator it = maStrPool.find(rStr);
-    return (it == maStrPool.end()) ? 0 : reinterpret_cast<StrIdType>(it->pData);
+    return (it == maStrPool.end()) ? 0 : reinterpret_cast<sal_uIntPtr>(it->pData);
 }
 
-StringPool::StrIdType StringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
+sal_uIntPtr StringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
 {
     StrHashType::const_iterator itOrig = maStrPool.find(rStr);
     if (itOrig == maStrPool.end())
@@ -64,7 +64,7 @@ StringPool::StrIdType StringPool::getIdentifierIgnoreCase( const OUString& rStr
         return 0;
 
     const rtl_uString* pUpper = itUpper->second.pData;
-    return reinterpret_cast<StrIdType>(pUpper);
+    return reinterpret_cast<sal_uIntPtr>(pUpper);
 }
 
 namespace {
commit a42ae406b047773e67d646056a02cbb5c489dcae
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Oct 3 10:55:48 2013 -0400

    Normalize all string objects that are cell contents before they get stored.
    
    Hopefully I've covered all entry points. There may be more lurking in some
    dark corneres...
    
    Change-Id: I62e655cc579aad08fa64b5d58e739c55425cd216

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 73d7c1c..6828d4d 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -234,6 +234,7 @@ friend class ScDocRowHeightUpdater;
 friend class ScColumnTextWidthIterator;
 friend class ScFormulaCell;
 friend class ScTable;
+friend class ScColumn;
 friend struct ScRefCellValue;
 friend class ScDocumentImport;
 friend class sc::ColumnSpanSet;
@@ -2065,6 +2066,8 @@ private: // CLOOK-Impl-methods
 
     ScRefCellValue GetRefCellValue( const ScAddress& rPos );
 
+    svl::StringPool& GetCellStringPool();
+
     std::map< SCTAB, ScSortParam > mSheetSortParams;
 
 };
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 90f0f2b..f5eccae 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -57,6 +57,7 @@
 #include <svl/zforlist.hxx>
 #include <svl/zformat.hxx>
 #include <svl/broadcast.hxx>
+#include "svl/stringpool.hxx"
 #include "editeng/editstat.hxx"
 
 #include <cstdio>
@@ -1601,6 +1602,7 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
 
 void ScColumn::SetEditText( SCROW nRow, EditTextObject* pEditText )
 {
+    pEditText->NormalizeString(pDocument->GetCellStringPool());
     sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
     maCells.set(it, nRow, pEditText);
     maCellTextAttrs.set(nRow, sc::CellTextAttr());
@@ -1611,6 +1613,7 @@ void ScColumn::SetEditText( SCROW nRow, EditTextObject* pEditText )
 
 void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, EditTextObject* pEditText )
 {
+    pEditText->NormalizeString(pDocument->GetCellStringPool());
     rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
     rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pEditText);
     rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
@@ -1632,24 +1635,9 @@ void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, cons
     // Sadly there is no other way to change the Pool than to
     // "spool" the Object through a corresponding Engine
     EditEngine& rEngine = pDocument->GetEditEngine();
-    if (!rEditText.HasOnlineSpellErrors())
-    {
-        rEngine.SetText(rEditText);
-        SetEditText(rBlockPos, nRow, rEngine.CreateTextObject());
-        return;
-    }
-
-    sal_uLong nControl = rEngine.GetControlWord();
-    const sal_uLong nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
-    bool bNewControl = (nControl & nSpellControl) != nSpellControl;
-    if (bNewControl)
-        rEngine.SetControlWord(nControl | nSpellControl);
     rEngine.SetText(rEditText);
-    EditTextObject* pData = rEngine.CreateTextObject();
-    if (bNewControl)
-        rEngine.SetControlWord(nControl);
-
-    SetEditText(rBlockPos, nRow, pData);
+    SetEditText(rBlockPos, nRow, rEngine.CreateTextObject());
+    return;
 }
 
 void ScColumn::SetEditText( SCROW nRow, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
@@ -1664,24 +1652,9 @@ void ScColumn::SetEditText( SCROW nRow, const EditTextObject& rEditText, const S
     // Sadly there is no other way to change the Pool than to
     // "spool" the Object through a corresponding Engine
     EditEngine& rEngine = pDocument->GetEditEngine();
-    if (!rEditText.HasOnlineSpellErrors())
-    {
-        rEngine.SetText(rEditText);
-        SetEditText(nRow, rEngine.CreateTextObject());
-        return;
-    }
-
-    sal_uLong nControl = rEngine.GetControlWord();
-    const sal_uLong nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
-    bool bNewControl = (nControl & nSpellControl) != nSpellControl;
-    if (bNewControl)
-        rEngine.SetControlWord(nControl | nSpellControl);
     rEngine.SetText(rEditText);
-    EditTextObject* pData = rEngine.CreateTextObject();
-    if (bNewControl)
-        rEngine.SetControlWord(nControl);
-
-    SetEditText(nRow, pData);
+    SetEditText(nRow, rEngine.CreateTextObject());
+    return;
 }
 
 void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram )
@@ -2157,8 +2130,12 @@ void ScColumn::SetRawString( SCROW nRow, const OUString& rStr, bool bBroadcast )
     if (!ValidRow(nRow))
         return;
 
+    rtl_uString* pStr = pDocument->GetCellStringPool().intern(rStr);
+    if (!pStr)
+        return;
+
     sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
-    maCells.set(it, nRow, rStr);
+    maCells.set(it, nRow, OUString(pStr));
     maCellTextAttrs.set(nRow, sc::CellTextAttr());
     CellStorageModified();
 
@@ -2172,8 +2149,12 @@ void ScColumn::SetRawString(
     if (!ValidRow(nRow))
         return;
 
+    rtl_uString* pStr = pDocument->GetCellStringPool().intern(rStr);
+    if (!pStr)
+        return;
+
     rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
-    rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, rStr);
+    rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, OUString(pStr));
     rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
         rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
     CellStorageModified();
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 500bc1b..9f64090 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -118,8 +118,8 @@ private:
 
 // STATIC DATA -----------------------------------------------------------
 
-ScDocument::ScDocument( ScDocumentMode  eMode,
-                        SfxObjectShell* pDocShell ) :
+ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
+        mpCellStringPool(new svl::StringPool(ScGlobal::pCharClass)),
         mpUndoManager( NULL ),
         pEditEngine( NULL ),
         pNoteEngine( NULL ),
@@ -600,6 +600,11 @@ ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos )
     return maTabs[rPos.Tab()]->GetRefCellValue(rPos.Col(), rPos.Row());
 }
 
+svl::StringPool& ScDocument::GetCellStringPool()
+{
+    return *mpCellStringPool;
+}
+
 bool ScDocument::GetPrintArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow,
                                 bool bNotes ) const
 {
diff --git a/sc/source/core/data/documentimport.cxx b/sc/source/core/data/documentimport.cxx
index 9998e83..4c9157d 100644
--- a/sc/source/core/data/documentimport.cxx
+++ b/sc/source/core/data/documentimport.cxx
@@ -17,6 +17,8 @@
 #include "mtvelements.hxx"
 #include "tokenarray.hxx"
 
+#include "svl/stringpool.hxx"
+
 struct ScDocumentImportImpl
 {
     ScDocument& mrDoc;
@@ -148,8 +150,12 @@ void ScDocumentImport::setStringCell(const ScAddress& rPos, const OUString& rStr
     if (!pBlockPos)
         return;
 
+    rtl_uString* pStr = mpImpl->mrDoc.GetCellStringPool().intern(rStr);
+    if (!pStr)
+        return;
+
     sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
-    pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), rStr);
+    pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), OUString(pStr));
 }
 
 void ScDocumentImport::setEditCell(const ScAddress& rPos, EditTextObject* pEditText)
@@ -164,6 +170,7 @@ void ScDocumentImport::setEditCell(const ScAddress& rPos, EditTextObject* pEditT
     if (!pBlockPos)
         return;
 
+    pEditText->NormalizeString(mpImpl->mrDoc.GetCellStringPool());
     sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
     pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), pEditText);
 }
commit 0bd3f6e5387571b6a9dbe8fe00701315f4c59b60
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 21:46:40 2013 -0400

    Add string pool to document.
    
    Change-Id: I7430af7486a2f7a150ed17a0c345aeeb987ec993

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 1e720a8..73d7c1c 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -50,6 +50,7 @@
 
 namespace editeng { class SvxBorderLine; }
 namespace formula { struct VectorRefArray; }
+namespace svl { class StringPool; }
 
 namespace sc {
     struct FormulaGroupContext;
@@ -243,6 +244,8 @@ private:
 
     rtl::Reference<ScPoolHelper> xPoolHelper;
 
+    boost::scoped_ptr<svl::StringPool> mpCellStringPool;
+
     SfxUndoManager*     mpUndoManager;
     ScFieldEditEngine*  pEditEngine;                    // uses pEditPool from xPoolHelper
     ScNoteEditEngine*   pNoteEngine;                    // uses pEditPool from xPoolHelper
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 1086bd1..500bc1b 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -35,6 +35,7 @@
 #include <vcl/virdev.hxx>
 #include <comphelper/processfactory.hxx>
 #include <svl/PasswordHelper.hxx>
+#include "svl/stringpool.hxx"
 #include <tools/tenccvt.hxx>
 #include <tools/urlobj.hxx>
 #include <rtl/crc.h>
@@ -439,6 +440,8 @@ ScDocument::~ScDocument()
 
     delete pPreviewFont;
     OSL_POSTCOND( !pAutoNameCache, "AutoNameCache still set in dtor" );
+
+    mpCellStringPool.reset();
 }
 
 void ScDocument::InitClipPtrs( ScDocument* pSourceDoc )
commit 503ad4f11df7996b22e311e42104f2baed266808
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 19:11:28 2013 -0400

    A little more test on shared string pool's life cycle management.
    
    Change-Id: Ic676dd875c27ce60a0707903d7f22207764829e0

diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 90f4c44..11a52e6 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -36,6 +36,8 @@
 #include "svl/stringpool.hxx"
 #include "unotools/syslocale.hxx"
 
+#include <boost/scoped_ptr.hpp>
+
 #define DEBUG_UNIT_TEST 1
 
 #if DEBUG_UNIT_TEST
@@ -353,6 +355,48 @@ void Test::testStringPoolPurge()
     aPool.purge();
     CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 0);
     CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 0);
+
+    // Now, create string objects on the heap.
+    boost::scoped_ptr<OUString> pStr1(new OUString("Andy"));
+    boost::scoped_ptr<OUString> pStr2(new OUString("andy"));
+    boost::scoped_ptr<OUString> pStr3(new OUString("ANDY"));
+    boost::scoped_ptr<OUString> pStr4(new OUString("Bruce"));
+    aPool.intern(*pStr1);
+    aPool.intern(*pStr2);
+    aPool.intern(*pStr3);
+    aPool.intern(*pStr4);
+
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 4);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 2);
+
+    // This shouldn't purge anything.
+    aPool.purge();
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 4);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 2);
+
+    // Delete one heap string object, and purge. That should purge one string.
+    pStr1.reset();
+    aPool.purge();
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 3);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 2);
+
+    // Ditto...
+    pStr3.reset();
+    aPool.purge();
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 2);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 2);
+
+    // Again.
+    pStr2.reset();
+    aPool.purge();
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 1);
+
+    // Delete 'Bruce' and purge.
+    pStr4.reset();
+    aPool.purge();
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 0);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 0);
 }
 
 void Test::checkPreviewString(SvNumberFormatter& aFormatter,
commit 9bf08ab4f8dea6e28da9d1111b42cf55215484b9
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 18:54:28 2013 -0400

    No need to intern strings here; all OUString's are ref-counted.
    
    Calling intern() simply moves it to a global hash storage.  Now
    the test passes.
    
    Change-Id: I0a93420abce1c3adaaa61d469dff5f359dd5ada4

diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 26cad83..90f4c44 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -75,7 +75,7 @@ public:
     CPPUNIT_TEST_SUITE(Test);
     CPPUNIT_TEST(testNumberFormat);
     CPPUNIT_TEST(testStringPool);
-//  CPPUNIT_TEST(testStringPoolPurge); // FIXME: String pool's life cycle needs more work.
+    CPPUNIT_TEST(testStringPoolPurge);
     CPPUNIT_TEST(testFdo60915);
     CPPUNIT_TEST(testI116701);
     CPPUNIT_TEST_SUITE_END();
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index f4d9996..4760348 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -128,7 +128,7 @@ StringPool::InsertResultType StringPool::findOrInsert( StrHashType& rPool, const
     if (it == rPool.end())
     {
         // Not yet in the pool.
-        std::pair<StrHashType::iterator, bool> r = rPool.insert(rStr.intern());
+        std::pair<StrHashType::iterator, bool> r = rPool.insert(rStr);
         if (!r.second)
             // Insertion failed.
             return InsertResultType(rPool.end(), false);
commit 9d78c7f1d6af94fe9fb7fd5d727261090e27e56c
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 16:35:41 2013 -0400

    Add purge() method to purge unreferenced strings from the pool.
    
    But this code needs more work.
    
    Change-Id: I538eebf5eb1738a2cfeebc22052b3d5db6001b6b

diff --git a/include/svl/stringpool.hxx b/include/svl/stringpool.hxx
index d2eca12..cac7637 100644
--- a/include/svl/stringpool.hxx
+++ b/include/svl/stringpool.hxx
@@ -54,7 +54,8 @@ public:
 
     /**
      * Get a unique ID of string object that's expected to be in the shared
-     * string pool. If the string is not in the pool, NULL is returned.
+     * string pool. If the string is not in the pool, NULL is returned.  The
+     * ID obtained by this method can be used for case sensitive comparison.
      *
      * @param rStr string object to get the ID of.
      *
@@ -62,8 +63,27 @@ public:
      */
     StrIdType getIdentifier( const OUString& rStr ) const;
 
+    /**
+     * Get a unique ID of string object for case insensitive comparison. The
+     * string object is expected to be in the pool.
+     *
+     * @param rStr string object to get the ID of.
+     *
+     * @return unique ID of the string object usable for case insensitive
+     *         comparison.
+     */
     StrIdType getIdentifierIgnoreCase( const OUString& rStr ) const;
 
+    /**
+     * Go through all string objects in the pool, and clear those that are no
+     * longer used outside of the pool.
+     */
+    void purge();
+
+    size_t getCount() const;
+
+    size_t getCountIgnoreCase() const;
+
 private:
     InsertResultType findOrInsert( StrHashType& rPool, const OUString& rStr ) const;
 };
diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 58882bb..26cad83 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -36,7 +36,7 @@
 #include "svl/stringpool.hxx"
 #include "unotools/syslocale.hxx"
 
-#define DEBUG_UNIT_TEST 0
+#define DEBUG_UNIT_TEST 1
 
 #if DEBUG_UNIT_TEST
 #include <iostream>
@@ -68,12 +68,14 @@ public:
 
     void testNumberFormat();
     void testStringPool();
+    void testStringPoolPurge();
     void testFdo60915();
     void testI116701();
 
     CPPUNIT_TEST_SUITE(Test);
     CPPUNIT_TEST(testNumberFormat);
     CPPUNIT_TEST(testStringPool);
+//  CPPUNIT_TEST(testStringPoolPurge); // FIXME: String pool's life cycle needs more work.
     CPPUNIT_TEST(testFdo60915);
     CPPUNIT_TEST(testI116701);
     CPPUNIT_TEST_SUITE_END();
@@ -335,6 +337,24 @@ void Test::testStringPool()
     CPPUNIT_ASSERT_EQUAL(si1, si2);
 }
 
+void Test::testStringPoolPurge()
+{
+    SvtSysLocale aSysLocale;
+    svl::StringPool aPool(aSysLocale.GetCharClassPtr());
+    aPool.intern("Andy");
+    aPool.intern("andy");
+    aPool.intern("ANDY");
+
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 3);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 1);
+
+    // Since no string objects referencing the pooled strings exist, purging
+    // the pool should empty it.
+    aPool.purge();
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 0);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 0);
+}
+
 void Test::checkPreviewString(SvNumberFormatter& aFormatter,
                               const OUString& sCode,
                               double fPreviewNumber,
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index 11b6288..f4d9996 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -67,6 +67,60 @@ StringPool::StrIdType StringPool::getIdentifierIgnoreCase( const OUString& rStr
     return reinterpret_cast<StrIdType>(pUpper);
 }
 
+namespace {
+
+inline sal_Int32 getRefCount( const rtl_uString* p )
+{
+    return (p->refCount & 0x3FFFFFFF);
+}
+
+}
+
+void StringPool::purge()
+{
+    StrHashType aNewStrPool;
+    StrHashType::iterator it = maStrPool.begin(), itEnd = maStrPool.end();
+    for (; it != itEnd; ++it)
+    {
+        const rtl_uString* p = it->pData;
+        if (getRefCount(p) == 1)
+        {
+            // Remove it from the upper string map.  This should unref the
+            // upper string linked to this original string.
+            maToUpperMap.erase(p);
+        }
+        else
+            // Still referenced outside the pool. Keep it.
+            aNewStrPool.insert(*it);
+    }
+
+    maStrPool.swap(aNewStrPool);
+
+    aNewStrPool.clear(); // for re-use.
+
+    // Purge the upper string pool as well.
+    it = maStrPoolUpper.begin();
+    itEnd = maStrPoolUpper.end();
+    for (; it != itEnd; ++it)
+    {
+        const rtl_uString* p = it->pData;
+        if (getRefCount(p) > 1)
+            aNewStrPool.insert(*it);
+    }
+
+    maStrPoolUpper.swap(aNewStrPool);
+}
+
+size_t StringPool::getCount() const
+{
+    return maStrPool.size();
+}
+
+size_t StringPool::getCountIgnoreCase() const
+{
+    return maStrPoolUpper.size();
+}
+
 StringPool::InsertResultType StringPool::findOrInsert( StrHashType& rPool, const OUString& rStr ) const
 {
     StrHashType::iterator it = rPool.find(rStr);
commit 9a905d633596b2de42d60eb344a4ef2246cb6877
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 14:06:13 2013 -0400

    The map actualy needs to store OUString to have it ref-counted automatically.
    
    Change-Id: Iff6fcf3aba73f2d06ac0c885b39e69ac0febc49f

diff --git a/include/svl/stringpool.hxx b/include/svl/stringpool.hxx
index 4436efe..d2eca12 100644
--- a/include/svl/stringpool.hxx
+++ b/include/svl/stringpool.hxx
@@ -29,7 +29,7 @@ class SVL_DLLPUBLIC StringPool
 {
     typedef boost::unordered_set<OUString, OUStringHash> StrHashType;
     typedef std::pair<StrHashType::iterator, bool> InsertResultType;
-    typedef boost::unordered_map<const rtl_uString*, const rtl_uString*> StrIdMapType;
+    typedef boost::unordered_map<const rtl_uString*, OUString> StrIdMapType;
 
     StrHashType maStrPool;
     StrHashType maStrPoolUpper;
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index 76dc4aa..11b6288 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -40,8 +40,7 @@ rtl_uString* StringPool::intern( const OUString& rStr )
         return pOrig;
 
     // Set mapping.
-    rtl_uString* pUpper = aRes.first->pData;
-    maToUpperMap.insert(StrIdMapType::value_type(pOrig, pUpper));
+    maToUpperMap.insert(StrIdMapType::value_type(pOrig, *aRes.first));
 
     return pOrig;
 }
@@ -64,7 +63,7 @@ StringPool::StrIdType StringPool::getIdentifierIgnoreCase( const OUString& rStr
         // Passed string is not in the pool.
         return 0;
 
-    const rtl_uString* pUpper = itUpper->second;
+    const rtl_uString* pUpper = itUpper->second.pData;
     return reinterpret_cast<StrIdType>(pUpper);
 }
 
commit e786c5eb3c0a2889cc1cc5ca8906be3035c49bbe
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 13:06:20 2013 -0400

    Correct way to get case-insensitive string identifiers.
    
    Change-Id: Ia343165941231fab34c4904b7a2fa10b07fa32bb

diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 003a152..58882bb 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -307,7 +307,11 @@ void Test::testStringPool()
     OUString aAndy("Andy");
     svl::StringPool::StrIdType si1 = aPool.getIdentifier("Andy");
     svl::StringPool::StrIdType si2 = aPool.getIdentifier(aAndy);
+    CPPUNIT_ASSERT_MESSAGE("Identifier shouldn't be 0.", si1);
+    CPPUNIT_ASSERT_MESSAGE("Identifier shouldn't be 0.", si2);
     CPPUNIT_ASSERT_EQUAL(si1, si2);
+    si1 = aPool.getIdentifierIgnoreCase(aAndy);
+    CPPUNIT_ASSERT_MESSAGE("Case insensitive identifier shouldn't be 0.", si1);
 
     // Test case insensitive string ID's.
     OUString aAndyLower("andy"), aAndyUpper("ANDY");
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index c0030fe..76dc4aa 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -48,18 +48,24 @@ rtl_uString* StringPool::intern( const OUString& rStr )
 
 StringPool::StrIdType StringPool::getIdentifier( const OUString& rStr ) const
 {
-    StrHashType::iterator it = maStrPool.find(rStr);
+    StrHashType::const_iterator it = maStrPool.find(rStr);
     return (it == maStrPool.end()) ? 0 : reinterpret_cast<StrIdType>(it->pData);
 }
 
 StringPool::StrIdType StringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
 {
-    if (!mpCharClass)
+    StrHashType::const_iterator itOrig = maStrPool.find(rStr);
+    if (itOrig == maStrPool.end())
+        // Not in the pool.
         return 0;
 
-    OUString aUpper = mpCharClass->uppercase(rStr);
-    StrHashType::iterator it = maStrPoolUpper.find(aUpper);
-    return (it == maStrPool.end()) ? 0 : reinterpret_cast<StrIdType>(it->pData);
+    StrIdMapType::const_iterator itUpper = maToUpperMap.find(itOrig->pData);
+    if (itUpper == maToUpperMap.end())
+        // Passed string is not in the pool.
+        return 0;
+
+    const rtl_uString* pUpper = itUpper->second;
+    return reinterpret_cast<StrIdType>(pUpper);
 }
 
 StringPool::InsertResultType StringPool::findOrInsert( StrHashType& rPool, const OUString& rStr ) const
commit 3e2ff089b54159fafaf68db8ad0702b19ba68e46
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 12:19:19 2013 -0400

    Let's not expose the internal pointer. Define different ID type.
    
    To prevent the string ID's from being used to instantiate string objects,
    which can mess up shared string object's life cycles.
    
    Change-Id: Ibcd9a4fa9f591d5c27a9e1b50bc9f83ae230e86a

diff --git a/include/svl/stringpool.hxx b/include/svl/stringpool.hxx
index 26785e3..4436efe 100644
--- a/include/svl/stringpool.hxx
+++ b/include/svl/stringpool.hxx
@@ -37,6 +37,8 @@ class SVL_DLLPUBLIC StringPool
     const CharClass* mpCharClass;
 
 public:
+    typedef sal_uIntPtr StrIdType;
+
     StringPool();
     StringPool( const CharClass* pCharClass );
 
@@ -58,9 +60,9 @@ public:
      *
      * @return unique ID of the string object.
      */
-    const rtl_uString* getIdentifier( const OUString& rStr ) const;
+    StrIdType getIdentifier( const OUString& rStr ) const;
 
-    const rtl_uString* getIdentifierIgnoreCase( const OUString& rStr ) const;
+    StrIdType getIdentifierIgnoreCase( const OUString& rStr ) const;
 
 private:
     InsertResultType findOrInsert( StrHashType& rPool, const OUString& rStr ) const;
diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index f41ab73..003a152 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -305,27 +305,30 @@ void Test::testStringPool()
     CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
 
     OUString aAndy("Andy");
-    p2 = aPool.getIdentifier(aAndy);
-    CPPUNIT_ASSERT_EQUAL(p1, p2);
+    svl::StringPool::StrIdType si1 = aPool.getIdentifier("Andy");
+    svl::StringPool::StrIdType si2 = aPool.getIdentifier(aAndy);
+    CPPUNIT_ASSERT_EQUAL(si1, si2);
 
     // Test case insensitive string ID's.
     OUString aAndyLower("andy"), aAndyUpper("ANDY");
-    p1 = aPool.getIdentifier("Andy");
-    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p1);
-    p2 = aPool.intern(aAndyLower);
-    CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
-    p2 = aPool.intern(aAndyUpper);
-    CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
-
-    p1 = aPool.getIdentifierIgnoreCase("Andy");
-    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p1);
-    p2 = aPool.getIdentifierIgnoreCase("andy");
-    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p2);
-    CPPUNIT_ASSERT_EQUAL(p1, p2);
-
-    p2 = aPool.getIdentifierIgnoreCase("ANDY");
-    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p2);
-    CPPUNIT_ASSERT_EQUAL(p1, p2);
+    si1 = aPool.getIdentifier("Andy");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", si1);
+    aPool.intern(aAndyLower);
+    si2 = aPool.getIdentifier(aAndyLower);
+    CPPUNIT_ASSERT_MESSAGE("They must differ.", si1 != si2);
+    aPool.intern(aAndyUpper);
+    si2 = aPool.getIdentifier(aAndyUpper);
+    CPPUNIT_ASSERT_MESSAGE("They must differ.", si1 != si2);
+
+    si1 = aPool.getIdentifierIgnoreCase("Andy");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", si1);
+    si2 = aPool.getIdentifierIgnoreCase("andy");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", si2);
+    CPPUNIT_ASSERT_EQUAL(si1, si2);
+
+    si2 = aPool.getIdentifierIgnoreCase("ANDY");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", si2);
+    CPPUNIT_ASSERT_EQUAL(si1, si2);
 }
 
 void Test::checkPreviewString(SvNumberFormatter& aFormatter,
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index 1181538..c0030fe 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -46,20 +46,20 @@ rtl_uString* StringPool::intern( const OUString& rStr )
     return pOrig;
 }
 
-const rtl_uString* StringPool::getIdentifier( const OUString& rStr ) const
+StringPool::StrIdType StringPool::getIdentifier( const OUString& rStr ) const
 {
     StrHashType::iterator it = maStrPool.find(rStr);
-    return (it == maStrPool.end()) ? NULL : it->pData;
+    return (it == maStrPool.end()) ? 0 : reinterpret_cast<StrIdType>(it->pData);
 }
 
-const rtl_uString* StringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
+StringPool::StrIdType StringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
 {
     if (!mpCharClass)
-        return NULL;
+        return 0;
 
     OUString aUpper = mpCharClass->uppercase(rStr);
     StrHashType::iterator it = maStrPoolUpper.find(aUpper);
-    return (it == maStrPool.end()) ? NULL : it->pData;
+    return (it == maStrPool.end()) ? 0 : reinterpret_cast<StrIdType>(it->pData);
 }
 
 StringPool::InsertResultType StringPool::findOrInsert( StrHashType& rPool, const OUString& rStr ) const
commit 8229b99ef9f3fcbeda0ef1aeaef2408f4487d41e
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 11:29:42 2013 -0400

    Write some rudimentary tests for the new shared string pool class.
    
    Change-Id: Ie66de46d69f664839aa0a2d056cd3b8df4d4989b

diff --git a/include/svl/stringpool.hxx b/include/svl/stringpool.hxx
index 2541568..26785e3 100644
--- a/include/svl/stringpool.hxx
+++ b/include/svl/stringpool.hxx
@@ -34,11 +34,11 @@ class SVL_DLLPUBLIC StringPool
     StrHashType maStrPool;
     StrHashType maStrPoolUpper;
     StrIdMapType maToUpperMap;
-    CharClass* mpCharClass;
+    const CharClass* mpCharClass;
 
 public:
     StringPool();
-    StringPool( CharClass* pCharClass );
+    StringPool( const CharClass* pCharClass );
 
     /**
      * Intern a string object into the shared string pool.
@@ -60,6 +60,8 @@ public:
      */
     const rtl_uString* getIdentifier( const OUString& rStr ) const;
 
+    const rtl_uString* getIdentifierIgnoreCase( const OUString& rStr ) const;
+
 private:
     InsertResultType findOrInsert( StrHashType& rPool, const OUString& rStr ) const;
 };
diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 8d46ecf..f41ab73 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -33,6 +33,8 @@
 
 #include "svl/zforlist.hxx"
 #include "svl/zformat.hxx"
+#include "svl/stringpool.hxx"
+#include "unotools/syslocale.hxx"
 
 #define DEBUG_UNIT_TEST 0
 
@@ -65,11 +67,13 @@ public:
     virtual void tearDown();
 
     void testNumberFormat();
+    void testStringPool();
     void testFdo60915();
     void testI116701();
 
     CPPUNIT_TEST_SUITE(Test);
     CPPUNIT_TEST(testNumberFormat);
+    CPPUNIT_TEST(testStringPool);
     CPPUNIT_TEST(testFdo60915);
     CPPUNIT_TEST(testI116701);
     CPPUNIT_TEST_SUITE_END();
@@ -288,6 +292,42 @@ void Test::testNumberFormat()
     }
 }
 
+void Test::testStringPool()
+{
+    SvtSysLocale aSysLocale;
+    svl::StringPool aPool(aSysLocale.GetCharClassPtr());
+
+    const rtl_uString* p1 = aPool.intern("Andy");
+    const rtl_uString* p2 = aPool.intern("Andy");
+    CPPUNIT_ASSERT_EQUAL(p1, p2);
+
+    p2 = aPool.intern("Bruce");
+    CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
+
+    OUString aAndy("Andy");
+    p2 = aPool.getIdentifier(aAndy);
+    CPPUNIT_ASSERT_EQUAL(p1, p2);
+
+    // Test case insensitive string ID's.
+    OUString aAndyLower("andy"), aAndyUpper("ANDY");
+    p1 = aPool.getIdentifier("Andy");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p1);
+    p2 = aPool.intern(aAndyLower);
+    CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
+    p2 = aPool.intern(aAndyUpper);
+    CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
+
+    p1 = aPool.getIdentifierIgnoreCase("Andy");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p1);
+    p2 = aPool.getIdentifierIgnoreCase("andy");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p2);
+    CPPUNIT_ASSERT_EQUAL(p1, p2);
+
+    p2 = aPool.getIdentifierIgnoreCase("ANDY");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p2);
+    CPPUNIT_ASSERT_EQUAL(p1, p2);
+}
+
 void Test::checkPreviewString(SvNumberFormatter& aFormatter,
                               const OUString& sCode,
                               double fPreviewNumber,
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index 46462d1..1181538 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -13,7 +13,7 @@
 namespace svl {
 
 StringPool::StringPool() : mpCharClass(NULL) {}
-StringPool::StringPool( CharClass* pCharClass ) : mpCharClass(pCharClass) {}
+StringPool::StringPool( const CharClass* pCharClass ) : mpCharClass(pCharClass) {}
 
 rtl_uString* StringPool::intern( const OUString& rStr )
 {
@@ -52,6 +52,16 @@ const rtl_uString* StringPool::getIdentifier( const OUString& rStr ) const
     return (it == maStrPool.end()) ? NULL : it->pData;
 }
 
+const rtl_uString* StringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
+{
+    if (!mpCharClass)
+        return NULL;
+
+    OUString aUpper = mpCharClass->uppercase(rStr);
+    StrHashType::iterator it = maStrPoolUpper.find(aUpper);
+    return (it == maStrPool.end()) ? NULL : it->pData;
+}
+
 StringPool::InsertResultType StringPool::findOrInsert( StrHashType& rPool, const OUString& rStr ) const
 {
     StrHashType::iterator it = rPool.find(rStr);
commit 7103314ab54243f4aaee302cad48bf1c60a1f3e3
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 10:47:28 2013 -0400

    Establish mapping between original strings and upper strings.
    
    This will be used to retrieve case insensitive string identifiers
    later.
    
    Change-Id: Ia34f57d0e8d0cb6bd4630f8d110853ed049770b5

diff --git a/include/svl/stringpool.hxx b/include/svl/stringpool.hxx
index 643c846..2541568 100644
--- a/include/svl/stringpool.hxx
+++ b/include/svl/stringpool.hxx
@@ -13,18 +13,55 @@
 #include "svl/svldllapi.h"
 #include "rtl/ustring.hxx"
 
+#include <boost/unordered_map.hpp>
 #include <boost/unordered_set.hpp>
 
+class CharClass;
+
 namespace svl {
 
+/**
+ * Storage for pool of shared strings.  It also provides mapping from
+ * original-cased strings to upper-cased strings for case insensitive
+ * operations.
+ */
 class SVL_DLLPUBLIC StringPool
 {
     typedef boost::unordered_set<OUString, OUStringHash> StrHashType;
+    typedef std::pair<StrHashType::iterator, bool> InsertResultType;
+    typedef boost::unordered_map<const rtl_uString*, const rtl_uString*> StrIdMapType;
+
     StrHashType maStrPool;
+    StrHashType maStrPoolUpper;
+    StrIdMapType maToUpperMap;
+    CharClass* mpCharClass;
+
 public:
     StringPool();
+    StringPool( CharClass* pCharClass );
 
+    /**
+     * Intern a string object into the shared string pool.
+     *
+     * @param rStr string object to intern.
+     *
+     * @return a pointer to the string object stored inside the pool, or NULL
+     *         if the insertion fails.
+     */
     rtl_uString* intern( const OUString& rStr );
+
+    /**
+     * Get a unique ID of string object that's expected to be in the shared
+     * string pool. If the string is not in the pool, NULL is returned.
+     *
+     * @param rStr string object to get the ID of.
+     *
+     * @return unique ID of the string object.
+     */
+    const rtl_uString* getIdentifier( const OUString& rStr ) const;
+
+private:
+    InsertResultType findOrInsert( StrHashType& rPool, const OUString& rStr ) const;
 };
 
 }
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index f8ddda9..46462d1 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -8,26 +8,67 @@
  */
 
 #include "svl/stringpool.hxx"
+#include "unotools/charclass.hxx"
 
 namespace svl {
 
-StringPool::StringPool() {}
+StringPool::StringPool() : mpCharClass(NULL) {}
+StringPool::StringPool( CharClass* pCharClass ) : mpCharClass(pCharClass) {}
 
 rtl_uString* StringPool::intern( const OUString& rStr )
 {
+    InsertResultType aRes = findOrInsert(maStrPool, rStr);
+    if (aRes.first == maStrPool.end())
+        // Insertion failed.
+        return NULL;
+
+    rtl_uString* pOrig = aRes.first->pData;
+
+    if (!aRes.second)
+        // No new string has been inserted. Return the existing string in the pool.
+        return pOrig;
+
+    if (!mpCharClass)
+        return pOrig;
+
+    // This is a new string insertion. Establish mapping to upper-case variant.
+
+    OUString aUpper = mpCharClass->uppercase(rStr);
+    aRes = findOrInsert(maStrPoolUpper, aUpper);
+    if (aRes.first == maStrPoolUpper.end())
+        // Failed to insert or fetch upper-case variant. Should never happen.
+        return pOrig;
+
+    // Set mapping.
+    rtl_uString* pUpper = aRes.first->pData;
+    maToUpperMap.insert(StrIdMapType::value_type(pOrig, pUpper));
+
+    return pOrig;
+}
+
+const rtl_uString* StringPool::getIdentifier( const OUString& rStr ) const
+{
     StrHashType::iterator it = maStrPool.find(rStr);
-    if (it == maStrPool.end())
+    return (it == maStrPool.end()) ? NULL : it->pData;
+}
+
+StringPool::InsertResultType StringPool::findOrInsert( StrHashType& rPool, const OUString& rStr ) const
+{
+    StrHashType::iterator it = rPool.find(rStr);
+    bool bInserted = false;
+    if (it == rPool.end())
     {
         // Not yet in the pool.
-        std::pair<StrHashType::iterator, bool> r = maStrPool.insert(rStr.intern());
+        std::pair<StrHashType::iterator, bool> r = rPool.insert(rStr.intern());
         if (!r.second)
             // Insertion failed.
-            return NULL;
+            return InsertResultType(rPool.end(), false);
 
         it = r.first;
+        bInserted = true;
     }
 
-    return it->pData;
+    return InsertResultType(it, bInserted);
 }
 
 }
commit 86fcc46ab97b852d78e560419151275f28bb1179
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Oct 1 21:51:50 2013 -0400

    Add method to normalize strings in EditTextObject.
    
    Change-Id: I1adb57279db0afeb8387599ec11984380e5a2e4a

diff --git a/editeng/source/editeng/editobj.cxx b/editeng/source/editeng/editobj.cxx
index 8e35a57..aaf5e5f 100644
--- a/editeng/source/editeng/editobj.cxx
+++ b/editeng/source/editeng/editobj.cxx
@@ -44,6 +44,7 @@
 
 #include <vcl/graph.hxx>
 #include <svl/intitem.hxx>
+#include "svl/stringpool.hxx"
 #include <unotools/fontcvt.hxx>
 #include <tools/tenccvt.hxx>
 
@@ -148,6 +149,11 @@ ContentInfo::~ContentInfo()
     aAttribs.clear();
 }
 
+void ContentInfo::NormalizeString( svl::StringPool& rPool )
+{
+    aText = OUString(rPool.intern(aText));
+}
+
 const WrongList* ContentInfo::GetWrongList() const
 {
     return mpWrongs.get();
@@ -316,6 +322,11 @@ editeng::FieldUpdater EditTextObject::GetFieldUpdater()
     return mpImpl->GetFieldUpdater();
 }
 
+void EditTextObject::NormalizeString( svl::StringPool& rPool )
+{
+    mpImpl->NormalizeString(rPool);
+}
+
 const SfxItemPool* EditTextObject::GetPool() const
 {
     return mpImpl->GetPool();
@@ -602,6 +613,16 @@ void EditTextObjectImpl::SetUserType( sal_uInt16 n )
     nUserType = n;
 }
 
+void EditTextObjectImpl::NormalizeString( svl::StringPool& rPool )
+{
+    ContentInfosType::iterator it = aContents.begin(), itEnd = aContents.end();
+    for (; it != itEnd; ++it)
+    {
+        ContentInfo& rInfo = *it;
+        rInfo.NormalizeString(rPool);
+    }
+}
+
 bool EditTextObjectImpl::IsVertical() const
 {
     return bVertical;
diff --git a/editeng/source/editeng/editobj2.hxx b/editeng/source/editeng/editobj2.hxx
index b704e48..c331134 100644
--- a/editeng/source/editeng/editobj2.hxx
+++ b/editeng/source/editeng/editobj2.hxx
@@ -35,6 +35,12 @@ struct Section;
 
 }
 
+namespace svl {
+
+class StringPool;
+
+}
+
 class XEditAttribute
 {
 private:
@@ -136,6 +142,8 @@ private:
 public:
                         ~ContentInfo();
 
+    void NormalizeString( svl::StringPool& rPool );
+
     const XEditAttributesType& GetAttribs() const { return aAttribs; }
     XEditAttributesType& GetAttribs() { return aAttribs; }
 
@@ -198,6 +206,8 @@ public:
     sal_uInt16 GetUserType() const;
     void SetUserType( sal_uInt16 n );
 
+    void NormalizeString( svl::StringPool& rPool );
+
     bool                    IsVertical() const;
     void                    SetVertical( bool b );
 
diff --git a/include/editeng/editobj.hxx b/include/editeng/editobj.hxx
index cdb8fbb..36392e2 100644
--- a/include/editeng/editobj.hxx
+++ b/include/editeng/editobj.hxx
@@ -49,6 +49,12 @@ struct Section;
 
 }
 
+namespace svl {
+
+class StringPool;
+
+}
+
 class EditTextObjectImpl;
 
 class EDITENG_DLLPUBLIC EditTextObject : public SfxItemPoolUser
@@ -72,6 +78,13 @@ public:
     EditTextObject( const EditTextObject& r );
     virtual ~EditTextObject();
 
+    /**
+     * Set paragraph strings to the shared string pool.
+     *
+     * @param rPool shared string pool.
+     */
+    void NormalizeString( svl::StringPool& rPool );
+
     const SfxItemPool* GetPool() const;
     sal_uInt16 GetUserType() const;    // For OutlinerMode, it can however not save in compatible format
     void SetUserType( sal_uInt16 n );
commit 23302c7db699b26a47fe8af92be32474ffc57b00
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Oct 1 20:57:56 2013 -0400

    Move this string pool code to svl.
    
    Change-Id: I1379fbc377607be8831133d64db2e14f8c75bff8

diff --git a/include/svl/stringpool.hxx b/include/svl/stringpool.hxx
new file mode 100644
index 0000000..643c846
--- /dev/null
+++ b/include/svl/stringpool.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef SVL_STRINGPOOL_HXX
+#define SVL_STRINGPOOL_HXX
+
+#include "svl/svldllapi.h"
+#include "rtl/ustring.hxx"
+
+#include <boost/unordered_set.hpp>
+
+namespace svl {
+
+class SVL_DLLPUBLIC StringPool
+{
+    typedef boost::unordered_set<OUString, OUStringHash> StrHashType;
+    StrHashType maStrPool;
+public:
+    StringPool();
+
+    rtl_uString* intern( const OUString& rStr );
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
index e7c13cd..a8d20bb 100644
--- a/sc/inc/formulagroup.hxx
+++ b/sc/inc/formulagroup.hxx
@@ -14,6 +14,8 @@
 #include "types.hxx"
 #include "platforminfo.hxx"
 
+#include "svl/stringpool.hxx"
+
 #include <vector>
 #include <boost/noncopyable.hpp>
 #include <boost/ptr_container/ptr_vector.hpp>
@@ -26,17 +28,14 @@ namespace sc {
 
 struct FormulaGroupContext : boost::noncopyable
 {
-    typedef boost::unordered_set<OUString, OUStringHash> StrHashType;
     typedef std::vector<double> NumArrayType;
     typedef std::vector<rtl_uString*> StrArrayType;
     typedef boost::ptr_vector<NumArrayType> NumArrayStoreType;
     typedef boost::ptr_vector<StrArrayType> StrArrayStoreType;
 
-    StrHashType maStrPool;
+    svl::StringPool maStrPool;
     NumArrayStoreType maNumArrays;
     StrArrayStoreType maStrArrays;
-
-    rtl_uString* intern( const OUString& rStr );
 };
 
 /**
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index eda83ff..9601583 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2174,7 +2174,7 @@ bool appendStrings(
                 getBlockIterators<sc::string_block>(it, nLenRemain, itData, itDataEnd);
 
                 for (; itData != itDataEnd; ++itData)
-                    rArray.push_back(rCxt.intern(*itData));
+                    rArray.push_back(rCxt.maStrPool.intern(*itData));
             }
             break;
             case sc::element_type_edittext:
@@ -2185,7 +2185,7 @@ bool appendStrings(
                 for (; itData != itDataEnd; ++itData)
                 {
                     OUString aStr = ScEditUtil::GetString(**itData, pDoc);
-                    rArray.push_back(rCxt.intern(aStr));
+                    rArray.push_back(rCxt.maStrPool.intern(aStr));
                 }
             }
             break;
@@ -2210,7 +2210,7 @@ bool appendStrings(
                         return false;
                     }
 
-                    rArray.push_back(rCxt.intern(aStr));
+                    rArray.push_back(rCxt.maStrPool.intern(aStr));
                 }
             }
             break;
@@ -2250,7 +2250,7 @@ void copyFirstBlock( sc::FormulaGroupContext& rCxt, size_t nLen, const sc::CellS
     const OUString* p = &sc::string_block::at(*rPos.first->data, rPos.second);
     const OUString* pEnd = p + nLen;
     for (; p != pEnd; ++p)
-        rArray.push_back(rCxt.intern(*p));
+        rArray.push_back(rCxt.maStrPool.intern(*p));
 }
 
 }
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 677ac9f..98ae0b4 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -38,23 +38,6 @@ extern "C" void compileOpenCLKernels(const OUString*);
 
 namespace sc {
 
-rtl_uString* FormulaGroupContext::intern( const OUString& rStr )
-{
-    StrHashType::iterator it = maStrPool.find(rStr);
-    if (it == maStrPool.end())
-    {
-        // Not yet in the pool.
-        std::pair<StrHashType::iterator, bool> r = maStrPool.insert(rStr.intern());
-        if (!r.second)
-            // Insertion failed.
-            return NULL;
-
-        it = r.first;
-    }
-
-    return it->pData;
-}
-
 namespace {
 
 /**
diff --git a/svl/Library_svl.mk b/svl/Library_svl.mk
index 277be91..eddabf0 100644
--- a/svl/Library_svl.mk
+++ b/svl/Library_svl.mk
@@ -110,6 +110,7 @@ $(eval $(call gb_Library_add_exception_objects,svl,\
     svl/source/misc/lockfilecommon \
     svl/source/misc/ownlist \
     svl/source/misc/sharecontrolfile \
+    svl/source/misc/stringpool \
     svl/source/misc/strmadpt \
     svl/source/misc/urihelper \
     svl/source/notify/brdcst \
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
new file mode 100644
index 0000000..f8ddda9
--- /dev/null
+++ b/svl/source/misc/stringpool.cxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "svl/stringpool.hxx"
+
+namespace svl {
+
+StringPool::StringPool() {}
+
+rtl_uString* StringPool::intern( const OUString& rStr )
+{
+    StrHashType::iterator it = maStrPool.find(rStr);
+    if (it == maStrPool.end())
+    {
+        // Not yet in the pool.
+        std::pair<StrHashType::iterator, bool> r = maStrPool.insert(rStr.intern());
+        if (!r.second)
+            // Insertion failed.
+            return NULL;
+
+        it = r.first;
+    }
+
+    return it->pData;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 457e0aef522583675247029e77cb212fb65d6cd1
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Fri Oct 4 20:21:55 2013 +0200

    DOCX styles: Check that we roundtrip rPrDefaults.
    
    Change-Id: I3aef9fdedf9877d1243940c429e05ff36f7fa760

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
index 223f26f..f771ef9 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
@@ -1402,6 +1402,10 @@ void Test::testStyleInheritance()
     assertXPath(pXmlStyles, "/w:styles/w:style[2]", "styleId", "Heading1");
     // w:ind was copied from the parent (Normal) style without a good reason.
     assertXPath(pXmlStyles, "/w:styles/w:style[2]/w:pPr/w:ind", 0);
+
+    // Check that we output real content of rPrDefault
+    assertXPath(pXmlStyles, "/w:styles/w:docDefaults/w:rPrDefault/w:rPr/w:rFonts", "ascii", "Times New Roman");
+    assertXPath(pXmlStyles, "/w:styles/w:docDefaults/w:rPrDefault/w:rPr/w:lang", "bidi", "ar-SA");
 }
 
 void Test::testSmartart()
commit 9f8fb9fce00caf1672844444a737a6477e34c9cb
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Fri Oct 4 20:10:01 2013 +0200

    DOCX styles: Output real rPrDefault's.
    
    Not complete - to be checked which of the properties are we supposed to
    output; so far we support only w:rFont and w:lang.
    
    Change-Id: I142dd075735ba2c5cb1022768bfecf793148078f

diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index d215e25..8e3c1c3 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -2358,13 +2358,27 @@ void DocxAttributeOutput::StartStyles()
 
 void DocxAttributeOutput::DocDefaults( )
 {
-    // To-Do : fill the '<w:docDefaults>' node with actual data
-
     // Write the '<w:docDefaults>' section here
-    m_pSerializer->startElementNS( XML_w, XML_docDefaults, FSEND );
-    m_pSerializer->singleElementNS( XML_w, XML_rPrDefault, FSEND );
-    m_pSerializer->singleElementNS( XML_w, XML_pPrDefault, FSEND );
-    m_pSerializer->endElementNS( XML_w, XML_docDefaults );
+    m_pSerializer->startElementNS(XML_w, XML_docDefaults, FSEND);
+
+    // Output the default run properties
+    m_pSerializer->startElementNS(XML_w, XML_rPrDefault, FSEND);
+    StartRunProperties();
+
+    // TODO find out which run properties do we want to write
+    const RES_CHRATR aDefaultRunProperties[] = {
+        RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT,
+        RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CTL_LANGUAGE,
+    };
+    for (size_t i = 0; i < SAL_N_ELEMENTS(aDefaultRunProperties); ++i)
+        OutputItem(m_rExport.pDoc->GetDefault(aDefaultRunProperties[i]));
+
+    EndRunProperties(NULL);
+    m_pSerializer->endElementNS(XML_w, XML_rPrDefault);
+
+    // TODO should we output some paragraph properties too?
+    m_pSerializer->singleElementNS(XML_w, XML_pPrDefault, FSEND);
+    m_pSerializer->endElementNS(XML_w, XML_docDefaults);
 }
 

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list