[Libreoffice-commits] core.git: Branch 'feature/sparklines' - 370 commits - accessibility/inc accessibility/source avmedia/source basctl/inc basic/qa basic/source bridges/source chart2/inc chart2/qa chart2/source compilerplugins/clang config_host/config_features.h.in config_host.mk.in configure.ac connectivity/source cppuhelper/source cui/inc cui/source cui/uiconfig dbaccess/qa desktop/inc desktop/source desktop/uiconfig download.lst drawinglayer/source editeng/source embeddedobj/qa external/boost external/firebird external/nss filter/qa filter/source forms/source framework/qa framework/source helpcontent2 hwpfilter/qa hwpfilter/source i18npool/CppunitTest_i18npool_breakiterator.mk i18npool/CppunitTest_i18npool_calendar.mk i18npool/CppunitTest_i18npool_characterclassification.mk i18npool/CppunitTest_i18npool_ordinalsuffix.mk i18npool/CppunitTest_i18npool_test_breakiterator.mk i18npool/CppunitTest_i18npool_test_characterclassification.mk i18npool/CppunitTest_i18npool_test_ordinalsuffix.mk i18npool /CppunitTest_i18npool_test_textsearch.mk i18npool/CppunitTest_i18npool_textsearch.mk i18npool/inc i18npool/Module_i18npool.mk i18npool/qa i18npool/source icon-themes/colibre icon-themes/colibre_svg icon-themes/sukapura icon-themes/sukapura_svg include/avmedia include/editeng include/i18nutil include/o3tl include/oox include/rtl include/sfx2 include/svl include/svtools include/svx include/tools include/unotest include/unotools include/vcl include/xmloff instsetoo_native/inc_ooohelppack instsetoo_native/inc_openoffice instsetoo_native/inc_sdkoo io/Library_io.mk io/source javaunohelper/Library_juhx.mk javaunohelper/source jurt/source o3tl/qa odk/CustomTarget_check.mk odk/docs odk/examples odk/Package_examples.mk odk/settings odk/util offapi/com offapi/type_reference offapi/UnoApi_offapi.mk oox/inc oox/source qadevOOo/Jar_OOoRunner.mk qadevOOo/objdsc qadevOOo/tests readlicense_oo/license README.md reportdesign/inc reportdesign/source Repository.mk sal/CppunitTest_sal_rtl.mk sal/qa sal/r tl sax/source sccomp/qa sc/CppunitTest_sc_sparkline_test.mk schema/libreoffice sc/inc sc/Library_scfilt.mk sc/Module_sc.mk sc/qa sc/sdi sc/source sc/TODO.performance sc/uiconfig sd/inc sd/qa sd/sdi sd/source sfx2/inc sfx2/IwyuFilter_sfx2.yaml sfx2/qa sfx2/sdi sfx2/source shell/source slideshow/inc slideshow/IwyuFilter_slideshow.yaml slideshow/source slideshow/test solenv/gbuild soltools/mkdepend sot/IwyuFilter_sot.yaml sot/source starmath/inc starmath/IwyuFilter_starmath.yaml starmath/qa starmath/source stoc/Library_bootstrap.mk stoc/Library_javaloader.mk stoc/Library_javavm.mk stoc/source stoc/test svgio/inc svgio/qa svgio/source svl/IwyuFilter_svl.yaml svl/source svtools/inc svtools/IwyuFilter_svtools.yaml svtools/source svx/inc svx/IwyuFilter_svx.yaml svx/qa svx/README.md svx/sdi svx/source sw/CppunitTest_sw_uiwriter5.mk sw/CppunitTest_sw_uiwriter6.mk sw/inc sw/Library_sw.mk sw/Module_sw.mk sw/qa sw/sdi sw/source tools/source tsan-suppress.txt uitest/impress_tests uitest/test_mai n.py uitest/uitest unoidl/README.md unotest/Library_unotest.mk unotest/source unotools/source ure/source uui/inc vcl/inc vcl/jsdialog vcl/qa vcl/source vcl/unx vcl/workben winaccessibility/inc winaccessibility/source wizards/source writerfilter/qa writerfilter/source xmloff/inc xmloff/qa xmloff/source xmlsecurity/qa xmlsecurity/README.md xmlsecurity/source

Fri, 04 Mar 2022 03:55:47 -0800

Rebased ref, commits from common ancestor:
commit fcdeafd4bdc483d71b42fdd0a3980213f1c755aa
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Fri Mar 4 20:40:14 2022 +0900
Commit:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
CommitDate: Fri Mar 4 20:54:34 2022 +0900

    sc: Sparkline export for OOXML documents + roundtrip test
    
    Change-Id: I4ab93d7ad33867ae817aa98d13ea9bc724b7d710

diff --git a/sc/CppunitTest_sc_sparkline_test.mk 
b/sc/CppunitTest_sc_sparkline_test.mk
index edf7a3cac7da..00db7396cdb0 100644
--- a/sc/CppunitTest_sc_sparkline_test.mk
+++ b/sc/CppunitTest_sc_sparkline_test.mk
@@ -32,6 +32,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sc_sparkline_test, 
\
     test \
     tl \
     unotest \
+    utl \
     vcl \
 ))
 
diff --git a/sc/Library_scfilt.mk b/sc/Library_scfilt.mk
index 8e23db6662fa..84b6e5fd5edd 100644
--- a/sc/Library_scfilt.mk
+++ b/sc/Library_scfilt.mk
@@ -130,6 +130,7 @@ $(eval $(call gb_Library_add_exception_objects,scfilt,\
        sc/source/filter/excel/xltools \
        sc/source/filter/excel/xltracer \
        sc/source/filter/excel/xlview \
+       sc/source/filter/excel/export/SparklineExt \
        sc/source/filter/ftools/fapihelper \
        sc/source/filter/ftools/fprogressbar \
        sc/source/filter/ftools/ftools \
diff --git a/sc/qa/extras/SparklineTest.cxx b/sc/qa/extras/SparklineTest.cxx
index 122a6b23f5be..a217747899d2 100644
--- a/sc/qa/extras/SparklineTest.cxx
+++ b/sc/qa/extras/SparklineTest.cxx
@@ -10,19 +10,36 @@
 #include <test/calc_unoapi_test.hxx>
 
 #include <com/sun/star/lang/XComponent.hpp>
+#include <unotools/tempfile.hxx>
+#include <comphelper/propertyvalue.hxx>
 #include <docsh.hxx>
 #include <Sparkline.hxx>
 
 using namespace css;
 
-namespace sc_apitest
-{
 class SparklineTest : public CalcUnoApiTest
 {
     uno::Reference<lang::XComponent> mxComponent;
 
 public:
-    SparklineTest();
+    SparklineTest()
+        : CalcUnoApiTest("sc/qa/extras/testdocuments")
+    {
+    }
+
+    void saveAndReload(uno::Reference<lang::XComponent>& xComponent, const 
OUString& rFilter)
+    {
+        utl::TempFile aTempFile;
+        aTempFile.EnableKillingFile();
+        // "calc8", "Calc Office Open XML", ...
+        uno::Sequence aArgs{ comphelper::makePropertyValue("FilterName", 
rFilter) };
+        uno::Reference<frame::XStorable> xStorable(xComponent, 
uno::UNO_QUERY_THROW);
+        xStorable->storeAsURL(aTempFile.GetURL(), aArgs);
+        uno::Reference<util::XCloseable> xCloseable(xComponent, 
uno::UNO_QUERY_THROW);
+        xCloseable->close(true);
+
+        xComponent = loadFromDesktop(aTempFile.GetURL(), 
"com.sun.star.sheet.SpreadsheetDocument");
+    }
 
     void testSparklines();
 
@@ -31,121 +48,224 @@ public:
     CPPUNIT_TEST_SUITE_END();
 };
 
-SparklineTest::SparklineTest()
-    : CalcUnoApiTest("sc/qa/extras/testdocuments")
-{
-}
-
 void SparklineTest::testSparklines()
 {
     OUString aFileURL;
     createFileURL(u"Sparklines.xlsx", aFileURL);
     mxComponent = loadFromDesktop(aFileURL);
 
-    SfxObjectShell* pFoundShell = 
SfxObjectShell::GetShellFromComponent(mxComponent);
-    CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell);
-    ScDocShellRef xDocSh = dynamic_cast<ScDocShell*>(pFoundShell);
-    CPPUNIT_ASSERT(xDocSh);
-
-    ScDocument& rDocument = xDocSh->GetDocument();
-    // Sparkline at Sheet1:A2
-    {
-        sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 1, 
0)); // A2
-        CPPUNIT_ASSERT(pSparkline);
-        auto pSparklineGroup = pSparkline->getSparklineGroup();
-        CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, 
pSparklineGroup->m_eType);
-
-        CPPUNIT_ASSERT_EQUAL(Color(0x376092), pSparklineGroup->m_aColorSeries);
-        CPPUNIT_ASSERT_EQUAL(Color(0x00b050), 
pSparklineGroup->m_aColorNegative);
-        CPPUNIT_ASSERT_EQUAL(Color(0x000000), pSparklineGroup->m_aColorAxis);
-        CPPUNIT_ASSERT_EQUAL(Color(0x000000), 
pSparklineGroup->m_aColorMarkers);
-        CPPUNIT_ASSERT_EQUAL(Color(0x7030a0), pSparklineGroup->m_aColorFirst);
-        CPPUNIT_ASSERT_EQUAL(Color(0xff0000), pSparklineGroup->m_aColorLast);
-        CPPUNIT_ASSERT_EQUAL(Color(0x92d050), pSparklineGroup->m_aColorHigh);
-        CPPUNIT_ASSERT_EQUAL(Color(0x00b0f0), pSparklineGroup->m_aColorLow);
-
-        CPPUNIT_ASSERT_EQUAL(1.0, pSparklineGroup->m_fLineWeight);
-        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDateAxis);
-        CPPUNIT_ASSERT_EQUAL(sc::DisplayEmptyCellAs::Gap, 
pSparklineGroup->m_eDisplayEmptyCellsAs);
-
-        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bMarkers);
-        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bHigh);
-        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLow);
-        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bFirst);
-        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLast);
-        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bNegative);
-        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bDisplayXAxis);
-        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayHidden);
-        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bRightToLeft);
-
-        CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMax));
-        CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMin));
-    }
-    // Sparkline at Sheet1:A3
-    {
-        sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 2, 
0)); // A3
-        CPPUNIT_ASSERT(pSparkline);
-        auto pSparklineGroup = pSparkline->getSparklineGroup();
-        CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column, 
pSparklineGroup->m_eType);
-
-        CPPUNIT_ASSERT_EQUAL(Color(0x376092), pSparklineGroup->m_aColorSeries);
-        CPPUNIT_ASSERT_EQUAL(Color(0xff0000), 
pSparklineGroup->m_aColorNegative);
-        CPPUNIT_ASSERT_EQUAL(Color(0x000000), pSparklineGroup->m_aColorAxis);
-        CPPUNIT_ASSERT_EQUAL(Color(0xd00000), 
pSparklineGroup->m_aColorMarkers);
-        CPPUNIT_ASSERT_EQUAL(Color(0x92d050), pSparklineGroup->m_aColorFirst);
-        CPPUNIT_ASSERT_EQUAL(Color(0x00b0f0), pSparklineGroup->m_aColorLast);
-        CPPUNIT_ASSERT_EQUAL(Color(0x7030a0), pSparklineGroup->m_aColorHigh);
-        CPPUNIT_ASSERT_EQUAL(Color(0xffc000), pSparklineGroup->m_aColorLow);
-
-        CPPUNIT_ASSERT_EQUAL(0.75, pSparklineGroup->m_fLineWeight);
-        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDateAxis);
-        CPPUNIT_ASSERT_EQUAL(sc::DisplayEmptyCellAs::Gap, 
pSparklineGroup->m_eDisplayEmptyCellsAs);
-
-        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bMarkers);
-        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bHigh);
-        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLow);
-        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bFirst);
-        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLast);
-        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bNegative);
-        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayXAxis);
-        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayHidden);
-        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bRightToLeft);
-
-        CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMax));
-        CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMin));
-    }
-    // Sparkline at Sheet2:B1
     {
-        sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 0, 
1)); //B1
-        CPPUNIT_ASSERT(pSparkline);
-        auto pSparklineGroup = pSparkline->getSparklineGroup();
-        CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column, 
pSparklineGroup->m_eType);
-    }
-    // Sparkline at Sheet2:B2
-    {
-        sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 1, 
1)); //B2
-        CPPUNIT_ASSERT(pSparkline);
-        auto pSparklineGroup = pSparkline->getSparklineGroup();
-        CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, 
pSparklineGroup->m_eType);
-    }
-    // Sparkline at Sheet2:B2
-    {
-        sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 1, 
1)); //B2
-        CPPUNIT_ASSERT(pSparkline);
-        auto pSparklineGroup = pSparkline->getSparklineGroup();
-        CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, 
pSparklineGroup->m_eType);
+        SfxObjectShell* pFoundShell = 
SfxObjectShell::GetShellFromComponent(mxComponent);
+        CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell);
+        ScDocShellRef xDocSh = dynamic_cast<ScDocShell*>(pFoundShell);
+        CPPUNIT_ASSERT(xDocSh);
+
+        ScDocument& rDocument = xDocSh->GetDocument();
+        // Sparkline at Sheet1:A2
+        {
+            sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 1, 
0)); // A2
+            CPPUNIT_ASSERT(pSparkline);
+            auto pSparklineGroup = pSparkline->getSparklineGroup();
+            CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, 
pSparklineGroup->m_eType);
+
+            CPPUNIT_ASSERT_EQUAL(Color(0x376092), 
pSparklineGroup->m_aColorSeries);
+            CPPUNIT_ASSERT_EQUAL(Color(0x00b050), 
pSparklineGroup->m_aColorNegative);
+            CPPUNIT_ASSERT_EQUAL(Color(0x000000), 
pSparklineGroup->m_aColorAxis);
+            CPPUNIT_ASSERT_EQUAL(Color(0x000000), 
pSparklineGroup->m_aColorMarkers);
+            CPPUNIT_ASSERT_EQUAL(Color(0x7030a0), 
pSparklineGroup->m_aColorFirst);
+            CPPUNIT_ASSERT_EQUAL(Color(0xff0000), 
pSparklineGroup->m_aColorLast);
+            CPPUNIT_ASSERT_EQUAL(Color(0x92d050), 
pSparklineGroup->m_aColorHigh);
+            CPPUNIT_ASSERT_EQUAL(Color(0x00b0f0), 
pSparklineGroup->m_aColorLow);
+
+            CPPUNIT_ASSERT_EQUAL(1.0, pSparklineGroup->m_fLineWeight);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDateAxis);
+            CPPUNIT_ASSERT_EQUAL(sc::DisplayEmptyCellAs::Gap,
+                                 pSparklineGroup->m_eDisplayEmptyCellsAs);
+
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bMarkers);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bHigh);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLow);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bFirst);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLast);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bNegative);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bDisplayXAxis);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayHidden);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bRightToLeft);
+
+            CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMax));
+            CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMin));
+        }
+        // Sparkline at Sheet1:A3
+        {
+            sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 2, 
0)); // A3
+            CPPUNIT_ASSERT(pSparkline);
+            auto pSparklineGroup = pSparkline->getSparklineGroup();
+            CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column, 
pSparklineGroup->m_eType);
+
+            CPPUNIT_ASSERT_EQUAL(Color(0x376092), 
pSparklineGroup->m_aColorSeries);
+            CPPUNIT_ASSERT_EQUAL(Color(0xff0000), 
pSparklineGroup->m_aColorNegative);
+            CPPUNIT_ASSERT_EQUAL(Color(0x000000), 
pSparklineGroup->m_aColorAxis);
+            CPPUNIT_ASSERT_EQUAL(Color(0xd00000), 
pSparklineGroup->m_aColorMarkers);
+            CPPUNIT_ASSERT_EQUAL(Color(0x92d050), 
pSparklineGroup->m_aColorFirst);
+            CPPUNIT_ASSERT_EQUAL(Color(0x00b0f0), 
pSparklineGroup->m_aColorLast);
+            CPPUNIT_ASSERT_EQUAL(Color(0x7030a0), 
pSparklineGroup->m_aColorHigh);
+            CPPUNIT_ASSERT_EQUAL(Color(0xffc000), 
pSparklineGroup->m_aColorLow);
+
+            CPPUNIT_ASSERT_EQUAL(0.75, pSparklineGroup->m_fLineWeight);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDateAxis);
+            CPPUNIT_ASSERT_EQUAL(sc::DisplayEmptyCellAs::Gap,
+                                 pSparklineGroup->m_eDisplayEmptyCellsAs);
+
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bMarkers);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bHigh);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLow);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bFirst);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLast);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bNegative);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayXAxis);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayHidden);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bRightToLeft);
+
+            CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMax));
+            CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMin));
+        }
+        // Sparkline at Sheet2:B1
+        {
+            sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 0, 
1)); //B1
+            CPPUNIT_ASSERT(pSparkline);
+            auto pSparklineGroup = pSparkline->getSparklineGroup();
+            CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column, 
pSparklineGroup->m_eType);
+        }
+        // Sparkline at Sheet2:B2
+        {
+            sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 1, 
1)); //B2
+            CPPUNIT_ASSERT(pSparkline);
+            auto pSparklineGroup = pSparkline->getSparklineGroup();
+            CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, 
pSparklineGroup->m_eType);
+        }
+        // Sparkline at Sheet2:B2
+        {
+            sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 1, 
1)); //B2
+            CPPUNIT_ASSERT(pSparkline);
+            auto pSparklineGroup = pSparkline->getSparklineGroup();
+            CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, 
pSparklineGroup->m_eType);
+        }
+        // Sparkline doesn't exists at A4
+        {
+            sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 3, 
0)); //A4
+            CPPUNIT_ASSERT(!pSparkline);
+        }
     }
-    // Sparkline doesn't exists at A4
+
+    saveAndReload(mxComponent, "Calc Office Open XML");
+
     {
-        sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 3, 
0)); //A4
-        CPPUNIT_ASSERT(!pSparkline);
+        SfxObjectShell* pFoundShell = 
SfxObjectShell::GetShellFromComponent(mxComponent);
+        CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell);
+        ScDocShellRef xDocSh = dynamic_cast<ScDocShell*>(pFoundShell);
+        CPPUNIT_ASSERT(xDocSh);
+
+        ScDocument& rDocument = xDocSh->GetDocument();
+        // Sparkline at Sheet1:A2
+        {
+            sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 1, 
0)); // A2
+            CPPUNIT_ASSERT(pSparkline);
+            auto pSparklineGroup = pSparkline->getSparklineGroup();
+            CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, 
pSparklineGroup->m_eType);
+
+            CPPUNIT_ASSERT_EQUAL(Color(0x376092), 
pSparklineGroup->m_aColorSeries);
+            CPPUNIT_ASSERT_EQUAL(Color(0x00b050), 
pSparklineGroup->m_aColorNegative);
+            CPPUNIT_ASSERT_EQUAL(Color(0x000000), 
pSparklineGroup->m_aColorAxis);
+            CPPUNIT_ASSERT_EQUAL(Color(0x000000), 
pSparklineGroup->m_aColorMarkers);
+            CPPUNIT_ASSERT_EQUAL(Color(0x7030a0), 
pSparklineGroup->m_aColorFirst);
+            CPPUNIT_ASSERT_EQUAL(Color(0xff0000), 
pSparklineGroup->m_aColorLast);
+            CPPUNIT_ASSERT_EQUAL(Color(0x92d050), 
pSparklineGroup->m_aColorHigh);
+            CPPUNIT_ASSERT_EQUAL(Color(0x00b0f0), 
pSparklineGroup->m_aColorLow);
+
+            CPPUNIT_ASSERT_EQUAL(1.0, pSparklineGroup->m_fLineWeight);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDateAxis);
+            CPPUNIT_ASSERT_EQUAL(sc::DisplayEmptyCellAs::Gap,
+                                 pSparklineGroup->m_eDisplayEmptyCellsAs);
+
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bMarkers);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bHigh);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLow);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bFirst);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLast);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bNegative);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bDisplayXAxis);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayHidden);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bRightToLeft);
+
+            CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMax));
+            CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMin));
+        }
+        // Sparkline at Sheet1:A3
+        {
+            sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 2, 
0)); // A3
+            CPPUNIT_ASSERT(pSparkline);
+            auto pSparklineGroup = pSparkline->getSparklineGroup();
+            CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column, 
pSparklineGroup->m_eType);
+
+            CPPUNIT_ASSERT_EQUAL(Color(0x376092), 
pSparklineGroup->m_aColorSeries);
+            CPPUNIT_ASSERT_EQUAL(Color(0xff0000), 
pSparklineGroup->m_aColorNegative);
+            CPPUNIT_ASSERT_EQUAL(Color(0x000000), 
pSparklineGroup->m_aColorAxis);
+            CPPUNIT_ASSERT_EQUAL(Color(0xd00000), 
pSparklineGroup->m_aColorMarkers);
+            CPPUNIT_ASSERT_EQUAL(Color(0x92d050), 
pSparklineGroup->m_aColorFirst);
+            CPPUNIT_ASSERT_EQUAL(Color(0x00b0f0), 
pSparklineGroup->m_aColorLast);
+            CPPUNIT_ASSERT_EQUAL(Color(0x7030a0), 
pSparklineGroup->m_aColorHigh);
+            CPPUNIT_ASSERT_EQUAL(Color(0xffc000), 
pSparklineGroup->m_aColorLow);
+
+            CPPUNIT_ASSERT_EQUAL(0.75, pSparklineGroup->m_fLineWeight);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDateAxis);
+            CPPUNIT_ASSERT_EQUAL(sc::DisplayEmptyCellAs::Gap,
+                                 pSparklineGroup->m_eDisplayEmptyCellsAs);
+
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bMarkers);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bHigh);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLow);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bFirst);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLast);
+            CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bNegative);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayXAxis);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayHidden);
+            CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bRightToLeft);
+
+            CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMax));
+            CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMin));
+        }
+        // Sparkline at Sheet2:B1
+        {
+            sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 0, 
1)); //B1
+            CPPUNIT_ASSERT(pSparkline);
+            auto pSparklineGroup = pSparkline->getSparklineGroup();
+            CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column, 
pSparklineGroup->m_eType);
+        }
+        // Sparkline at Sheet2:B2
+        {
+            sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 1, 
1)); //B2
+            CPPUNIT_ASSERT(pSparkline);
+            auto pSparklineGroup = pSparkline->getSparklineGroup();
+            CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, 
pSparklineGroup->m_eType);
+        }
+        // Sparkline at Sheet2:B2
+        {
+            sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 1, 
1)); //B2
+            CPPUNIT_ASSERT(pSparkline);
+            auto pSparklineGroup = pSparkline->getSparklineGroup();
+            CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, 
pSparklineGroup->m_eType);
+        }
+        // Sparkline doesn't exists at A4
+        {
+            sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 3, 
0)); //A4
+            CPPUNIT_ASSERT(!pSparkline);
+        }
     }
 
     closeDocument(mxComponent);
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(SparklineTest);
-}
 
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sc/source/filter/excel/excdoc.cxx 
b/sc/source/filter/excel/excdoc.cxx
index 6b02457f70f6..529e76971cbc 100644
--- a/sc/source/filter/excel/excdoc.cxx
+++ b/sc/source/filter/excel/excdoc.cxx
@@ -39,6 +39,7 @@
 #include <xecontent.hxx>
 #include <xeescher.hxx>
 #include <xepivot.hxx>
+#include <export/SparklineExt.hxx>
 #include <XclExpChangeTrack.hxx>
 #include <xepivotxml.hxx>
 #include <xedbdata.hxx>
@@ -611,6 +612,8 @@ void ExcTable::FillAsTableXml()
     // conditional formats
     Add( new XclExpCondFormatBuffer( GetRoot(), xExtLst ) );
 
+    Add(new xcl::exp::SparklineBuffer(GetRoot(), xExtLst));
+
     // data validation (DVAL and list of DV records), generated by the cell 
table
     aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID_DVAL ) );
 
diff --git a/sc/source/filter/excel/export/SparklineExt.cxx 
b/sc/source/filter/excel/export/SparklineExt.cxx
new file mode 100644
index 000000000000..f1e97b2c62ed
--- /dev/null
+++ b/sc/source/filter/excel/export/SparklineExt.cxx
@@ -0,0 +1,246 @@
+/* -*- 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 "export/SparklineExt.hxx"
+
+#include <oox/export/utils.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/token/tokens.hxx>
+
+using namespace oox;
+
+namespace xcl::exp
+{
+SparklineExt::SparklineExt(const XclExpRoot& rRoot,
+                           std::vector<std::shared_ptr<sc::Sparkline>> const& 
pSparklines)
+    : XclExpExt(rRoot)
+{
+    maURI = "{05C60535-1F16-4fd2-B633-F4F36F0B64E0}";
+
+    for (auto const& pSparkline : pSparklines)
+    {
+        auto* pGroupPointer = pSparkline->getSparklineGroup().get();
+
+        auto aIterator = m_aSparklineGroupMap.find(pGroupPointer);
+        if (aIterator == m_aSparklineGroupMap.end())
+        {
+            std::vector<std::shared_ptr<sc::Sparkline>> aSparklineVector;
+            aSparklineVector.push_back(pSparkline);
+            m_aSparklineGroupMap.emplace(pGroupPointer, aSparklineVector);
+        }
+        else
+        {
+            aIterator->second.push_back(pSparkline);
+        }
+    }
+}
+
+void SparklineExt::SaveXml(XclExpXmlStream& rStream)
+{
+    sax_fastparser::FSHelperPtr& rWorksheet = rStream.GetCurrentStream();
+    rWorksheet->startElement(XML_ext, FSNS(XML_xmlns, XML_x14),
+                             rStream.getNamespaceURL(OOX_NS(xls14Lst)), 
XML_uri, maURI);
+
+    rWorksheet->startElementNS(XML_x14, XML_sparklineGroups, FSNS(XML_xmlns, 
XML_xm),
+                               rStream.getNamespaceURL(OOX_NS(xm)));
+
+    for (auto const & [ pSparklineGroup, rSparklineVector ] : 
m_aSparklineGroupMap)
+    {
+        addSparklineGroup(rStream, *pSparklineGroup, rSparklineVector);
+    }
+
+    rWorksheet->endElementNS(XML_x14, XML_sparklineGroups);
+    rWorksheet->endElement(XML_ext);
+}
+
+void SparklineExt::addSparklineGroupAttributes(
+    rtl::Reference<sax_fastparser::FastAttributeList>& pAttrList,
+    sc::SparklineGroup& rSparklineGroup)
+{
+    if (rSparklineGroup.m_fLineWeight != 0.75)
+        pAttrList->add(XML_lineWeight, 
OString::number(rSparklineGroup.m_fLineWeight));
+
+    if (rSparklineGroup.m_eType != sc::SparklineType::Line)
+    {
+        if (rSparklineGroup.m_eType == sc::SparklineType::Column)
+            pAttrList->add(XML_type, "column");
+        else if (rSparklineGroup.m_eType == sc::SparklineType::Stacked)
+            pAttrList->add(XML_type, "stacked");
+    }
+
+    if (rSparklineGroup.m_bDateAxis)
+        pAttrList->add(XML_dateAxis, "1");
+
+    if (rSparklineGroup.m_eDisplayEmptyCellsAs != sc::DisplayEmptyCellAs::Zero)
+    {
+        if (rSparklineGroup.m_eDisplayEmptyCellsAs == 
sc::DisplayEmptyCellAs::Gap)
+            pAttrList->add(XML_displayEmptyCellsAs, "gap");
+        else if (rSparklineGroup.m_eDisplayEmptyCellsAs == 
sc::DisplayEmptyCellAs::Span)
+            pAttrList->add(XML_displayEmptyCellsAs, "span");
+    }
+
+    if (rSparklineGroup.m_bMarkers)
+        pAttrList->add(XML_markers, "1");
+    if (rSparklineGroup.m_bHigh)
+        pAttrList->add(XML_high, "1");
+    if (rSparklineGroup.m_bLow)
+        pAttrList->add(XML_low, "1");
+    if (rSparklineGroup.m_bFirst)
+        pAttrList->add(XML_first, "1");
+    if (rSparklineGroup.m_bLast)
+        pAttrList->add(XML_last, "1");
+    if (rSparklineGroup.m_bNegative)
+        pAttrList->add(XML_negative, "1");
+    if (rSparklineGroup.m_bDisplayXAxis)
+        pAttrList->add(XML_displayXAxis, "1");
+    if (rSparklineGroup.m_bDisplayHidden)
+        pAttrList->add(XML_displayHidden, "1");
+
+    if (rSparklineGroup.m_eMinAxisType != sc::AxisType::Individual)
+    {
+        if (rSparklineGroup.m_eMinAxisType == sc::AxisType::Group)
+            pAttrList->add(XML_minAxisType, "group");
+        else if (rSparklineGroup.m_eMinAxisType == sc::AxisType::Custom)
+            pAttrList->add(XML_minAxisType, "custom");
+    }
+
+    if (rSparklineGroup.m_eMaxAxisType != sc::AxisType::Individual)
+    {
+        if (rSparklineGroup.m_eMaxAxisType == sc::AxisType::Group)
+            pAttrList->add(XML_maxAxisType, "group");
+        else if (rSparklineGroup.m_eMaxAxisType == sc::AxisType::Custom)
+            pAttrList->add(XML_maxAxisType, "custom");
+    }
+
+    if (rSparklineGroup.m_bRightToLeft)
+        pAttrList->add(XML_rightToLeft, "1");
+
+    if (rSparklineGroup.m_aManualMax && rSparklineGroup.m_eMaxAxisType == 
sc::AxisType::Custom)
+        pAttrList->add(XML_manualMax, 
OString::number(*rSparklineGroup.m_aManualMax));
+
+    if (rSparklineGroup.m_aManualMin && rSparklineGroup.m_eMinAxisType == 
sc::AxisType::Custom)
+        pAttrList->add(XML_manualMin, 
OString::number(*rSparklineGroup.m_aManualMin));
+}
+
+void SparklineExt::addSparklineGroupColors(XclExpXmlStream& rStream,
+                                           sc::SparklineGroup& rSparklineGroup)
+{
+    sax_fastparser::FSHelperPtr& rWorksheet = rStream.GetCurrentStream();
+
+    rWorksheet->singleElementNS(XML_x14, XML_colorSeries, XML_rgb,
+                                
XclXmlUtils::ToOString(rSparklineGroup.m_aColorSeries));
+
+    if (rSparklineGroup.m_aColorSeries != COL_TRANSPARENT)
+    {
+        rWorksheet->singleElementNS(XML_x14, XML_colorNegative, XML_rgb,
+                                    
XclXmlUtils::ToOString(rSparklineGroup.m_aColorNegative));
+    }
+
+    if (rSparklineGroup.m_aColorAxis != COL_TRANSPARENT)
+    {
+        rWorksheet->singleElementNS(XML_x14, XML_colorAxis, XML_rgb,
+                                    
XclXmlUtils::ToOString(rSparklineGroup.m_aColorAxis));
+    }
+
+    if (rSparklineGroup.m_aColorMarkers != COL_TRANSPARENT)
+    {
+        rWorksheet->singleElementNS(XML_x14, XML_colorMarkers, XML_rgb,
+                                    
XclXmlUtils::ToOString(rSparklineGroup.m_aColorMarkers));
+    }
+
+    if (rSparklineGroup.m_aColorFirst != COL_TRANSPARENT)
+    {
+        rWorksheet->singleElementNS(XML_x14, XML_colorFirst, XML_rgb,
+                                    
XclXmlUtils::ToOString(rSparklineGroup.m_aColorFirst));
+    }
+
+    if (rSparklineGroup.m_aColorLast != COL_TRANSPARENT)
+    {
+        rWorksheet->singleElementNS(XML_x14, XML_colorLast, XML_rgb,
+                                    
XclXmlUtils::ToOString(rSparklineGroup.m_aColorLast));
+    }
+
+    if (rSparklineGroup.m_aColorHigh != COL_TRANSPARENT)
+    {
+        rWorksheet->singleElementNS(XML_x14, XML_colorHigh, XML_rgb,
+                                    
XclXmlUtils::ToOString(rSparklineGroup.m_aColorHigh));
+    }
+
+    if (rSparklineGroup.m_aColorLow != COL_TRANSPARENT)
+    {
+        rWorksheet->singleElementNS(XML_x14, XML_colorLow, XML_rgb,
+                                    
XclXmlUtils::ToOString(rSparklineGroup.m_aColorLow));
+    }
+}
+
+void SparklineExt::addSparklineGroup(XclExpXmlStream& rStream, 
sc::SparklineGroup& rSparklineGroup,
+                                     
std::vector<std::shared_ptr<sc::Sparkline>> const& rSparklines)
+{
+    sax_fastparser::FSHelperPtr& rWorksheet = rStream.GetCurrentStream();
+
+    // Sparkline Group Attributes
+    auto pAttrList = sax_fastparser::FastSerializerHelper::createAttrList();
+    addSparklineGroupAttributes(pAttrList, rSparklineGroup);
+
+    rWorksheet->startElementNS(XML_x14, XML_sparklineGroup, pAttrList);
+
+    addSparklineGroupColors(rStream, rSparklineGroup);
+
+    // Sparklines
+
+    rWorksheet->startElementNS(XML_x14, XML_sparklines);
+    for (auto const& rSparkline : rSparklines)
+    {
+        rWorksheet->startElementNS(XML_x14, XML_sparkline);
+
+        {
+            rWorksheet->startElementNS(XML_xm, XML_f);
+
+            OUString sRangeFormula;
+            ScRefFlags eFlags = ScRefFlags::VALID | ScRefFlags::TAB_3D;
+            rSparkline->getInputRange().Format(sRangeFormula, eFlags, GetDoc(),
+                                               
formula::FormulaGrammar::CONV_XL_OOX, ' ', true);
+
+            rWorksheet->writeEscaped(sRangeFormula);
+            rWorksheet->endElementNS(XML_xm, XML_f);
+        }
+
+        {
+            rWorksheet->startElementNS(XML_xm, XML_sqref);
+
+            ScAddress::Details detailsXL(formula::FormulaGrammar::CONV_XL_OOX);
+            ScAddress aAddress(rSparkline->getColumn(), rSparkline->getRow(), 
GetCurrScTab());
+            OUString sLocation = aAddress.Format(ScRefFlags::VALID, &GetDoc(), 
detailsXL);
+
+            rWorksheet->writeEscaped(sLocation);
+            rWorksheet->endElementNS(XML_xm, XML_sqref);
+        }
+
+        rWorksheet->endElementNS(XML_x14, XML_sparkline);
+    }
+    rWorksheet->endElementNS(XML_x14, XML_sparklines);
+    rWorksheet->endElementNS(XML_x14, XML_sparklineGroup);
+}
+
+SparklineBuffer::SparklineBuffer(const XclExpRoot& rRoot, XclExtLstRef const& 
xExtLst)
+    : XclExpRoot(rRoot)
+{
+    if (sc::SparklineList* pSparklineList = 
GetDoc().GetSparklineList(GetCurrScTab()))
+    {
+        auto pSparklines = pSparklineList->getSparklines();
+        if (!pSparklines.empty())
+        {
+            xExtLst->AddRecord(new xcl::exp::SparklineExt(GetRoot(), 
pSparklines));
+        }
+    }
+}
+
+} // end namespace xcl::exp
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/export/SparklineExt.hxx 
b/sc/source/filter/inc/export/SparklineExt.hxx
new file mode 100644
index 000000000000..116462c5f3c4
--- /dev/null
+++ b/sc/source/filter/inc/export/SparklineExt.hxx
@@ -0,0 +1,52 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+#include <map>
+#include <rangelst.hxx>
+#include <Sparkline.hxx>
+
+#include <sax/fastattribs.hxx>
+
+#include "xerecord.hxx"
+#include "xeroot.hxx"
+#include "xeextlst.hxx"
+
+namespace xcl::exp
+{
+class SparklineExt : public XclExpExt
+{
+    std::map<sc::SparklineGroup*, std::vector<std::shared_ptr<sc::Sparkline>>> 
m_aSparklineGroupMap;
+
+public:
+    SparklineExt(const XclExpRoot& rRoot,
+                 std::vector<std::shared_ptr<sc::Sparkline>> const& 
pSparklines);
+
+    void SaveXml(XclExpXmlStream& rStream) override;
+    void addSparklineGroup(XclExpXmlStream& rStream, sc::SparklineGroup& 
rSparklineGroup,
+                           std::vector<std::shared_ptr<sc::Sparkline>> const& 
rSparklines);
+    void 
addSparklineGroupAttributes(rtl::Reference<sax_fastparser::FastAttributeList>& 
pAttrList,
+                                     sc::SparklineGroup& rSparklineGroup);
+    void addSparklineGroupColors(XclExpXmlStream& rStream, sc::SparklineGroup& 
rSparklineGroup);
+
+    XclExpExtType GetType() override { return XclExpExtSparklineType; }
+};
+
+class SparklineBuffer : public XclExpRecordBase, protected XclExpRoot
+{
+public:
+    explicit SparklineBuffer(const XclExpRoot& rRoot, const XclExtLstRef& 
xExtLst);
+};
+
+} // end namespace xcl::exp
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/xeextlst.hxx 
b/sc/source/filter/inc/xeextlst.hxx
index c5db5fcaff99..1770f9af191d 100644
--- a/sc/source/filter/inc/xeextlst.hxx
+++ b/sc/source/filter/inc/xeextlst.hxx
@@ -19,7 +19,8 @@
 enum XclExpExtType
 {
     XclExpExtDataBarType,
-    XclExpExtDataFooType
+    XclExpExtDataFooType,
+    XclExpExtSparklineType,
 };
 
 struct XclExpExtCondFormatData
commit e42cb7e66f5bb427421708142be9bd804bfa4960
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Fri Mar 4 17:26:34 2022 +0900
Commit:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
CommitDate: Fri Mar 4 20:54:34 2022 +0900

    sc: set colors in SparklineGroup construction to COL_TRANSPARENT
    
    Change-Id: I67ceab2ffd723511fbf0616cca661992f0a8cf69

diff --git a/sc/inc/SparklineGroup.hxx b/sc/inc/SparklineGroup.hxx
index 32e4b757378f..170ccee51539 100644
--- a/sc/inc/SparklineGroup.hxx
+++ b/sc/inc/SparklineGroup.hxx
@@ -74,7 +74,17 @@ public:
     std::optional<double> m_aManualMin;
     OUString m_sUID;
 
-    SparklineGroup() {}
+    SparklineGroup()
+        : m_aColorSeries(COL_TRANSPARENT)
+        , m_aColorNegative(COL_TRANSPARENT)
+        , m_aColorAxis(COL_TRANSPARENT)
+        , m_aColorMarkers(COL_TRANSPARENT)
+        , m_aColorFirst(COL_TRANSPARENT)
+        , m_aColorLast(COL_TRANSPARENT)
+        , m_aColorHigh(COL_TRANSPARENT)
+        , m_aColorLow(COL_TRANSPARENT)
+    {
+    }
 
     SparklineGroup(const SparklineGroup&) = delete;
     SparklineGroup& operator=(const SparklineGroup&) = delete;
commit b2160dc8db765ced65f17495734b4d5726002966
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Wed Mar 2 17:44:08 2022 +0900
Commit:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
CommitDate: Fri Mar 4 20:54:34 2022 +0900

    sc: refactor sparkline struture to store a list of sparklines
    
    We need to access a list of sparklines and sparkline groups for
    a sheet. To preven going through all the columns of a sheet, we
    need to store all the created sparklines in a list. For this it
    is necessary to change the model structrue a bit. A cell now has
    a container that stores a shared_ptr to the sparkline instead of
    storing the sparkline directly. With this we can store a list
    of weak_ptr to the sparklines in a list (vector), which can be
    accessed at any time and is quite fast.
    
    This is needed by the OOXML export.
    
    Change-Id: Iaca0a41e20912775f072ea6e8cab9c44367d6f30

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 11449217edd9..62ab22a797c4 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -185,7 +185,6 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
     sc/source/core/data/sheetevents \
     sc/source/core/data/simpleformulacalc \
     sc/source/core/data/sortparam \
-    sc/source/core/data/Sparkline \
     sc/source/core/data/stlpool \
     sc/source/core/data/stlsheet \
     sc/source/core/data/subtotalparam \
diff --git a/sc/inc/Sparkline.hxx b/sc/inc/Sparkline.hxx
index 8969fa3bfd3e..ad4688f33a5e 100644
--- a/sc/inc/Sparkline.hxx
+++ b/sc/inc/Sparkline.hxx
@@ -19,20 +19,67 @@ namespace sc
 {
 class SC_DLLPUBLIC Sparkline
 {
-private:
+    SCCOL m_nColumn;
+    SCROW m_nRow;
+
     ScRangeList m_aInputRange;
     std::shared_ptr<SparklineGroup> m_pSparklineGroup;
 
 public:
-    Sparkline(std::shared_ptr<SparklineGroup>& pSparklineGroup);
+    Sparkline(SCCOL nColumn, SCROW nRow, std::shared_ptr<SparklineGroup> 
const& pSparklineGroup)
+        : m_nColumn(nColumn)
+        , m_nRow(nRow)
+        , m_pSparklineGroup(pSparklineGroup)
+    {
+    }
 
     Sparkline(const Sparkline&) = delete;
     Sparkline& operator=(const Sparkline&) = delete;
 
     void setInputRange(ScRangeList const& rInputRange) { m_aInputRange = 
rInputRange; }
+
     ScRangeList const& getInputRange() { return m_aInputRange; }
 
     std::shared_ptr<SparklineGroup> const& getSparklineGroup() { return 
m_pSparklineGroup; }
+
+    SCCOL getColumn() { return m_nColumn; }
+
+    SCROW getRow() { return m_nRow; }
+};
+
+class SC_DLLPUBLIC SparklineList
+{
+private:
+    std::vector<std::weak_ptr<Sparkline>> m_pSparklines;
+
+public:
+    SparklineList() {}
+
+    void addSparkline(std::shared_ptr<Sparkline> const& pSparkline)
+    {
+        m_pSparklines.push_back(pSparkline);
+    }
+
+    std::vector<std::shared_ptr<Sparkline>> getSparklines()
+    {
+        std::vector<std::shared_ptr<Sparkline>> toReturn;
+
+        std::vector<std::weak_ptr<Sparkline>>::iterator aIter;
+        for (aIter = m_pSparklines.begin(); aIter != m_pSparklines.end();)
+        {
+            if (auto aSparkline = aIter->lock())
+            {
+                toReturn.push_back(aSparkline);
+                aIter++;
+            }
+            else
+            {
+                aIter = m_pSparklines.erase(aIter);
+            }
+        }
+
+        return toReturn;
+    }
 };
 
 } // end sc
diff --git a/sc/inc/SparklineCell.hxx b/sc/inc/SparklineCell.hxx
new file mode 100644
index 000000000000..0aca857170c9
--- /dev/null
+++ b/sc/inc/SparklineCell.hxx
@@ -0,0 +1,47 @@
+/* -*- 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/.
+ *
+ */
+
+#pragma once
+
+#include "scdllapi.h"
+#include "Sparkline.hxx"
+#include <memory>
+
+namespace sc
+{
+class SC_DLLPUBLIC SparklineCell
+{
+private:
+    std::shared_ptr<Sparkline> m_pSparkline;
+
+public:
+    SparklineCell(std::shared_ptr<Sparkline> const& pSparkline)
+        : m_pSparkline(pSparkline)
+    {
+    }
+
+    SparklineCell(const SparklineCell&) = delete;
+    SparklineCell& operator=(const SparklineCell&) = delete;
+
+    void setInputRange(ScRangeList const& rInputRange) { 
m_pSparkline->setInputRange(rInputRange); }
+
+    ScRangeList const& getInputRange() { return m_pSparkline->getInputRange(); 
}
+
+    std::shared_ptr<SparklineGroup> const& getSparklineGroup()
+    {
+        return m_pSparkline->getSparklineGroup();
+    }
+
+    std::shared_ptr<Sparkline> const& getSparkline() { return m_pSparkline; }
+};
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index f4b603c5c721..5472419e2297 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -617,8 +617,8 @@ public:
     void BroadcastRows( SCROW nStartRow, SCROW nEndRow, SfxHintId nHint );
 
     // Spaklines
-    sc::Sparkline* GetSparkline(SCROW nRow);
-    void SetSparkline(SCROW nRow, std::unique_ptr<sc::Sparkline> pSparkline);
+    sc::SparklineCell* GetSparklineCell(SCROW nRow);
+    void CreateSparklineCell(SCROW nRow, std::shared_ptr<sc::Sparkline> const& 
pSparkline);
 
     // cell notes
     ScPostIt* GetCellNote( SCROW nRow );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 86bd4ebd02bf..1b86695ba94b 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -103,6 +103,7 @@ class ColumnIterator;
 class ExternalDataMapper;
 class Sparkline;
 class SparklineGroup;
+class SparklineList;
 
 }
 
@@ -1244,6 +1245,7 @@ public:
     /** Spaklines */
     SC_DLLPUBLIC sc::Sparkline* GetSparkline(ScAddress const & rPosition);
     SC_DLLPUBLIC sc::Sparkline* CreateSparkline(ScAddress const & rPosition, 
std::shared_ptr<sc::SparklineGroup> & pSparklineGroup);
+    SC_DLLPUBLIC sc::SparklineList* GetSparklineList(SCTAB nTab);
 
     /** Notes **/
     SC_DLLPUBLIC ScPostIt*       GetNote(const ScAddress& rPos);
diff --git a/sc/inc/mtvelements.hxx b/sc/inc/mtvelements.hxx
index 6de0f3e7ec23..ee669c0a6e6b 100644
--- a/sc/inc/mtvelements.hxx
+++ b/sc/inc/mtvelements.hxx
@@ -15,7 +15,7 @@
 #include <editeng/editobj.hxx>
 #include "calcmacros.hxx"
 #include "postit.hxx"
-#include "Sparkline.hxx"
+#include "SparklineCell.hxx"
 #include "celltextattr.hxx"
 
 #if DEBUG_COLUMN_STORAGE
@@ -59,7 +59,7 @@ const mdds::mtv::element_t element_type_uint16 = 
mdds::mtv::element_type_uint16;
 
 /// Custom element blocks.
 
-typedef mdds::mtv::noncopyable_managed_element_block<element_type_sparkline, 
sc::Sparkline> sparkline_block;
+typedef mdds::mtv::noncopyable_managed_element_block<element_type_sparkline, 
sc::SparklineCell> sparkline_block;
 typedef mdds::mtv::noncopyable_managed_element_block<element_type_cellnote, 
ScPostIt> cellnote_block;
 typedef mdds::mtv::noncopyable_managed_element_block<element_type_broadcaster, 
SvtBroadcaster> broadcaster_block;
 typedef mdds::mtv::default_element_block<element_type_celltextattr, 
CellTextAttr> celltextattr_block;
@@ -77,7 +77,7 @@ typedef mdds::mtv::uint16_element_block uint16_block;
 /// For example sc types like sc::CellTextAttr, ScFormulaCell in global 
namespace.
 namespace sc {
 MDDS_MTV_DEFINE_ELEMENT_CALLBACKS(CellTextAttr, element_type_celltextattr, 
CellTextAttr(), celltextattr_block)
-MDDS_MTV_DEFINE_ELEMENT_CALLBACKS_PTR(Sparkline, sc::element_type_sparkline, 
nullptr, sc::sparkline_block)
+MDDS_MTV_DEFINE_ELEMENT_CALLBACKS_PTR(SparklineCell, 
sc::element_type_sparkline, nullptr, sc::sparkline_block)
 }
 
 /// These need to be in global namespace just like their respective types are.
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 4a8654a67344..39cc4736d12d 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -227,6 +227,7 @@ private:
     mutable std::unique_ptr<ScRangeName> mpRangeName;
 
     std::unique_ptr<ScConditionalFormatList> mpCondFormatList;
+    sc::SparklineList maSparklineList;
 
     ScAddress       maLOKFreezeCell;
 
@@ -472,6 +473,14 @@ public:
     void        GetFirstDataPos(SCCOL& rCol, SCROW& rRow) const;
     void        GetLastDataPos(SCCOL& rCol, SCROW& rRow) const;
 
+    // Sparklines
+
+    sc::Sparkline* GetSparkline(SCCOL nCol, SCROW nRow);
+    sc::Sparkline* CreateSparkline(SCCOL nCol, SCROW nRow, 
std::shared_ptr<sc::SparklineGroup> & pSparklineGroup);
+
+    sc::SparklineList& GetSparklineList();
+
+    // Notes / Comments
     std::unique_ptr<ScPostIt> ReleaseNote( SCCOL nCol, SCROW nRow );
     ScPostIt*                 GetNote( SCCOL nCol, SCROW nRow );
     void                      SetNote( SCCOL nCol, SCROW nRow, 
std::unique_ptr<ScPostIt> pNote );
diff --git a/sc/source/core/data/Sparkline.cxx 
b/sc/source/core/data/Sparkline.cxx
deleted file mode 100644
index 301fda820ff2..000000000000
--- a/sc/source/core/data/Sparkline.cxx
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- 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 <memory>
-#include <Sparkline.hxx>
-
-namespace sc
-{
-Sparkline::Sparkline(std::shared_ptr<SparklineGroup>& pSparklineGroup)
-    : m_pSparklineGroup(pSparklineGroup)
-{
-}
-}
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index c2755f8f3cbb..cccd2af0fb34 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1979,14 +1979,14 @@ void ScColumn::PrepareBroadcastersForDestruction()
     }
 }
 
-sc::Sparkline* ScColumn::GetSparkline(SCROW nRow)
+sc::SparklineCell* ScColumn::GetSparklineCell(SCROW nRow)
 {
-    return maSparklines.get<sc::Sparkline*>(nRow);
+    return maSparklines.get<sc::SparklineCell*>(nRow);
 }
 
-void ScColumn::SetSparkline(SCROW nRow, std::unique_ptr<sc::Sparkline> 
pSparkline)
+void ScColumn::CreateSparklineCell(SCROW nRow, std::shared_ptr<sc::Sparkline> 
const& pSparkline)
 {
-    maSparklines.set(nRow, pSparkline.release());
+    maSparklines.set(nRow, new sc::SparklineCell(pSparkline));
 }
 
 ScPostIt* ScColumn::GetCellNote(SCROW nRow)
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 92bf74e40c30..e0b1037c8d3e 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -6505,33 +6505,41 @@ bool ScDocument::IsInVBAMode() const
     return false;
 }
 
+// Sparklines
 sc::Sparkline* ScDocument::GetSparkline(ScAddress const& rPosition)
 {
     SCTAB nTab = rPosition.Tab();
-    SCCOL nCol = rPosition.Col();
 
-    if (ValidTab(nTab) && nTab < SCTAB(maTabs.size()) &&
-        nCol < maTabs[nTab]->GetAllocatedColumnsCount())
+    if (ValidTab(nTab) && nTab < SCTAB(maTabs.size()))
     {
-        SCROW nRow = rPosition.Row();
-        return maTabs[nTab]->aCol[nCol].GetSparkline(nRow);
+        return maTabs[nTab]->GetSparkline(rPosition.Col(), rPosition.Row());
     }
     return nullptr;
 }
 
 sc::Sparkline* ScDocument::CreateSparkline(ScAddress const & rPosition, 
std::shared_ptr<sc::SparklineGroup> & pSparklineGroup)
 {
-    std::unique_ptr<sc::Sparkline> pSparkline(new 
sc::Sparkline(pSparklineGroup));
-    sc::Sparkline* pCreated = pSparkline.get();
-
     SCTAB nTab = rPosition.Tab();
-    SCCOL nCol = rPosition.Col();
-    SCROW nRow = rPosition.Row();
-    maTabs[nTab]->CreateColumnIfNotExists(nCol).SetSparkline(nRow, 
std::move(pSparkline));
 
-    return pCreated;
+    if (ValidTab(nTab) && nTab < SCTAB(maTabs.size()))
+    {
+        return maTabs[nTab]->CreateSparkline(rPosition.Col(), rPosition.Row(), 
pSparklineGroup);
+    }
+
+    return nullptr;
+}
+
+sc::SparklineList* ScDocument::GetSparklineList(SCTAB nTab)
+{
+    if (ValidTab(nTab) && nTab < SCTAB(maTabs.size()))
+    {
+        return &maTabs[nTab]->GetSparklineList();
+    }
+    return nullptr;
 }
 
+// Notes
+
 ScPostIt* ScDocument::GetNote(const ScAddress& rPos)
 {
     return GetNote(rPos.Col(), rPos.Row(), rPos.Tab());
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index b65d1651e56d..aa218ee44cec 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1809,6 +1809,43 @@ ScFormulaCell* ScTable::GetFormulaCell( SCCOL nCol, 
SCROW nRow )
     return aCol[nCol].GetFormulaCell(nRow);
 }
 
+// Sparklines
+
+sc::Sparkline* ScTable::GetSparkline(SCCOL nCol, SCROW nRow)
+{
+    if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
+        return nullptr;
+
+    sc::SparklineCell* pSparklineCell = aCol[nCol].GetSparklineCell(nRow);
+    if (!pSparklineCell)
+        return nullptr;
+
+    std::shared_ptr<sc::Sparkline> pSparkline(pSparklineCell->getSparkline());
+    assert(pSparkline);
+
+    return pSparkline.get();
+}
+
+sc::Sparkline* ScTable::CreateSparkline(SCCOL nCol, SCROW nRow, 
std::shared_ptr<sc::SparklineGroup>& pSparklineGroup)
+{
+    if (!ValidCol(nCol))
+        return nullptr;
+
+    ScColumn& rColumn = CreateColumnIfNotExists(nCol);
+
+    std::shared_ptr<sc::Sparkline> pSparkline(new sc::Sparkline(nCol, nRow, 
pSparklineGroup));
+    maSparklineList.addSparkline(pSparkline);
+    rColumn.CreateSparklineCell(nRow, pSparkline);
+    return pSparkline.get();
+}
+
+sc::SparklineList& ScTable::GetSparklineList()
+{
+    return maSparklineList;
+}
+
+// Notes
+
 std::unique_ptr<ScPostIt> ScTable::ReleaseNote( SCCOL nCol, SCROW nRow )
 {
     if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
commit fd7698f4c97a9aea69788d28d38bd90a96f62fac
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Mon Feb 28 15:35:48 2022 +0900
Commit:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
CommitDate: Fri Mar 4 20:54:33 2022 +0900

    sc: support sparkline bar colors, add markers to sparkline lines
    
    Change-Id: I705a7f57cc4d6544ecb35a5f93c18a27056b9944

diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx
index 213f4c1cc69b..c504cd7f32c0 100644
--- a/sc/source/ui/view/output.cxx
+++ b/sc/source/ui/view/output.cxx
@@ -2316,33 +2316,121 @@ void ScOutputData::DrawChangeTrack()
 namespace
 {
 
+struct SparklineMarker
+{
+    basegfx::B2DPolygon maPolygon;
+    Color maColor;
+};
+
+void createMarker(std::vector<SparklineMarker> & rMarkers, double x, double y, 
Color const & rColor)
+{
+    auto & rMarker = rMarkers.emplace_back();
+    basegfx::B2DRectangle aRectangle(x - 2, y - 2, x + 2, y + 2);
+    rMarker.maPolygon = basegfx::utils::createPolygonFromRect(aRectangle);
+    rMarker.maColor = rColor;
+}
+
 void drawLine(vcl::RenderContext& rRenderContext, tools::Rectangle const & 
rRectangle,
-                std::vector<double> const & rValues, double nMin, double nMax)
+                std::vector<double> const & rValues, double nMin, double nMax,
+                std::shared_ptr<sc::SparklineGroup> const & pSparklineGroup)
 {
     basegfx::B2DPolygon aPolygon;
     double numebrOfSteps = rValues.size() - 1;
     double xStep = 0;
     double nDelta = nMax - nMin;
 
-    for (double aValue : rValues)
+    std::vector<SparklineMarker> aMarkers;
+    sal_Int64 nValueIndex = 0;
+    sal_Int64 nValuesSize = rValues.size();
+
+    for (double nValue : rValues)
     {
-        double nP = (aValue - nMin) / nDelta;
+        double nP = (nValue - nMin) / nDelta;
         double x = rRectangle.GetWidth() * (xStep / numebrOfSteps);
         double y = rRectangle.GetHeight() - rRectangle.GetHeight() * nP;
 
         aPolygon.append({ x, y } );
+
+        if (pSparklineGroup->m_bFirst && nValueIndex == 0)
+        {
+            createMarker(aMarkers, x, y, pSparklineGroup->m_aColorFirst);
+        }
+        else if (pSparklineGroup->m_bLast && nValueIndex == (nValuesSize - 1))
+        {
+            createMarker(aMarkers, x, y, pSparklineGroup->m_aColorLast);
+        }
+        else if (pSparklineGroup->m_bHigh && nValue == nMax)
+        {
+            createMarker(aMarkers, x, y, pSparklineGroup->m_aColorHigh);
+        }
+        else if (pSparklineGroup->m_bLow && nValue == nMin)
+        {
+            createMarker(aMarkers, x, y, pSparklineGroup->m_aColorLow);
+        }
+        else if (pSparklineGroup->m_bNegative && nValue < 0.0)
+        {
+            createMarker(aMarkers, x, y, pSparklineGroup->m_aColorNegative);
+        }
+
         xStep++;
+        nValueIndex++;
     }
 
     basegfx::B2DHomMatrix aMatrix;
     aMatrix.translate(rRectangle.Left(), rRectangle.Top());
     aPolygon.transform(aMatrix);
 
+    rRenderContext.SetLineColor(pSparklineGroup->m_aColorSeries);
     rRenderContext.DrawPolyLine(aPolygon);
+
+    for (auto const & rMarker : aMarkers)
+    {
+        rRenderContext.SetLineColor(rMarker.maColor);
+        rRenderContext.SetFillColor(rMarker.maColor);
+        aPolygon = rMarker.maPolygon;
+        aPolygon.transform(aMatrix);
+        rRenderContext.DrawPolygon(aPolygon);
+    }
+}
+
+void setFillAndLineColor(vcl::RenderContext& rRenderContext, 
std::shared_ptr<sc::SparklineGroup> const & pSparklineGroup,
+                         double nValue, sal_Int64 nValueIndex, sal_Int64 
nValuesSize, double nMin, double nMax)
+{
+    if (pSparklineGroup->m_bFirst && nValueIndex == 0)
+    {
+        rRenderContext.SetLineColor(pSparklineGroup->m_aColorFirst);
+        rRenderContext.SetFillColor(pSparklineGroup->m_aColorFirst);
+    }
+    else if (pSparklineGroup->m_bLast && nValueIndex == (nValuesSize - 1))
+    {
+        rRenderContext.SetLineColor(pSparklineGroup->m_aColorLast);
+        rRenderContext.SetFillColor(pSparklineGroup->m_aColorLast);
+    }
+    else if (pSparklineGroup->m_bHigh && nValue == nMax)
+    {
+        rRenderContext.SetLineColor(pSparklineGroup->m_aColorHigh);
+        rRenderContext.SetFillColor(pSparklineGroup->m_aColorHigh);
+    }
+    else if (pSparklineGroup->m_bLow && nValue == nMin)
+    {
+        rRenderContext.SetLineColor(pSparklineGroup->m_aColorLow);
+        rRenderContext.SetFillColor(pSparklineGroup->m_aColorLow);
+    }
+    else if (pSparklineGroup->m_bNegative && nValue < 0.0)
+    {
+        rRenderContext.SetLineColor(pSparklineGroup->m_aColorNegative);
+        rRenderContext.SetFillColor(pSparklineGroup->m_aColorNegative);
+    }
+    else
+    {
+        rRenderContext.SetLineColor(pSparklineGroup->m_aColorSeries);
+        rRenderContext.SetFillColor(pSparklineGroup->m_aColorSeries);
+    }
 }
 
 void drawColumn(vcl::RenderContext& rRenderContext, tools::Rectangle const & 
rRectangle,
-                std::vector<double> const & rValues, double nMin, double nMax)
+                std::vector<double> const & rValues, double nMin, double nMax,
+                std::shared_ptr<sc::SparklineGroup> const & pSparklineGroup)
 {
     basegfx::B2DPolygon aPolygon;
 
@@ -2359,11 +2447,15 @@ void drawColumn(vcl::RenderContext& rRenderContext, 
tools::Rectangle const & rRe
     else
         nZeroPosition = rRectangle.GetHeight();
 
-    for (double aValue : rValues)
+    sal_Int64 nValueIndex = 0;
+
+    for (double nValue : rValues)
     {
-        if (aValue != 0.0)
+        if (nValue != 0.0)
         {
-            double nP = (aValue - nMin) / nDelta;
+            setFillAndLineColor(rRenderContext, pSparklineGroup, nValue, 
nValueIndex, sal_Int64(rValues.size()), nMax, nMin);
+
+            double nP = (nValue - nMin) / nDelta;
             double x = rRectangle.GetWidth() * (xStep / numberOfSteps);
             double y = rRectangle.GetHeight() - rRectangle.GetHeight() * nP;
 
@@ -2376,6 +2468,7 @@ void drawColumn(vcl::RenderContext& rRenderContext, 
tools::Rectangle const & rRe
             rRenderContext.DrawPolygon(aPolygon);
         }
         xStep++;
+        nValueIndex++;
     }
 }
 
@@ -2391,9 +2484,6 @@ void drawSparkline(sc::Sparkline* pSparkline, 
vcl::RenderContext& rRenderContext
 
     rRenderContext.SetAntialiasing(AntialiasingFlags::Enable);
 
-    rRenderContext.SetLineColor(pSparklineGroup->m_aColorSeries);
-    rRenderContext.SetFillColor(pSparklineGroup->m_aColorSeries);
-
     ScRange aRange = rRangeList[0];
 
     std::vector<double> aValues;
@@ -2434,7 +2524,7 @@ void drawSparkline(sc::Sparkline* pSparkline, 
vcl::RenderContext& rRenderContext
 
     if (pSparklineGroup->m_eType == sc::SparklineType::Column)
     {
-        drawColumn(rRenderContext, rRectangle, aValues, nMin, nMax);
+        drawColumn(rRenderContext, rRectangle, aValues, nMin, nMax, 
pSparklineGroup);
     }
     else if (pSparklineGroup->m_eType == sc::SparklineType::Stacked)
     {
@@ -2444,11 +2534,11 @@ void drawSparkline(sc::Sparkline* pSparkline, 
vcl::RenderContext& rRenderContext
             if (rValue != 0.0)
                 rValue = rValue > 0.0 ? 1.0 : -1.0;
         }
-        drawColumn(rRenderContext, rRectangle, aValues, -1, 1);
+        drawColumn(rRenderContext, rRectangle, aValues, -1, 1, 
pSparklineGroup);
     }
     else if (pSparklineGroup->m_eType == sc::SparklineType::Line)
     {
-        drawLine(rRenderContext, rRectangle, aValues, nMin, nMax);
+        drawLine(rRenderContext, rRectangle, aValues, nMin, nMax, 
pSparklineGroup);
     }
 }
 } // end anonymous namespace
commit e0b8cf9dedd98165909cd5d93e490e77b1fa5497
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Thu Feb 24 18:04:37 2022 +0900
Commit:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
CommitDate: Fri Mar 4 20:54:33 2022 +0900

    sc: first simple test for Sparklines
    
    Change-Id: I513571de398be419074d54c5861374effae07709

diff --git a/sc/CppunitTest_sc_sparkline_test.mk 
b/sc/CppunitTest_sc_sparkline_test.mk
new file mode 100644
index 000000000000..edf7a3cac7da
--- /dev/null
+++ b/sc/CppunitTest_sc_sparkline_test.mk
@@ -0,0 +1,60 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# 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/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,sc_sparkline_test))
+
+$(eval $(call gb_CppunitTest_use_common_precompiled_header,sc_sparkline_test))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sc_sparkline_test, \
+    sc/qa/extras/SparklineTest \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,sc_sparkline_test, \
+    basegfx \
+    comphelper \
+    cppu \
+    cppuhelper \
+    sal \
+    salhelper \
+    sax \
+    sc \
+    scqahelper \
+    sfx \
+    subsequenttest \
+    test \
+    tl \
+    unotest \
+    vcl \
+))
+
+$(eval $(call gb_CppunitTest_set_include,sc_sparkline_test,\
+    -I$(SRCDIR)/sc/source/ui/inc \
+    -I$(SRCDIR)/sc/inc \
+    $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_api,sc_sparkline_test,\
+    offapi \
+    udkapi \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,sc_sparkline_test))
+
+$(eval $(call gb_CppunitTest_use_ure,sc_sparkline_test))
+$(eval $(call gb_CppunitTest_use_vcl,sc_sparkline_test))
+
+$(eval $(call gb_CppunitTest_use_rdb,sc_sparkline_test,services))
+
+$(eval $(call gb_CppunitTest_use_components,sc_sparkline_test))
+
+$(eval $(call gb_CppunitTest_use_configuration,sc_sparkline_test))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk
index 5179c5fdb292..4dcefc694ea7 100644
--- a/sc/Module_sc.mk
+++ b/sc/Module_sc.mk
@@ -209,6 +209,7 @@ $(eval $(call gb_Module_add_subsequentcheck_targets,sc,\
        CppunitTest_sc_sheetlinkobj \
        CppunitTest_sc_sheetlinksobj \
        CppunitTest_sc_sortdescriptorbaseobj \
+       CppunitTest_sc_sparkline_test \
        CppunitTest_sc_spreadsheetsettings \
        CppunitTest_sc_spreadsheetsettingsobj \
        CppunitTest_sc_styleobj \
diff --git a/sc/qa/extras/SparklineTest.cxx b/sc/qa/extras/SparklineTest.cxx
new file mode 100644
index 000000000000..122a6b23f5be
--- /dev/null
+++ b/sc/qa/extras/SparklineTest.cxx
@@ -0,0 +1,152 @@
+/* -*- 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 <test/calc_unoapi_test.hxx>
+
+#include <com/sun/star/lang/XComponent.hpp>
+#include <docsh.hxx>
+#include <Sparkline.hxx>
+
+using namespace css;
+
+namespace sc_apitest
+{
+class SparklineTest : public CalcUnoApiTest
+{
+    uno::Reference<lang::XComponent> mxComponent;
+
+public:
+    SparklineTest();
+
+    void testSparklines();
+
+    CPPUNIT_TEST_SUITE(SparklineTest);
+    CPPUNIT_TEST(testSparklines);
+    CPPUNIT_TEST_SUITE_END();
+};
+
+SparklineTest::SparklineTest()
+    : CalcUnoApiTest("sc/qa/extras/testdocuments")
+{
+}
+
+void SparklineTest::testSparklines()
+{
+    OUString aFileURL;
+    createFileURL(u"Sparklines.xlsx", aFileURL);
+    mxComponent = loadFromDesktop(aFileURL);
+
+    SfxObjectShell* pFoundShell = 
SfxObjectShell::GetShellFromComponent(mxComponent);
+    CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell);
+    ScDocShellRef xDocSh = dynamic_cast<ScDocShell*>(pFoundShell);
+    CPPUNIT_ASSERT(xDocSh);
+
+    ScDocument& rDocument = xDocSh->GetDocument();
+    // Sparkline at Sheet1:A2
+    {
+        sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 1, 
0)); // A2
+        CPPUNIT_ASSERT(pSparkline);
+        auto pSparklineGroup = pSparkline->getSparklineGroup();
+        CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, 
pSparklineGroup->m_eType);
+
+        CPPUNIT_ASSERT_EQUAL(Color(0x376092), pSparklineGroup->m_aColorSeries);
+        CPPUNIT_ASSERT_EQUAL(Color(0x00b050), 
pSparklineGroup->m_aColorNegative);
+        CPPUNIT_ASSERT_EQUAL(Color(0x000000), pSparklineGroup->m_aColorAxis);
+        CPPUNIT_ASSERT_EQUAL(Color(0x000000), 
pSparklineGroup->m_aColorMarkers);
+        CPPUNIT_ASSERT_EQUAL(Color(0x7030a0), pSparklineGroup->m_aColorFirst);
+        CPPUNIT_ASSERT_EQUAL(Color(0xff0000), pSparklineGroup->m_aColorLast);
+        CPPUNIT_ASSERT_EQUAL(Color(0x92d050), pSparklineGroup->m_aColorHigh);
+        CPPUNIT_ASSERT_EQUAL(Color(0x00b0f0), pSparklineGroup->m_aColorLow);
+
+        CPPUNIT_ASSERT_EQUAL(1.0, pSparklineGroup->m_fLineWeight);
+        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDateAxis);
+        CPPUNIT_ASSERT_EQUAL(sc::DisplayEmptyCellAs::Gap, 
pSparklineGroup->m_eDisplayEmptyCellsAs);
+
+        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bMarkers);
+        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bHigh);
+        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLow);
+        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bFirst);
+        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLast);
+        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bNegative);
+        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bDisplayXAxis);
+        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayHidden);
+        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bRightToLeft);
+
+        CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMax));
+        CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMin));
+    }
+    // Sparkline at Sheet1:A3
+    {
+        sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 2, 
0)); // A3
+        CPPUNIT_ASSERT(pSparkline);
+        auto pSparklineGroup = pSparkline->getSparklineGroup();
+        CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column, 
pSparklineGroup->m_eType);
+
+        CPPUNIT_ASSERT_EQUAL(Color(0x376092), pSparklineGroup->m_aColorSeries);
+        CPPUNIT_ASSERT_EQUAL(Color(0xff0000), 
pSparklineGroup->m_aColorNegative);
+        CPPUNIT_ASSERT_EQUAL(Color(0x000000), pSparklineGroup->m_aColorAxis);
+        CPPUNIT_ASSERT_EQUAL(Color(0xd00000), 
pSparklineGroup->m_aColorMarkers);
+        CPPUNIT_ASSERT_EQUAL(Color(0x92d050), pSparklineGroup->m_aColorFirst);
+        CPPUNIT_ASSERT_EQUAL(Color(0x00b0f0), pSparklineGroup->m_aColorLast);
+        CPPUNIT_ASSERT_EQUAL(Color(0x7030a0), pSparklineGroup->m_aColorHigh);
+        CPPUNIT_ASSERT_EQUAL(Color(0xffc000), pSparklineGroup->m_aColorLow);
+
+        CPPUNIT_ASSERT_EQUAL(0.75, pSparklineGroup->m_fLineWeight);
+        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDateAxis);
+        CPPUNIT_ASSERT_EQUAL(sc::DisplayEmptyCellAs::Gap, 
pSparklineGroup->m_eDisplayEmptyCellsAs);
+
+        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bMarkers);
+        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bHigh);
+        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLow);
+        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bFirst);
+        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bLast);
+        CPPUNIT_ASSERT_EQUAL(true, pSparklineGroup->m_bNegative);
+        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayXAxis);
+        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bDisplayHidden);
+        CPPUNIT_ASSERT_EQUAL(false, pSparklineGroup->m_bRightToLeft);
+
+        CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMax));
+        CPPUNIT_ASSERT_EQUAL(false, bool(pSparklineGroup->m_aManualMin));
+    }
+    // Sparkline at Sheet2:B1
+    {
+        sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 0, 
1)); //B1
+        CPPUNIT_ASSERT(pSparkline);
+        auto pSparklineGroup = pSparkline->getSparklineGroup();
+        CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column, 
pSparklineGroup->m_eType);
+    }
+    // Sparkline at Sheet2:B2
+    {
+        sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 1, 
1)); //B2
+        CPPUNIT_ASSERT(pSparkline);
+        auto pSparklineGroup = pSparkline->getSparklineGroup();
+        CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, 
pSparklineGroup->m_eType);
+    }
+    // Sparkline at Sheet2:B2
+    {
+        sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 1, 
1)); //B2
+        CPPUNIT_ASSERT(pSparkline);
+        auto pSparklineGroup = pSparkline->getSparklineGroup();
+        CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, 
pSparklineGroup->m_eType);
+    }
+    // Sparkline doesn't exists at A4
+    {
+        sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 3, 
0)); //A4
+        CPPUNIT_ASSERT(!pSparkline);
+    }
+
+    closeDocument(mxComponent);
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SparklineTest);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/qa/extras/testdocuments/Sparklines.xlsx 
b/sc/qa/extras/testdocuments/Sparklines.xlsx
new file mode 100644
index 000000000000..3725841603be
Binary files /dev/null and b/sc/qa/extras/testdocuments/Sparklines.xlsx differ
commit bc536879a4d10ea3ab10b855e01586ae07d950ac
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Fri Feb 25 11:57:15 2022 +0900
Commit:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
CommitDate: Fri Mar 4 20:54:33 2022 +0900

    sc: use enums instead strings for some SparklineGroup props.
    
    Change-Id: I082c0a7693c97a67bc4972398224bce4bdae85eb

diff --git a/sc/inc/SparklineGroup.hxx b/sc/inc/SparklineGroup.hxx
index abc1cc71333c..32e4b757378f 100644
--- a/sc/inc/SparklineGroup.hxx
+++ b/sc/inc/SparklineGroup.hxx
@@ -16,6 +16,27 @@
 
 namespace sc
 {
+enum class SparklineType
+{
+    Line,
+    Column,
+    Stacked
+};
+
+enum class AxisType
+{
+    Individual,
+    Group,
+    Custom
+};
+
+enum class DisplayEmptyCellAs
+{
+    Span,
+    Gap,
+    Zero
+};
+
 class SC_DLLPUBLIC SparklineGroup
 {
 public:
@@ -28,16 +49,16 @@ public:
     Color m_aColorHigh;
     Color m_aColorLow;
 
-    OUString m_sMinAxisType; // individual, group, custom
-    OUString m_sMaxAxisType;
+    AxisType m_eMinAxisType;
+    AxisType m_eMaxAxisType;
 
     double m_fLineWeight; // In pt
 
-    OUString m_sType; // line, column, stacked
+    SparklineType m_eType;
 
     bool m_bDateAxis;
 
-    OUString m_sDisplayEmptyCellsAs; // span, gap, zero
+    DisplayEmptyCellAs m_eDisplayEmptyCellsAs; // span, gap, zero
 
     bool m_bMarkers;
     bool m_bHigh;
diff --git a/sc/source/filter/oox/SparklineFragment.cxx 
b/sc/source/filter/oox/SparklineFragment.cxx
index bfc5a259a883..b4c5089dbfa1 100644
--- a/sc/source/filter/oox/SparklineFragment.cxx
+++ b/sc/source/filter/oox/SparklineFragment.cxx
@@ -90,6 +90,33 @@ void addColorsToSparklineGroup(sc::SparklineGroup& 
rSparklineGroup, sal_Int32 nE
     }
 }
 
+sc::SparklineType parseSparklineType(OUString const& rString)
+{
+    if (rString == "column")
+        return sc::SparklineType::Column;
+    else if (rString == "stacked")
+        return sc::SparklineType::Stacked;
+    return sc::SparklineType::Line;
+}
+
+sc::DisplayEmptyCellAs parseDisplayEmptyCellAs(OUString const& rString)
+{
+    if (rString == "span")
+        return sc::DisplayEmptyCellAs::Span;
+    else if (rString == "gap")
+        return sc::DisplayEmptyCellAs::Gap;
+    return sc::DisplayEmptyCellAs::Zero;
+}
+
+sc::AxisType parseAxisType(OUString const& rString)
+{
+    if (rString == "group")
+        return sc::AxisType::Group;
+    else if (rString == "custom")
+        return sc::AxisType::Custom;
+    return sc::AxisType::Individual;
+}
+
 void addAttributesToSparklineGroup(sc::SparklineGroup& rSparklineGroup,
                                    const AttributeList& rAttribs)
 {
@@ -98,11 +125,13 @@ void addAttributesToSparklineGroup(sc::SparklineGroup& 
rSparklineGroup,
 
     rSparklineGroup.m_fLineWeight = rAttribs.getDouble(XML_lineWeight, 0.75);
 
-    rSparklineGroup.m_sType = rAttribs.getString(XML_type, "line");
+    OUString sType = rAttribs.getString(XML_type, "line");
+    rSparklineGroup.m_eType = parseSparklineType(sType);
 
     rSparklineGroup.m_bDateAxis = rAttribs.getBool(XML_dateAxis, false);
 
-    rSparklineGroup.m_sDisplayEmptyCellsAs = 
rAttribs.getString(XML_displayEmptyCellsAs, "zero");
+    OUString sDisplayEmptyCellsAs = 
rAttribs.getString(XML_displayEmptyCellsAs, "zero");
+    rSparklineGroup.m_eDisplayEmptyCellsAs = 
parseDisplayEmptyCellAs(sDisplayEmptyCellsAs);
 
     rSparklineGroup.m_bMarkers = rAttribs.getBool(XML_markers, false);
     rSparklineGroup.m_bHigh = rAttribs.getBool(XML_high, false);
@@ -113,16 +142,19 @@ void addAttributesToSparklineGroup(sc::SparklineGroup& 
rSparklineGroup,
     rSparklineGroup.m_bDisplayXAxis = rAttribs.getBool(XML_displayXAxis, 
false);
     rSparklineGroup.m_bDisplayHidden = rAttribs.getBool(XML_displayHidden, 
false);
 
-    rSparklineGroup.m_sMinAxisType = rAttribs.getString(XML_minAxisType, 
"individual");
-    rSparklineGroup.m_sMaxAxisType = rAttribs.getString(XML_maxAxisType, 
"individual");
+    OUString sMinAxisType = rAttribs.getString(XML_minAxisType, "individual");
+    rSparklineGroup.m_eMinAxisType = parseAxisType(sMinAxisType);
+
+    OUString sMaxAxisType = rAttribs.getString(XML_maxAxisType, "individual");
+    rSparklineGroup.m_eMaxAxisType = parseAxisType(sMaxAxisType);
 
     rSparklineGroup.m_bRightToLeft = rAttribs.getBool(XML_rightToLeft, false);
 
     rSparklineGroup.m_sUID = rAttribs.getString(XML_uid, OUString());
 
-    if (rSparklineGroup.m_sMaxAxisType == "custom")
+    if (rSparklineGroup.m_eMaxAxisType == sc::AxisType::Custom)
         rSparklineGroup.m_aManualMax = oManualMax.get();
-    if (rSparklineGroup.m_sMinAxisType == "custom")
+    if (rSparklineGroup.m_eMinAxisType == sc::AxisType::Custom)
         rSparklineGroup.m_aManualMin = oManualMin.get();
 }
 
diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx
index 32879a8aa153..213f4c1cc69b 100644
--- a/sc/source/ui/view/output.cxx
+++ b/sc/source/ui/view/output.cxx
@@ -2432,12 +2432,13 @@ void drawSparkline(sc::Sparkline* pSparkline, 
vcl::RenderContext& rRenderContext
         }
     }
 
-    if (pSparklineGroup->m_sType == "column")
+    if (pSparklineGroup->m_eType == sc::SparklineType::Column)
     {
         drawColumn(rRenderContext, rRectangle, aValues, nMin, nMax);
     }
-    else if (pSparklineGroup->m_sType == "stacked")
+    else if (pSparklineGroup->m_eType == sc::SparklineType::Stacked)
     {
+        // transform the data to 1, -1
         for (auto & rValue : aValues)
         {
             if (rValue != 0.0)
@@ -2445,7 +2446,7 @@ void drawSparkline(sc::Sparkline* pSparkline, 
vcl::RenderContext& rRenderContext
         }
         drawColumn(rRenderContext, rRectangle, aValues, -1, 1);
     }
-    else if (pSparklineGroup->m_sType == "line")
+    else if (pSparklineGroup->m_eType == sc::SparklineType::Line)
     {
         drawLine(rRenderContext, rRectangle, aValues, nMin, nMax);
     }
commit 733ed6914d5cbfe6520f2b97e07470975873f65c
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Thu Feb 24 17:43:00 2022 +0900
Commit:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
CommitDate: Fri Mar 4 20:54:33 2022 +0900

    sc: initial code to draw sparkline into  a cell
    
    Change-Id: I82861f4210a24f57573f0ec96489e86ab168677b

diff --git a/sc/source/ui/inc/output.hxx b/sc/source/ui/inc/output.hxx
index 61873156d264..d44f7052589b 100644
--- a/sc/source/ui/inc/output.hxx
+++ b/sc/source/ui/inc/output.hxx
@@ -382,6 +382,7 @@ public:
 
     void    DrawNoteMarks(vcl::RenderContext& rRenderContext);
     void    AddPDFNotes();
+    void    DrawSparklines(vcl::RenderContext& rRenderContext);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx
index 9b8d5c634b25..50ffcdf67709 100644
--- a/sc/source/ui/view/gridwin4.cxx
+++ b/sc/source/ui/view/gridwin4.cxx
@@ -903,6 +903,8 @@ void ScGridWindow::DrawContent(OutputDevice &rDevice, const 
ScTableInfo& rTableI
     aOutputData.DrawShadow();
     aOutputData.DrawFrame(*pContentDev);
 
+    aOutputData.DrawSparklines(*pContentDev);
+
     // Show Note Mark
     if ( rOpts.GetOption( VOPT_NOTES ) )
         aOutputData.DrawNoteMarks(*pContentDev);
diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx
index 045066e96689..32879a8aa153 100644
--- a/sc/source/ui/view/output.cxx
+++ b/sc/source/ui/view/output.cxx
@@ -30,7 +30,6 @@
 #include <svx/framelinkarray.hxx>
 #include <drawinglayer/geometry/viewinformation2d.hxx>
 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
-#include <basegfx/matrix/b2dhommatrix.hxx>
 #include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
 #include <vcl/lineinfo.hxx>
 #include <vcl/gradient.hxx>
@@ -39,6 +38,10 @@
 #include <sal/log.hxx>
 #include <comphelper/lok.hxx>
 #include <o3tl/unit_conversion.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/range/b2drectangle.hxx>
 
 #include <output.hxx>
 #include <document.hxx>
@@ -60,6 +63,7 @@
 #include <detfunc.hxx>
 
 #include <colorscale.hxx>
+#include <Sparkline.hxx>
 
 #include <math.h>
 #include <memory>
@@ -2309,6 +2313,200 @@ void ScOutputData::DrawChangeTrack()
     }
 }
 
+namespace
+{
+
+void drawLine(vcl::RenderContext& rRenderContext, tools::Rectangle const & 
rRectangle,
+                std::vector<double> const & rValues, double nMin, double nMax)
+{
+    basegfx::B2DPolygon aPolygon;
+    double numebrOfSteps = rValues.size() - 1;
+    double xStep = 0;
+    double nDelta = nMax - nMin;
+
+    for (double aValue : rValues)
+    {
+        double nP = (aValue - nMin) / nDelta;
+        double x = rRectangle.GetWidth() * (xStep / numebrOfSteps);
+        double y = rRectangle.GetHeight() - rRectangle.GetHeight() * nP;
+
+        aPolygon.append({ x, y } );
+        xStep++;
+    }
+
+    basegfx::B2DHomMatrix aMatrix;
+    aMatrix.translate(rRectangle.Left(), rRectangle.Top());
+    aPolygon.transform(aMatrix);
+
+    rRenderContext.DrawPolyLine(aPolygon);
+}
+
+void drawColumn(vcl::RenderContext& rRenderContext, tools::Rectangle const & 
rRectangle,
+                std::vector<double> const & rValues, double nMin, double nMax)
+{
+    basegfx::B2DPolygon aPolygon;
+
+    double xStep = 0;
+    double numberOfSteps = rValues.size();
+    double nDelta = nMax - nMin;
+
+    double nColumnSize = rRectangle.GetWidth() / numberOfSteps;
+
+    double nZero = (0 - nMin) / nDelta;
+    double nZeroPosition;
+    if (nZero >= 0)
+        nZeroPosition = rRectangle.GetHeight() - rRectangle.GetHeight() * 
nZero;
+    else
+        nZeroPosition = rRectangle.GetHeight();
+
+    for (double aValue : rValues)
+    {
+        if (aValue != 0.0)
+        {
+            double nP = (aValue - nMin) / nDelta;
+            double x = rRectangle.GetWidth() * (xStep / numberOfSteps);
+            double y = rRectangle.GetHeight() - rRectangle.GetHeight() * nP;
+
+            basegfx::B2DRectangle aRectangle(x, y, x + nColumnSize, 
nZeroPosition);
+            aPolygon = basegfx::utils::createPolygonFromRect(aRectangle);
+
+            basegfx::B2DHomMatrix aMatrix;
+            aMatrix.translate(rRectangle.Left(), rRectangle.Top());
+            aPolygon.transform(aMatrix);
+            rRenderContext.DrawPolygon(aPolygon);
+        }
+        xStep++;
+    }
+}
+
+void drawSparkline(sc::Sparkline* pSparkline, vcl::RenderContext& 
rRenderContext, ScDocument* pDocument,
+                                 tools::Rectangle const & rRectangle)
+{
+    auto const & rRangeList = pSparkline->getInputRange();
+
+    if (rRangeList.empty())
+        return;
+
+    auto pSparklineGroup = pSparkline->getSparklineGroup();
+
+    rRenderContext.SetAntialiasing(AntialiasingFlags::Enable);
+
+    rRenderContext.SetLineColor(pSparklineGroup->m_aColorSeries);
+    rRenderContext.SetFillColor(pSparklineGroup->m_aColorSeries);
+
+    ScRange aRange = rRangeList[0];
+
+    std::vector<double> aValues;
+
+    double nMin = std::numeric_limits<double>::max();
+    double nMax = std::numeric_limits<double>::min();
+
+    if (aRange.aStart.Row() == aRange.aEnd.Row())
+    {
+        ScAddress aAddress = aRange.aStart;
+
+        while (aAddress.Col() <= aRange.aEnd.Col())
+        {
+            double fCellValue = pDocument->GetValue(aAddress);
+            aValues.push_back(fCellValue);
+            if (fCellValue < nMin)
+                nMin = fCellValue;
+            if (fCellValue > nMax)
+                nMax = fCellValue;
+            aAddress.IncCol();
+        }
+    }
+    else if (aRange.aStart.Col() == aRange.aEnd.Col())
+    {
+        ScAddress aAddress = aRange.aStart;
+
+        while (aAddress.Row() <= aRange.aEnd.Row())
+        {
+            double fCellValue = pDocument->GetValue(aAddress);
+            aValues.push_back(fCellValue);
+            if (fCellValue < nMin)
+                nMin = fCellValue;
+            if (fCellValue > nMax)
+                nMax = fCellValue;
+            aAddress.IncRow();
+        }
+    }
+
+    if (pSparklineGroup->m_sType == "column")
+    {
+        drawColumn(rRenderContext, rRectangle, aValues, nMin, nMax);
+    }
+    else if (pSparklineGroup->m_sType == "stacked")
+    {
+        for (auto & rValue : aValues)
+        {
+            if (rValue != 0.0)
+                rValue = rValue > 0.0 ? 1.0 : -1.0;
+        }
+        drawColumn(rRenderContext, rRectangle, aValues, -1, 1);
+    }
+    else if (pSparklineGroup->m_sType == "line")
+    {
+        drawLine(rRenderContext, rRectangle, aValues, nMin, nMax);
+    }
+}
+} // end anonymous namespace
+
+void ScOutputData::DrawSparklines(vcl::RenderContext& rRenderContext)
+{
+    tools::Long nInitPosX = nScrX;
+    if ( bLayoutRTL )
+        nInitPosX += nMirrorW - 1;              // always in pixels
+    tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+    tools::Long nPosY = nScrY;
+    for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
+    {
+        RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+        if ( pThisRowInfo->bChanged )
+        {
+            tools::Long nPosX = nInitPosX;
+            for (SCCOL nX=nX1; nX<=nX2; nX++)
+            {
+                CellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
+                bool bIsMerged = false;
+
+                if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
+                {
+                    // find start of merged cell
+                    bIsMerged = true;
+                    SCROW nY = pRowInfo[nArrY].nRowNo;
+                    SCCOL nMergeX = nX;
+                    SCROW nMergeY = nY;
+                    mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
+                }
+
+                sc::Sparkline* pSparkline = nullptr;
+                ScAddress aCurrentAddress(nX, pRowInfo[nArrY].nRowNo, nTab);
+
+                if (!mpDoc->ColHidden(nX, nTab) && (pSparkline = 
mpDoc->GetSparkline(aCurrentAddress))
+                    && (bIsMerged || (!pInfo->bHOverlapped && 
!pInfo->bVOverlapped)))
+                {
+                    constexpr tools::Long constMarginX = 6;
+                    constexpr tools::Long constMarginY = 3;
+
+                    const tools::Long nWidth = pRowInfo[0].cellInfo(nX).nWidth;
+                    const tools::Long nHeight = pThisRowInfo->nHeight;
+
+                    Point aPoint(nPosX + constMarginX , nPosY + constMarginY);
+                    Size aSize(nWidth - 2 * constMarginX, nHeight - 2 * 
constMarginY);
+
+                    drawSparkline(pSparkline, rRenderContext, mpDoc, 
tools::Rectangle(aPoint, aSize));
+                }
+
+                nPosX += pRowInfo[0].cellInfo(nX).nWidth * nLayoutSign;
+            }
+        }
+        nPosY += pThisRowInfo->nHeight;
+    }
+
+}
+
 //TODO: moggi Need to check if this can't be written simpler
 void ScOutputData::DrawNoteMarks(vcl::RenderContext& rRenderContext)
 {
commit 73fc5112c3fbf33a40342b2c86988acf7e468a5e
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Wed Feb 23 10:06:20 2022 +0900
Commit:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
CommitDate: Fri Mar 4 20:54:32 2022 +0900

    sc: write the OOXML Sparkline props. to the model
    
    Change-Id: I09ecf560f1870624cb984722bdb8ee306d839dfe

diff --git a/sc/inc/SparklineGroup.hxx b/sc/inc/SparklineGroup.hxx
index 250488671190..abc1cc71333c 100644
--- a/sc/inc/SparklineGroup.hxx
+++ b/sc/inc/SparklineGroup.hxx
@@ -11,6 +11,7 @@
 #pragma once
 
 #include "scdllapi.h"
+#include <tools/color.hxx>
 #include <optional>
 
 namespace sc
@@ -18,6 +19,40 @@ namespace sc
 class SC_DLLPUBLIC SparklineGroup
 {
 public:
+    Color m_aColorSeries;
+    Color m_aColorNegative;
+    Color m_aColorAxis;
+    Color m_aColorMarkers;
+    Color m_aColorFirst;
+    Color m_aColorLast;
+    Color m_aColorHigh;
+    Color m_aColorLow;
+
+    OUString m_sMinAxisType; // individual, group, custom
+    OUString m_sMaxAxisType;
+
+    double m_fLineWeight; // In pt
+
+    OUString m_sType; // line, column, stacked
+
+    bool m_bDateAxis;
+
+    OUString m_sDisplayEmptyCellsAs; // span, gap, zero
+
+    bool m_bMarkers;
+    bool m_bHigh;
+    bool m_bLow;
+    bool m_bFirst;
+    bool m_bLast;
+    bool m_bNegative;
+    bool m_bDisplayXAxis;
+    bool m_bDisplayHidden;
+    bool m_bRightToLeft;
+
+    std::optional<double> m_aManualMax;
+    std::optional<double> m_aManualMin;
+    OUString m_sUID;
+
     SparklineGroup() {}
 
     SparklineGroup(const SparklineGroup&) = delete;
diff --git a/sc/source/filter/inc/SparklineFragment.hxx 
b/sc/source/filter/inc/SparklineFragment.hxx
index 36a7b5ca9f05..de1f9ae7ebda 100644
--- a/sc/source/filter/inc/SparklineFragment.hxx
+++ b/sc/source/filter/inc/SparklineFragment.hxx
@@ -11,10 +11,10 @@
 
 #include "excelhandlers.hxx"
 #include <oox/core/contexthandler.hxx>
+#include <SparklineGroup.hxx>
 
 #include <vector>
 #include <memory>
-#include <optional>
 
 namespace oox
 {
@@ -36,40 +36,15 @@ class SparklineGroup
 private:
     std::vector<Sparkline> m_aSparklines;
 
-public:
-    Color m_aColorSeries;
-    Color m_aColorNegative;
-    Color m_aColorAxis;
-    Color m_aColorMarkers;
-    Color m_aColorFirst;
-    Color m_aColorLast;
-    Color m_aColorHigh;
-    Color m_aColorLow;
-
-    OUString m_sMinAxisType; // individual, group, custom
-    OUString m_sMaxAxisType;
-
-    double m_fLineWeight; // In pt
-
-    OUString m_sType; // line, column, stacked
+    std::shared_ptr<sc::SparklineGroup> m_pSparklineGroup;
 
-    bool m_bDateAxis;
-
-    OUString m_sDisplayEmptyCellsAs; // span, gap, zero
-
-    bool m_bMarkers;
-    bool m_bHigh;
-    bool m_bLow;
-    bool m_bFirst;
-    bool m_bLast;
-    bool m_bNegative;
-    bool m_bDisplayXAxis;
-    bool m_bDisplayHidden;
-    bool m_bRightToLeft;
+public:
+    SparklineGroup()
+        : m_pSparklineGroup(new sc::SparklineGroup())
+    {
+    }
 
-    std::optional<double> m_aManualMax;
-    std::optional<double> m_aManualMin;
-    OUString m_sUID;
+    std::shared_ptr<sc::SparklineGroup> getSparklineGroup() { return 
m_pSparklineGroup; }
 
     std::vector<Sparkline>& getSparklines() { return m_aSparklines; }
 };
@@ -87,6 +62,8 @@ public:
     void onStartElement(const AttributeList& rAttribs) override;
     void onCharacters(const OUString& rCharacters) override;
     void onEndElement() override;
+
+    void insertSparkline(SparklineGroup& rSparklineGroup, Sparkline& 
rSparkline);
 };
 
 } //namespace oox::xls
diff --git a/sc/source/filter/oox/SparklineFragment.cxx 
b/sc/source/filter/oox/SparklineFragment.cxx
index a743b886b7db..bfc5a259a883 100644
--- a/sc/source/filter/oox/SparklineFragment.cxx
+++ b/sc/source/filter/oox/SparklineFragment.cxx
@@ -15,6 +15,8 @@
 #include <oox/helper/attributelist.hxx>
 #include <document.hxx>
 #include <rangeutl.hxx>
+#include <Sparkline.hxx>
+#include <themebuffer.hxx>
 
 using ::oox::core::ContextHandlerRef;
 
@@ -22,51 +24,74 @@ namespace oox::xls
 {
 namespace
 {
-Color getColor(const AttributeList& rAttribs)
+// TODO: deduplicate with importOOXColor
+::Color getColor(const AttributeList& rAttribs, ThemeBuffer const& 
rThemeBuffer)
 {
     if (rAttribs.hasAttribute(XML_rgb))
     {
-        return Color(ColorTransparency,
-                     rAttribs.getIntegerHex(XML_rgb, 
sal_Int32(API_RGB_TRANSPARENT)));
+        return ::Color(ColorAlpha, rAttribs.getIntegerHex(XML_rgb, 
sal_Int32(API_RGB_TRANSPARENT)));
     }
-    return Color();
+    else if (rAttribs.hasAttribute(XML_theme))
+    {
+        sal_uInt32 nThemeIndex = rAttribs.getUnsigned(XML_theme, 0);
+
+        // Excel has a bug in the mapping of index 0, 1, 2 and 3.
+        if (nThemeIndex == 0)
+            nThemeIndex = 1;
+        else if (nThemeIndex == 1)
+            nThemeIndex = 0;
+        else if (nThemeIndex == 2)
+            nThemeIndex = 3;
+        else if (nThemeIndex == 3)
+            nThemeIndex = 2;
+
+        ::Color aColor = rThemeBuffer.getColorByIndex(nThemeIndex);
+        double nTint = rAttribs.getDouble(XML_tint, 0.0);
+
+        if (nTint > 0.0)
+            aColor.ApplyTintOrShade(nTint * 10000);
+        return aColor;
+    }
+
+    return ::Color();
 }
 
-void addColorsToSparklineGroup(SparklineGroup& rSparklineGroup, sal_Int32 
nElement,
-                               const AttributeList& rAttribs)
+void addColorsToSparklineGroup(sc::SparklineGroup& rSparklineGroup, sal_Int32 
nElement,
+                               const AttributeList& rAttribs, ThemeBuffer& 
rThemeBuffer)
 {
     switch (nElement)
     {
         case XLS14_TOKEN(colorSeries):
-            rSparklineGroup.m_aColorSeries = getColor(rAttribs);
+            rSparklineGroup.m_aColorSeries = getColor(rAttribs, rThemeBuffer);
             break;
         case XLS14_TOKEN(colorNegative):
-            rSparklineGroup.m_aColorNegative = getColor(rAttribs);
+            rSparklineGroup.m_aColorNegative = getColor(rAttribs, 
rThemeBuffer);
             break;
         case XLS14_TOKEN(colorAxis):
-            rSparklineGroup.m_aColorAxis = getColor(rAttribs);
+            rSparklineGroup.m_aColorAxis = getColor(rAttribs, rThemeBuffer);
             break;
         case XLS14_TOKEN(colorMarkers):
-            rSparklineGroup.m_aColorMarkers = getColor(rAttribs);
+            rSparklineGroup.m_aColorMarkers = getColor(rAttribs, rThemeBuffer);
             break;
         case XLS14_TOKEN(colorFirst):
-            rSparklineGroup.m_aColorFirst = getColor(rAttribs);
+            rSparklineGroup.m_aColorFirst = getColor(rAttribs, rThemeBuffer);
             break;
         case XLS14_TOKEN(colorLast):
-            rSparklineGroup.m_aColorLast = getColor(rAttribs);
+            rSparklineGroup.m_aColorLast = getColor(rAttribs, rThemeBuffer);
             break;
         case XLS14_TOKEN(colorHigh):
-            rSparklineGroup.m_aColorHigh = getColor(rAttribs);
+            rSparklineGroup.m_aColorHigh = getColor(rAttribs, rThemeBuffer);
             break;
         case XLS14_TOKEN(colorLow):
-            rSparklineGroup.m_aColorLow = getColor(rAttribs);
+            rSparklineGroup.m_aColorLow = getColor(rAttribs, rThemeBuffer);
             break;
         default:
             break;
     }
 }
 
-void addAttributesToSparklineGroup(SparklineGroup& rSparklineGroup, const 
AttributeList& rAttribs)
+void addAttributesToSparklineGroup(sc::SparklineGroup& rSparklineGroup,
+                                   const AttributeList& rAttribs)
 {
     auto oManualMax = rAttribs.getDouble(XML_manualMax);
     auto oManualMin = rAttribs.getDouble(XML_manualMin);
@@ -116,7 +141,7 @@ ContextHandlerRef 
SparklineGroupsContext::onCreateContext(sal_Int32 nElement,
         case XLS14_TOKEN(sparklineGroup):
         {
             auto& rLastGroup = m_aSparklineGroups.emplace_back();
-            addAttributesToSparklineGroup(rLastGroup, rAttribs);
+            addAttributesToSparklineGroup(*rLastGroup.getSparklineGroup(), 
rAttribs);
             return this;
         }
         case XLS14_TOKEN(colorSeries):
@@ -129,7 +154,8 @@ ContextHandlerRef 
SparklineGroupsContext::onCreateContext(sal_Int32 nElement,
         case XLS14_TOKEN(colorLow):
         {
             auto& rLastGroup = m_aSparklineGroups.back();
-            addColorsToSparklineGroup(rLastGroup, nElement, rAttribs);
+            addColorsToSparklineGroup(*rLastGroup.getSparklineGroup(), 
nElement, rAttribs,
+                                      getTheme());
             return this;
         }
         case XLS14_TOKEN(sparklines):
@@ -155,7 +181,6 @@ void SparklineGroupsContext::onCharacters(const OUString& 
rChars)
         ScDocument& rDocument = getScDocument();
         auto& rLastGroup = m_aSparklineGroups.back();
         auto& rLastSparkline = rLastGroup.getSparklines().back();
-
         ScRangeList aRange;
         if (ScRangeStringConverter::GetRangeListFromString(aRange, rChars, 
rDocument,
                                                            
formula::FormulaGrammar::CONV_XL_OOX))
@@ -182,7 +207,32 @@ void SparklineGroupsContext::onCharacters(const OUString& 
rChars)
     }
 }
 
-void SparklineGroupsContext::onEndElement() {}
+void SparklineGroupsContext::onEndElement()
+{
+    if (getCurrentElement() == XLS14_TOKEN(sparklineGroup))
+    {
+        auto& rLastGroup = m_aSparklineGroups.back();
+        for (Sparkline& rSparkline : rLastGroup.getSparklines())
+        {
+            insertSparkline(rLastGroup, rSparkline);
+        }
+    }
+}
+
+void SparklineGroupsContext::insertSparkline(SparklineGroup& rSparklineGroup, 
Sparkline& rSparkline)
+{
+    auto& rDocument = getScDocument();
+    if (rSparkline.m_aTargetRange.size() == 1)
+    {
+        auto& rRange = rSparkline.m_aTargetRange[0];
+        if (rRange.aStart == rRange.aEnd)
+        {
+            auto pSparklineGroup = rSparklineGroup.getSparklineGroup();
+            auto* pCreated = rDocument.CreateSparkline(rRange.aStart, 
pSparklineGroup);
+            pCreated->setInputRange(rSparkline.m_aInputRange);
+        }
+    }
+}
 
 } //namespace oox::xls
 
commit cdf4d1e25a8dfb84fcd53e0a73edb8dc6e42c67e
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Wed Feb 23 09:52:50 2022 +0900
Commit:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
CommitDate: Fri Mar 4 20:54:32 2022 +0900

    sc: add Sparkline to the model as a column multi_type_vector
    
    Change-Id: Id309ded34bfa7a35c1be43f7c0543d88594e66ff

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 62ab22a797c4..11449217edd9 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -185,6 +185,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
     sc/source/core/data/sheetevents \
     sc/source/core/data/simpleformulacalc \
     sc/source/core/data/sortparam \
+    sc/source/core/data/Sparkline \
     sc/source/core/data/stlpool \
     sc/source/core/data/stlsheet \
     sc/source/core/data/subtotalparam \
diff --git a/sc/inc/Sparkline.hxx b/sc/inc/Sparkline.hxx
new file mode 100644
index 000000000000..8969fa3bfd3e
--- /dev/null
+++ b/sc/inc/Sparkline.hxx
@@ -0,0 +1,40 @@
+/* -*- 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/.
+ *
+ */
+
+#pragma once
+
+#include "scdllapi.h"
+#include "SparklineGroup.hxx"
+#include "rangelst.hxx"
+#include <memory>
+
+namespace sc
+{
+class SC_DLLPUBLIC Sparkline
+{
+private:
+    ScRangeList m_aInputRange;
+    std::shared_ptr<SparklineGroup> m_pSparklineGroup;
+
+public:
+    Sparkline(std::shared_ptr<SparklineGroup>& pSparklineGroup);
+
+    Sparkline(const Sparkline&) = delete;
+    Sparkline& operator=(const Sparkline&) = delete;
+
+    void setInputRange(ScRangeList const& rInputRange) { m_aInputRange = 
rInputRange; }
+    ScRangeList const& getInputRange() { return m_aInputRange; }
+
+    std::shared_ptr<SparklineGroup> const& getSparklineGroup() { return 
m_pSparklineGroup; }
+};
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/SparklineGroup.hxx b/sc/inc/SparklineGroup.hxx
new file mode 100644
index 000000000000..250488671190
--- /dev/null
+++ b/sc/inc/SparklineGroup.hxx
@@ -0,0 +1,29 @@
+/* -*- 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/.
+ *
+ */
+
+#pragma once
+
+#include "scdllapi.h"
+#include <optional>
+
+namespace sc
+{
+class SC_DLLPUBLIC SparklineGroup
+{
+public:
+    SparklineGroup() {}
+
+    SparklineGroup(const SparklineGroup&) = delete;
+    SparklineGroup& operator=(const SparklineGroup&) = delete;
+};
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index e23eac0fdab1..f4b603c5c721 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -65,6 +65,7 @@ class CompileFormulaContext;
 struct SetFormulaDirtyContext;
 enum class MatrixEdge;
 class ColumnIterator;
+class Sparkline;
 
 }
 
@@ -99,7 +100,7 @@ struct ScInterpreterContext;
 
 struct ScNeededSizeOptions
 {
-    const ScPatternAttr*    pPattern;
+    const ScPatternAttr* pPattern;
     bool                bFormula;
     bool                bSkipMerged;
     bool                bGetFont;
@@ -126,6 +127,9 @@ class ScColumn
     // Cell values.
     sc::CellStoreType maCells;
 
+    // Sparklines
+    sc::SparklineStoreType maSparklines;
+
     std::unique_ptr<ScAttrArray> pAttrArray;
 
     size_t mnBlkCountFormula;
@@ -612,6 +616,10 @@ public:
     void BroadcastCells( const std::vector<SCROW>& rRows, SfxHintId nHint );
     void BroadcastRows( SCROW nStartRow, SCROW nEndRow, SfxHintId nHint );
 
+    // Spaklines
+    sc::Sparkline* GetSparkline(SCROW nRow);
+    void SetSparkline(SCROW nRow, std::unique_ptr<sc::Sparkline> pSparkline);
+
     // cell notes
     ScPostIt* GetCellNote( SCROW nRow );
     const ScPostIt* GetCellNote( SCROW nRow ) const;
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 4e8eab09ed5d..86bd4ebd02bf 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -101,6 +101,8 @@ class UpdatedRangeNames;
 class TableColumnBlockPositionSet;
 class ColumnIterator;
 class ExternalDataMapper;
+class Sparkline;
+class SparklineGroup;
 
 }
 
@@ -1239,6 +1241,10 @@ public:
      */
     sc::MultiDataCellState HasMultipleDataCells( const ScRange& rRange ) const;
 
+    /** Spaklines */
+    SC_DLLPUBLIC sc::Sparkline* GetSparkline(ScAddress const & rPosition);
+    SC_DLLPUBLIC sc::Sparkline* CreateSparkline(ScAddress const & rPosition, 
std::shared_ptr<sc::SparklineGroup> & pSparklineGroup);
+
     /** Notes **/
     SC_DLLPUBLIC ScPostIt*       GetNote(const ScAddress& rPos);
     SC_DLLPUBLIC ScPostIt*       GetNote(SCCOL nCol, SCROW nRow, SCTAB nTab);
@@ -1270,6 +1276,7 @@ public:
     SC_DLLPUBLIC void GetAllNoteEntries( std::vector<sc::NoteEntry>& rNotes ) 
const;
     SC_DLLPUBLIC void GetAllNoteEntries( SCTAB nTab, 
std::vector<sc::NoteEntry>& rNotes ) const;
     void              GetNotesInRange( const ScRangeList& rRange, 
std::vector<sc::NoteEntry>& rNotes ) const;
+
     bool              ContainsNotesInRange( const ScRangeList& rRange ) const;
 
     SC_DLLPUBLIC void SetDrawPageSize(SCTAB nTab);
diff --git a/sc/inc/mtvelements.hxx b/sc/inc/mtvelements.hxx
index c74e1bc7d91b..6de0f3e7ec23 100644
--- a/sc/inc/mtvelements.hxx
+++ b/sc/inc/mtvelements.hxx
@@ -15,6 +15,7 @@
 #include <editeng/editobj.hxx>
 #include "calcmacros.hxx"
 #include "postit.hxx"
+#include "Sparkline.hxx"
 #include "celltextattr.hxx"
 
 #if DEBUG_COLUMN_STORAGE
@@ -49,6 +50,7 @@ const mdds::mtv::element_t element_type_edittext = 
mdds::mtv::element_type_user_
 const mdds::mtv::element_t element_type_formula = 
mdds::mtv::element_type_user_start + 4;
 
 const mdds::mtv::element_t element_type_cellnote = 
mdds::mtv::element_type_user_start + 5;
+const mdds::mtv::element_t element_type_sparkline = 
mdds::mtv::element_type_user_start + 6;
 
 /// Mapped standard element types (for convenience).
 const mdds::mtv::element_t element_type_numeric = 
mdds::mtv::element_type_double;
@@ -57,6 +59,7 @@ const mdds::mtv::element_t element_type_uint16 = 
mdds::mtv::element_type_uint16;
 
 /// Custom element blocks.
 
+typedef mdds::mtv::noncopyable_managed_element_block<element_type_sparkline, 
sc::Sparkline> sparkline_block;
 typedef mdds::mtv::noncopyable_managed_element_block<element_type_cellnote, 
ScPostIt> cellnote_block;
 typedef mdds::mtv::noncopyable_managed_element_block<element_type_broadcaster, 
SvtBroadcaster> broadcaster_block;
 typedef mdds::mtv::default_element_block<element_type_celltextattr, 
CellTextAttr> celltextattr_block;
@@ -68,8 +71,13 @@ typedef 
mdds::mtv::noncopyable_managed_element_block<element_type_formula, ScFor
 typedef mdds::mtv::double_element_block numeric_block;
 typedef mdds::mtv::uint16_element_block uint16_block;
 
-/// This needs to be in the same namespace as CellTextAttr.
+} // end sc namespace
+
+/// CAUTION! The following defines must be in the same namespace as the 
respective type.
+/// For example sc types like sc::CellTextAttr, ScFormulaCell in global 
namespace.
+namespace sc {
 MDDS_MTV_DEFINE_ELEMENT_CALLBACKS(CellTextAttr, element_type_celltextattr, 
CellTextAttr(), celltextattr_block)
+MDDS_MTV_DEFINE_ELEMENT_CALLBACKS_PTR(Sparkline, sc::element_type_sparkline, 
nullptr, sc::sparkline_block)
 }
 
 /// These need to be in global namespace just like their respective types are.
@@ -79,9 +87,7 @@ MDDS_MTV_DEFINE_ELEMENT_CALLBACKS_PTR(ScFormulaCell, 
sc::element_type_formula, n
 MDDS_MTV_DEFINE_ELEMENT_CALLBACKS_PTR(EditTextObject, 
sc::element_type_edittext, nullptr, sc::edittext_block)
 
 namespace svl {
-
 MDDS_MTV_DEFINE_ELEMENT_CALLBACKS(SharedString, sc::element_type_string, 
SharedString(), sc::string_block)
-
 }
 
 namespace sc {
@@ -110,6 +116,10 @@ struct CellStoreTrait
     static constexpr mdds::mtv::lu_factor_t loop_unrolling = 
mdds::mtv::lu_factor_t::lu16;
 };
 
+/// Sparkline container
+typedef mdds::mtv::custom_block_func1<sc::sparkline_block> CSparklineFunction;
+typedef mdds::mtv::soa::multi_type_vector<CSparklineFunction> 
SparklineStoreType;
+
 /// Cell note container
 typedef mdds::mtv::custom_block_func1<sc::cellnote_block> CNoteFunc;
 typedef mdds::mtv::soa::multi_type_vector<CNoteFunc> CellNoteStoreType;
diff --git a/sc/source/core/data/Sparkline.cxx 
b/sc/source/core/data/Sparkline.cxx
new file mode 100644
index 000000000000..301fda820ff2
--- /dev/null
+++ b/sc/source/core/data/Sparkline.cxx
@@ -0,0 +1,22 @@
+/* -*- 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 <memory>
+#include <Sparkline.hxx>
+
+namespace sc
+{
+Sparkline::Sparkline(std::shared_ptr<SparklineGroup>& pSparklineGroup)
+    : m_pSparklineGroup(pSparklineGroup)
+{
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 5b6cb6d0d824..b66638336a11 100644
--- a/sc/source/core/data/column.cxx

... etc. - the rest is truncated

Reply via email to