include/svx/ColorSets.hxx       |    3 +
 include/tools/color.hxx         |    8 +++
 svx/CppunitTest_svx_styles.mk   |   44 +++++++++++++++++
 svx/Module_svx.mk               |    1 
 svx/qa/unit/data/theme.pptx     |binary
 svx/qa/unit/styles.cxx          |  100 ++++++++++++++++++++++++++++++++++++++++
 svx/source/styles/ColorSets.cxx |   59 +++++++++++++++++++++++
 svx/source/svdraw/svdpage.cxx   |   21 ++++++++
 tools/qa/cppunit/test_color.cxx |   13 +++++
 tools/source/generic/color.cxx  |   32 ++++++++++++
 10 files changed, 280 insertions(+), 1 deletion(-)

New commits:
commit 70ce55234f93e6dc11d61e7930398c4f16d6aaa8
Author:     Miklos Vajna <[email protected]>
AuthorDate: Tue Nov 30 08:44:02 2021 +0100
Commit:     Miklos Vajna <[email protected]>
CommitDate: Mon Jun 27 08:58:37 2022 +0200

    svx: update objects of pages of a master page when the theme changes
    
    Only text color as a start, and without effects.
    
    (cherry picked from commit 48f0c5f73f99c919ec24deadc96c3cf5483c9314)
    
    Change-Id: I52b1c110870605134c414bcc94b50871cd49975b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136372
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Miklos Vajna <[email protected]>

diff --git a/include/svx/ColorSets.hxx b/include/svx/ColorSets.hxx
index e6c9f1b4e7ee..c4aa0ae2b9bc 100644
--- a/include/svx/ColorSets.hxx
+++ b/include/svx/ColorSets.hxx
@@ -19,6 +19,7 @@
 #include <tools/color.hxx>
 
 typedef struct _xmlTextWriter* xmlTextWriterPtr;
+class SdrPage;
 
 namespace svx
 {
@@ -89,6 +90,8 @@ public:
     void ToAny(css::uno::Any& rVal) const;
 
     static std::unique_ptr<Theme> FromAny(const css::uno::Any& rVal);
+
+    void UpdateSdrPage(SdrPage* pPage);
 };
 
 } // end of namespace svx
diff --git a/svx/CppunitTest_svx_styles.mk b/svx/CppunitTest_svx_styles.mk
new file mode 100644
index 000000000000..f617668ad705
--- /dev/null
+++ b/svx/CppunitTest_svx_styles.mk
@@ -0,0 +1,44 @@
+# -*- 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,svx_styles))
+
+$(eval $(call gb_CppunitTest_use_externals,svx_styles,\
+       boost_headers \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,svx_styles, \
+    svx/qa/unit/styles \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,svx_styles, \
+    comphelper \
+    cppu \
+    svx \
+    sal \
+    test \
+    unotest \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,svx_styles))
+
+$(eval $(call gb_CppunitTest_use_ure,svx_styles))
+$(eval $(call gb_CppunitTest_use_vcl,svx_styles))
+
+$(eval $(call gb_CppunitTest_use_rdb,svx_styles,services))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,svx_styles,\
+       officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,svx_styles))
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/Module_svx.mk b/svx/Module_svx.mk
index 3891829c8108..3fc4e889173e 100644
--- a/svx/Module_svx.mk
+++ b/svx/Module_svx.mk
@@ -39,6 +39,7 @@ $(eval $(call gb_Module_add_check_targets,svx,\
        CppunitTest_svx_unit \
        CppunitTest_svx_gallery_test \
        CppunitTest_svx_removewhichrange \
+       CppunitTest_svx_styles \
 ))
 
 # screenshots
diff --git a/svx/qa/unit/data/theme.pptx b/svx/qa/unit/data/theme.pptx
new file mode 100644
index 000000000000..397b6706ffa4
Binary files /dev/null and b/svx/qa/unit/data/theme.pptx differ
diff --git a/svx/qa/unit/styles.cxx b/svx/qa/unit/styles.cxx
new file mode 100644
index 000000000000..9cbae8f997ba
--- /dev/null
+++ b/svx/qa/unit/styles.cxx
@@ -0,0 +1,100 @@
+/* -*- 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/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XMasterPageTarget.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for svx/source/styles/ code.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+    uno::Reference<lang::XComponent> mxComponent;
+
+public:
+    void setUp() override;
+    void tearDown() override;
+    uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+    test::BootstrapFixture::setUp();
+
+    mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+    if (mxComponent.is())
+        mxComponent->dispose();
+
+    test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/svx/qa/unit/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testThemeChange)
+{
+    // Given a document, with a first slide and blue shape text from theme:
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "theme.pptx";
+    getComponent() = loadFromDesktop(aURL);
+    uno::Reference<drawing::XDrawPagesSupplier> 
xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+    uno::Reference<drawing::XMasterPageTarget> xDrawPage(
+        xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY);
+    uno::Reference<drawing::XShapes> xDrawPageShapes(xDrawPage, 
uno::UNO_QUERY);
+    uno::Reference<text::XTextRange> xShape(xDrawPageShapes->getByIndex(0), 
uno::UNO_QUERY);
+    {
+        uno::Reference<container::XEnumerationAccess> xText(xShape->getText(), 
uno::UNO_QUERY);
+        uno::Reference<container::XEnumerationAccess> xPara(
+            xText->createEnumeration()->nextElement(), uno::UNO_QUERY);
+        uno::Reference<beans::XPropertySet> 
xPortion(xPara->createEnumeration()->nextElement(),
+                                                     uno::UNO_QUERY);
+        sal_Int32 nColor{};
+        xPortion->getPropertyValue("CharColor") >>= nColor;
+        // Blue.
+        CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0x4472c4), nColor);
+    }
+
+    // When changing the master slide of slide 1 to use the theme of the 
second master slide:
+    uno::Reference<drawing::XMasterPageTarget> xDrawPage2(
+        xDrawPagesSupplier->getDrawPages()->getByIndex(1), uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> 
xMasterPage2(xDrawPage2->getMasterPage(), uno::UNO_QUERY);
+    uno::Any aTheme = xMasterPage2->getPropertyValue("Theme");
+    uno::Reference<beans::XPropertySet> 
xMasterPage(xDrawPage->getMasterPage(), uno::UNO_QUERY);
+    xMasterPage->setPropertyValue("Theme", aTheme);
+
+    // Then make sure the shape text color is now green:
+    uno::Reference<container::XEnumerationAccess> xText(xShape->getText(), 
uno::UNO_QUERY);
+    uno::Reference<container::XEnumerationAccess> 
xPara(xText->createEnumeration()->nextElement(),
+                                                        uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> 
xPortion(xPara->createEnumeration()->nextElement(),
+                                                 uno::UNO_QUERY);
+    sal_Int32 nColor{};
+    xPortion->getPropertyValue("CharColor") >>= nColor;
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 9486886 (#90c226, green)
+    // - Actual  : 4485828 (#4472c4, blue)
+    // i.e. shape text was not updated on theme change.
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0x90c226), nColor);
+}
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/styles/ColorSets.cxx b/svx/source/styles/ColorSets.cxx
index 773e7c414ef3..a5f8c6e7c548 100644
--- a/svx/source/styles/ColorSets.cxx
+++ b/svx/source/styles/ColorSets.cxx
@@ -16,14 +16,55 @@
 
 #include <com/sun/star/beans/PropertyValues.hpp>
 #include <com/sun/star/util/Color.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
 
 #include <comphelper/propertyvalue.hxx>
 #include <comphelper/sequenceashashmap.hxx>
 #include <comphelper/sequence.hxx>
 #include <sal/log.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svditer.hxx>
+#include <editeng/unoprnms.hxx>
 
 using namespace com::sun::star;
 
+namespace
+{
+void UpdateSdrObject(svx::Theme* pTheme, SdrObject* pObject)
+{
+    svx::ColorSet* pColorSet = pTheme->GetColorSet();
+    if (!pColorSet)
+    {
+        return;
+    }
+
+    uno::Reference<text::XTextRange> xShape(pObject->getUnoShape(), 
uno::UNO_QUERY);
+    uno::Reference<container::XEnumerationAccess> xText(xShape->getText(), 
uno::UNO_QUERY);
+    uno::Reference<container::XEnumeration> xParagraphs = 
xText->createEnumeration();
+    while (xParagraphs->hasMoreElements())
+    {
+        uno::Reference<container::XEnumerationAccess> 
xParagraph(xParagraphs->nextElement(), uno::UNO_QUERY);
+        uno::Reference<container::XEnumeration> xPortions = 
xParagraph->createEnumeration();
+        while (xPortions->hasMoreElements())
+        {
+            uno::Reference<beans::XPropertySet> 
xPortion(xPortions->nextElement(), uno::UNO_QUERY);
+            sal_Int16 nCharColorTheme = -1;
+            xPortion->getPropertyValue(UNO_NAME_EDIT_CHAR_COLOR_THEME) >>= 
nCharColorTheme;
+            if (nCharColorTheme < 0 || nCharColorTheme > 11)
+            {
+                continue;
+            }
+
+            Color aColor = pColorSet->getColor(nCharColorTheme);
+            xPortion->setPropertyValue(UNO_NAME_EDIT_CHAR_COLOR, 
uno::makeAny(static_cast<sal_Int32>(aColor)));
+        }
+    }
+}
+}
+
 namespace svx
 {
 
@@ -229,6 +270,24 @@ std::unique_ptr<Theme> Theme::FromAny(const css::uno::Any& 
rVal)
     return pTheme;
 }
 
+void Theme::UpdateSdrPage(SdrPage* pPage)
+{
+    for (size_t nObject = 0; nObject < pPage->GetObjCount(); ++nObject)
+    {
+        SdrObject* pObject = pPage->GetObj(nObject);
+        UpdateSdrObject(this, pObject);
+        SdrObjList* pList = pObject->GetSubList();
+        if (pList)
+        {
+            SdrObjListIter aIter(pList, SdrIterMode::DeepWithGroups);
+            while (aIter.IsMore())
+            {
+                UpdateSdrObject(this, aIter.Next());
+            }
+        }
+    }
+}
+
 } // end of namespace svx
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdpage.cxx b/svx/source/svdraw/svdpage.cxx
index 7354b86adbb8..b6ef5a450e5c 100644
--- a/svx/source/svdraw/svdpage.cxx
+++ b/svx/source/svdraw/svdpage.cxx
@@ -1277,7 +1277,26 @@ void SdrPageProperties::SetStyleSheet(SfxStyleSheet* 
pStyleSheet)
     ImpPageChange(*mpSdrPage);
 }
 
-void SdrPageProperties::SetTheme(std::unique_ptr<svx::Theme> pTheme) { mpTheme 
= std::move(pTheme); }
+void SdrPageProperties::SetTheme(std::unique_ptr<svx::Theme> pTheme)
+{
+    mpTheme = std::move(pTheme);
+
+    if (mpTheme && mpSdrPage->IsMasterPage())
+    {
+        SdrModel& rModel = mpSdrPage->getSdrModelFromSdrPage();
+        sal_uInt16 nPageCount = rModel.GetPageCount();
+        for (sal_uInt16 nPage = 0; nPage < nPageCount; ++nPage)
+        {
+            SdrPage* pPage = rModel.GetPage(nPage);
+            if (!pPage->TRG_HasMasterPage() || &pPage->TRG_GetMasterPage() != 
mpSdrPage)
+            {
+                continue;
+            }
+
+            mpTheme->UpdateSdrPage(pPage);
+        }
+    }
+}
 
 svx::Theme* SdrPageProperties::GetTheme() { return mpTheme.get(); }
 
commit bad177d0604b76672af2612cf8ab39f8e8345dc7
Author:     Miklos Vajna <[email protected]>
AuthorDate: Mon Nov 29 08:28:28 2021 +0100
Commit:     Miklos Vajna <[email protected]>
CommitDate: Mon Jun 27 08:58:25 2022 +0200

    tools Color: implement MSO-style luminance modulation/offset filter
    
    To be used when a filtered theme color will be applied on the UI, and
    not at PPTX import time.
    
    (cherry picked from commit 8662293d17a875f4389ea21be00e768e3de3d048)
    
    Change-Id: Ifb56e38e59b529ef436063c407ee156d76a77f9c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136371
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Miklos Vajna <[email protected]>

diff --git a/include/tools/color.hxx b/include/tools/color.hxx
index 555017a21dee..5fcf840edfe6 100644
--- a/include/tools/color.hxx
+++ b/include/tools/color.hxx
@@ -335,6 +335,14 @@ public:
      **/
     void ApplyTintOrShade(sal_Int16 n100thPercent);
 
+    /**
+     * Apply luminance offset and/or modulation.
+     *
+     * The input values are in percentages (in 100th percents). 100% 
modulation and 0% offset
+     * results in no change.
+     */
+    void ApplyLumModOff(sal_Int16 nMod, sal_Int16 nOff);
+
     /** Inverts color. 1 and 0 are switched.
       * Note that the result will be the complementary color.
       * For example, if you have red, you will get cyan: FF0000 -> 00FFFF.
diff --git a/tools/qa/cppunit/test_color.cxx b/tools/qa/cppunit/test_color.cxx
index f3ffd9c692cd..3dd4225cb20f 100644
--- a/tools/qa/cppunit/test_color.cxx
+++ b/tools/qa/cppunit/test_color.cxx
@@ -22,6 +22,7 @@ public:
     void testVariables();
     void test_asRGBColor();
     void test_ApplyTintOrShade();
+    void test_ApplyLumModOff();
     void testGetColorError();
     void testInvert();
     void testBColor();
@@ -31,6 +32,7 @@ public:
     CPPUNIT_TEST(testVariables);
     CPPUNIT_TEST(test_asRGBColor);
     CPPUNIT_TEST(test_ApplyTintOrShade);
+    CPPUNIT_TEST(test_ApplyLumModOff);
     CPPUNIT_TEST(testGetColorError);
     CPPUNIT_TEST(testInvert);
     CPPUNIT_TEST(testBColor);
@@ -163,6 +165,17 @@ void Test::test_ApplyTintOrShade()
     CPPUNIT_ASSERT_EQUAL(OUString("000000"), createTintShade(0x80, 0x80, 0x80, 
u"808080", -10000));
 }
 
+void Test::test_ApplyLumModOff()
+{
+    // Kind of blue.
+    Color aColor(0x44, 0x72, 0xC4);
+
+    // PowerPoint calls this "Ligher 40%".
+    aColor.ApplyLumModOff(6000, 4000);
+
+    CPPUNIT_ASSERT_EQUAL(OUString("8faadc"), aColor.AsRGBHexString());
+}
+
 void Test::testGetColorError()
 {
     CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), Color(0xAA, 0xBB, 
0xCC).GetColorError(Color(0xAA, 0xBB, 0xCC)));
diff --git a/tools/source/generic/color.cxx b/tools/source/generic/color.cxx
index cf4e084b722f..5df32719eb2c 100644
--- a/tools/source/generic/color.cxx
+++ b/tools/source/generic/color.cxx
@@ -230,4 +230,36 @@ void Color::ApplyTintOrShade(sal_Int16 n100thPercent)
     B = sal_uInt8(std::lround(aBColor.getBlue()  * 255.0));
 }
 
+void Color::ApplyLumModOff(sal_Int16 nMod, sal_Int16 nOff)
+{
+    if (nMod == 10000 && nOff == 0)
+    {
+        return;
+    }
+    // Switch to HSL, where applying these transforms is easier.
+    basegfx::BColor aBColor = basegfx::utils::rgb2hsl(getBColor());
+
+    // 50% is half luminance, 200% is double luminance. Unit is 100th percent.
+    aBColor.setBlue(std::clamp(aBColor.getBlue() * nMod / 10000, 0.0, 1.0));
+    // If color changes to black or white, it will stay gray if luminance 
changes again.
+    if ((aBColor.getBlue() == 0.0) || (aBColor.getBlue() == 1.0))
+    {
+        aBColor.setGreen(0.0);
+    }
+
+    // Luminance offset means hue and saturation is left unchanged. Unit is 
100th percent.
+    aBColor.setBlue(std::clamp(aBColor.getBlue() + static_cast<double>(nOff) / 
10000, 0.0, 1.0));
+    // If color changes to black or white, it will stay gray if luminance 
changes again.
+    if ((aBColor.getBlue() == 0.0) || (aBColor.getBlue() == 1.0))
+    {
+        aBColor.setGreen(0.0);
+    }
+
+    // Switch back to RGB.
+    aBColor = basegfx::utils::hsl2rgb(aBColor);
+    R = sal_uInt8(std::lround(aBColor.getRed()   * 255.0));
+    G = sal_uInt8(std::lround(aBColor.getGreen() * 255.0));
+    B = sal_uInt8(std::lround(aBColor.getBlue()  * 255.0));
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to