[Libreoffice-commits] core.git: Branch 'feature/formula-core-rework' - 250 commits - accessibility/inc afms/ExternalPackage_fontunxafm.mk afms/Module_afms.mk afms/Zip_fontunxafm.mk android/experimental avmedia/AllLangResTarget_avmedia.mk avmedia/Library_avmediagst_0_10.mk avmedia/Library_avmediagst.mk avmedia/Library_avmedia.mk avmedia/Library_avmediaQuickTime.mk avmedia/Library_avmediawin.mk avmedia/Module_avmedia.mk basctl/source basegfx/qa basegfx/source basic/qa basic/source bean/Jar_officebean.mk bean/JunitTest_bean_complex.mk bean/Library_officebean.mk bean/Module_bean.mk binaryurp/CppunitTest_binaryurp_test-cache.mk binaryurp/CppunitTest_binaryurp_test-unmarshal.mk binaryurp/Library_binaryurp.mk binaryurp/Module_binaryurp.mk bin/doubleNewlines.pl bin/fuzzfiles bin/java-set-classpath.in bin/unpack-sources bluez_bluetooth/Module_bluez_bluetooth.mk bluez_bluetooth/Package_inc.mk canvas/Library_nullcanvas.mk canvas/Module_canvas.mk canvas/source chart2/source cli_ure/Executable_climake r.mk cli_ure/source codemaker/Executable_cppumaker.mk codemaker/Module_codemaker.mk codemaker/StaticLibrary_codemaker_cpp.mk codemaker/StaticLibrary_codemaker_java.mk codemaker/StaticLibrary_codemaker.mk comphelper/source configmgr/Library_configmgr.mk configure.ac connectivity/AllLangResTarget_cnr.mk connectivity/Jar_ConnectivityTools.mk connectivity/Jar_sdbc_hsqldb.mk connectivity/Library_ado.mk connectivity/Library_calc.mk connectivity/Library_dbase.mk connectivity/Library_dbpool2.mk connectivity/Library_dbtools.mk connectivity/Library_evoab.mk connectivity/Library_file.mk connectivity/Library_flat.mk connectivity/Library_jdbc.mk connectivity/Library_kab1.mk connectivity/Library_kabdrv1.mk connectivity/Library_macab1.mk connectivity/Library_macabdrv1.mk connectivity/Library_mysql.mk connectivity/Library_odbcbase.mk connectivity/Library_odbc.mk connectivity/Library_sdbc2.mk connectivity/Library_tdeab1.mk connectivity/Library_tdeabdrv1.mk connectivity/Module_connectivity.mk connectivity/registry connectivity/source cppcanvas/source cppu/CppunitTest_cppu_qa_any.mk cppu/CppunitTest_cppu_qa_recursion.mk cppu/CppunitTest_cppu_qa_reference.mk cppu/CppunitTest_cppu_qa_unotype.mk cppu/CppunitTest_cppu_test_cppumaker.mk cppuhelper/CppunitTest_cppuhelper_cppu_ifcontainer.mk cppuhelper/CppunitTest_cppuhelper_cppu_unourl.mk cppuhelper/CppunitTest_cppuhelper_qa_weak.mk cppuhelper/Library_cppuhelper.mk cppuhelper/Module_cppuhelper.mk cppuhelper/Package_unorc.mk cppuhelper/source cppu/Library_affine_uno.mk cppu/Library_cppu.mk cppu/Library_log_uno.mk cppu/Library_purpenvhelper.mk cppu/Library_unsafe_uno.mk cppu/Module_cppu.mk cpputools/Executable_sp2bv.mk cpputools/Executable_uno.mk cpputools/Module_cpputools.mk cui/source cui/uiconfig dbaccess/source desktop/inc desktop/source desktop/unx desktop/win32 dictionaries distro-configs/LibreOfficeWin64.conf distro-configs/README drawinglayer/source editeng/qa editeng/source embeddedobj/Library_embobj.mk embedded obj/Library_emboleobj.mk embeddedobj/Module_embeddedobj.mk embedserv/Library_emser.mk embedserv/Library_inprocserv.mk embedserv/Module_embedserv.mk eventattacher/Library_evtatt.mk eventattacher/Module_eventattacher.mk extensions/AllLangResTarget_abp.mk extensions/AllLangResTarget_bib.mk extensions/AllLangResTarget_dbp.mk extensions/Configuration_updchk.mk extensions/CppunitTest_extensions_test_update.mk extensions/Executable_nsplugin.mk extensions/Executable_pluginapp.bin.mk extensions/Library_abp.mk extensions/Library_bib.mk extensions/Library_dbp.mk extensions/Library_ldapbe2.mk extensions/Library_log.mk extensions/Library_npsoplugin.mk extensions/Library_oleautobridge.mk extensions/Library_OOoSpotlightImporter.mk extensions/Library_pl.mk extensions/Library_res.mk extensions/Library_so_activex.mk extensions/Library_so_activex_x64.mk extensions/Library_updchk.mk extensions/Module_extensions.mk extensions/qa extensions/source extensions/WinResTarget_activex.mk extensions/Win ResTarget_npsoplugin.mk extensions/Zip_mdibundle.mk external/wine extras/source filter/Executable_svg2odf.mk filter/source forms/source formula/Library_for.mk formula/source fpicker/AllLangResTarget_fps_office.mk fpicker/Library_fpicker.mk fpicker/Library_fps_aqua.mk fpicker/Library_fps.mk fpicker/Library_fps_office.mk fpicker/Module_fpicker.mk fpicker/source framework/inc framework/source helpcompiler/Executable_helpindexer.mk helpcompiler/Executable_helplinker.mk helpcompiler/inc helpcompiler/Library_helplinker.mk helpcompiler/source helpcontent2 i18nlangtag/Library_i18nlangtag.mk i18npool/CppunitTest_i18npool_test_breakiterator.mk i18npool/CppunitTest_i18npool_test_characterclassification.mk i18npool/CustomTarget_breakiterator.mk i18npool/CustomTarget_collator.mk i18npool/CustomTarget_indexentry.mk i18npool/CustomTarget_localedata.mk i18npool/CustomTarget_textconversion.mk i18npool/Executable_gencoll_rule.mk i18npool/Executable_genconv_dict.mk i18npool/Executable_gendict. mk i18npool/Executable_genindex_data.mk i18npool/Executable_saxparser.mk i18npool/Library_collator_data.mk i18npool/Library_dict_ja.mk i18npool/Library_dict_zh.mk i18npool/Library_i18npool.mk i18npool/Library_i18nsearch.mk i18npool/Library_index_data.mk i18npool/Library_localedata_en.mk i18npool/Library_localedata_es.mk i18npool/Library_localedata_euro.mk i18npool/Library_localedata_others.mk i18npool/Library_textconv_dict.mk i18npool/Module_i18npool.mk i18npool/source idlc/Executable_idlc.mk include/basegfx include/connectivity include/drawinglayer include/editeng include/filter include/formula include/oox include/sal include/sax include/sfx2 include/svl include/svtools include/svx include/test include/tools include/tubes include/unoidl include/vcl include/xmloff instsetoo_native/config instsetoo_native/CustomTarget_setup.mk instsetoo_native/inc_ooohelppack instsetoo_native/inc_openoffice instsetoo_native/inc_sdkoo instsetoo_native/Module_instsetoo_native.mk instsetoo_nativ e/Package_config.mk instsetoo_native/Package_rdb.mk instsetoo_native/Package_setup.mk instsetoo_native/util l10ntools/Executable_cfgex.mk l10ntools/Executable_helpex.mk l10ntools/Executable_localize.mk l10ntools/Executable_transex3.mk l10ntools/Executable_ulfex.mk l10ntools/Executable_xrmex.mk l10ntools/Module_l10ntools.mk l10ntools/source l10ntools/StaticLibrary_transex.mk libcdr/libcdr-0.0.13.patch liblangtag/ExternalPackage_liblangtag_data.mk liblangtag/Module_liblangtag.mk liblangtag/Zip_liblangtag_data.mk liborcus/ExternalProject_liborcus.mk Library_merged.mk librelogo/source libxmlsec/ExternalProject_xmlsec.mk libxmlsec/xmlsec1-configure.patch lingucomponent/Library_guesslang.mk lingucomponent/Library_hyphen.mk lingucomponent/Library_lnth.mk lingucomponent/Library_MacOSXSpell.mk lingucomponent/Library_spell.mk lingucomponent/Module_lingucomponent.mk lingucomponent/Package_config.mk lingucomponent/StaticLibrary_ulingu.mk lotuswordpro/source Makefile.in MathMLDTD/Module_ MathMLDTD.mk MathMLDTD/Package_bin.mk Mesa/Module_Mesa.mk Mesa/Package_inc.mk nlpsolver/Extension_nlpsolver.mk nlpsolver/src np_sdk/Module_np_sdk.mk np_sdk/Package_inc.mk np_sdk/Package_npapi.mk np_sdk/StaticLibrary_nputils.mk odk/CppunitTest_checkapi.mk odk/CustomTarget_allheaders.mk odk/examples odk/pack offapi/com officecfg/CppunitTest_officecfg_cppheader_test.mk officecfg/CustomTarget_registry.mk officecfg/Package_cppheader.mk officecfg/registry oovbaapi/ooo oox/source package/Library_package2.mk package/Library_xstor.mk package/Module_package.mk package/Package_dtd.mk postprocess/CustomTarget_images.mk postprocess/Module_postprocess.mk postprocess/Package_images_install.mk postprocess/Package_images.mk postprocess/Package_registry_install.mk python3/CustomTarget_PythonFramework.mk python3/Zip_PythonFramework.mk pyuno/CustomTarget_python_bin.mk pyuno/CustomTarget_python_shell.mk pyuno/CustomTarget_zipcore.mk pyuno/Executable_python_wrapper.mk pyuno/Library_pythonloader.m k pyuno/Library_pyuno.mk pyuno/Library_pyuno_wrapper.mk pyuno/Module_pyuno.mk pyuno/Package_python_bin.mk pyuno/Package_python_scripts.mk pyuno/Package_python_shell.mk pyuno/Package_pyunorc.mk pyuno/Package_zipcore.mk qadevOOo/Jar_OOoRunnerLight.mk qadevOOo/Jar_OOoRunner.mk readlicense_oo/docs registry/Executable_regcompare.mk registry/Executable_regmerge.mk registry/Executable_regview.mk registry/Library_reg.mk registry/Module_registry.mk registry/StaticLibrary_registry_helper.mk Repository.mk rsc/Executable_rsc.mk rsc/Module_rsc.mk sal/CppunitTest_Module_DLL.mk sal/CppunitTest_sal_bytesequence.mk sal/CppunitTest_sal_osl_condition.mk sal/CppunitTest_sal_osl_file.mk sal/CppunitTest_sal_osl_getsystempathfromfileurl.mk sal/CppunitTest_sal_osl_module.mk sal/CppunitTest_sal_osl_old_test_file.mk sal/CppunitTest_sal_osl_process.mk sal/CppunitTest_sal_osl_security.mk sal/CppunitTest_sal_osl_thread.mk sal/CppunitTest_sal_rtl_alloc.mk sal/CppunitTest_sal_rtl_cipher.mk sal/CppunitTest _sal_rtl_crc32.mk sal/CppunitTest_sal_rtl_doublelock.mk sal/CppunitTest_sal_rtl_locale.mk sal/CppunitTest_sal_rtl_ostringbuffer.mk sal/CppunitTest_sal_rtl_oustringbuffer.mk sal/CppunitTest_sal_rtl_strings.mk sal/CppunitTest_sal_tcwf.mk sal/CppunitTest_sal_types.mk sal/Executable_cppunittester.mk sal/Executable_osl_process_child.mk salhelper/Library_salhelper.mk salhelper/Module_salhelper.mk sal/Library_lo-bootstrap.mk sal/Library_sal.mk sal/Library_sal_textenc.mk sal/Library_uwinapi.mk sal/osl sal/StaticLibrary_salcpprt.mk sane/Module_sane.mk sane/Package_inc.mk sc/CppunitTest_sc_annotationobj.mk sc/CppunitTest_sc_annotationsobj.mk sc/CppunitTest_sc_outlineobj.mk sc/inc sc/Library_sc.mk scp2/source sc/qa scripting/Jar_HelloWorld.mk scripting/Jar_Highlight.mk scripting/Jar_MemoryUsage.mk scripting/Jar_ScriptFramework.mk scripting/Jar_ScriptProviderForBeanShell.mk scripting/Jar_ScriptProviderForJava.mk scripting/Jar_ScriptProviderForJavaScript.mk scripting/Library_basprov.mk s cripting/Library_dlgprov.mk scripting/Library_protocolhandler.mk scripting/Library_scriptframe.mk scripting/Library_stringresource.mk scripting/Library_vbaevents.mk scripting/Module_scripting.mk scripting/Package_scriptbindinglib.mk scripting/Package_ScriptsBeanShell.mk scripting/Package_ScriptsJavaScript.mk scripting/Package_ScriptsPython.mk scripting/Pyuno_mailmerge.mk scripting/source scripting/Zip_ScriptsJava.mk sc/sdi sc/source sd/AllLangResTarget_sd.mk sdext/Executable_pdf2xml.mk sdext/Executable_pdfunzip.mk sdext/source sd/inc sd/sdi sd/source sd/uiconfig sd/UIConfig_sdraw.mk sd/UIConfig_simpress.mk setup_native/source sfx2/inc sfx2/sdi sfx2/source shell/source smoketest/CppunitTest_smoketest.mk smoketest/Jar_TestExtension.mk smoketest/Library_smoketest.mk smoketest/lodownloadtest.py smoketest/losmoketest smoketest/Module_smoketest.mk smoketest/Package_losmoketest.mk smoketest/Zip_smoketestdoc.mk solenv/bin solenv/gbuild solenv/gdb solenv/Module_solenv.mk solenv/Packa ge_gdb_install.mk starmath/inc starmath/qa starmath/source store/Library_store.mk store/Module_store.mk svl/CppunitTest_svl_lngmisc.mk svl/CppunitTest_svl_urihelper.mk svl/qa svl/source svtools/source svx/source svx/uiconfig svx/UIConfig_svx.mk sw/AllLangResTarget_sw.mk swext/Configuration_mediawiki.mk swext/Extension_wiki-publisher.mk swext/Jar_mediawiki.mk swext/Module_swext.mk sw/inc sw/PythonTest_sw_python.mk sw/qa sw/sdi sw/source sw/uiconfig sw/UIConfig_swriter.mk test/source testtools/CustomTarget_bridgetest_climaker.mk testtools/CustomTarget_bridgetest_javamaker.mk testtools/CustomTarget_bridgetest.mk testtools/CustomTarget_uno_test.mk testtools/InternalUnoApi_bridgetest.mk testtools/Jar_testComponent.mk testtools/Library_bridgetest.mk testtools/Library_constructors.mk testtools/Library_cppobj.mk testtools/Module_testtools.mk testtools/Rdb_uno_services.mk testtools/StaticLibrary_bridgetest.mk test/user-template toolkit/source tools/qa tools/source touch/CustomTarget_ touch_javamaker.mk touch/idl touch/InternalUnoApi_touch.mk touch/Library_libotouch.mk touch/Module_touch.mk touch/source tubes/Executable_liboapprover.mk tubes/source twain/Module_twain.mk twain/Package_inc.mk ucb/Library_cached1.mk ucb/Library_srtrs1.mk ucb/Library_ucb1.mk ucb/Library_ucpcmis1.mk ucb/Library_ucpdav1.mk ucb/Library_ucpexpand1.mk ucb/Library_ucpext.mk ucb/Library_ucpfile1.mk ucb/Library_ucpftp1.mk ucb/Library_ucpgio1.mk ucb/Library_ucpgvfs1.mk ucb/Library_ucphier1.mk ucb/Library_ucppkg1.mk ucb/Library_ucptdoc1.mk ucb/source unixODBC/Module_unixODBC.mk unixODBC/Package_inc.mk unodevtools/Executable_skeletonmaker.mk unodevtools/Module_unodevtools.mk unodevtools/source unoil/CustomTarget_climaker.mk unotest/Jar_test.mk unotest/Jar_test-tools.mk unotest/Library_unobootstrapprotector.mk unotest/Library_unoexceptionprotector.mk unotest/Library_unotest.mk unotest/Module_unotest.mk unotest/source ure/source uui/AllLangResTarget_uui.mk uui/Library_uui.mk uui/Module_uu i.mk uui/source vcl/Executable_kdefilepicker.mk vcl/Executable_tdefilepicker.mk vcl/generic vcl/headless vcl/inc vcl/Module_vcl.mk vcl/Package_osxres.mk vcl/source vcl/StaticLibrary_headless.mk vcl/unx vcl/Zip_osxres.mk writerfilter/source xmerge/Jar_XMergeBridge.mk xmerge/Jar_xmerge.mk xmerge/Module_xmerge.mk xmlhelp/Module_xmlhelp.mk xmlhelp/Package_helpxsl.mk xmlhelp/Zip_helpxsl.mk xmloff/source xmlsecurity/AllLangResTarget_xsec.mk xmlsecurity/CppunitTest_qa_certext.mk xmlsecurity/Library_xmlsecurity.mk xmlsecurity/Library_xsec_fw.mk xmlsecurity/Library_xsec_xmlsec.mk xmlsecurity/Module_xmlsecurity.mk xmlsecurity/source

Kohei Yoshida kohei.yoshida at gmail.com
Tue Apr 30 08:31:15 PDT 2013


Rebased ref, commits from common ancestor:
commit 69abbc7fe5721b7dc8fa7111595a346c3961bf24
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Apr 30 11:27:46 2013 -0400

    Surpress warning on comparison between signed and unsigned.
    
    Change-Id: Ia155114817e3b28a201f734647b758cf7cebefce

diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index c554e9c..1ee57b5 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -39,7 +39,7 @@ bool FormulaGroupInterpreter::interpret()
                 {
                     const formula::SingleVectorRefToken* p2 = static_cast<const formula::SingleVectorRefToken*>(p);
                     const double* pArray = p2->GetArray();
-                    aCode2.AddDouble(i < p2->GetArrayLength() ? pArray[i] : 0.0);
+                    aCode2.AddDouble(static_cast<size_t>(i) < p2->GetArrayLength() ? pArray[i] : 0.0);
                 }
                 break;
                 case formula::svDoubleVectorRef:
commit e12855c3f8bbfe630d89b017ce10ccb7694efdc7
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Apr 30 11:24:29 2013 -0400

    Ensure that modified formula cells are redrawn.
    
    ScFormulaCell::bChanged is responsible for this, though, we should only
    set it to true for visible cells only. That's a TODO for later.
    
    Change-Id: Ic237c45fb271f901320f4843c89710aedd16c906

diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 2a8546f..2d0d04c 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -192,7 +192,7 @@ public:
     void            FindRangeNamesInUse(std::set<sal_uInt16>& rIndexes) const;
     bool            IsSubTotal() const                      { return bSubTotal; }
     bool            IsChanged() const;
-    void            ResetChanged();
+    void SetChanged(bool b);
     bool            IsEmpty();      // formula::svEmptyCell result
                     // display as empty string if formula::svEmptyCell result
     bool            IsEmptyDisplayedAsString();
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index da9aa3c..2933e9f 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -2382,7 +2382,7 @@ void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
         {
             ScBaseCell* pCell = maItems[nIndex].pCell;
             if (pCell->GetCellType() == CELLTYPE_FORMULA)
-                ((ScFormulaCell*)pCell)->ResetChanged();
+                ((ScFormulaCell*)pCell)->SetChanged(false);
             ++nIndex;
         }
     }
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index d271edc..80305c2 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2730,9 +2730,9 @@ bool ScFormulaCell::IsChanged() const
     return bChanged;
 }
 
-void ScFormulaCell::ResetChanged()
+void ScFormulaCell::SetChanged(bool b)
 {
-    bChanged = false;
+    bChanged = b;
 }
 
 void ScFormulaCell::CompileDBFormula()
@@ -3153,8 +3153,7 @@ bool ScFormulaCell::InterpretInvariantFormulaGroup()
         // Ensure the cell truly has a result:
         pCell->aResult = aResult;
         pCell->ResetDirty();
-
-        // FIXME: there is a view / refresh missing here it appears.
+        pCell->SetChanged(true);
     }
 
     return true;
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 9f76fe2..c554e9c 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -88,7 +88,10 @@ bool FormulaGroupInterpreter::interpret()
 
         pDest->SetResultToken(aInterpreter.GetResultToken().get());
         pDest->ResetDirty();
+        pDest->SetChanged(true);
     }
+
+    return true;
 }
 
 }
diff --git a/sc/source/filter/oox/formulabuffer.cxx b/sc/source/filter/oox/formulabuffer.cxx
index 6a934dc..eba84aba 100644
--- a/sc/source/filter/oox/formulabuffer.cxx
+++ b/sc/source/filter/oox/formulabuffer.cxx
@@ -151,7 +151,7 @@ void FormulaBuffer::applyCellFormulaValues( const std::vector< ValueAddressPair
         {
             pCell->SetHybridDouble( it->second );
             pCell->ResetDirty();
-            pCell->ResetChanged();
+            pCell->SetChanged(false);
         }
     }
 }
diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx
index 6006181..dc40193 100644
--- a/sc/source/ui/unoobj/cellsuno.cxx
+++ b/sc/source/ui/unoobj/cellsuno.cxx
@@ -6609,7 +6609,7 @@ void SAL_CALL ScCellObj::setFormulaResult( double nValue ) throw(uno::RuntimeExc
         ScFormulaCell* pCell = pDocSh->GetDocument()->GetFormulaCell(aCellPos);
         pCell->SetHybridDouble( nValue );
         pCell->ResetDirty();
-        pCell->ResetChanged();
+        pCell->SetChanged(false);
     }
 }
 
commit eff234a35478b01bde4cd044311c2697cbf51397
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Apr 30 11:16:21 2013 -0400

    Move the group calculation code into its own class.
    
    To isolate the code that will be re-written for true vectorized
    calculation...
    
    Change-Id: I3ccd15841ed6fcdc6a22a590ba82d46d0b4863c5

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index fe5b4b1..f7be65cc 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -190,6 +190,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
 	sc/source/core/tool/doubleref \
 	sc/source/core/tool/editutil \
 	sc/source/core/tool/filtopt \
+	sc/source/core/tool/formulagroup \
 	sc/source/core/tool/formulaopt \
 	sc/source/core/tool/formulaparserpool \
 	sc/source/core/tool/formularesult \
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index e70f108..e0773aa 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -82,8 +82,6 @@ struct ScFormulaCellGroup;
 struct ScRefCellValue;
 class ScDocumentImport;
 
-typedef ::boost::intrusive_ptr<ScFormulaCellGroup> ScFormulaCellGroupRef;
-
 struct ScNeededSizeOptions
 {
     const ScPatternAttr*    pPattern;
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index e4f1cfa..2a8546f 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -51,8 +51,6 @@ inline void intrusive_ptr_release(ScFormulaCellGroup *p)
         delete p;
 }
 
-typedef ::boost::intrusive_ptr<ScFormulaCellGroup> ScFormulaCellGroupRef;
-
 enum ScMatrixMode {
     MM_NONE      = 0,                   // No matrix formula
     MM_FORMULA   = 1,                   // Upper left matrix formula cell
@@ -282,6 +280,8 @@ public:
      */
     void            SetResultDouble( double n )     { aResult.SetDouble( n); }
 
+    void SetResultToken( const formula::FormulaToken* pToken );
+
     double GetResultDouble() const { return aResult.GetDouble(); }
 
     void            SetErrCode( sal_uInt16 n );
diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
index 0a8e3f7..55f6e09 100644
--- a/sc/inc/formulagroup.hxx
+++ b/sc/inc/formulagroup.hxx
@@ -10,9 +10,15 @@
 #ifndef SC_FORMULAGROUP_HXX
 #define SC_FORMULAGROUP_HXX
 
+#include "address.hxx"
+#include "types.hxx"
+
 #include <boost/noncopyable.hpp>
 #include <boost/ptr_container/ptr_vector.hpp>
 
+class ScDocument;
+class ScTokenArray;
+
 namespace sc {
 
 struct FormulaGroupContext : boost::noncopyable
@@ -23,6 +29,22 @@ struct FormulaGroupContext : boost::noncopyable
     ArrayStoreType maArrays;
 };
 
+/**
+ * All the vectorized formula calculation code should be collectd here.
+ */
+class FormulaGroupInterpreter
+{
+    ScDocument& mrDoc;
+    ScAddress maTopPos;
+    ScFormulaCellGroupRef mxGroup;
+    ScTokenArray& mrCode;
+public:
+    FormulaGroupInterpreter(
+        ScDocument& rDoc, const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode);
+
+    bool interpret();
+};
+
 }
 
 #endif
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 1af6e2d..9654271c4 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -20,6 +20,9 @@ typedef ::boost::intrusive_ptr<const ScMatrix>  ScConstMatrixRef;
 class ScToken;
 typedef ::boost::intrusive_ptr<ScToken> ScTokenRef;
 
+struct ScFormulaCellGroup;
+typedef ::boost::intrusive_ptr<ScFormulaCellGroup> ScFormulaCellGroupRef;
+
 /**
  * When vectorization is enabled, we could potentially mass-calculate a
  * series of formula token arrays in adjacent formula cells in one step,
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 2e20d0f..c93e043 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1665,7 +1665,6 @@ bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow
 const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& /*rCxt*/, SCROW nRow1, SCROW nRow2 ) const
 {
     // TODO: I'll use the context object later.
-
     if (nRow1 > nRow2)
         return NULL;
 
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 3e85a9e..d271edc 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -1611,6 +1611,10 @@ bool ScFormulaCell::IsDirtyOrInTableOpDirty() const
     return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp());
 }
 
+void ScFormulaCell::SetResultToken( const formula::FormulaToken* pToken )
+{
+    aResult.SetToken(pToken);
+}
 
 void ScFormulaCell::SetErrCode( sal_uInt16 n )
 {
@@ -3071,77 +3075,8 @@ bool ScFormulaCell::InterpretFormulaGroup()
         }
     }
 
-#if 0
-    // TODO: Calculate the formula group via vectorization.
-#else
-    // Until we implement group calculation for real, decompose the group into
-    // individual formula token arrays for individual calculation.
-    ScAddress aTmpPos = aPos;
-    for (sal_Int32 i = 0; i < xGroup->mnLength; ++i)
-    {
-        aTmpPos.SetRow(xGroup->mnStart + i);
-        ScTokenArray aCode2;
-        for (const formula::FormulaToken* p = aCode.First(); p; p = aCode.Next())
-        {
-            switch (p->GetType())
-            {
-                case svSingleVectorRef:
-                {
-                    const formula::SingleVectorRefToken* p2 = static_cast<const formula::SingleVectorRefToken*>(p);
-                    const double* pArray = p2->GetArray();
-                    aCode2.AddDouble(i < p2->GetArrayLength() ? pArray[i] : 0.0);
-                }
-                break;
-                case svDoubleVectorRef:
-                {
-                    const formula::DoubleVectorRefToken* p2 = static_cast<const formula::DoubleVectorRefToken*>(p);
-                    const std::vector<const double*>& rArrays = p2->GetArrays();
-                    size_t nColSize = rArrays.size();
-                    size_t nRowStart = p2->IsStartFixed() ? 0 : i;
-                    size_t nRowEnd = p2->GetRefRowSize() - 1;
-                    if (!p2->IsEndFixed())
-                        nRowEnd += i;
-
-                    size_t nRowSize = nRowEnd - nRowStart + 1;
-                    ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize, 0.0));
-                    for (size_t nCol = 0; nCol < nColSize; ++nCol)
-                    {
-                        const double* pArray = rArrays[nCol];
-                        for (size_t nRow = 0; nRow < nRowSize; ++nRow)
-                        {
-                            if (nRowStart + nRow < p2->GetArrayLength())
-                            {
-                                double fVal = pArray[nRowStart+nRow];
-                                pMat->PutDouble(fVal, nCol, nRow);
-                            }
-                        }
-                    }
-
-                    ScMatrixToken aTok(pMat);
-                    aCode2.AddToken(aTok);
-                }
-                break;
-                default:
-                    aCode2.AddToken(*p);
-            }
-        }
-
-        ScFormulaCell* pDest = pDocument->GetFormulaCell(aTmpPos);
-        if (!pDest)
-            return false;
-
-        ScCompiler aComp(pDocument, aPos, aCode2);
-        aComp.SetGrammar(pDocument->GetGrammar());
-        aComp.CompileTokenArray(); // Create RPN token array.
-        ScInterpreter aInterpreter(pDest, pDocument, aTmpPos, aCode2);
-        aInterpreter.Interpret();
-
-        pDest->aResult.SetToken(aInterpreter.GetResultToken().get());
-        pDest->ResetDirty();
-    }
-
-    return true;
-#endif
+    sc::FormulaGroupInterpreter aInterpreter(*pDocument, aPos, xGroup, aCode);
+    return aInterpreter.interpret();
 }
 
 bool ScFormulaCell::InterpretInvariantFormulaGroup()
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
new file mode 100644
index 0000000..9f76fe2
--- /dev/null
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -0,0 +1,96 @@
+/* -*- 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 "formulagroup.hxx"
+#include "document.hxx"
+#include "formulacell.hxx"
+#include "tokenarray.hxx"
+#include "compiler.hxx"
+#include "interpre.hxx"
+
+#include "formula/vectortoken.hxx"
+
+namespace sc {
+
+FormulaGroupInterpreter::FormulaGroupInterpreter(
+    ScDocument& rDoc, const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode) :
+    mrDoc(rDoc), maTopPos(rTopPos), mxGroup(xGroup), mrCode(rCode) {}
+
+bool FormulaGroupInterpreter::interpret()
+{
+    // Until we implement group calculation for real, decompose the group into
+    // individual formula token arrays for individual calculation.
+    ScAddress aTmpPos = maTopPos;
+    for (sal_Int32 i = 0; i < mxGroup->mnLength; ++i)
+    {
+        aTmpPos.SetRow(mxGroup->mnStart + i);
+        ScTokenArray aCode2;
+        for (const formula::FormulaToken* p = mrCode.First(); p; p = mrCode.Next())
+        {
+            switch (p->GetType())
+            {
+                case formula::svSingleVectorRef:
+                {
+                    const formula::SingleVectorRefToken* p2 = static_cast<const formula::SingleVectorRefToken*>(p);
+                    const double* pArray = p2->GetArray();
+                    aCode2.AddDouble(i < p2->GetArrayLength() ? pArray[i] : 0.0);
+                }
+                break;
+                case formula::svDoubleVectorRef:
+                {
+                    const formula::DoubleVectorRefToken* p2 = static_cast<const formula::DoubleVectorRefToken*>(p);
+                    const std::vector<const double*>& rArrays = p2->GetArrays();
+                    size_t nColSize = rArrays.size();
+                    size_t nRowStart = p2->IsStartFixed() ? 0 : i;
+                    size_t nRowEnd = p2->GetRefRowSize() - 1;
+                    if (!p2->IsEndFixed())
+                        nRowEnd += i;
+
+                    size_t nRowSize = nRowEnd - nRowStart + 1;
+                    ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize, 0.0));
+                    for (size_t nCol = 0; nCol < nColSize; ++nCol)
+                    {
+                        const double* pArray = rArrays[nCol];
+                        for (size_t nRow = 0; nRow < nRowSize; ++nRow)
+                        {
+                            if (nRowStart + nRow < p2->GetArrayLength())
+                            {
+                                double fVal = pArray[nRowStart+nRow];
+                                pMat->PutDouble(fVal, nCol, nRow);
+                            }
+                        }
+                    }
+
+                    ScMatrixToken aTok(pMat);
+                    aCode2.AddToken(aTok);
+                }
+                break;
+                default:
+                    aCode2.AddToken(*p);
+            }
+        }
+
+        ScFormulaCell* pDest = mrDoc.GetFormulaCell(aTmpPos);
+        if (!pDest)
+            return false;
+
+        ScCompiler aComp(&mrDoc, aTmpPos, aCode2);
+        aComp.SetGrammar(mrDoc.GetGrammar());
+        aComp.CompileTokenArray(); // Create RPN token array.
+        ScInterpreter aInterpreter(pDest, &mrDoc, aTmpPos, aCode2);
+        aInterpreter.Interpret();
+
+        pDest->SetResultToken(aInterpreter.GetResultToken().get());
+        pDest->ResetDirty();
+    }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 70eef961cd9a1d1f79a120d03c85caf435667a26
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Apr 30 10:19:58 2013 -0400

    Typo.
    
    Change-Id: I46eba8fff2a1b18d267b0fce0bb1a2abcce779a8

diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 34be0d1..7abc279 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2149,7 +2149,7 @@ const double* ScTable::FetchDoubleArray(
     if (!ValidCol(nCol) || !ValidRow(nRow1) || !ValidRow(nRow2))
         return NULL;
 
-    return aCol[nCol].FetchDoubleArray(rCxt, nRow1, nRow1);
+    return aCol[nCol].FetchDoubleArray(rCxt, nRow1, nRow2);
 }
 
 ScRefCellValue ScTable::GetRefCellValue( SCCOL nCol, SCROW nRow )
commit 4a1a06fa745c286e36f4e1851f7bce3a6788fa7a
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Apr 30 10:01:43 2013 -0400

    Reset dirty.
    
    Change-Id: I20a8b56a9241081192e32b3d3a0de9295277e38a

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 7158b69..3e85a9e 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3137,6 +3137,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
         aInterpreter.Interpret();
 
         pDest->aResult.SetToken(aInterpreter.GetResultToken().get());
+        pDest->ResetDirty();
     }
 
     return true;
commit 813ee7db3fc3b60157831421a75fe4a198fd1a5e
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Apr 29 19:27:41 2013 -0400

    We don't need this code.
    
    Change-Id: I7be5869672be17faefd369d03f69cac5ed2d03b6

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 7e85225..7158b69 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3132,8 +3132,6 @@ bool ScFormulaCell::InterpretFormulaGroup()
 
         ScCompiler aComp(pDocument, aPos, aCode2);
         aComp.SetGrammar(pDocument->GetGrammar());
-        OUStringBuffer aBuf;
-        aComp.CreateStringFromTokenArray(aBuf);
         aComp.CompileTokenArray(); // Create RPN token array.
         ScInterpreter aInterpreter(pDest, pDocument, aTmpPos, aCode2);
         aInterpreter.Interpret();
commit 55d32c03b481762a35543d0907cd22e4269959a8
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Apr 29 19:19:48 2013 -0400

    Handle range references for group calculation. This is still untested.
    
    Change-Id: I1eb1c217db66615028faa85720838579056dc150

diff --git a/formula/source/core/api/vectortoken.cxx b/formula/source/core/api/vectortoken.cxx
index e016fd3..74339397 100644
--- a/formula/source/core/api/vectortoken.cxx
+++ b/formula/source/core/api/vectortoken.cxx
@@ -12,11 +12,11 @@
 namespace formula {
 
 SingleVectorRefToken::SingleVectorRefToken( const double* pArray, size_t nLength ) :
-    FormulaToken(svSingleVectorRef, ocPush), mpArray(pArray), mnLength(nLength) {}
+    FormulaToken(svSingleVectorRef, ocPush), mpArray(pArray), mnArrayLength(nLength) {}
 
 FormulaToken* SingleVectorRefToken::Clone() const
 {
-    return new SingleVectorRefToken(mpArray, mnLength);
+    return new SingleVectorRefToken(mpArray, mnArrayLength);
 }
 
 const double* SingleVectorRefToken::GetArray() const
@@ -24,19 +24,19 @@ const double* SingleVectorRefToken::GetArray() const
     return mpArray;
 }
 
-size_t SingleVectorRefToken::GetLength() const
+size_t SingleVectorRefToken::GetArrayLength() const
 {
-    return mnLength;
+    return mnArrayLength;
 }
 
 DoubleVectorRefToken::DoubleVectorRefToken(
-    const std::vector<const double*>& rArrays, size_t nRowSize, bool bAbsStart, bool bAbsEnd ) :
+    const std::vector<const double*>& rArrays, size_t nArrayLength, size_t nRefRowSize, bool bStartFixed, bool bEndFixed ) :
     FormulaToken(svDoubleVectorRef, ocPush),
-    maArrays(rArrays), mnRowSize(nRowSize), mbAbsStart(bAbsStart), mbAbsEnd(bAbsEnd) {}
+    maArrays(rArrays), mnArrayLength(nArrayLength), mnRefRowSize(nRefRowSize), mbStartFixed(bStartFixed), mbEndFixed(bEndFixed) {}
 
 FormulaToken* DoubleVectorRefToken::Clone() const
 {
-    return new DoubleVectorRefToken(maArrays, mnRowSize, mbAbsStart, mbAbsEnd);
+    return new DoubleVectorRefToken(maArrays, mnArrayLength, mnRefRowSize, mbStartFixed, mbEndFixed);
 }
 
 const std::vector<const double*>& DoubleVectorRefToken::GetArrays() const
@@ -44,6 +44,26 @@ const std::vector<const double*>& DoubleVectorRefToken::GetArrays() const
     return maArrays;
 }
 
+size_t DoubleVectorRefToken::GetArrayLength() const
+{
+    return mnArrayLength;
+}
+
+size_t DoubleVectorRefToken::GetRefRowSize() const
+{
+    return mnRefRowSize;
+}
+
+bool DoubleVectorRefToken::IsStartFixed() const
+{
+    return mbStartFixed;
+}
+
+bool DoubleVectorRefToken::IsEndFixed() const
+{
+    return mbEndFixed;
+}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/formula/vectortoken.hxx b/include/formula/vectortoken.hxx
index db44355..2679b4e 100644
--- a/include/formula/vectortoken.hxx
+++ b/include/formula/vectortoken.hxx
@@ -17,7 +17,7 @@ namespace formula {
 class FORMULA_DLLPUBLIC SingleVectorRefToken : public FormulaToken
 {
     const double* mpArray;
-    size_t mnLength;
+    size_t mnArrayLength;
 
 public:
     SingleVectorRefToken( const double* pArray, size_t nLength );
@@ -25,7 +25,7 @@ public:
     virtual FormulaToken* Clone() const;
 
     const double* GetArray() const;
-    size_t GetLength() const;
+    size_t GetArrayLength() const;
 };
 
 /**
@@ -36,18 +36,23 @@ class FORMULA_DLLPUBLIC DoubleVectorRefToken : public FormulaToken
 {
     std::vector<const double*> maArrays;
 
-    size_t mnRowSize;
+    size_t mnArrayLength;
+    size_t mnRefRowSize;
 
-    bool mbAbsStart:1; /// whether or not the start row position is absolute.
-    bool mbAbsEnd:1; /// whether or not the end row position is absolute.
+    bool mbStartFixed:1; /// whether or not the start row position is absolute.
+    bool mbEndFixed:1; /// whether or not the end row position is absolute.
 
 public:
     DoubleVectorRefToken(
-        const std::vector<const double*>& rArrays, size_t nRowSize, bool bAbsStart, bool bAbsEnd );
+        const std::vector<const double*>& rArrays, size_t nArrayLength, size_t nRefRowSize, bool bStartFixed, bool bEndFixed );
 
     virtual FormulaToken* Clone() const;
 
     const std::vector<const double*>& GetArrays() const;
+    size_t GetArrayLength() const;
+    size_t GetRefRowSize() const;
+    bool IsStartFixed() const;
+    bool IsEndFixed() const;
 };
 
 }
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 5987253..7e85225 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3030,24 +3030,25 @@ bool ScFormulaCell::InterpretFormulaGroup()
                     size_t nCols = aRef.Ref2.nCol - aRef.Ref1.nCol + 1;
                     std::vector<const double*> aArrays;
                     aArrays.reserve(nCols);
-                    SCROW nLength = xGroup->mnLength;
+                    SCROW nArrayLength = xGroup->mnLength;
+                    SCROW nRefRowSize = aRef.Ref2.nRow - aRef.Ref1.nRow + 1;
                     if (!bAbsLast)
                     {
-                        // range end position is relative. Extend it.
-                        nLength += aRef.Ref2.nRow - aRef.Ref1.nRow;
+                        // range end position is relative. Extend the array length.
+                        nArrayLength += nRefRowSize - 1;
                     }
 
                     for (SCCOL i = aRef.Ref1.nCol; i <= aRef.Ref2.nCol; ++i)
                     {
                         aRefPos.SetCol(i);
-                        const double* pArray = pDocument->FetchDoubleArray(aCxt, aRefPos, nLength);
+                        const double* pArray = pDocument->FetchDoubleArray(aCxt, aRefPos, nArrayLength);
                         if (!pArray)
                             return false;
 
                         aArrays.push_back(pArray);
                     }
 
-                    formula::DoubleVectorRefToken aTok(aArrays, nLength, bAbsFirst, bAbsLast);
+                    formula::DoubleVectorRefToken aTok(aArrays, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast);
                     aCode.AddToken(aTok);
                 }
                 else
@@ -3088,11 +3089,37 @@ bool ScFormulaCell::InterpretFormulaGroup()
                 {
                     const formula::SingleVectorRefToken* p2 = static_cast<const formula::SingleVectorRefToken*>(p);
                     const double* pArray = p2->GetArray();
-                    aCode2.AddDouble(pArray[i]);
+                    aCode2.AddDouble(i < p2->GetArrayLength() ? pArray[i] : 0.0);
                 }
                 break;
                 case svDoubleVectorRef:
-                    return false;
+                {
+                    const formula::DoubleVectorRefToken* p2 = static_cast<const formula::DoubleVectorRefToken*>(p);
+                    const std::vector<const double*>& rArrays = p2->GetArrays();
+                    size_t nColSize = rArrays.size();
+                    size_t nRowStart = p2->IsStartFixed() ? 0 : i;
+                    size_t nRowEnd = p2->GetRefRowSize() - 1;
+                    if (!p2->IsEndFixed())
+                        nRowEnd += i;
+
+                    size_t nRowSize = nRowEnd - nRowStart + 1;
+                    ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize, 0.0));
+                    for (size_t nCol = 0; nCol < nColSize; ++nCol)
+                    {
+                        const double* pArray = rArrays[nCol];
+                        for (size_t nRow = 0; nRow < nRowSize; ++nRow)
+                        {
+                            if (nRowStart + nRow < p2->GetArrayLength())
+                            {
+                                double fVal = pArray[nRowStart+nRow];
+                                pMat->PutDouble(fVal, nCol, nRow);
+                            }
+                        }
+                    }
+
+                    ScMatrixToken aTok(pMat);
+                    aCode2.AddToken(aTok);
+                }
                 break;
                 default:
                     aCode2.AddToken(*p);
commit 4eca65f05aca10e5dc8d0cfd82e9e781d0d766ff
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Apr 29 17:51:41 2013 -0400

    Handle range reference as well for group calculation. Not tested yet.
    
    Change-Id: I3bf58a20f0b8c017862ae23202e4b2272f7c952c

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index ba039b6..5987253 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3023,8 +3023,32 @@ bool ScFormulaCell::InterpretFormulaGroup()
                 aRef.CalcAbsIfRel(aPos);
                 if (aRef.Ref1.IsRowRel() || aRef.Ref2.IsRowRel())
                 {
-                    // TODO: Implement this.
-                    return false;
+                    // Row reference is relative.
+                    bool bAbsFirst = !aRef.Ref1.IsRowRel();
+                    bool bAbsLast = !aRef.Ref2.IsRowRel();
+                    ScAddress aRefPos(aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab);
+                    size_t nCols = aRef.Ref2.nCol - aRef.Ref1.nCol + 1;
+                    std::vector<const double*> aArrays;
+                    aArrays.reserve(nCols);
+                    SCROW nLength = xGroup->mnLength;
+                    if (!bAbsLast)
+                    {
+                        // range end position is relative. Extend it.
+                        nLength += aRef.Ref2.nRow - aRef.Ref1.nRow;
+                    }
+
+                    for (SCCOL i = aRef.Ref1.nCol; i <= aRef.Ref2.nCol; ++i)
+                    {
+                        aRefPos.SetCol(i);
+                        const double* pArray = pDocument->FetchDoubleArray(aCxt, aRefPos, nLength);
+                        if (!pArray)
+                            return false;
+
+                        aArrays.push_back(pArray);
+                    }
+
+                    formula::DoubleVectorRefToken aTok(aArrays, nLength, bAbsFirst, bAbsLast);
+                    aCode.AddToken(aTok);
                 }
                 else
                 {
commit 2d57b42b778a99b7e003b8aecc5c08bb418c4315
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Apr 29 17:30:23 2013 -0400

    Let's not use VectorArray struct. There is no use for it.
    
    Change-Id: Ic011143206c13fcbc1b3403bf5b7df46c6934899

diff --git a/formula/source/core/api/vectortoken.cxx b/formula/source/core/api/vectortoken.cxx
index 94a071c..e016fd3 100644
--- a/formula/source/core/api/vectortoken.cxx
+++ b/formula/source/core/api/vectortoken.cxx
@@ -11,24 +11,26 @@
 
 namespace formula {
 
-VectorArray::VectorArray( const double* pArray, size_t nLength ) :
-    mpArray(pArray), mnLength(nLength) {}
-
 SingleVectorRefToken::SingleVectorRefToken( const double* pArray, size_t nLength ) :
-    FormulaToken(svSingleVectorRef, ocPush), maArray(pArray, nLength) {}
+    FormulaToken(svSingleVectorRef, ocPush), mpArray(pArray), mnLength(nLength) {}
 
 FormulaToken* SingleVectorRefToken::Clone() const
 {
-    return new SingleVectorRefToken(maArray.mpArray, maArray.mnLength);
+    return new SingleVectorRefToken(mpArray, mnLength);
+}
+
+const double* SingleVectorRefToken::GetArray() const
+{
+    return mpArray;
 }
 
-const VectorArray& SingleVectorRefToken::GetArray() const
+size_t SingleVectorRefToken::GetLength() const
 {
-    return maArray;
+    return mnLength;
 }
 
 DoubleVectorRefToken::DoubleVectorRefToken(
-    const std::vector<VectorArray>& rArrays, size_t nRowSize, bool bAbsStart, bool bAbsEnd ) :
+    const std::vector<const double*>& rArrays, size_t nRowSize, bool bAbsStart, bool bAbsEnd ) :
     FormulaToken(svDoubleVectorRef, ocPush),
     maArrays(rArrays), mnRowSize(nRowSize), mbAbsStart(bAbsStart), mbAbsEnd(bAbsEnd) {}
 
@@ -37,7 +39,7 @@ FormulaToken* DoubleVectorRefToken::Clone() const
     return new DoubleVectorRefToken(maArrays, mnRowSize, mbAbsStart, mbAbsEnd);
 }
 
-const std::vector<VectorArray>& DoubleVectorRefToken::GetArrays() const
+const std::vector<const double*>& DoubleVectorRefToken::GetArrays() const
 {
     return maArrays;
 }
diff --git a/include/formula/vectortoken.hxx b/include/formula/vectortoken.hxx
index 82051d4..db44355 100644
--- a/include/formula/vectortoken.hxx
+++ b/include/formula/vectortoken.hxx
@@ -14,23 +14,18 @@
 
 namespace formula {
 
-struct VectorArray
+class FORMULA_DLLPUBLIC SingleVectorRefToken : public FormulaToken
 {
     const double* mpArray;
     size_t mnLength;
 
-    VectorArray( const double* pArray, size_t nLength );
-};
-
-class FORMULA_DLLPUBLIC SingleVectorRefToken : public FormulaToken
-{
-    const VectorArray maArray;
 public:
     SingleVectorRefToken( const double* pArray, size_t nLength );
 
     virtual FormulaToken* Clone() const;
 
-    const VectorArray& GetArray() const;
+    const double* GetArray() const;
+    size_t GetLength() const;
 };
 
 /**
@@ -39,7 +34,7 @@ public:
  */
 class FORMULA_DLLPUBLIC DoubleVectorRefToken : public FormulaToken
 {
-    std::vector<VectorArray> maArrays;
+    std::vector<const double*> maArrays;
 
     size_t mnRowSize;
 
@@ -48,11 +43,11 @@ class FORMULA_DLLPUBLIC DoubleVectorRefToken : public FormulaToken
 
 public:
     DoubleVectorRefToken(
-        const std::vector<VectorArray>& rArrays, size_t nRowSize, bool bAbsStart, bool bAbsEnd );
+        const std::vector<const double*>& rArrays, size_t nRowSize, bool bAbsStart, bool bAbsEnd );
 
     virtual FormulaToken* Clone() const;
 
-    const std::vector<VectorArray>& GetArrays() const;
+    const std::vector<const double*>& GetArrays() const;
 };
 
 }
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 5753e44..ba039b6 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3063,8 +3063,8 @@ bool ScFormulaCell::InterpretFormulaGroup()
                 case svSingleVectorRef:
                 {
                     const formula::SingleVectorRefToken* p2 = static_cast<const formula::SingleVectorRefToken*>(p);
-                    const formula::VectorArray& rArray = p2->GetArray();
-                    aCode2.AddDouble(rArray.mpArray[i]);
+                    const double* pArray = p2->GetArray();
+                    aCode2.AddDouble(pArray[i]);
                 }
                 break;
                 case svDoubleVectorRef:
commit 1333793da34c664a09ba4b34e13e86069e53b5b1
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Apr 29 17:22:31 2013 -0400

    Some comment.
    
    Change-Id: Ie7015231944547254562031864e7691333f02947

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 236474d..5753e44 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2993,6 +2993,12 @@ bool ScFormulaCell::InterpretFormulaGroup()
                     // Fetch double array guarantees that the length of the
                     // returned array equals or greater than the requested
                     // length.
+
+                    // TODO: For now, it returns an array pointer only when
+                    // the entire array is in contiguous memory space.  Once
+                    // we finish cell storage rework, we'll support temporary
+                    // generation of a double array which is a combination of
+                    // multiple cell array segments.
                     const double* pArray = pDocument->FetchDoubleArray(aCxt, aRefPos, xGroup->mnLength);
                     if (!pArray)
                         return false;
commit b9ac1d59bb0ededb7fbac4081bff7eb8f892900b
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Apr 29 17:15:32 2013 -0400

    Pass formula group context to FetchDoubleArray. Not yet used.
    
    In the future I'll use it to store temporary double array buffer here,
    in case the requested row span is over multiple arrays.
    
    Change-Id: Id4260ec4ced4c8c1ee718106f37a7374c62b204c

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 9b6e614..e70f108 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -45,6 +45,10 @@
 
 namespace editeng { class SvxBorderLine; }
 
+namespace sc {
+    struct FormulaGroupContext;
+}
+
 class Fraction;
 class OutputDevice;
 class SfxItemPoolCache;
@@ -460,7 +464,7 @@ public:
     ScFormulaVectorState GetFormulaVectorState( SCROW nRow ) const;
     formula::FormulaTokenRef ResolveStaticReference( SCROW nRow );
     bool ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 );
-    const double* FetchDoubleArray( SCROW nRow1, SCROW nRow2 ) const;
+    const double* FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW nRow1, SCROW nRow2 ) const;
 
     ScRefCellValue GetRefCellValue( SCROW );
 
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 876c9d7..0920dd5e 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -47,6 +47,9 @@
 #include <boost/scoped_ptr.hpp>
 
 namespace editeng { class SvxBorderLine; }
+namespace sc {
+    struct FormulaGroupContext;
+}
 class SvxFontItem;
 
 class KeyEvent;
@@ -1944,7 +1947,8 @@ public:
     formula::FormulaTokenRef ResolveStaticReference( const ScAddress& rPos );
     formula::FormulaTokenRef ResolveStaticReference( const ScRange& rRange );
 
-    const double* FetchDoubleArray( const ScAddress& rPos, SCROW nLength ) const;
+    const double* FetchDoubleArray(
+        sc::FormulaGroupContext& rCxt, const ScAddress& rPos, SCROW nLength ) const;
 
 private: // CLOOK-Impl-methods
 
diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
new file mode 100644
index 0000000..0a8e3f7
--- /dev/null
+++ b/sc/inc/formulagroup.hxx
@@ -0,0 +1,30 @@
+/* -*- 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 SC_FORMULAGROUP_HXX
+#define SC_FORMULAGROUP_HXX
+
+#include <boost/noncopyable.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+namespace sc {
+
+struct FormulaGroupContext : boost::noncopyable
+{
+    typedef std::vector<double> DoubleArrayType;
+    typedef boost::ptr_vector<DoubleArrayType> ArrayStoreType;
+
+    ArrayStoreType maArrays;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 7c45a57..c090f8b 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -47,6 +47,10 @@ namespace com { namespace sun { namespace star {
     }
 } } }
 
+namespace sc {
+    struct FormulaGroupContext;
+}
+
 class SfxItemSet;
 class SfxStyleSheetBase;
 class SvxBoxInfoItem;
@@ -822,7 +826,8 @@ public:
     ScFormulaVectorState GetFormulaVectorState( SCCOL nCol, SCROW nRow ) const;
     formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol, SCROW nRow );
     formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
-    const double* FetchDoubleArray( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const;
+    const double* FetchDoubleArray(
+        sc::FormulaGroupContext& rCxt, SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const;
 
     ScRefCellValue GetRefCellValue( SCCOL nCol, SCROW nRow );
 
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 434edad..2e20d0f 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -57,6 +57,7 @@
 #include "cellvalue.hxx"
 #include "tokenarray.hxx"
 #include "globalnames.hxx"
+#include "formulagroup.hxx"
 
 #include <math.h>
 
@@ -1661,8 +1662,10 @@ bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow
     return true;
 }
 
-const double* ScColumn::FetchDoubleArray( SCROW nRow1, SCROW nRow2 ) const
+const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& /*rCxt*/, SCROW nRow1, SCROW nRow2 ) const
 {
+    // TODO: I'll use the context object later.
+
     if (nRow1 > nRow2)
         return NULL;
 
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index c4f93c6..3a07d3f 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1593,13 +1593,14 @@ formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRan
         rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
 }
 
-const double* ScDocument::FetchDoubleArray( const ScAddress& rPos, SCROW nLength ) const
+const double* ScDocument::FetchDoubleArray(
+    sc::FormulaGroupContext& rCxt, const ScAddress& rPos, SCROW nLength ) const
 {
     SCTAB nTab = rPos.Tab();
     if (!TableExists(nTab))
         return NULL;
 
-    return maTabs[nTab]->FetchDoubleArray(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
+    return maTabs[nTab]->FetchDoubleArray(rCxt, rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
 }
 
 bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 278a299..236474d 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -43,6 +43,7 @@
 #include "formula/vectortoken.hxx"
 #include "svl/intitem.hxx"
 #include "rtl/strbuf.hxx"
+#include "formulagroup.hxx"
 
 #include <boost/bind.hpp>
 
@@ -2968,6 +2969,8 @@ bool ScFormulaCell::InterpretFormulaGroup()
     if (xGroup->mbInvariant)
         return InterpretInvariantFormulaGroup();
 
+    sc::FormulaGroupContext aCxt;
+
     ScTokenArray aCode;
     pCode->Reset();
     for (const formula::FormulaToken* p = pCode->First(); p; p = pCode->Next())
@@ -2990,7 +2993,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
                     // Fetch double array guarantees that the length of the
                     // returned array equals or greater than the requested
                     // length.
-                    const double* pArray = pDocument->FetchDoubleArray(aRefPos, xGroup->mnLength);
+                    const double* pArray = pDocument->FetchDoubleArray(aCxt, aRefPos, xGroup->mnLength);
                     if (!pArray)
                         return false;
 
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index a6c60425..34be0d1 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2140,7 +2140,8 @@ formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol1, SCROW nRo
     return formula::FormulaTokenRef(new ScMatrixToken(pMat));
 }
 
-const double* ScTable::FetchDoubleArray( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
+const double* ScTable::FetchDoubleArray(
+    sc::FormulaGroupContext& rCxt, SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
 {
     if (nRow2 < nRow1)
         return NULL;
@@ -2148,7 +2149,7 @@ const double* ScTable::FetchDoubleArray( SCCOL nCol, SCROW nRow1, SCROW nRow2 )
     if (!ValidCol(nCol) || !ValidRow(nRow1) || !ValidRow(nRow2))
         return NULL;
 
-    return aCol[nCol].FetchDoubleArray(nRow1, nRow1);
+    return aCol[nCol].FetchDoubleArray(rCxt, nRow1, nRow1);
 }
 
 ScRefCellValue ScTable::GetRefCellValue( SCCOL nCol, SCROW nRow )
commit bd6880404b36421c100a83faeffe9b3f9bd5cbcf
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Apr 29 15:28:30 2013 -0400

    Let's not forget to check this in...
    
    Curse the sc / formula split...
    
    Change-Id: Ib8d17ba63d05eb4df7e6918e0034d91dd82869e3

diff --git a/formula/source/core/api/vectortoken.cxx b/formula/source/core/api/vectortoken.cxx
index 0c2e455..94a071c 100644
--- a/formula/source/core/api/vectortoken.cxx
+++ b/formula/source/core/api/vectortoken.cxx
@@ -17,6 +17,11 @@ VectorArray::VectorArray( const double* pArray, size_t nLength ) :
 SingleVectorRefToken::SingleVectorRefToken( const double* pArray, size_t nLength ) :
     FormulaToken(svSingleVectorRef, ocPush), maArray(pArray, nLength) {}
 
+FormulaToken* SingleVectorRefToken::Clone() const
+{
+    return new SingleVectorRefToken(maArray.mpArray, maArray.mnLength);
+}
+
 const VectorArray& SingleVectorRefToken::GetArray() const
 {
     return maArray;
@@ -27,6 +32,11 @@ DoubleVectorRefToken::DoubleVectorRefToken(
     FormulaToken(svDoubleVectorRef, ocPush),
     maArrays(rArrays), mnRowSize(nRowSize), mbAbsStart(bAbsStart), mbAbsEnd(bAbsEnd) {}
 
+FormulaToken* DoubleVectorRefToken::Clone() const
+{
+    return new DoubleVectorRefToken(maArrays, mnRowSize, mbAbsStart, mbAbsEnd);
+}
+
 const std::vector<VectorArray>& DoubleVectorRefToken::GetArrays() const
 {
     return maArrays;
diff --git a/include/formula/vectortoken.hxx b/include/formula/vectortoken.hxx
index 90e28d8..82051d4 100644
--- a/include/formula/vectortoken.hxx
+++ b/include/formula/vectortoken.hxx
@@ -28,6 +28,8 @@ class FORMULA_DLLPUBLIC SingleVectorRefToken : public FormulaToken
 public:
     SingleVectorRefToken( const double* pArray, size_t nLength );
 
+    virtual FormulaToken* Clone() const;
+
     const VectorArray& GetArray() const;
 };
 
@@ -48,6 +50,8 @@ public:
     DoubleVectorRefToken(
         const std::vector<VectorArray>& rArrays, size_t nRowSize, bool bAbsStart, bool bAbsEnd );
 
+    virtual FormulaToken* Clone() const;
+
     const std::vector<VectorArray>& GetArrays() const;
 };
 
commit f7e8e05a63c62fe3bf897cd88fa1d5e1ac9d2636
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Apr 29 15:17:47 2013 -0400

    CellStorageModified() is the right (and only) place to mark group dirty.
    
    CellStorageModified is supposed to be called whenever the cell array
    content changes. We should take advantage of it.
    
    Change-Id: Ib1cd0e91f3d5a3d03d2172ed6cc916520d1baa49

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 6b3202a..9b6e614 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -139,7 +139,7 @@ class ScColumn
 
     ScAttrArray*          pAttrArray;
     ScDocument*           pDocument;
-    bool                  bDirtyGroups;     /// formula groups are dirty.
+    bool mbDirtyGroups;     /// formula groups are dirty.
 
 friend class ScDocument;                    // for FillInfo
 friend class ScDocumentIterator;
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 17bbe68..da9aa3c 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -116,7 +116,7 @@ ScColumn::ScColumn() :
     nCol( 0 ),
     pAttrArray( NULL ),
     pDocument( NULL ),
-    bDirtyGroups( true )
+    mbDirtyGroups(true)
 {
 }
 
@@ -134,7 +134,6 @@ void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
     nTab = nNewTab;
     pDocument = pDoc;
     pAttrArray = new ScAttrArray( nCol, nTab, pDocument );
-    bDirtyGroups = true;
 }
 
 
@@ -893,8 +892,6 @@ void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
         ::std::swap( pCell1, pCell2 );
     }
 
-    bDirtyGroups = true;
-
     // from here: first cell (pCell1, nIndex1) exists always
 
     ScAddress aPos1( nCol, nRow1, nTab );
@@ -1054,8 +1051,6 @@ void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol)
         return;
     }
 
-    bDirtyGroups = true;
-
     // from here: own cell (pCell1, nIndex1) exists always
 
     ScFormulaCell* pFmlaCell1 = (pCell1->GetCellType() == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0;
@@ -1175,8 +1170,6 @@ void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
     if ( i >= maItems.size() )
         return ;
 
-    bDirtyGroups = true;
-
     bool bOldAutoCalc = pDocument->GetAutoCalc();
     pDocument->SetAutoCalc( false );    // avoid recalculations
 
@@ -1711,9 +1704,7 @@ void ScColumn::SwapCol(ScColumn& rCol)
     pAttrArray->SetCol(nCol);
     rCol.pAttrArray->SetCol(rCol.nCol);
 
-    bool bDirty = bDirtyGroups;
-    bDirtyGroups = rCol.bDirtyGroups;
-    rCol.bDirtyGroups = bDirty;
+    std::swap(mbDirtyGroups, rCol.mbDirtyGroups);
 
     SCSIZE i;
     for (i = 0; i < maItems.size(); i++)
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 25725ae..434edad 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1398,6 +1398,7 @@ SCROW ScColumn::FindNextVisibleRowWithContent(SCROW nRow, bool bForward) const
 
 void ScColumn::CellStorageModified()
 {
+    mbDirtyGroups = true;
 #if DEBUG_COLUMN_STORAGE
     if (maItems.empty())
     {
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 615fbaf..63b3a5f 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -87,7 +87,6 @@ void ScColumn::Insert( SCROW nRow, ScBaseCell* pNewCell )
                     ScAddress( nCol, nRow, nTab ), pNewCell->GetBroadcaster()) );
         }
     }
-    bDirtyGroups = true;
 }
 
 
@@ -95,7 +94,6 @@ void ScColumn::Insert( SCROW nRow, sal_uInt32 nNumberFormat, ScBaseCell* pCell )
 {
     Insert(nRow, pCell);
     SetNumberFormat(nRow, nNumberFormat);
-    bDirtyGroups = true;
 }
 
 
@@ -105,7 +103,6 @@ void ScColumn::Append( SCROW nRow, ScBaseCell* pCell )
     maItems.back().pCell = pCell;
     maItems.back().nRow  = nRow;
 
-    bDirtyGroups = true;
     maTextWidths.set<unsigned short>(nRow, TEXTWIDTH_DIRTY);
     maScriptTypes.set<unsigned short>(nRow, SC_SCRIPTTYPE_UNKNOWN);
     CellStorageModified();
@@ -138,7 +135,6 @@ void ScColumn::Delete( SCROW nRow )
         if (pCell->GetCellType() == CELLTYPE_FORMULA)
             static_cast<ScFormulaCell*>(pCell)->EndListeningTo(pDocument);
         pCell->Delete();
-        bDirtyGroups = true;
 
         CellStorageModified();
     }
@@ -159,7 +155,6 @@ void ScColumn::DeleteAtIndex( SCSIZE nIndex )
         static_cast<ScFormulaCell*>(pCell)->EndListeningTo(pDocument);
     pCell->Delete();
 
-    bDirtyGroups = true;
     maTextWidths.set_empty(nRow, nRow);
     maScriptTypes.set_empty(nRow, nRow);
     CellStorageModified();
@@ -196,8 +191,6 @@ void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize )
     sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
     pDocument->SetAutoCalc( false ); // Avoid calculating it multiple times
 
-    bDirtyGroups = true;
-
     sal_Bool bFound=false;
     SCROW nEndRow = nStartRow + nSize - 1;
     SCSIZE nStartIndex = 0;
@@ -526,8 +519,6 @@ void ScColumn::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex, sal_uInt16 nDe
             (*aIt)->Delete();
         }
     }
-
-    bDirtyGroups = true;
 }
 
 
@@ -575,8 +566,6 @@ void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag)
     // Delete attributes just now
     if ((nDelFlag & IDF_ATTRIB) == IDF_ATTRIB) pAttrArray->DeleteArea( nStartRow, nEndRow );
     else if ((nDelFlag & IDF_ATTRIB) != 0) pAttrArray->DeleteHardAttr( nStartRow, nEndRow );
-
-    bDirtyGroups = true;
 }
 
 
@@ -2072,7 +2061,7 @@ public:
 // of similar formulae into a formulagroup
 void ScColumn::RebuildFormulaGroups()
 {
-    if ( maItems.empty() || !bDirtyGroups )
+    if ( maItems.empty() || !mbDirtyGroups )
         return;
 
     // clear double groups
@@ -2180,7 +2169,7 @@ void ScColumn::RebuildFormulaGroups()
     }
 #endif
 
-    bDirtyGroups = false;
+    mbDirtyGroups = false;
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit af99ed66236a9603ca8c2136c0859ef1ea15d472
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Apr 29 15:09:42 2013 -0400

    Test-drive grouped formula calculation.
    
    But of course since we haven't yet implemented the real vectorized
    calculation backend, we calculate the cells individually...
    
    Change-Id: I27e0a3e846f62a7fcda86a79e9455c81e3737ddf

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 20ec752..278a299 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3037,34 +3037,52 @@ bool ScFormulaCell::InterpretFormulaGroup()
         }
     }
 
-    // scan the formula ...
-    // have a document method: "Get2DRangeAsDoublesArray" that does the
-    // column-based heavy lifting call it for each absolute range from the
-    // first cell pos in the formula group.
-    //
-    // Project single references to ranges by adding their vector * xGroup->mnLength
-    //
-    // TODO:
-    //    elide multiple dimensional movement in vectors eg. =SUM(A1<1,1>)
-    //    produces a diagonal 'column' that serves no useful purpose for us.
-    //    these should be very rare. Should elide in GetDeltas anyway and
-    //    assert here.
-    //
-    // Having built our input data ...
-    // Throw it, and the formula over to some 'OpenCLCalculage' hook
-    //
-    // on return - release references on these double buffers
-    //
-    // transfer the result to the formula cells (as above)
-    // store the doubles in the columns' maDoubles array for
-    // dependent formulae
-    //
-    // TODO:
-    //    need to abort/fail when we get errors returned and fallback to
-    //    stock interpreting [ I guess ], unless we can use NaN etc. to
-    //    signal errors.
+#if 0
+    // TODO: Calculate the formula group via vectorization.
+#else
+    // Until we implement group calculation for real, decompose the group into
+    // individual formula token arrays for individual calculation.
+    ScAddress aTmpPos = aPos;
+    for (sal_Int32 i = 0; i < xGroup->mnLength; ++i)
+    {
+        aTmpPos.SetRow(xGroup->mnStart + i);
+        ScTokenArray aCode2;
+        for (const formula::FormulaToken* p = aCode.First(); p; p = aCode.Next())
+        {
+            switch (p->GetType())
+            {
+                case svSingleVectorRef:
+                {
+                    const formula::SingleVectorRefToken* p2 = static_cast<const formula::SingleVectorRefToken*>(p);
+                    const formula::VectorArray& rArray = p2->GetArray();
+                    aCode2.AddDouble(rArray.mpArray[i]);
+                }
+                break;
+                case svDoubleVectorRef:
+                    return false;
+                break;
+                default:
+                    aCode2.AddToken(*p);
+            }
+        }
 
-    return false;
+        ScFormulaCell* pDest = pDocument->GetFormulaCell(aTmpPos);
+        if (!pDest)
+            return false;
+
+        ScCompiler aComp(pDocument, aPos, aCode2);
+        aComp.SetGrammar(pDocument->GetGrammar());
+        OUStringBuffer aBuf;
+        aComp.CreateStringFromTokenArray(aBuf);
+        aComp.CompileTokenArray(); // Create RPN token array.
+        ScInterpreter aInterpreter(pDest, pDocument, aTmpPos, aCode2);
+        aInterpreter.Interpret();
+
+        pDest->aResult.SetToken(aInterpreter.GetResultToken().get());
+    }
+
+    return true;
+#endif
 }
 
 bool ScFormulaCell::InterpretInvariantFormulaGroup()
commit b63477661b10f5dfb048be25322356cf78b54f3b
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Apr 29 14:14:43 2013 -0400

    Add method to allow fetching of double array, and store it in token.
    
    Change-Id: If094dbf139e18ad23c73d6cf5a78ac4844132b14

diff --git a/formula/source/core/api/vectortoken.cxx b/formula/source/core/api/vectortoken.cxx
index b7cab77..0c2e455 100644
--- a/formula/source/core/api/vectortoken.cxx
+++ b/formula/source/core/api/vectortoken.cxx
@@ -23,9 +23,9 @@ const VectorArray& SingleVectorRefToken::GetArray() const
 }
 
 DoubleVectorRefToken::DoubleVectorRefToken(
-    const std::vector<VectorArray>& rArrays, size_t nColSize, size_t nRowSize, bool bAbsStart, bool bAbsEnd ) :
+    const std::vector<VectorArray>& rArrays, size_t nRowSize, bool bAbsStart, bool bAbsEnd ) :
     FormulaToken(svDoubleVectorRef, ocPush),
-    maArrays(rArrays), mnColSize(nColSize), mnRowSize(nRowSize), mbAbsStart(bAbsStart), mbAbsEnd(bAbsEnd) {}
+    maArrays(rArrays), mnRowSize(nRowSize), mbAbsStart(bAbsStart), mbAbsEnd(bAbsEnd) {}
 
 const std::vector<VectorArray>& DoubleVectorRefToken::GetArrays() const
 {
diff --git a/include/formula/vectortoken.hxx b/include/formula/vectortoken.hxx
index 5af2690..90e28d8 100644
--- a/include/formula/vectortoken.hxx
+++ b/include/formula/vectortoken.hxx
@@ -39,7 +39,6 @@ class FORMULA_DLLPUBLIC DoubleVectorRefToken : public FormulaToken
 {
     std::vector<VectorArray> maArrays;
 
-    size_t mnColSize;
     size_t mnRowSize;
 
     bool mbAbsStart:1; /// whether or not the start row position is absolute.
@@ -47,8 +46,7 @@ class FORMULA_DLLPUBLIC DoubleVectorRefToken : public FormulaToken
 
 public:
     DoubleVectorRefToken(
-        const std::vector<VectorArray>& rArrays, size_t nColSize, size_t nRowSize,
-        bool bAbsStart, bool bAbsEnd );
+        const std::vector<VectorArray>& rArrays, size_t nRowSize, bool bAbsStart, bool bAbsEnd );
 
     const std::vector<VectorArray>& GetArrays() const;
 };
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 157bc17..6b3202a 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -106,6 +106,11 @@ struct ColDoubleEntry
 {
     SCROW               mnStart;
     std::vector<double> maData;
+
+    struct LessByPtr : std::binary_function<ColDoubleEntry*, ColDoubleEntry*, bool>
+    {
+        bool operator() (const ColDoubleEntry* p1, const ColDoubleEntry* p2) const;
+    };
 };
 
 class ScColumn
@@ -155,6 +160,9 @@ friend class ScDocumentImport;
 
     static void SwapScriptTypes( ScriptType& rSrc, SCROW nSrcRow, ScriptType& rDest, SCROW nDestRow );
 
+    std::vector<ColEntry>::iterator Search( SCROW nRow );
+    std::vector<ColEntry>::const_iterator Search( SCROW nRow ) const;
+
 public:
                 ScColumn();
                 ~ScColumn();
@@ -452,6 +460,7 @@ public:
     ScFormulaVectorState GetFormulaVectorState( SCROW nRow ) const;
     formula::FormulaTokenRef ResolveStaticReference( SCROW nRow );
     bool ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 );
+    const double* FetchDoubleArray( SCROW nRow1, SCROW nRow2 ) const;
 
     ScRefCellValue GetRefCellValue( SCROW );
 
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index cdb80e0..876c9d7 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1944,6 +1944,8 @@ public:
     formula::FormulaTokenRef ResolveStaticReference( const ScAddress& rPos );
     formula::FormulaTokenRef ResolveStaticReference( const ScRange& rRange );
 
+    const double* FetchDoubleArray( const ScAddress& rPos, SCROW nLength ) const;
+
 private: // CLOOK-Impl-methods
 
     /**
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index c04b902..7c45a57 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -822,6 +822,7 @@ public:
     ScFormulaVectorState GetFormulaVectorState( SCCOL nCol, SCROW nRow ) const;
     formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol, SCROW nRow );
     formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
+    const double* FetchDoubleArray( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const;
 
     ScRefCellValue GetRefCellValue( SCCOL nCol, SCROW nRow );
 
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 0c3e630..17bbe68 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -50,6 +50,11 @@ bool ColEntry::Less::operator() (const ColEntry& r1, const ColEntry& r2) const
     return r1.nRow < r2.nRow;
 }
 
+bool ColDoubleEntry::LessByPtr::operator() (const ColDoubleEntry* p1, const ColDoubleEntry* p2) const
+{
+    return p1->mnStart < p2->mnStart;
+}
+
 namespace {
 
 inline bool IsAmbiguousScriptNonZero( sal_uInt8 nScript )
@@ -89,6 +94,22 @@ void ScColumn::SwapScriptTypes( ScriptType& rSrc, SCROW nSrcRow, ScriptType& rDe
         rDest.set_empty(nDestRow, nDestRow);
 }
 
+std::vector<ColEntry>::iterator ScColumn::Search( SCROW nRow )
+{
+    // Find first cell whose position is equal or greater than nRow.
+    ColEntry aBound;
+    aBound.nRow = nRow;
+    return std::lower_bound(maItems.begin(), maItems.end(), aBound, ColEntry::Less());
+}
+
+std::vector<ColEntry>::const_iterator ScColumn::Search( SCROW nRow ) const
+{
+    // Find first cell whose position is equal or greater than nRow.
+    ColEntry aBound;
+    aBound.nRow = nRow;
+    return std::lower_bound(maItems.begin(), maItems.end(), aBound, ColEntry::Less());
+}
+
 ScColumn::ScColumn() :
     maTextWidths(MAXROWCOUNT),
     maScriptTypes(MAXROWCOUNT),
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 6bcf282..25725ae 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1591,12 +1591,8 @@ ScFormulaVectorState ScColumn::GetFormulaVectorState( SCROW nRow ) const
 
 formula::FormulaTokenRef ScColumn::ResolveStaticReference( SCROW nRow )
 {
+    std::vector<ColEntry>::iterator it = Search(nRow);
     std::vector<ColEntry>::iterator itEnd = maItems.end();
-    // Find first cell whose position is equal or greater than nRow1.
-    ColEntry aBound;
-    aBound.nRow = nRow;
-    std::vector<ColEntry>::iterator it =
-        std::lower_bound(maItems.begin(), itEnd, aBound, ColEntry::Less());
 
     if (it == itEnd || it->nRow != nRow)
     {
@@ -1633,12 +1629,8 @@ bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow
     if (nRow1 > nRow2)
         return false;
 
+    std::vector<ColEntry>::iterator it = Search(nRow1);
     std::vector<ColEntry>::iterator itEnd = maItems.end();
-    // Find first cell whose position is equal or greater than nRow1.
-    ColEntry aBound;
-    aBound.nRow = nRow1;
-    std::vector<ColEntry>::iterator it =
-        std::lower_bound(maItems.begin(), itEnd, aBound, ColEntry::Less());
 
     for (; it != itEnd && it->nRow <= nRow2; ++it)
     {
@@ -1668,6 +1660,50 @@ bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow
     return true;
 }
 
+const double* ScColumn::FetchDoubleArray( SCROW nRow1, SCROW nRow2 ) const
+{
+    if (nRow1 > nRow2)
+        return NULL;
+
+    ColDoubleEntry aBound;
+    aBound.mnStart = nRow1;
+    std::vector<ColDoubleEntry*>::const_iterator it =
+        std::lower_bound(maDoubles.begin(), maDoubles.end(), &aBound, ColDoubleEntry::LessByPtr());
+
+    if (it == maDoubles.end())
+        return NULL;
+
+    // There should never be an entry with empty double array. So we don't
+    // even bother checking for emptiness here.
+
+    const ColDoubleEntry& rEntry = **it;
+
+    if (rEntry.mnStart == nRow1)
+    {
+        SCROW nLastRow = rEntry.mnStart + rEntry.maData.size() - 1;
+        if (nLastRow < nRow2)
+            // Array is shorter than requested length.
+            return NULL;
+
+        return &rEntry.maData[0];
+    }
+
+    OSL_ASSERT(nRow1 < rEntry.mnStart);
+
+    if (it == maDoubles.begin())
+        // This is the very first array entry.
+        return NULL;
+
+    --it; // Go to previous array so that rEntry.mnStart < nRow1.
+    OSL_ASSERT((**it).mnStart < nRow1);
+    SCROW nLastRow = rEntry.mnStart + rEntry.maData.size() - 1;
+    if (nLastRow < nRow2)
+        // Array is shorter than requested length.
+        return NULL;
+
+    return &rEntry.maData[nRow1 - rEntry.mnStart];
+}
+
 ScRefCellValue ScColumn::GetRefCellValue( SCROW nRow )
 {
     ScRefCellValue aCell; // start empty
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 9a3dcf7..c4f93c6 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1593,6 +1593,15 @@ formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRan
         rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
 }
 
+const double* ScDocument::FetchDoubleArray( const ScAddress& rPos, SCROW nLength ) const
+{
+    SCTAB nTab = rPos.Tab();
+    if (!TableExists(nTab))
+        return NULL;
+
+    return maTabs[nTab]->FetchDoubleArray(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
+}
+
 bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
 {
     if ( rOld == rNew )
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 3bfd458..20ec752 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -40,6 +40,7 @@
 #include "tokenarray.hxx"
 
 #include "formula/errorcodes.hxx"
+#include "formula/vectortoken.hxx"
 #include "svl/intitem.hxx"
 #include "rtl/strbuf.hxx"
 
@@ -2912,7 +2913,7 @@ ScFormulaCell::CompareState ScFormulaCell::CompareByTokenArray( ScFormulaCell *p
                 if (rRef != pOtherTok->GetSingleRef())
                     return NotEqual;
 
-                if (rRef.IsColRel() || rRef.IsRowRel())
+                if (rRef.IsRowRel())
                     bInvariant = false;
             }
             break;
@@ -2927,10 +2928,10 @@ ScFormulaCell::CompareState ScFormulaCell::CompareByTokenArray( ScFormulaCell *p
                 if (rRef2 != pOtherTok->GetSingleRef2())
                     return NotEqual;
 
-                if (rRef1.IsColRel() || rRef1.IsRowRel())
+                if (rRef1.IsRowRel())
                     bInvariant = false;
 
-                if (rRef2.IsColRel() || rRef2.IsRowRel())
+                if (rRef2.IsRowRel())
                     bInvariant = false;
             }
             break;
@@ -2967,6 +2968,75 @@ bool ScFormulaCell::InterpretFormulaGroup()
     if (xGroup->mbInvariant)
         return InterpretInvariantFormulaGroup();
 
+    ScTokenArray aCode;
+    pCode->Reset();
+    for (const formula::FormulaToken* p = pCode->First(); p; p = pCode->Next())
+    {
+        // A reference can be either absolute or relative.  If it's absolute,
+        // convert it to a static value token.  If relative, convert it to a
+        // vector reference token.  Note: we only care about relative vs
+        // absolute reference state for row directions.
+
+        const ScToken* pToken = static_cast<const ScToken*>(p);
+        switch (pToken->GetType())
+        {
+            case svSingleRef:
+            {
+                ScSingleRefData aRef = pToken->GetSingleRef();
+                aRef.CalcAbsIfRel(aPos);
+                ScAddress aRefPos(aRef.nCol, aRef.nRow, aRef.nTab);
+                if (aRef.IsRowRel())
+                {
+                    // Fetch double array guarantees that the length of the
+                    // returned array equals or greater than the requested
+                    // length.
+                    const double* pArray = pDocument->FetchDoubleArray(aRefPos, xGroup->mnLength);
+                    if (!pArray)
+                        return false;
+
+                    formula::SingleVectorRefToken aTok(pArray, xGroup->mnLength);
+                    aCode.AddToken(aTok);
+                }
+                else
+                {
+                    // Absolute row reference.
+                    formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefPos);
+                    if (!pNewToken)
+                        return false;
+
+                    aCode.AddToken(*pNewToken);
+                }
+            }
+            break;
+            case svDoubleRef:
+            {
+                ScComplexRefData aRef = pToken->GetDoubleRef();
+                aRef.CalcAbsIfRel(aPos);
+                if (aRef.Ref1.IsRowRel() || aRef.Ref2.IsRowRel())
+                {
+                    // TODO: Implement this.
+                    return false;
+                }
+                else
+                {
+                    // Absolute row reference.
+                    ScRange aRefRange(
+                        aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab,
+                        aRef.Ref2.nCol, aRef.Ref2.nRow, aRef.Ref2.nTab);
+
+                    formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefRange);
+                    if (!pNewToken)
+                        return false;
+
+                    aCode.AddToken(*pNewToken);
+                }
+            }
+            break;
+            default:
+                aCode.AddToken(*pToken);
+        }
+    }
+
     // scan the formula ...
     // have a document method: "Get2DRangeAsDoublesArray" that does the
     // column-based heavy lifting call it for each absolute range from the
@@ -3001,7 +3071,7 @@ bool ScFormulaCell::InterpretInvariantFormulaGroup()
 {
     if (pCode->GetVectorState() == FormulaVectorCheckReference)
     {
-        // An invariant group should only have absolute references, and no
+        // An invariant group should only have absolute row references, and no
         // external references are allowed.
 
         ScTokenArray aCode;
@@ -3013,8 +3083,9 @@ bool ScFormulaCell::InterpretInvariantFormulaGroup()
             {
                 case svSingleRef:
                 {
-                    const ScSingleRefData& rRef = pToken->GetSingleRef();
-                    ScAddress aRefPos(rRef.nCol, rRef.nRow, rRef.nTab);
+                    ScSingleRefData aRef = pToken->GetSingleRef();
+                    aRef.CalcAbsIfRel(aPos); // column may be relative.
+                    ScAddress aRefPos(aRef.nCol, aRef.nRow, aRef.nTab);
                     formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefPos);
                     if (!pNewToken)
                         return false;
@@ -3024,10 +3095,11 @@ bool ScFormulaCell::InterpretInvariantFormulaGroup()
                 break;
                 case svDoubleRef:
                 {
-                    const ScComplexRefData& rRef = pToken->GetDoubleRef();
+                    ScComplexRefData aRef = pToken->GetDoubleRef();
+                    aRef.CalcAbsIfRel(aPos); // column may be relative.
                     ScRange aRefRange(
-                        rRef.Ref1.nCol, rRef.Ref1.nRow, rRef.Ref1.nTab,
-                        rRef.Ref2.nCol, rRef.Ref2.nRow, rRef.Ref2.nTab);
+                        aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab,
+                        aRef.Ref2.nCol, aRef.Ref2.nRow, aRef.Ref2.nTab);
 
                     formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefRange);
                     if (!pNewToken)
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 52e0bb9..a6c60425 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2140,6 +2140,17 @@ formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol1, SCROW nRo
     return formula::FormulaTokenRef(new ScMatrixToken(pMat));
 }
 
+const double* ScTable::FetchDoubleArray( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
+{
+    if (nRow2 < nRow1)
+        return NULL;
+
+    if (!ValidCol(nCol) || !ValidRow(nRow1) || !ValidRow(nRow2))
+        return NULL;
+
+    return aCol[nCol].FetchDoubleArray(nRow1, nRow1);
+}
+
 ScRefCellValue ScTable::GetRefCellValue( SCCOL nCol, SCROW nRow )
 {
     if (!ValidColRow(nCol, nRow))
commit ecc076f1201d50f56e58d8a5eae3f574b6173186
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Apr 29 11:18:54 2013 -0400

    Initial cut on vector formula ref tokens. Not used yet.
    
    Change-Id: I4b28c269759bc01bfc94cfdd6a1c651d03d829c7

diff --git a/formula/Library_for.mk b/formula/Library_for.mk
index 52e157f..832d7cd 100644
--- a/formula/Library_for.mk
+++ b/formula/Library_for.mk
@@ -43,6 +43,7 @@ $(eval $(call gb_Library_add_exception_objects,for,\
     formula/source/core/api/FormulaOpCodeMapperObj \
     formula/source/core/api/services \
     formula/source/core/api/token \
+    formula/source/core/api/vectortoken \
     formula/source/core/resource/core_resource \
 ))
 
diff --git a/formula/source/core/api/vectortoken.cxx b/formula/source/core/api/vectortoken.cxx
new file mode 100644
index 0000000..b7cab77
--- /dev/null
+++ b/formula/source/core/api/vectortoken.cxx
@@ -0,0 +1,37 @@
+/* -*- 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 "formula/vectortoken.hxx"
+
+namespace formula {
+
+VectorArray::VectorArray( const double* pArray, size_t nLength ) :
+    mpArray(pArray), mnLength(nLength) {}
+
+SingleVectorRefToken::SingleVectorRefToken( const double* pArray, size_t nLength ) :
+    FormulaToken(svSingleVectorRef, ocPush), maArray(pArray, nLength) {}
+
+const VectorArray& SingleVectorRefToken::GetArray() const
+{
+    return maArray;
+}
+
+DoubleVectorRefToken::DoubleVectorRefToken(
+    const std::vector<VectorArray>& rArrays, size_t nColSize, size_t nRowSize, bool bAbsStart, bool bAbsEnd ) :
+    FormulaToken(svDoubleVectorRef, ocPush),
+    maArrays(rArrays), mnColSize(nColSize), mnRowSize(nRowSize), mbAbsStart(bAbsStart), mbAbsEnd(bAbsEnd) {}
+
+const std::vector<VectorArray>& DoubleVectorRefToken::GetArrays() const
+{
+    return maArrays;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/formula/token.hxx b/include/formula/token.hxx
index 82bdf7f..c7fa0cd 100644
--- a/include/formula/token.hxx
+++ b/include/formula/token.hxx
@@ -63,6 +63,8 @@ enum StackVarEnum
     svExternalSingleRef,
     svExternalDoubleRef,
     svExternalName,
+    svSingleVectorRef,
+    svDoubleVectorRef,
     svSubroutine,                       // A token with a subroutine token array.
     svError,                            // error token
     svMissing = 0x70,                   // 0 or ""
diff --git a/include/formula/vectortoken.hxx b/include/formula/vectortoken.hxx
new file mode 100644
index 0000000..5af2690
--- /dev/null
+++ b/include/formula/vectortoken.hxx
@@ -0,0 +1,60 @@
+/* -*- 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 FORMULA_VECTORTOKEN_HXX
+#define FORMULA_VECTORTOKEN_HXX
+
+#include "formula/token.hxx"
+
+namespace formula {
+
+struct VectorArray
+{
+    const double* mpArray;
+    size_t mnLength;
+
+    VectorArray( const double* pArray, size_t nLength );
+};
+
+class FORMULA_DLLPUBLIC SingleVectorRefToken : public FormulaToken
+{
+    const VectorArray maArray;
+public:
+    SingleVectorRefToken( const double* pArray, size_t nLength );
+
+    const VectorArray& GetArray() const;
+};
+
+/**
+ * This token describes a range reference in a vectorized formula
+ * calculation context.
+ */
+class FORMULA_DLLPUBLIC DoubleVectorRefToken : public FormulaToken
+{
+    std::vector<VectorArray> maArrays;
+
+    size_t mnColSize;
+    size_t mnRowSize;
+
+    bool mbAbsStart:1; /// whether or not the start row position is absolute.
+    bool mbAbsEnd:1; /// whether or not the end row position is absolute.
+
+public:
+    DoubleVectorRefToken(
+        const std::vector<VectorArray>& rArrays, size_t nColSize, size_t nRowSize,
+        bool bAbsStart, bool bAbsEnd );
+
+    const std::vector<VectorArray>& GetArrays() const;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit b6e6961631a124c5242b2c022c64e90b597c5bd5
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Fri Apr 26 23:16:43 2013 -0400

    Move the invariant group handler into its own method.
    
    Change-Id: I3ed8da3c9673b990d5ae17d235bcf4fc1a4541f1

diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 397fd9c..e4f1cfa 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -302,7 +302,8 @@ public:
 
     CompareState CompareByTokenArray( ScFormulaCell *pOther ) const;
 
-    bool                   InterpretFormulaGroup();
+    bool InterpretFormulaGroup();
+    bool InterpretInvariantFormulaGroup();
 
     // nOnlyNames may be one or more of SC_LISTENING_NAMES_*
     void StartListeningTo( ScDocument* pDoc );
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 43d80cf..3bfd458 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2965,82 +2965,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
     }
 
     if (xGroup->mbInvariant)
-    {
-        if (pCode->GetVectorState() == FormulaVectorCheckReference)
-        {
-            // An invariant group should only have absolute references, and no
-            // external references are allowed.
-
-            ScTokenArray aCode;
-            pCode->Reset();
-            for (const formula::FormulaToken* p = pCode->First(); p; p = pCode->Next())
-            {
-                const ScToken* pToken = static_cast<const ScToken*>(p);
-                switch (pToken->GetType())
-                {
-                    case svSingleRef:
-                    {
-                        const ScSingleRefData& rRef = pToken->GetSingleRef();
-                        ScAddress aRefPos(rRef.nCol, rRef.nRow, rRef.nTab);
-                        formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefPos);
-                        if (!pNewToken)
-                            return false;
-
-                        aCode.AddToken(*pNewToken);
-                    }
-                    break;
-                    case svDoubleRef:
-                    {
-                        const ScComplexRefData& rRef = pToken->GetDoubleRef();
-                        ScRange aRefRange(
-                            rRef.Ref1.nCol, rRef.Ref1.nRow, rRef.Ref1.nTab,
-                            rRef.Ref2.nCol, rRef.Ref2.nRow, rRef.Ref2.nTab);
-
-                        formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefRange);
-                        if (!pNewToken)
-                            return false;
-
-                        aCode.AddToken(*pNewToken);
-                    }
-                    break;
-                    default:
-                        aCode.AddToken(*pToken);
-                }
-            }
-
-            ScCompiler aComp(pDocument, aPos, aCode);
-            aComp.SetGrammar(pDocument->GetGrammar());
-            aComp.CompileTokenArray(); // Create RPN token array.
-            ScInterpreter aInterpreter(this, pDocument, aPos, aCode);
-            aInterpreter.Interpret();
-            aResult.SetToken(aInterpreter.GetResultToken().get());
-        }
-        else
-        {
-            // Formula contains no references.
-            ScInterpreter aInterpreter(this, pDocument, aPos, *pCode);
-            aInterpreter.Interpret();
-            aResult.SetToken(aInterpreter.GetResultToken().get());
-        }
-
-        for ( sal_Int32 i = 0; i < xGroup->mnLength; i++ )
-        {
-            ScAddress aTmpPos = aPos;
-            aTmpPos.SetRow(xGroup->mnStart + i);
-            ScFormulaCell* pCell = pDocument->GetFormulaCell(aTmpPos);
-            assert( pCell != NULL );
-
-            // FIXME: this set of horrors is unclear to me ... certainly
-            // the above GetCell is profoundly nasty & slow ...
-
-            // Ensure the cell truly has a result:
-            pCell->aResult = aResult;
-            pCell->ResetDirty();
-
-            // FIXME: there is a view / refresh missing here it appears.
-        }
-        return true;
-    }
+        return InterpretInvariantFormulaGroup();
 
     // scan the formula ...
     // have a document method: "Get2DRangeAsDoublesArray" that does the
@@ -3072,6 +2997,85 @@ bool ScFormulaCell::InterpretFormulaGroup()
     return false;
 }
 
+bool ScFormulaCell::InterpretInvariantFormulaGroup()
+{
+    if (pCode->GetVectorState() == FormulaVectorCheckReference)
+    {
+        // An invariant group should only have absolute references, and no
+        // external references are allowed.
+
+        ScTokenArray aCode;
+        pCode->Reset();
+        for (const formula::FormulaToken* p = pCode->First(); p; p = pCode->Next())
+        {
+            const ScToken* pToken = static_cast<const ScToken*>(p);
+            switch (pToken->GetType())
+            {
+                case svSingleRef:
+                {
+                    const ScSingleRefData& rRef = pToken->GetSingleRef();
+                    ScAddress aRefPos(rRef.nCol, rRef.nRow, rRef.nTab);
+                    formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefPos);
+                    if (!pNewToken)
+                        return false;
+
+                    aCode.AddToken(*pNewToken);
+                }
+                break;
+                case svDoubleRef:
+                {
+                    const ScComplexRefData& rRef = pToken->GetDoubleRef();
+                    ScRange aRefRange(
+                        rRef.Ref1.nCol, rRef.Ref1.nRow, rRef.Ref1.nTab,
+                        rRef.Ref2.nCol, rRef.Ref2.nRow, rRef.Ref2.nTab);
+
+                    formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefRange);
+                    if (!pNewToken)
+                        return false;
+
+                    aCode.AddToken(*pNewToken);
+                }
+                break;
+                default:
+                    aCode.AddToken(*pToken);
+            }
+        }
+
+        ScCompiler aComp(pDocument, aPos, aCode);
+        aComp.SetGrammar(pDocument->GetGrammar());
+        aComp.CompileTokenArray(); // Create RPN token array.
+        ScInterpreter aInterpreter(this, pDocument, aPos, aCode);
+        aInterpreter.Interpret();
+        aResult.SetToken(aInterpreter.GetResultToken().get());
+    }
+    else
+    {
+        // Formula contains no references.
+        ScInterpreter aInterpreter(this, pDocument, aPos, *pCode);
+        aInterpreter.Interpret();
+        aResult.SetToken(aInterpreter.GetResultToken().get());
+    }
+
+    for ( sal_Int32 i = 0; i < xGroup->mnLength; i++ )
+    {
+        ScAddress aTmpPos = aPos;
+        aTmpPos.SetRow(xGroup->mnStart + i);
+        ScFormulaCell* pCell = pDocument->GetFormulaCell(aTmpPos);
+        assert( pCell != NULL );
+
+        // FIXME: this set of horrors is unclear to me ... certainly
+        // the above GetCell is profoundly nasty & slow ...
+
+        // Ensure the cell truly has a result:
+        pCell->aResult = aResult;
+        pCell->ResetDirty();
+
+        // FIXME: there is a view / refresh missing here it appears.
+    }
+
+    return true;
+}
+
 void ScFormulaCell::StartListeningTo( ScDocument* pDoc )
 {
     if (pDoc->IsClipOrUndo() || pDoc->GetNoListening() || IsInChangeTrack())
commit 539097833ab88b2bb239954ca9dc77d070109acf
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Fri Apr 26 23:07:03 2013 -0400

    Don't forget to add breaks here...
    
    Change-Id: I2887382d8eb30a0ba715493a38dda3d0e5ec4d7d

diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 20483f8..6bcf282 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1649,6 +1649,7 @@ bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow
                 ScValueCell* pVC = static_cast<ScValueCell*>(it->pCell);
                 rMat.PutDouble(pVC->GetValue(), nMatCol, it->nRow - nRow1);
             }
+            break;
             case CELLTYPE_FORMULA:
             {
                 ScFormulaCell* pFC = static_cast<ScFormulaCell*>(it->pCell);
@@ -1658,6 +1659,7 @@ bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow
 
                 rMat.PutDouble(pFC->GetResultDouble(), nMatCol, it->nRow - nRow1);
             }
+            break;
             default:
                 ;
         }
commit 92bd98cdcfefa502a84a55f1768deb00392ca6c6
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Fri Apr 26 22:53:04 2013 -0400

    Handle invariant group with single references.
    
    Change-Id: Ifbbac2b11b1023a5cf3d21204c12b9740af09aaf

diff --git a/include/formula/token.hxx b/include/formula/token.hxx
index 3a174d7..82bdf7f 100644
--- a/include/formula/token.hxx
+++ b/include/formula/token.hxx
@@ -27,8 +27,7 @@
 #include <tools/mempool.hxx>
 #include "formula/IFunctionDescription.hxx"
 #include "formula/formuladllapi.h"
-
-#include <boost/intrusive_ptr.hpp>
+#include "formula/types.hxx"
 
 namespace formula
 {
@@ -79,11 +78,6 @@ typedef sal_uInt8 StackVar;
 typedef StackVarEnum StackVar;
 #endif
 
-
-class FormulaToken;
-typedef ::boost::intrusive_ptr<FormulaToken>        FormulaTokenRef;
-typedef ::boost::intrusive_ptr<const FormulaToken>  FormulaConstTokenRef;
-
 class FormulaTokenArray;
 
 class FORMULA_DLLPUBLIC FormulaToken : public IFormulaToken
diff --git a/include/formula/types.hxx b/include/formula/types.hxx
new file mode 100644
index 0000000..33ead51
--- /dev/null
+++ b/include/formula/types.hxx
@@ -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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef FORMULA_TYPES_HXX
+#define FORMULA_TYPES_HXX
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace formula {
+
+class FormulaToken;
+typedef ::boost::intrusive_ptr<FormulaToken>        FormulaTokenRef;
+typedef ::boost::intrusive_ptr<const FormulaToken>  FormulaConstTokenRef;
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 866fce3..157bc17 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -25,11 +25,13 @@
 #include "address.hxx"
 #include "rangenam.hxx"
 #include "types.hxx"
-#include <boost/intrusive_ptr.hpp>
+#include "formula/types.hxx"
 
 #include <set>
 #include <vector>
 
+#include <boost/intrusive_ptr.hpp>
+
 #define DEBUG_COLUMN_STORAGE 0
 
 #if DEBUG_COLUMN_STORAGE
@@ -448,7 +450,8 @@ public:
     size_t GetFormulaHash( SCROW nRow ) const;
 
     ScFormulaVectorState GetFormulaVectorState( SCROW nRow ) const;
-    bool ResolveVectorReference( SCROW nRow1, SCROW nRow2 );
+    formula::FormulaTokenRef ResolveStaticReference( SCROW nRow );
+    bool ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 );
 
     ScRefCellValue GetRefCellValue( SCROW );
 
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 052b81d..cdb80e0 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -32,6 +32,7 @@
 #include "sortparam.hxx"
 #include "types.hxx"
 #include "formula/grammar.hxx"
+#include "formula/types.hxx"
 #include <com/sun/star/chart2/XChartDocument.hpp>
 #include "typedstrdata.hxx"
 #include "compressedarray.hxx"
@@ -1940,14 +1941,8 @@ public:
 
     ScFormulaVectorState GetFormulaVectorState( const ScAddress& rPos ) const;
 
-    /**
-     * Check if the range contains any "dirty" formula cells.  In the future
-     * we'll use this function to interpret those "dirty" formula cells on
-     * demand.
-     *
-     * @return true if the range is totally clean, false otherwise.
-     */
-    bool ResolveVectorReference( const ScAddress& rPos, SCROW nEndRow );
+    formula::FormulaTokenRef ResolveStaticReference( const ScAddress& rPos );
+    formula::FormulaTokenRef ResolveStaticReference( const ScRange& rRange );
 
 private: // CLOOK-Impl-methods
 
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index e6239e3..397fd9c 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -282,6 +282,8 @@ public:
      */
     void            SetResultDouble( double n )     { aResult.SetDouble( n); }
 
+    double GetResultDouble() const { return aResult.GetDouble(); }
+
     void            SetErrCode( sal_uInt16 n );
     bool IsHyperLinkCell() const;
     EditTextObject* CreateURLObject();
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index eb5f756..c04b902 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -30,6 +30,7 @@
 #include "compressedarray.hxx"
 #include "postit.hxx"
 #include "types.hxx"
+#include "formula/types.hxx"
 
 #include <set>
 #include <map>
@@ -819,7 +820,8 @@ public:
     size_t GetFormulaHash( SCCOL nCol, SCROW nRow ) const;
 
     ScFormulaVectorState GetFormulaVectorState( SCCOL nCol, SCROW nRow ) const;
-    bool ResolveVectorReference( SCCOL nCol, SCROW nRow1, SCROW nRow2 );
+    formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol, SCROW nRow );
+    formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
 
     ScRefCellValue GetRefCellValue( SCCOL nCol, SCROW nRow );
 
diff --git a/sc/inc/token.hxx b/sc/inc/token.hxx
index a540555..abd3cd5 100644
--- a/sc/inc/token.hxx
+++ b/sc/inc/token.hxx
@@ -31,13 +31,11 @@
 #include "scdllapi.h"
 #include "formula/IFunctionDescription.hxx"
 #include "formula/token.hxx"
-
+#include "types.hxx"
 
 class ScJumpMatrix;
-class ScToken;
 
 typedef ::std::vector< ScComplexRefData > ScRefList;
-typedef ::boost::intrusive_ptr<ScToken> ScTokenRef;
 
 class SC_DLLPUBLIC ScToken : public formula::FormulaToken
 {
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 7227472..1af6e2d 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -17,6 +17,9 @@ class ScMatrix;
 typedef ::boost::intrusive_ptr<ScMatrix>        ScMatrixRef;
 typedef ::boost::intrusive_ptr<const ScMatrix>  ScConstMatrixRef;
 
+class ScToken;
+typedef ::boost::intrusive_ptr<ScToken> ScTokenRef;
+
 /**
  * When vectorization is enabled, we could potentially mass-calculate a
  * series of formula token arrays in adjacent formula cells in one step,
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index e95dcf9..20483f8 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1589,28 +1589,78 @@ ScFormulaVectorState ScColumn::GetFormulaVectorState( SCROW nRow ) const
     return pCell ? pCell->GetVectorState() : FormulaVectorUnknown;
 }
 
-bool ScColumn::ResolveVectorReference( SCROW nRow1, SCROW nRow2 )
+formula::FormulaTokenRef ScColumn::ResolveStaticReference( SCROW nRow )
 {
     std::vector<ColEntry>::iterator itEnd = maItems.end();
     // Find first cell whose position is equal or greater than nRow1.
     ColEntry aBound;
-    aBound.nRow = nRow1;
+    aBound.nRow = nRow;
     std::vector<ColEntry>::iterator it =
         std::lower_bound(maItems.begin(), itEnd, aBound, ColEntry::Less());
 
-    if (it == itEnd)
+    if (it == itEnd || it->nRow != nRow)
+    {
+        // Empty cell.
+        return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
+    }
+
+    ScBaseCell* pCell = it->pCell;
+    switch (pCell->GetCellType())
+    {
+        case CELLTYPE_VALUE:
+        {
+            ScValueCell* pVC = static_cast<ScValueCell*>(pCell);
+            return formula::FormulaTokenRef(new formula::FormulaDoubleToken(pVC->GetValue()));
+        }
+        case CELLTYPE_FORMULA:
+        {
+            ScFormulaCell* pFC = static_cast<ScFormulaCell*>(pCell);
+            if (pFC->GetDirty())
+                // Dirty formula cell is not considered static. Return null token.
+                return formula::FormulaTokenRef();
+
+            return formula::FormulaTokenRef(new formula::FormulaDoubleToken(pFC->GetResultDouble()));
+        }
+        default:
+            ;
+    }
+
+    return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
+}
+
+bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 )
+{
+    if (nRow1 > nRow2)
         return false;
 
+    std::vector<ColEntry>::iterator itEnd = maItems.end();
+    // Find first cell whose position is equal or greater than nRow1.
+    ColEntry aBound;
+    aBound.nRow = nRow1;
+    std::vector<ColEntry>::iterator it =
+        std::lower_bound(maItems.begin(), itEnd, aBound, ColEntry::Less());
+
     for (; it != itEnd && it->nRow <= nRow2; ++it)
     {
-        if (it->pCell->GetCellType() != CELLTYPE_FORMULA)
-            // Non-formula cells are fine.
-            continue;
+        switch (it->pCell->GetCellType())
+        {
+            case CELLTYPE_VALUE:
+            {
+                ScValueCell* pVC = static_cast<ScValueCell*>(it->pCell);
+                rMat.PutDouble(pVC->GetValue(), nMatCol, it->nRow - nRow1);
+            }
+            case CELLTYPE_FORMULA:
+            {
+                ScFormulaCell* pFC = static_cast<ScFormulaCell*>(it->pCell);
+                if (pFC->GetDirty())
+                    // Dirty formula cell is not considered static. Return null token.
+                    return false;
 
-        ScFormulaCell* pFC = static_cast<ScFormulaCell*>(it->pCell);
-        if (pFC->GetDirty())
-            // Dirty formula cells are not supported yet.
-            return false;
+                rMat.PutDouble(pFC->GetResultDouble(), nMatCol, it->nRow - nRow1);
+            }
+            default:
+                ;
+        }
     }
 
     return true;
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 6a00d36..9a3dcf7 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1574,13 +1574,23 @@ ScFormulaVectorState ScDocument::GetFormulaVectorState( const ScAddress& rPos )
     return maTabs[nTab]->GetFormulaVectorState(rPos.Col(), rPos.Row());
 }
 
-bool ScDocument::ResolveVectorReference( const ScAddress& rPos, SCROW nEndRow )
+formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScAddress& rPos )
 {
     SCTAB nTab = rPos.Tab();
     if (!TableExists(nTab))
-        return false;
+        return formula::FormulaTokenRef();
+
+    return maTabs[nTab]->ResolveStaticReference(rPos.Col(), rPos.Row());
+}
+
+formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRange )
+{
+    SCTAB nTab = rRange.aStart.Tab();
+    if (nTab != rRange.aEnd.Tab() || !TableExists(nTab))
+        return formula::FormulaTokenRef();
 
-    return maTabs[nTab]->ResolveVectorReference(rPos.Col(), rPos.Row(), nEndRow);
+    return maTabs[nTab]->ResolveStaticReference(
+        rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
 }
 
 bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index e73641d..43d80cf 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2954,27 +2954,75 @@ bool ScFormulaCell::InterpretFormulaGroup()
     switch (pCode->GetVectorState())
     {
         case FormulaVectorEnabled:
+        case FormulaVectorCheckReference:
             // Good.
         break;
-        case FormulaVectorCheckReference:
-            // To support this we would need a real range-based dependency
-            // tracking. We can't support this right now.
-            return false;
         case FormulaVectorDisabled:
         case FormulaVectorUnknown:
         default:
+            // Not good.
             return false;
     }
 
-//    fprintf( stderr, "Interpret cell %d, %d\n", (int)aPos.Col(), (int)aPos.Row() );
-
     if (xGroup->mbInvariant)
     {
-//        fprintf( stderr, "struck gold - completely invariant for %d items !\n",
-//                 (int)xGroup->mnLength );
+        if (pCode->GetVectorState() == FormulaVectorCheckReference)
+        {
+            // An invariant group should only have absolute references, and no
+            // external references are allowed.
+
+            ScTokenArray aCode;
+            pCode->Reset();
+            for (const formula::FormulaToken* p = pCode->First(); p; p = pCode->Next())
+            {
+                const ScToken* pToken = static_cast<const ScToken*>(p);
+                switch (pToken->GetType())
+                {
+                    case svSingleRef:
+                    {
+                        const ScSingleRefData& rRef = pToken->GetSingleRef();
+                        ScAddress aRefPos(rRef.nCol, rRef.nRow, rRef.nTab);
+                        formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefPos);
+                        if (!pNewToken)
+                            return false;
+
+                        aCode.AddToken(*pNewToken);
+                    }
+                    break;
+                    case svDoubleRef:
+                    {
+                        const ScComplexRefData& rRef = pToken->GetDoubleRef();
+                        ScRange aRefRange(
+                            rRef.Ref1.nCol, rRef.Ref1.nRow, rRef.Ref1.nTab,
+                            rRef.Ref2.nCol, rRef.Ref2.nRow, rRef.Ref2.nTab);
+
+                        formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefRange);
+                        if (!pNewToken)
+                            return false;
+
+                        aCode.AddToken(*pNewToken);
+                    }
+                    break;
+                    default:
+                        aCode.AddToken(*pToken);
+                }
+            }
+
+            ScCompiler aComp(pDocument, aPos, aCode);
+            aComp.SetGrammar(pDocument->GetGrammar());
+            aComp.CompileTokenArray(); // Create RPN token array.
+            ScInterpreter aInterpreter(this, pDocument, aPos, aCode);
+            aInterpreter.Interpret();
+            aResult.SetToken(aInterpreter.GetResultToken().get());
+        }
+        else
+        {
+            // Formula contains no references.
+            ScInterpreter aInterpreter(this, pDocument, aPos, *pCode);
+            aInterpreter.Interpret();
+            aResult.SetToken(aInterpreter.GetResultToken().get());
+        }
 
-        // calculate ourselves:
-        InterpretTail( SCITP_NORMAL );
         for ( sal_Int32 i = 0; i < xGroup->mnLength; i++ )
         {
             ScAddress aTmpPos = aPos;
@@ -2993,37 +3041,35 @@ bool ScFormulaCell::InterpretFormulaGroup()
         }
         return true;
     }
-    else
-    {
-        // scan the formula ...
-        // have a document method: "Get2DRangeAsDoublesArray" that does the
-        // column-based heavy lifting call it for each absolute range from the
-        // first cell pos in the formula group.
-        //
-        // Project single references to ranges by adding their vector * xGroup->mnLength
-        //
-        // TODO:
-        //    elide multiple dimensional movement in vectors eg. =SUM(A1<1,1>)
-        //    produces a diagonal 'column' that serves no useful purpose for us.
-        //    these should be very rare. Should elide in GetDeltas anyway and
-        //    assert here.
-        //
-        // Having built our input data ...
-        // Throw it, and the formula over to some 'OpenCLCalculage' hook
-        //
-        // on return - release references on these double buffers
-        //
-        // transfer the result to the formula cells (as above)
-        // store the doubles in the columns' maDoubles array for
-        // dependent formulae
-        //
-        // TODO:
-        //    need to abort/fail when we get errors returned and fallback to
-        //    stock interpreting [ I guess ], unless we can use NaN etc. to
-        //    signal errors.
 
-        return false;
-    }
+    // scan the formula ...
+    // have a document method: "Get2DRangeAsDoublesArray" that does the
+    // column-based heavy lifting call it for each absolute range from the
+    // first cell pos in the formula group.
+    //
+    // Project single references to ranges by adding their vector * xGroup->mnLength
+    //
+    // TODO:
+    //    elide multiple dimensional movement in vectors eg. =SUM(A1<1,1>)
+    //    produces a diagonal 'column' that serves no useful purpose for us.
+    //    these should be very rare. Should elide in GetDeltas anyway and
+    //    assert here.
+    //
+    // Having built our input data ...
+    // Throw it, and the formula over to some 'OpenCLCalculage' hook
+    //
+    // on return - release references on these double buffers
+    //
+    // transfer the result to the formula cells (as above)
+    // store the doubles in the columns' maDoubles array for
+    // dependent formulae
+    //
+    // TODO:
+    //    need to abort/fail when we get errors returned and fallback to

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list