include/docmodel/color/ComplexColor.hxx | 5 ++ include/oox/export/ColorExportUtils.hxx | 55 ++++++++++++++++++++++++++++++++ sc/qa/unit/ThemeImportExportTest.cxx | 18 +++++----- sc/qa/unit/subsequent_export_test.cxx | 20 +++++++---- sc/source/filter/excel/xestream.cxx | 19 ++++++----- sc/source/filter/excel/xestyle.cxx | 40 ++++++++++++++++++----- 6 files changed, 127 insertions(+), 30 deletions(-)
New commits: commit e15806eae9b848989e76927a72214d510252959b Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Fri Jun 30 01:39:50 2023 +0900 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Fri Aug 25 13:33:56 2023 +0200 sc: OOXML export of theme colors for text and background Change-Id: Ifd0d8184c9210caa5ca099767baa5dbbf8783f36 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153785 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> (cherry picked from commit 20dbfa10d851b9df67fab561c3b86cba4f55cc8a) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156077 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/include/docmodel/color/ComplexColor.hxx b/include/docmodel/color/ComplexColor.hxx index 4952d91ac217..e9597b15186b 100644 --- a/include/docmodel/color/ComplexColor.hxx +++ b/include/docmodel/color/ComplexColor.hxx @@ -100,6 +100,11 @@ public: ThemeColorType getSchemeType() const { return meSchemeType; } + bool isValidSchemeType() const + { + return meType == model::ColorType::Scheme && meSchemeType != ThemeColorType::Unknown; + } + Color getRGBColor() const { return Color(mnComponent1, mnComponent2, mnComponent3); } std::vector<Transformation> const& getTransformations() const { return maTransformations; } diff --git a/include/oox/export/ColorExportUtils.hxx b/include/oox/export/ColorExportUtils.hxx new file mode 100644 index 000000000000..63716a10839d --- /dev/null +++ b/include/oox/export/ColorExportUtils.hxx @@ -0,0 +1,55 @@ +/* -*- 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 <sal/config.h> + +#include <docmodel/color/ComplexColor.hxx> + +namespace oox +{ +static double convertColorTransformsToTintOrShade(model::ComplexColor const& rComplexColor) +{ + sal_Int16 nLumMod = 10'000; + sal_Int16 nLumOff = 0; + + for (auto const& rTransform : rComplexColor.getTransformations()) + { + if (rTransform.meType == model::TransformationType::LumMod) + nLumMod = rTransform.mnValue; + if (rTransform.meType == model::TransformationType::LumOff) + nLumOff = rTransform.mnValue; + } + + if (nLumMod == 10'000 && nLumOff == 0) + return 0.0; + + double fTint = 0.0; + + if (nLumOff > 0) // tint + fTint = double(nLumOff) / 10'000.0; + else + fTint = -double(10'000 - nLumMod) / 10'000.0; + + return fTint; +} + +static sal_Int32 convertThemeColorTypeToExcelThemeNumber(model::ThemeColorType eType) +{ + if (eType == model::ThemeColorType::Unknown) + return -1; + + constexpr std::array<sal_Int32, 12> constMap = { 1, 0, 3, 2, 4, 5, 6, 7, 8, 9, 10, 11 }; + + return constMap[sal_Int32(eType)]; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/qa/unit/ThemeImportExportTest.cxx b/sc/qa/unit/ThemeImportExportTest.cxx index 106471f9a816..95e6d0e2351e 100644 --- a/sc/qa/unit/ThemeImportExportTest.cxx +++ b/sc/qa/unit/ThemeImportExportTest.cxx @@ -41,11 +41,9 @@ CPPUNIT_TEST_FIXTURE(ThemeImportExportTest, testThemeExport) // Fonts assertXPath(pXmlDoc, "/x:styleSheet/x:fonts/x:font", 6); - assertXPath(pXmlDoc, "/x:styleSheet/x:fonts/x:font[5]/x:color", "rgb", - "FFFFC000"); // need to be theme probably + assertXPath(pXmlDoc, "/x:styleSheet/x:fonts/x:font[5]/x:color", "theme", "7"); - assertXPath(pXmlDoc, "/x:styleSheet/x:fonts/x:font[6]/x:color", "rgb", - "FF9C5700"); // need to be theme probably + assertXPath(pXmlDoc, "/x:styleSheet/x:fonts/x:font[6]/x:color", "rgb", "FF9C5700"); // Fills assertXPath(pXmlDoc, "/x:styleSheet/x:fills/x:fill", 4); @@ -92,9 +90,9 @@ void checkCellBackgroundThemeColor(ScDocument* pDoc) auto& rTransformations = aComplexColor.getTransformations(); CPPUNIT_ASSERT_EQUAL(size_t(2), rTransformations.size()); CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod, rTransformations[0].meType); - CPPUNIT_ASSERT_EQUAL(sal_Int16(2000), rTransformations[0].mnValue); + CPPUNIT_ASSERT_EQUAL(20, sal_Int32(std::round(rTransformations[0].mnValue / 100.0))); CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff, rTransformations[1].meType); - CPPUNIT_ASSERT_EQUAL(sal_Int16(7999), rTransformations[1].mnValue); + CPPUNIT_ASSERT_EQUAL(80, sal_Int32(std::round(rTransformations[1].mnValue / 100.0))); } // A3 @@ -119,6 +117,8 @@ CPPUNIT_TEST_FIXTURE(ThemeImportExportTest, testCellBackgroundThemeColor) { loadFromURL(u"xlsx/Test_ThemeColor_Text_Background_Border.xlsx"); checkCellBackgroundThemeColor(getScDoc()); + saveAndReload("Calc Office Open XML"); + checkCellBackgroundThemeColor(getScDoc()); } void checkCellTextThemeColor(ScDocument* pDoc) @@ -151,9 +151,9 @@ void checkCellTextThemeColor(ScDocument* pDoc) auto& rTransformations = aComplexColor.getTransformations(); CPPUNIT_ASSERT_EQUAL(size_t(2), rTransformations.size()); CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod, rTransformations[0].meType); - CPPUNIT_ASSERT_EQUAL(sal_Int16(6000), rTransformations[0].mnValue); + CPPUNIT_ASSERT_EQUAL(60, sal_Int32(std::round(rTransformations[0].mnValue / 100.0))); CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff, rTransformations[1].meType); - CPPUNIT_ASSERT_EQUAL(sal_Int16(3999), rTransformations[1].mnValue); + CPPUNIT_ASSERT_EQUAL(40, sal_Int32(std::round(rTransformations[1].mnValue / 100.0))); } // B3 @@ -178,6 +178,8 @@ CPPUNIT_TEST_FIXTURE(ThemeImportExportTest, testCellTextThemeColor) { loadFromURL(u"xlsx/Test_ThemeColor_Text_Background_Border.xlsx"); checkCellTextThemeColor(getScDoc()); + saveAndReload("Calc Office Open XML"); + checkCellTextThemeColor(getScDoc()); } void checkCellBorderThemeColor(ScDocument* pDoc) diff --git a/sc/qa/unit/subsequent_export_test.cxx b/sc/qa/unit/subsequent_export_test.cxx index a010a9820ea4..02e7c8e28c5c 100644 --- a/sc/qa/unit/subsequent_export_test.cxx +++ b/sc/qa/unit/subsequent_export_test.cxx @@ -67,7 +67,7 @@ public: void test(); void testDefaultFontHeight(); void testTdf139167(); - void testTdf113271(); + void testFontColorWithMultipleAttributesDefined(); void testTdf139394(); void testExtCondFormatXLSX(); void testTdf90104(); @@ -188,7 +188,7 @@ public: CPPUNIT_TEST(test); CPPUNIT_TEST(testDefaultFontHeight); CPPUNIT_TEST(testTdf139167); - CPPUNIT_TEST(testTdf113271); + CPPUNIT_TEST(testFontColorWithMultipleAttributesDefined); CPPUNIT_TEST(testTdf139394); CPPUNIT_TEST(testExtCondFormatXLSX); CPPUNIT_TEST(testTdf90104); @@ -352,8 +352,13 @@ void ScExportTest::testTdf139167() "FFFFFF00"); } -void ScExportTest::testTdf113271() +void ScExportTest::testFontColorWithMultipleAttributesDefined() { + // Related: TDF #113271 + // Test font color where "rgb" and "theme" attribute is defined and + // is imported and exported correctly. Theme should have priority, + // so LO is fine to ignore "rgb" at export. + createScDoc("xlsx/tdf113271.xlsx"); save("Calc Office Open XML"); @@ -362,10 +367,11 @@ void ScExportTest::testTdf113271() assertXPath(pDoc, "/x:styleSheet/x:fonts", "count", "6"); - // Without the fix in place, this test would have failed with - // - Expected: FF000000 - // - Actual : FFFFFFFF - assertXPath(pDoc, "/x:styleSheet/x:fonts/x:font[1]/x:color", "rgb", "FF000000"); + // Expect "theme" attribute to be set correctly + assertXPath(pDoc, "/x:styleSheet/x:fonts/x:font[1]/x:color", "theme", "1"); + // We don't export "rgb" attribute + assertXPathNoAttribute(pDoc, "/x:styleSheet/x:fonts/x:font[1]/x:color", "rgb"); + // Just making sure the checked font is the correct one assertXPath(pDoc, "/x:styleSheet/x:fonts/x:font[1]/x:name", "val", "Calibri"); } diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx index ad11b0208551..c0b3b685b8c9 100644 --- a/sc/source/filter/excel/xestream.cxx +++ b/sc/source/filter/excel/xestream.cxx @@ -64,6 +64,7 @@ #include <oox/token/relationship.hxx> #include <oox/export/drawingml.hxx> #include <oox/export/utils.hxx> +#include <oox/export/ColorExportUtils.hxx> #include <formula/grammar.hxx> #include <oox/ole/vbaexport.hxx> #include <excelvbaproject.hxx> @@ -888,15 +889,19 @@ sax_fastparser::FSHelperPtr XclXmlUtils::WriteFontData( sax_fastparser::FSHelper pStream->singleElement(XML_vertAlign, XML_val, pVertAlign); pStream->singleElement(XML_sz, XML_val, OString::number( rFontData.mnHeight / 20.0 )); // Twips->Pt - if (rFontData.maComplexColor.getFinalColor() != Color( ColorAlpha, 0, 0xFF, 0xFF, 0xFF)) + auto& rComplexColor = rFontData.maComplexColor; + if (rComplexColor.isValidSchemeType()) { + sal_Int32 nTheme = oox::convertThemeColorTypeToExcelThemeNumber(rComplexColor.getSchemeType()); + double fTintShade = oox::convertColorTransformsToTintOrShade(rComplexColor); pStream->singleElement(XML_color, - // OOXTODO: XML_auto, bool - // OOXTODO: XML_indexed, uint - XML_rgb, XclXmlUtils::ToOString(rFontData.maComplexColor.getFinalColor()) - // OOXTODO: XML_theme, index into <clrScheme/> - // OOXTODO: XML_tint, double - ); + XML_theme, OString::number(nTheme), + XML_tint, sax_fastparser::UseIf(OString::number(fTintShade), fTintShade != 0.0)); + } + else if (rComplexColor.getFinalColor() != Color( ColorAlpha, 0, 0xFF, 0xFF, 0xFF)) + { + pStream->singleElement(XML_color, + XML_rgb, XclXmlUtils::ToOString(rComplexColor.getFinalColor())); } pStream->singleElement(nFontId, XML_val, rFontData.maName); pStream->singleElement(XML_family, XML_val, OString::number( rFontData.mnFamily )); diff --git a/sc/source/filter/excel/xestyle.cxx b/sc/source/filter/excel/xestyle.cxx index feab202a6b6c..b769be809147 100644 --- a/sc/source/filter/excel/xestyle.cxx +++ b/sc/source/filter/excel/xestyle.cxx @@ -52,6 +52,7 @@ #include <o3tl/safeint.hxx> #include <oox/export/utils.hxx> +#include <oox/export/ColorExportUtils.hxx> #include <oox/token/tokens.hxx> #include <oox/token/namespaces.hxx> #include <oox/token/relationship.hxx> @@ -1975,18 +1976,26 @@ void XclExpCellArea::SaveXml( XclExpXmlStream& rStrm ) const if (maForeColor != COL_TRANSPARENT || maBackColor != COL_TRANSPARENT) { - if (maForegroundComplexColor.getType() == model::ColorType::Scheme) + if (maForegroundComplexColor.isValidSchemeType()) { - rStyleSheet->singleElement(XML_fgColor, XML_theme, OString::number(sal_Int32(maForegroundComplexColor.getSchemeType()))); + sal_Int32 nTheme = oox::convertThemeColorTypeToExcelThemeNumber(maForegroundComplexColor.getSchemeType()); + double fTintShade = oox::convertColorTransformsToTintOrShade(maForegroundComplexColor); + rStyleSheet->singleElement(XML_fgColor, + XML_theme, OString::number(nTheme), + XML_tint, sax_fastparser::UseIf(OString::number(fTintShade), fTintShade != 0.0)); } else if (maForeColor != COL_TRANSPARENT) { rStyleSheet->singleElement(XML_fgColor, XML_rgb, XclXmlUtils::ToOString(maForeColor)); } - if (maBackgroundComplexColor.getType() == model::ColorType::Scheme) + if (maBackgroundComplexColor.isValidSchemeType()) { - rStyleSheet->singleElement(XML_fgColor, XML_theme, OString::number(sal_Int32(maBackgroundComplexColor.getSchemeType()))); + sal_Int32 nTheme = oox::convertThemeColorTypeToExcelThemeNumber(maBackgroundComplexColor.getSchemeType()); + double fTintShade = oox::convertColorTransformsToTintOrShade(maBackgroundComplexColor); + rStyleSheet->singleElement(XML_bgColor, + XML_theme, OString::number(nTheme), + XML_tint, sax_fastparser::UseIf(OString::number(fTintShade), fTintShade != 0.0)); } else if (maBackColor != COL_TRANSPARENT) { @@ -1995,9 +2004,14 @@ void XclExpCellArea::SaveXml( XclExpXmlStream& rStrm ) const } else { - if (maForegroundComplexColor.getType() == model::ColorType::Scheme) + if (maForegroundComplexColor.isValidSchemeType()) { - rStyleSheet->singleElement(XML_fgColor, XML_theme, OString::number(sal_Int32(maForegroundComplexColor.getSchemeType()))); + sal_Int32 nTheme = oox::convertThemeColorTypeToExcelThemeNumber(maForegroundComplexColor.getSchemeType()); + double fTintShade = oox::convertColorTransformsToTintOrShade(maForegroundComplexColor); + + rStyleSheet->singleElement(XML_fgColor, + XML_theme, OString::number(nTheme), + XML_tint, sax_fastparser::UseIf(OString::number(fTintShade), fTintShade != 0.0)); } else if (mnForeColor != 0) { @@ -2006,7 +2020,11 @@ void XclExpCellArea::SaveXml( XclExpXmlStream& rStrm ) const if (maBackgroundComplexColor.getType() == model::ColorType::Scheme) { - rStyleSheet->singleElement(XML_fgColor, XML_theme, OString::number(sal_Int32(maBackgroundComplexColor.getSchemeType()))); + sal_Int32 nTheme = oox::convertThemeColorTypeToExcelThemeNumber(maBackgroundComplexColor.getSchemeType()); + double fTintShade = oox::convertColorTransformsToTintOrShade(maBackgroundComplexColor); + rStyleSheet->singleElement(XML_bgColor, + XML_theme, OString::number(nTheme), + XML_tint, sax_fastparser::UseIf(OString::number(fTintShade), fTintShade != 0.0)); } else if (mnBackColor != 0) { @@ -2038,7 +2056,13 @@ void XclExpColor::SaveXml( XclExpXmlStream& rStrm ) const rStyleSheet->startElement(XML_fill); rStyleSheet->startElement(XML_patternFill); if (maComplexColor.getType() == model::ColorType::Scheme) - rStyleSheet->singleElement(XML_bgColor, XML_theme, OString::number(sal_Int32(maComplexColor.getSchemeType()))); + { + sal_Int32 nTheme = oox::convertThemeColorTypeToExcelThemeNumber(maComplexColor.getSchemeType()); + double fTintShade = oox::convertColorTransformsToTintOrShade(maComplexColor); + rStyleSheet->singleElement(XML_bgColor, + XML_theme, OString::number(nTheme), + XML_tint, sax_fastparser::UseIf(OString::number(fTintShade), fTintShade != 0.0)); + } else rStyleSheet->singleElement(XML_bgColor, XML_rgb, XclXmlUtils::ToOString(maColor));