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 | 16 ++++++--- sc/source/filter/excel/xestream.cxx | 19 ++++++----- sc/source/filter/excel/xestyle.cxx | 40 ++++++++++++++++++----- 6 files changed, 125 insertions(+), 28 deletions(-)
New commits: commit 20dbfa10d851b9df67fab561c3b86cba4f55cc8a Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Fri Jun 30 01:39:50 2023 +0900 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Tue Jul 4 08:40:20 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> 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 e528e3fc679c..1ce8ef99c926 100644 --- a/sc/qa/unit/subsequent_export_test.cxx +++ b/sc/qa/unit/subsequent_export_test.cxx @@ -105,8 +105,13 @@ CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf139167) "FFFFFF00"); } -CPPUNIT_TEST_FIXTURE(ScExportTest, testTdf113271) +CPPUNIT_TEST_FIXTURE(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"); @@ -115,10 +120,11 @@ CPPUNIT_TEST_FIXTURE(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 eeb42449f3c9..b91170cb1702 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> @@ -884,15 +885,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 652e5f77a951..87421c525fa2 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> @@ -1974,18 +1975,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) { @@ -1994,9 +2003,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) { @@ -2005,7 +2019,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) { @@ -2037,7 +2055,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));