docmodel/Library_docmodel.mk            |    1 
 docmodel/source/color/ComplexColor.cxx  |  176 ++++++++++++++++++++++++++++++++
 include/docmodel/color/ComplexColor.hxx |  141 +++----------------------
 include/tools/XmlWriter.hxx             |    4 
 tools/qa/cppunit/test_xmlwriter.cxx     |   18 ++-
 tools/source/xml/XmlWriter.cxx          |   32 ++++-
 6 files changed, 237 insertions(+), 135 deletions(-)

New commits:
commit ecf75f2637ca34eb8f60a0ad5e722d0d1ed9fc5f
Author:     Tomaž Vajngerl <[email protected]>
AuthorDate: Sat Dec 6 22:55:58 2025 +0900
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Mon Dec 8 04:15:21 2025 +0100

    tools: support XmlWriter construction from xmlTextWriterPtr
    
    So we can use it in dumpAsXml functions and eventually use it as
    a replacement to directly using libxml.
    
    Change-Id: I204d487b52343f69224fec2fd480657785bc0a69
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195167
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <[email protected]>

diff --git a/include/tools/XmlWriter.hxx b/include/tools/XmlWriter.hxx
index 8947c16ed1ff..1ad34bcdac0e 100644
--- a/include/tools/XmlWriter.hxx
+++ b/include/tools/XmlWriter.hxx
@@ -20,6 +20,8 @@
 #include <o3tl/concepts.hxx>
 
 class SvStream;
+struct _xmlTextWriter;
+typedef struct _xmlTextWriter* xmlTextWriterPtr;
 
 namespace tools
 {
@@ -41,7 +43,7 @@ private:
 
 public:
     XmlWriter(SvStream* pStream);
-
+    XmlWriter(xmlTextWriterPtr pWriter);
     ~XmlWriter();
 
     bool startDocument(sal_Int32 nIndent = 2, bool bWriteXmlHeader = true);
diff --git a/tools/qa/cppunit/test_xmlwriter.cxx 
b/tools/qa/cppunit/test_xmlwriter.cxx
index 6ab22950bf4d..61ce47533f13 100644
--- a/tools/qa/cppunit/test_xmlwriter.cxx
+++ b/tools/qa/cppunit/test_xmlwriter.cxx
@@ -22,25 +22,35 @@ public:
     {
     }
 
-    virtual void setUp() override {}
+    void setUp() override {}
 
     void testSimpleRoot();
     void testSpecialChars();
     void testAttributes();
+    void testStartAndEndDocument();
 
     CPPUNIT_TEST_SUITE(XmlWriterTest);
     CPPUNIT_TEST(testSimpleRoot);
     CPPUNIT_TEST(testSpecialChars);
     CPPUNIT_TEST(testAttributes);
+    CPPUNIT_TEST(testStartAndEndDocument);
     CPPUNIT_TEST_SUITE_END();
 };
 
+void XmlWriterTest::testStartAndEndDocument()
+{
+    SvMemoryStream aMemoryStream;
+    tools::XmlWriter aWriter(&aMemoryStream);
+    CPPUNIT_ASSERT(aWriter.startDocument());
+    CPPUNIT_ASSERT(!aWriter.startDocument());
+}
+
 void XmlWriterTest::testSimpleRoot()
 {
     SvMemoryStream aMemoryStream;
 
     tools::XmlWriter aWriter(&aMemoryStream);
-    aWriter.startDocument(0, false);
+    CPPUNIT_ASSERT(aWriter.startDocument(0, false));
     aWriter.startElement("test");
     aWriter.endElement();
     aWriter.endDocument();
@@ -55,7 +65,7 @@ void XmlWriterTest::testSpecialChars()
     SvMemoryStream aMemoryStream;
 
     tools::XmlWriter aWriter(&aMemoryStream);
-    aWriter.startDocument(0, false);
+    CPPUNIT_ASSERT(aWriter.startDocument(0, false));
     aWriter.startElement("test");
     aWriter.content("<>");
     aWriter.endElement();
@@ -71,7 +81,7 @@ void XmlWriterTest::testAttributes()
     SvMemoryStream aMemoryStream;
 
     tools::XmlWriter aWriter(&aMemoryStream);
-    aWriter.startDocument(0, false);
+    CPPUNIT_ASSERT(aWriter.startDocument(0, false));
     aWriter.startElement("test");
     aWriter.attribute("c", std::string_view("c"));
     aWriter.attribute("d", std::u16string_view(u"d"));
diff --git a/tools/source/xml/XmlWriter.cxx b/tools/source/xml/XmlWriter.cxx
index 5200c3dcd044..0df0b4e2c19d 100644
--- a/tools/source/xml/XmlWriter.cxx
+++ b/tools/source/xml/XmlWriter.cxx
@@ -42,16 +42,22 @@ requires(sizeof(T) == sizeof(char)) void 
attributeBase64_impl(xmlTextWriterPtr w
 
 struct XmlWriterImpl
 {
+    SvStream* mpStream = nullptr;
+    xmlTextWriterPtr mpWriter = nullptr;
+    bool mbWriteXmlHeader = true;
+    bool mbExternalXmlWriter = false;
+
     XmlWriterImpl(SvStream* pStream)
         : mpStream(pStream)
-        , mpWriter(nullptr)
-        , mbWriteXmlHeader(true)
     {
     }
 
-    SvStream* mpStream;
-    xmlTextWriterPtr mpWriter;
-    bool mbWriteXmlHeader;
+    XmlWriterImpl(xmlTextWriterPtr pWriter)
+        : mpWriter(pWriter)
+        , mbWriteXmlHeader(false)
+        , mbExternalXmlWriter(true)
+    {
+    }
 };
 
 XmlWriter::XmlWriter(SvStream* pStream)
@@ -59,29 +65,41 @@ XmlWriter::XmlWriter(SvStream* pStream)
 {
 }
 
+XmlWriter::XmlWriter(xmlTextWriterPtr pWriter)
+    : mpImpl(std::make_unique<XmlWriterImpl>(pWriter))
+{
+}
+
 XmlWriter::~XmlWriter()
 {
-    if (mpImpl && mpImpl->mpWriter != nullptr)
+    if (mpImpl)
         endDocument();
 }
 
 bool XmlWriter::startDocument(sal_Int32 nIndent, bool bWriteXmlHeader)
 {
+    if (mpImpl->mpWriter)
+        return false;
+
     mpImpl->mbWriteXmlHeader = bWriteXmlHeader;
     xmlCharEncodingHandlerPtr pEncodingHandler = 
xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
     xmlOutputBufferPtr xmlOutBuffer = 
xmlOutputBufferCreateIO(funcWriteCallback, funcCloseCallback,
                                                               
mpImpl->mpStream, pEncodingHandler);
     mpImpl->mpWriter = xmlNewTextWriter(xmlOutBuffer);
-    if (mpImpl->mpWriter == nullptr)
+    if (!mpImpl->mpWriter)
         return false;
     xmlTextWriterSetIndent(mpImpl->mpWriter, nIndent);
     if (mpImpl->mbWriteXmlHeader)
         (void)xmlTextWriterStartDocument(mpImpl->mpWriter, nullptr, "UTF-8", 
nullptr);
+
     return true;
 }
 
 void XmlWriter::endDocument()
 {
+    if (!mpImpl->mpWriter || mpImpl->mbExternalXmlWriter)
+        return;
+
     if (mpImpl->mbWriteXmlHeader)
         (void)xmlTextWriterEndDocument(mpImpl->mpWriter);
     xmlFreeTextWriter(mpImpl->mpWriter);
commit 1dbe0aa24f8276fc03da81813c19d980a4463633
Author:     Tomaž Vajngerl <[email protected]>
AuthorDate: Sat Dec 6 22:00:05 2025 +0900
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Mon Dec 8 04:15:06 2025 +0100

    docmodel: add ComplexColor.cxx and move function definitions there
    
    No need to be a template only class.
    
    Change-Id: I3d73fe18443662205967ce5904233a93d7785164
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195166
    Reviewed-by: Tomaž Vajngerl <[email protected]>
    Tested-by: Jenkins

diff --git a/docmodel/Library_docmodel.mk b/docmodel/Library_docmodel.mk
index 1de5c254a110..01e63c4b7e48 100644
--- a/docmodel/Library_docmodel.mk
+++ b/docmodel/Library_docmodel.mk
@@ -18,6 +18,7 @@ $(eval $(call gb_Library_add_exception_objects,docmodel,\
     docmodel/source/theme/ColorSet \
     docmodel/source/theme/Theme \
     docmodel/source/color/ComplexColorJSON \
+    docmodel/source/color/ComplexColor \
     docmodel/source/styles/ChartStyle \
     docmodel/source/styles/ChartColorStyle \
 ))
diff --git a/docmodel/source/color/ComplexColor.cxx 
b/docmodel/source/color/ComplexColor.cxx
new file mode 100644
index 000000000000..4b957abad991
--- /dev/null
+++ b/docmodel/source/color/ComplexColor.cxx
@@ -0,0 +1,176 @@
+/* -*- 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 <docmodel/color/ComplexColor.hxx>
+#include <sal/log.hxx>
+#include <tools/color.hxx>
+#include <docmodel/theme/ThemeColorType.hxx>
+#include <docmodel/color/Transformation.hxx>
+#include <o3tl/hash_combine.hxx>
+
+namespace model
+{
+void ComplexColor::addTransformation(Transformation const& rTransform)
+{
+    maTransformations.push_back(rTransform);
+}
+
+void ComplexColor::removeTransformations(TransformationType eType)
+{
+    std::erase_if(maTransformations,
+                  [eType](Transformation const& rTransform) { return 
rTransform.meType == eType; });
+}
+
+void ComplexColor::setCRGB(sal_Int32 nR, sal_Int32 nG, sal_Int32 nB)
+{
+    mnComponent1 = nR;
+    mnComponent2 = nG;
+    mnComponent3 = nB;
+    meType = ColorType::CRGB;
+}
+
+void ComplexColor::setRGB(double r, double g, double b)
+{
+    mnComponent1 = r;
+    mnComponent2 = g;
+    mnComponent3 = b;
+    maFinalColor = ::Color(sal_Int8(r), sal_Int8(g), sal_Int8(b));
+    meType = ColorType::RGB;
+}
+
+void ComplexColor::getRGB(double& r, double& g, double& b)
+{
+    if (meType != ColorType::RGB)
+        return;
+    r = mnComponent1;
+    g = mnComponent2;
+    b = mnComponent3;
+}
+
+Color ComplexColor::getRGB() const { return Color(mnComponent1, mnComponent2, 
mnComponent3); }
+
+void ComplexColor::setColor(Color const& rColor)
+{
+    mnComponent1 = rColor.GetRed();
+    mnComponent2 = rColor.GetGreen();
+    mnComponent3 = rColor.GetBlue();
+    maFinalColor = rColor;
+    meType = ColorType::RGB;
+}
+
+void ComplexColor::setRGB(sal_Int32 nRGB)
+{
+    ::Color aColor(ColorTransparency, nRGB);
+    setColor(aColor);
+}
+
+void ComplexColor::setHSL(sal_Int32 nH, sal_Int32 nS, sal_Int32 nL)
+{
+    mnComponent1 = nH;
+    mnComponent2 = nS;
+    mnComponent3 = nL;
+    meType = ColorType::HSL;
+}
+
+void ComplexColor::setSystemColor(SystemColorType eSystemColorType, sal_Int32 
nRGB)
+{
+    maLastColor = ::Color(ColorTransparency, nRGB);
+    meSystemColorType = eSystemColorType;
+    meType = ColorType::System;
+}
+
+bool ComplexColor::isOpaque() const
+{
+    for (const Transformation& t : maTransformations)
+    {
+        if (t.meType == model::TransformationType::Alpha && t.mnValue != 10000)
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool ComplexColor::isTransparent() const
+{
+    for (const Transformation& t : maTransformations)
+    {
+        if (t.meType == model::TransformationType::Alpha && t.mnValue == 0)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+void ComplexColor::setThemeColor(ThemeColorType eType)
+{
+    meThemeColorType = eType;
+    meType = ColorType::Theme;
+}
+
+bool ComplexColor::operator==(const ComplexColor& rComplexColor) const
+{
+    return meType == rComplexColor.meType && mnComponent1 == 
rComplexColor.mnComponent1
+           && mnComponent2 == rComplexColor.mnComponent2
+           && mnComponent3 == rComplexColor.mnComponent3
+           && meSystemColorType == rComplexColor.meSystemColorType
+           && maLastColor == rComplexColor.maLastColor
+           && meThemeColorType == rComplexColor.meThemeColorType
+           && maTransformations.size() == 
rComplexColor.maTransformations.size()
+           && std::equal(maTransformations.begin(), maTransformations.end(),
+                         rComplexColor.maTransformations.begin());
+}
+
+Color ComplexColor::applyTransformations(Color const& rColor) const
+{
+    Color aColor(rColor);
+
+    for (auto const& rTransform : maTransformations)
+    {
+        switch (rTransform.meType)
+        {
+            case TransformationType::Tint:
+                aColor.ApplyTintOrShade(rTransform.mnValue);
+                break;
+            case TransformationType::Shade:
+                aColor.ApplyTintOrShade(-rTransform.mnValue);
+                break;
+            case TransformationType::LumMod:
+                aColor.ApplyLumModOff(rTransform.mnValue, 0);
+                break;
+            case TransformationType::LumOff:
+                aColor.ApplyLumModOff(10000, rTransform.mnValue);
+                break;
+            default:
+                break;
+        }
+    }
+    return aColor;
+}
+
+std::size_t ComplexColor::getHash() const
+{
+    std::size_t seed = 0;
+    o3tl::hash_combine(seed, meType);
+    o3tl::hash_combine(seed, mnComponent1);
+    o3tl::hash_combine(seed, mnComponent2);
+    o3tl::hash_combine(seed, mnComponent3);
+    o3tl::hash_combine(seed, meSystemColorType);
+    o3tl::hash_combine(seed, sal_uInt32(maLastColor));
+    for (auto const& rTransform : maTransformations)
+        o3tl::hash_combine(seed, rTransform);
+    o3tl::hash_combine(seed, sal_uInt32(maFinalColor));
+    return seed;
+}
+
+} // end of namespace model
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/docmodel/color/ComplexColor.hxx 
b/include/docmodel/color/ComplexColor.hxx
index e57530936bda..0333b128fadf 100644
--- a/include/docmodel/color/ComplexColor.hxx
+++ b/include/docmodel/color/ComplexColor.hxx
@@ -142,17 +142,9 @@ public:
         maTransformations = rTransformations;
     }
 
-    void addTransformation(Transformation const& rTransform)
-    {
-        maTransformations.push_back(rTransform);
-    }
+    void addTransformation(Transformation const& rTransform);
 
-    void removeTransformations(TransformationType eType)
-    {
-        std::erase_if(maTransformations, [eType](Transformation const& 
rTransform) {
-            return rTransform.meType == eType;
-        });
-    }
+    void removeTransformations(TransformationType eType);
 
     void clearTransformations() { maTransformations.clear(); }
 
@@ -160,137 +152,40 @@ public:
     double getGreen() const { return mnComponent2; }
     double getBlue() const { return mnComponent3; }
 
-    void setCRGB(sal_Int32 nR, sal_Int32 nG, sal_Int32 nB)
-    {
-        mnComponent1 = nR;
-        mnComponent2 = nG;
-        mnComponent3 = nB;
-        meType = ColorType::CRGB;
-    }
+    void setCRGB(sal_Int32 nR, sal_Int32 nG, sal_Int32 nB);
 
-    Color getRGB() const { return Color(mnComponent1, mnComponent2, 
mnComponent3); }
+    void setRGB(double r, double g, double b);
 
-    void setColor(Color const& rColor)
-    {
-        mnComponent1 = rColor.GetRed();
-        mnComponent2 = rColor.GetGreen();
-        mnComponent3 = rColor.GetBlue();
-        maFinalColor = rColor;
-        meType = ColorType::RGB;
-    }
+    void getRGB(double& r, double& g, double& b);
 
-    void setRGB(sal_Int32 nRGB)
-    {
-        ::Color aColor(ColorTransparency, nRGB);
-        setColor(aColor);
-    }
+    Color getRGB() const;
 
-    void setHSL(sal_Int32 nH, sal_Int32 nS, sal_Int32 nL)
-    {
-        mnComponent1 = nH;
-        mnComponent2 = nS;
-        mnComponent3 = nL;
-        meType = ColorType::HSL;
-    }
+    void setColor(Color const& rColor);
 
-    void setSystemColor(SystemColorType eSystemColorType, sal_Int32 nRGB)
-    {
-        maLastColor = ::Color(ColorTransparency, nRGB);
-        meSystemColorType = eSystemColorType;
-        meType = ColorType::System;
-    }
+    void setRGB(sal_Int32 nRGB);
 
-    bool isOpaque() const
-    {
-        for (const Transformation& t : maTransformations)
-        {
-            if (t.meType == model::TransformationType::Alpha && t.mnValue != 
10000)
-            {
-                return false;
-            }
-        }
-        return true;
-    }
+    void setHSL(sal_Int32 nH, sal_Int32 nS, sal_Int32 nL);
 
-    bool isTransparent() const
-    {
-        for (const Transformation& t : maTransformations)
-        {
-            if (t.meType == model::TransformationType::Alpha && t.mnValue == 0)
-            {
-                return true;
-            }
-        }
-        return false;
-    }
+    void setSystemColor(SystemColorType eSystemColorType, sal_Int32 nRGB);
+
+    bool isOpaque() const;
+
+    bool isTransparent() const;
 
     void setThemePlaceholder() { meType = ColorType::Placeholder; }
 
-    void setThemeColor(ThemeColorType eType)
-    {
-        meThemeColorType = eType;
-        meType = ColorType::Theme;
-    }
+    void setThemeColor(ThemeColorType eType);
 
-    bool operator==(const ComplexColor& rComplexColor) const
-    {
-        return meType == rComplexColor.meType && mnComponent1 == 
rComplexColor.mnComponent1
-               && mnComponent2 == rComplexColor.mnComponent2
-               && mnComponent3 == rComplexColor.mnComponent3
-               && meSystemColorType == rComplexColor.meSystemColorType
-               && maLastColor == rComplexColor.maLastColor
-               && meThemeColorType == rComplexColor.meThemeColorType
-               && maTransformations.size() == 
rComplexColor.maTransformations.size()
-               && std::equal(maTransformations.begin(), 
maTransformations.end(),
-                             rComplexColor.maTransformations.begin());
-    }
+    bool operator==(const ComplexColor& rComplexColor) const;
 
     /** Applies the defined transformations to the input color */
-    Color applyTransformations(Color const& rColor) const
-    {
-        Color aColor(rColor);
-
-        for (auto const& rTransform : maTransformations)
-        {
-            switch (rTransform.meType)
-            {
-                case TransformationType::Tint:
-                    aColor.ApplyTintOrShade(rTransform.mnValue);
-                    break;
-                case TransformationType::Shade:
-                    aColor.ApplyTintOrShade(-rTransform.mnValue);
-                    break;
-                case TransformationType::LumMod:
-                    aColor.ApplyLumModOff(rTransform.mnValue, 0);
-                    break;
-                case TransformationType::LumOff:
-                    aColor.ApplyLumModOff(10000, rTransform.mnValue);
-                    break;
-                default:
-                    break;
-            }
-        }
-        return aColor;
-    }
+    Color applyTransformations(Color const& rColor) const;
 
     void setFinalColor(Color const& rColor) { maFinalColor = rColor; }
 
     Color const& getFinalColor() const { return maFinalColor; }
 
-    std::size_t getHash() const
-    {
-        std::size_t seed = 0;
-        o3tl::hash_combine(seed, meType);
-        o3tl::hash_combine(seed, mnComponent1);
-        o3tl::hash_combine(seed, mnComponent2);
-        o3tl::hash_combine(seed, mnComponent3);
-        o3tl::hash_combine(seed, meSystemColorType);
-        o3tl::hash_combine(seed, sal_uInt32(maLastColor));
-        for (auto const& rTransform : maTransformations)
-            o3tl::hash_combine(seed, rTransform);
-        o3tl::hash_combine(seed, sal_uInt32(maFinalColor));
-        return seed;
-    }
+    std::size_t getHash() const;
 
     static model::ComplexColor createRGB(Color const& rColor)
     {

Reply via email to