summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTamas Bunth <tamas.bunth@collabora.co.uk>2020-01-21 19:04:13 +0100
committerTamás Bunth <btomi96@gmail.com>2020-03-03 15:52:47 +0100
commitf9fc420dceb1ece2c98767da16a21aaff771f140 (patch)
tree299b9c856a3567ee85af11b7b314d2d02a03420b
parent224ab38f747dcafe711c10b54ad53c52bda9e41d (diff)
tdf#101181 Implement glow effect on shapes
Glow effect is a color-blurred outline outside of the shape. In ooxml document it is specified with the <a:glow> element. The commit contains the following: - Add support for importing and exporting <a:glow> from ooxml documents. - Assign new properties to XShape which stores glow-related attributes. - A new 2D primitive is introduced in module 'drawinglayer' which is responsible for representing the glow primitive which is to be rendered. + A glow primitive is a clone of the original shape which has been scaled up slightly and a new color has been assigned to it. The radius of the glow effect and the color is defined in the <a:glow> element being imported. - A blur algorithm is introduced in module 'vcl', which is called during rendering the primitive. + The blur algorithm works on a bitmap. + Since the algorithm is CPU-intensive, the result is cached in the processor and it is recalculated only if needed. - Add support for importing and exporting glow effect to ODF format. For that, new attributes of element <style:graphic-properties> has been added: + loext:glow, which can have the values "visible" or "hidden" + loext:glow-radius: which holds the radius of the glow effect in cm. + loext:glow-color: holds the color of the glow effect - Tests have been added to assert properties after pptx import and export. Change-Id: I836aeb5e0f24e2c8d5725834c8c0f98083bc82e7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89125 Tested-by: Jenkins Reviewed-by: Tamás Bunth <btomi96@gmail.com>
-rw-r--r--drawinglayer/Library_drawinglayer.mk2
-rw-r--r--drawinglayer/source/attribute/sdrglowattribute.cxx80
-rw-r--r--drawinglayer/source/primitive2d/Tools.cxx2
-rw-r--r--drawinglayer/source/primitive2d/glowprimitive2d.cxx87
-rw-r--r--drawinglayer/source/processor2d/vclpixelprocessor2d.cxx46
-rw-r--r--include/drawinglayer/attribute/sdrglowattribute.hxx54
-rw-r--r--include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx1
-rw-r--r--include/drawinglayer/primitive2d/glowprimitive2d.hxx71
-rw-r--r--include/oox/export/drawingml.hxx2
-rw-r--r--include/svx/sdglowmetricitem.hxx37
-rw-r--r--include/svx/strings.hrc3
-rw-r--r--include/svx/svddef.hxx9
-rw-r--r--include/svx/unoshprp.hxx5
-rw-r--r--include/vcl/BitmapFilterStackBlur.hxx34
-rw-r--r--include/xmloff/xmltoken.hxx3
-rw-r--r--oox/source/drawingml/effectproperties.cxx7
-rw-r--r--oox/source/drawingml/effectproperties.hxx10
-rw-r--r--oox/source/drawingml/effectpropertiescontext.cxx13
-rw-r--r--oox/source/drawingml/shape.cxx10
-rw-r--r--oox/source/export/drawingml.cxx67
-rw-r--r--oox/source/token/properties.txt2
-rwxr-xr-xsd/qa/unit/data/pptx/shape-glow-effect.pptxbin0 -> 13691 bytes
-rw-r--r--sd/qa/unit/export-tests-ooxml2.cxx18
-rw-r--r--sd/qa/unit/import-tests.cxx19
-rw-r--r--svx/inc/sdr/attribute/sdrlinefillshadowtextattribute.hxx3
-rw-r--r--svx/inc/sdr/attribute/sdrlineshadowtextattribute.hxx4
-rw-r--r--svx/inc/sdr/attribute/sdrshadowtextattribute.hxx8
-rw-r--r--svx/inc/sdr/primitive2d/sdrattributecreator.hxx4
-rw-r--r--svx/inc/sdr/primitive2d/sdrdecompositiontools.hxx6
-rw-r--r--svx/source/sdr/attribute/sdrlinefillshadowtextattribute.cxx5
-rw-r--r--svx/source/sdr/attribute/sdrlineshadowtextattribute.cxx5
-rw-r--r--svx/source/sdr/attribute/sdrshadowtextattribute.cxx15
-rw-r--r--svx/source/sdr/primitive2d/sdrattributecreator.cxx28
-rw-r--r--svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx8
-rw-r--r--svx/source/sdr/primitive2d/sdrdecompositiontools.cxx21
-rw-r--r--svx/source/sdr/properties/customshapeproperties.cxx3
-rw-r--r--svx/source/svdraw/svdattr.cxx8
-rw-r--r--svx/source/unodraw/unoprov.cxx11
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport7.cxx53
-rw-r--r--vcl/CppunitTest_vcl_bitmap_test.mk1
-rw-r--r--vcl/Library_vcl.mk1
-rw-r--r--vcl/qa/cppunit/BitmapFilterTest.cxx159
-rw-r--r--vcl/source/bitmap/BitmapFilterStackBlur.cxx554
-rw-r--r--vcl/source/outdev/bitmap.cxx4
-rw-r--r--xmloff/inc/xmlsdtypes.hxx1
-rw-r--r--xmloff/source/core/xmltoken.cxx3
-rw-r--r--xmloff/source/draw/sdpropls.cxx10
-rw-r--r--xmloff/source/token/tokens.txt3
48 files changed, 1409 insertions, 91 deletions
diff --git a/drawinglayer/Library_drawinglayer.mk b/drawinglayer/Library_drawinglayer.mk
index aba0ce9b6e08..0f93f8407b98 100644
--- a/drawinglayer/Library_drawinglayer.mk
+++ b/drawinglayer/Library_drawinglayer.mk
@@ -58,6 +58,7 @@ $(eval $(call gb_Library_add_exception_objects,drawinglayer,\
drawinglayer/source/attribute/sdrallattribute3d \
drawinglayer/source/attribute/sdrfillattribute \
drawinglayer/source/attribute/sdrfillgraphicattribute \
+ drawinglayer/source/attribute/sdrglowattribute \
drawinglayer/source/attribute/sdrlightattribute3d \
drawinglayer/source/attribute/sdrlightingattribute3d \
drawinglayer/source/attribute/sdrlineattribute \
@@ -82,6 +83,7 @@ $(eval $(call gb_Library_add_exception_objects,drawinglayer,\
drawinglayer/source/primitive2d/fillgraphicprimitive2d \
drawinglayer/source/primitive2d/fillgradientprimitive2d \
drawinglayer/source/primitive2d/fillhatchprimitive2d \
+ drawinglayer/source/primitive2d/glowprimitive2d \
drawinglayer/source/primitive2d/graphicprimitivehelper2d \
drawinglayer/source/primitive2d/graphicprimitive2d \
drawinglayer/source/primitive2d/gridprimitive2d \
diff --git a/drawinglayer/source/attribute/sdrglowattribute.cxx b/drawinglayer/source/attribute/sdrglowattribute.cxx
new file mode 100644
index 000000000000..bc42b170a8e9
--- /dev/null
+++ b/drawinglayer/source/attribute/sdrglowattribute.cxx
@@ -0,0 +1,80 @@
+/* -*- 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 <drawinglayer/attribute/sdrglowattribute.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <rtl/instance.hxx>
+
+#include <utility>
+
+#include <sal/log.hxx>
+
+namespace drawinglayer
+{
+namespace attribute
+{
+SdrGlowAttribute::SdrGlowAttribute(sal_Int32 nRadius, const basegfx::BColor& rColor)
+ : m_nRadius(nRadius)
+ , m_color(rColor)
+{
+}
+
+SdrGlowAttribute::SdrGlowAttribute()
+ : m_nRadius(0)
+{
+}
+
+SdrGlowAttribute::SdrGlowAttribute(const SdrGlowAttribute&) = default;
+
+SdrGlowAttribute::SdrGlowAttribute(SdrGlowAttribute&&) = default;
+
+SdrGlowAttribute::~SdrGlowAttribute() = default;
+
+SdrGlowAttribute& SdrGlowAttribute::operator=(const SdrGlowAttribute&) = default;
+
+SdrGlowAttribute& SdrGlowAttribute::operator=(SdrGlowAttribute&&) = default;
+
+bool SdrGlowAttribute::operator==(const SdrGlowAttribute& rCandidate) const
+{
+ if (rCandidate.isDefault() != isDefault())
+ return false;
+ return m_nRadius == rCandidate.m_nRadius && m_color == rCandidate.m_color;
+}
+
+const basegfx::B2DHomMatrix& SdrGlowAttribute::GetTransfMatrix(basegfx::B2DRange nRange) const
+{
+ if (!m_oTransfCache)
+ {
+ double dRadius100mm = static_cast<double>(m_nRadius) / 360.0;
+ // Apply a scaling with the center point of the shape as origin.
+ // 1) translate shape to the origin
+ basegfx::B2DHomMatrix matrix = basegfx::utils::createCoordinateSystemTransform(
+ nRange.getCenter(), basegfx::B2DVector(-1, 0), basegfx::B2DVector(0, -1));
+
+ basegfx::B2DHomMatrix inverse(matrix);
+ inverse.invert();
+
+ // 2) Scale up
+ double scale_x = (nRange.getWidth() + dRadius100mm) / nRange.getWidth();
+ double scale_y = (nRange.getHeight() + dRadius100mm) / nRange.getHeight();
+ matrix *= basegfx::utils::createScaleB2DHomMatrix(scale_x, scale_y);
+
+ // 3) Translate shape back to its place
+ matrix *= inverse;
+ m_oTransfCache = std::move(matrix);
+ }
+ return *m_oTransfCache;
+}
+
+} // end of namespace attribute
+} // end of namespace drawinglayer
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/Tools.cxx b/drawinglayer/source/primitive2d/Tools.cxx
index e9ff7a55394d..2a8b8239a569 100644
--- a/drawinglayer/source/primitive2d/Tools.cxx
+++ b/drawinglayer/source/primitive2d/Tools.cxx
@@ -228,6 +228,8 @@ OUString idToString(sal_uInt32 nId)
return "POLYPOLYGONSELECTION";
case PRIMITIVE2D_ID_PAGEHIERARCHYPRIMITIVE2D:
return "PAGEHIERARCHY";
+ case PRIMITIVE2D_ID_GLOWPRIMITIVE2D:
+ return "GLOWPRIMITIVE";
default:
return OUString::number((nId >> 16) & 0xFF) + "|" + OUString::number(nId & 0xFF);
}
diff --git a/drawinglayer/source/primitive2d/glowprimitive2d.cxx b/drawinglayer/source/primitive2d/glowprimitive2d.cxx
new file mode 100644
index 000000000000..1fc035bf5279
--- /dev/null
+++ b/drawinglayer/source/primitive2d/glowprimitive2d.cxx
@@ -0,0 +1,87 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <drawinglayer/primitive2d/glowprimitive2d.hxx>
+#include <basegfx/color/bcolormodifier.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+#include <sal/log.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+
+namespace drawinglayer::primitive2d
+{
+GlowPrimitive2D::GlowPrimitive2D(const basegfx::B2DHomMatrix& rGlowTransform,
+ const basegfx::BColor& rGlowColor,
+ const Primitive2DContainer& rChildren)
+ : GroupPrimitive2D(rChildren)
+ , maGlowTransform(rGlowTransform)
+ , maGlowColor(rGlowColor)
+{
+}
+
+bool GlowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+{
+ if (BasePrimitive2D::operator==(rPrimitive))
+ {
+ const GlowPrimitive2D& rCompare = static_cast<const GlowPrimitive2D&>(rPrimitive);
+
+ return (getGlowTransform() == rCompare.getGlowTransform()
+ && getGlowColor() == rCompare.getGlowColor());
+ }
+
+ return false;
+}
+
+basegfx::B2DRange
+GlowPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+{
+ basegfx::B2DRange aRetval(getChildren().getB2DRange(rViewInformation));
+ aRetval.transform(getGlowTransform());
+ return aRetval;
+}
+
+void GlowPrimitive2D::get2DDecomposition(
+ Primitive2DDecompositionVisitor& rVisitor,
+ const geometry::ViewInformation2D& /*rViewInformation*/) const
+{
+ if (!getChildren().empty())
+ {
+ // create a modifiedColorPrimitive containing the Glow color and the content
+ basegfx::BColorModifierSharedPtr aBColorModifier
+ = std::make_shared<basegfx::BColorModifier_replace>(getGlowColor());
+
+ const Primitive2DReference xRefA(
+ new ModifiedColorPrimitive2D(getChildren(), aBColorModifier));
+ const Primitive2DContainer aSequenceB{ xRefA };
+
+ // build transformed primitiveVector with Glow offset and add to target
+ rVisitor.append(new TransformPrimitive2D(getGlowTransform(), aSequenceB));
+ }
+}
+
+// provide unique ID
+ImplPrimitive2DIDBlock(GlowPrimitive2D, PRIMITIVE2D_ID_GLOWPRIMITIVE2D)
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index 2fa5a7d47a44..4bd490dcfe78 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -18,6 +18,8 @@
*/
#include "vclpixelprocessor2d.hxx"
+#include "vclhelperbufferdevice.hxx"
+#include <vcl/BitmapFilterStackBlur.hxx>
#include <vcl/outdev.hxx>
#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
#include <drawinglayer/primitive2d/Tools.hxx>
@@ -48,6 +50,9 @@
#include <drawinglayer/primitive2d/epsprimitive2d.hxx>
#include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
+#include <vcl/dibtools.hxx>
+#include <tools/stream.hxx>
+
using namespace com::sun::star;
namespace drawinglayer::processor2d
@@ -361,6 +366,47 @@ namespace drawinglayer::processor2d
processBorderLinePrimitive2D(static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate));
break;
}
+ case PRIMITIVE2D_ID_GLOWPRIMITIVE2D:
+ {
+ basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D()));
+ aRange.transform(maCurrentTransformation);
+ aRange.grow(10.0);
+ impBufferDevice aBufferDevice(*mpOutputDevice, aRange);
+ if(aBufferDevice.isVisible())
+ {
+ // remember last OutDev and set to content
+ OutputDevice* pLastOutputDevice = mpOutputDevice;
+ mpOutputDevice = &aBufferDevice.getTransparence();
+ // paint content to virtual device
+ mpOutputDevice->Erase();
+ process(rCandidate);
+
+ // obtain result as a bitmap
+ auto bitmap = mpOutputDevice->GetBitmapEx(Point(aRange.getMinX(), aRange.getMinY()), Size(aRange.getWidth(), aRange.getHeight()));
+ constexpr sal_Int32 nRadius = 5;
+ bitmap.Scale(Size(aRange.getWidth()-nRadius, aRange.getHeight()-nRadius));
+ // use bitmap later as mask
+ auto mask = bitmap.GetBitmap();
+
+ mpOutputDevice = &aBufferDevice.getContent();
+ process(rCandidate);
+ bitmap = mpOutputDevice->GetBitmapEx(Point(aRange.getMinX(), aRange.getMinY()), Size(aRange.getWidth(), aRange.getHeight()));
+ bitmap.Scale(Size(aRange.getWidth()-nRadius, aRange.getHeight()-nRadius));
+
+ // calculate blurry effect
+ BitmapFilterStackBlur glowFilter(nRadius);
+ BitmapFilter::Filter(bitmap, glowFilter);
+ // back to old OutDev
+ mpOutputDevice = pLastOutputDevice;
+ mpOutputDevice->DrawBitmapEx(Point(aRange.getMinX()-nRadius/2, aRange.getMinY()-nRadius/2), BitmapEx(bitmap.GetBitmap(), mask));
+
+ // paint result
+ //aBufferDevice.paint();
+ }
+ else
+ SAL_WARN("drawinglayer", "Temporary buffered virtual device is not visible");
+ break;
+ }
default :
{
SAL_INFO("drawinglayer", "default case for " << drawinglayer::primitive2d::idToString(rCandidate.getPrimitive2DID()));
diff --git a/include/drawinglayer/attribute/sdrglowattribute.hxx b/include/drawinglayer/attribute/sdrglowattribute.hxx
new file mode 100644
index 000000000000..f5120c1a2044
--- /dev/null
+++ b/include/drawinglayer/attribute/sdrglowattribute.hxx
@@ -0,0 +1,54 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_DRAWINGLAYER_ATTRIBUTE_SDRGLOWATTRIBUTE_HXX
+#define INCLUDED_DRAWINGLAYER_ATTRIBUTE_SDRGLOWATTRIBUTE_HXX
+
+#include <drawinglayer/drawinglayerdllapi.h>
+#include <o3tl/cow_wrapper.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <basegfx/range/b2drange.hxx>
+
+#include <optional>
+
+namespace drawinglayer
+{
+namespace attribute
+{
+class DRAWINGLAYER_DLLPUBLIC SdrGlowAttribute
+{
+private:
+ sal_Int32 m_nRadius = 0;
+ mutable std::optional<basegfx::B2DHomMatrix> m_oTransfCache;
+ basegfx::BColor m_color;
+
+public:
+ SdrGlowAttribute(sal_Int32 nRadius, const basegfx::BColor& rColor);
+ SdrGlowAttribute();
+ SdrGlowAttribute(const SdrGlowAttribute&);
+ SdrGlowAttribute(SdrGlowAttribute&&);
+ ~SdrGlowAttribute();
+ bool operator==(const SdrGlowAttribute& rCandidate) const;
+
+ SdrGlowAttribute& operator=(const SdrGlowAttribute&);
+ SdrGlowAttribute& operator=(SdrGlowAttribute&&);
+
+ // data access
+ const basegfx::B2DHomMatrix& GetTransfMatrix(basegfx::B2DRange nCenter) const;
+ const basegfx::BColor& getColor() const { return m_color; };
+ sal_Int32 getRadius() const { return m_nRadius; };
+ bool isDefault() const { return m_nRadius == 0; };
+};
+} // end of namespace attribute
+} // end of namespace drawinglayer
+
+#endif //INCLUDED_DRAWINGLAYER_ATTRIBUTE_SDRGLOWATTRIBUTE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx b/include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx
index 1cc379d3e521..0c9aa3c0b4ba 100644
--- a/include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx
+++ b/include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx
@@ -102,6 +102,7 @@
#define PRIMITIVE2D_ID_OBJECTINFOPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 68)
#define PRIMITIVE2D_ID_POLYPOLYGONSELECTIONPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 69)
#define PRIMITIVE2D_ID_PAGEHIERARCHYPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 70)
+#define PRIMITIVE2D_ID_GLOWPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 71)
// When you add a new primitive, please update the drawinglayer::primitive2d::idToString() function
// in drawinglayer/source/primitive2d/baseprimitive2d.cxx.
diff --git a/include/drawinglayer/primitive2d/glowprimitive2d.hxx b/include/drawinglayer/primitive2d/glowprimitive2d.hxx
new file mode 100644
index 000000000000..0c77a9a94a6c
--- /dev/null
+++ b/include/drawinglayer/primitive2d/glowprimitive2d.hxx
@@ -0,0 +1,71 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_GLOWPRIMITIVE2D_HXX
+#define INCLUDED_DRAWINGLAYER_PRIMITIVE2D_GLOWPRIMITIVE2D_HXX
+
+#include <drawinglayer/drawinglayerdllapi.h>
+
+#include <drawinglayer/primitive2d/groupprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/color/bcolor.hxx>
+
+namespace drawinglayer
+{
+namespace primitive2d
+{
+class DRAWINGLAYER_DLLPUBLIC GlowPrimitive2D final : public GroupPrimitive2D
+{
+private:
+ /// the Glow transformation, normally just an offset
+ basegfx::B2DHomMatrix maGlowTransform;
+
+ /// the Glow color to which all geometry is to be forced
+ basegfx::BColor maGlowColor;
+
+public:
+ /// constructor
+ GlowPrimitive2D(const basegfx::B2DHomMatrix& rGlowTransform, const basegfx::BColor& rGlowColor,
+ const Primitive2DContainer& rChildren);
+
+ /// data read access
+ const basegfx::B2DHomMatrix& getGlowTransform() const { return maGlowTransform; }
+ const basegfx::BColor& getGlowColor() const { return maGlowColor; }
+
+ /// compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ /// get range
+ virtual basegfx::B2DRange
+ getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
+
+ /// create decomposition
+ virtual void
+ get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor,
+ const geometry::ViewInformation2D& rViewInformation) const override;
+
+ /// provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+};
+} // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+#endif //INCLUDED_DRAWINGLAYER_PRIMITIVE2D_GLOWPRIMITIVE2D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx
index a3da6a3cb442..ce5c6e9668e2 100644
--- a/include/oox/export/drawingml.hxx
+++ b/include/oox/export/drawingml.hxx
@@ -167,6 +167,8 @@ protected:
static bool EqualGradients( css::awt::Gradient aGradient1, css::awt::Gradient aGradient2 );
+ void WriteGlowEffect(const css::uno::Reference<css::beans::XPropertySet>& rXPropSet);
+
public:
DrawingML( ::sax_fastparser::FSHelperPtr pFS, ::oox::core::XmlFilterBase* pFB, DocumentType eDocumentType = DOCUMENT_PPTX, DMLTextExport* pTextExport = nullptr )
: meDocumentType( eDocumentType ), mpTextExport(pTextExport), mpFS( pFS ), mpFB( pFB ), mbIsBackgroundDark( false ) {}
diff --git a/include/svx/sdglowmetricitem.hxx b/include/svx/sdglowmetricitem.hxx
new file mode 100644
index 000000000000..4a78cdedc19c
--- /dev/null
+++ b/include/svx/sdglowmetricitem.hxx
@@ -0,0 +1,37 @@
+/* -*- 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/.
+ */
+#ifndef INCLUDED_SVX_SDGLOWMETRICITEM_HXX
+#define INCLUDED_SVX_SDGLOWMETRICITEM_HXX
+
+#include <svx/svddef.hxx>
+#include <svl/poolitem.hxx>
+#include <svx/svxdllapi.h>
+
+#include <com/sun/star/table/GlowFormat.hpp>
+#include <drawinglayer/attribute/sdrglowattribute.hxx>
+
+class SVX_DLLPUBLIC SdrGlowItem : public SfxPoolItem
+{
+private:
+ css::uno::Reference<css::table::GlowFormat> m_xGlow;
+
+public:
+ SdrGlowItem();
+ virtual bool GetPresentation(SfxItemPresentation ePres, MapUnit eCoreMetric,
+ MapUnit ePresMetric, OUString& rText,
+ const IntlWrapper&) const override;
+ virtual bool operator==(const SfxPoolItem&) const override;
+ virtual bool QueryValue(css::uno::Any& rVal, sal_uInt8 nMemberId = 0) const override;
+ virtual bool PutValue(const css::uno::Any& rVal, sal_uInt8 nMemberId) override;
+ virtual SdrGlowItem* Clone(SfxItemPool* pPool = nullptr) const override;
+
+ drawinglayer::attribute::SdrGlowAttribute GetGlowAttr() const;
+};
+
+#endif
diff --git a/include/svx/strings.hrc b/include/svx/strings.hrc
index 0c4d78465364..b208d88605a4 100644
--- a/include/svx/strings.hrc
+++ b/include/svx/strings.hrc
@@ -512,6 +512,9 @@
#define SIP_SA_GRAFINVERT NC_("SIP_SA_GRAFINVERT", "Invert")
#define SIP_SA_GRAFMODE NC_("SIP_SA_GRAFMODE", "Image mode")
#define SIP_SA_GRAFCROP NC_("SIP_SA_GRAFCROP", "Crop")
+#define SIP_SA_GLOW NC_("SIP_SA_GRAD", "Glow effect")
+#define SIP_SA_GLOW_RAD NC_("SIP_SA_GLOW_RAD", "Radius of glow effect")
+#define SIP_SA_GLOW_COLOR NC_("SIP_SA_GLOW_COLOR", "Color of glow effect")
#define STR_ObjNameSingulMEDIA NC_("STR_ObjNameSingulMEDIA", "Media object")
#define STR_ObjNamePluralMEDIA NC_("STR_ObjNamePluralMEDIA", "Media objects")
// drawing layer table strings
diff --git a/include/svx/svddef.hxx b/include/svx/svddef.hxx
index a8696559c4fd..10713f61188b 100644
--- a/include/svx/svddef.hxx
+++ b/include/svx/svddef.hxx
@@ -401,10 +401,15 @@ class SdrTextHorzAdjustItem;
#define SDRATTR_TABLE_BORDER_TLBR TypedWhichId<SvxLineItem>(SDRATTR_TABLE_FIRST+2)
#define SDRATTR_TABLE_BORDER_BLTR TypedWhichId<SvxLineItem>(SDRATTR_TABLE_FIRST+3)
#define SDRATTR_TABLE_TEXT_ROTATION TypedWhichId<SvxTextRotateItem>(SDRATTR_TABLE_FIRST+4)
-
#define SDRATTR_TABLE_LAST (SDRATTR_TABLE_TEXT_ROTATION)
-#define SDRATTR_END SDRATTR_TABLE_LAST /* 1357 */ /* 1333 V4+++*/ /* 1243 V4+++*/ /*1213*/ /*1085*/ /*1040*/ /*Pool V2: 1123,V1: 1065 */
+#define SDRATTR_GLOW_FIRST (SDRATTR_TABLE_LAST+1)
+#define SDRATTR_GLOW TypedWhichId<SdrOnOffItem>(SDRATTR_GLOW_FIRST+0)
+#define SDRATTR_GLOW_RAD TypedWhichId<SdrMetricItem>(SDRATTR_GLOW_FIRST+1)
+#define SDRATTR_GLOW_COLOR TypedWhichId<XColorItem>(SDRATTR_GLOW_FIRST+2)
+#define SDRATTR_GLOW_LAST (SDRATTR_GLOW_COLOR)
+
+#define SDRATTR_END SDRATTR_GLOW_LAST /* 1357 */ /* 1333 V4+++*/ /* 1243 V4+++*/ /*1213*/ /*1085*/ /*1040*/ /*Pool V2: 1123,V1: 1065 */
#endif // INCLUDED_SVX_SVDDEF_HXX
diff --git a/include/svx/unoshprp.hxx b/include/svx/unoshprp.hxx
index 0861844be16d..fd70a04035fe 100644
--- a/include/svx/unoshprp.hxx
+++ b/include/svx/unoshprp.hxx
@@ -209,6 +209,11 @@
{ OUString("FontWorkHideForm"), XATTR_FORMTXTHIDEFORM, cppu::UnoType<bool>::get(), 0, 0}, \
{ OUString("FontWorkShadowTransparence"),XATTR_FORMTXTSHDWTRANSP, ::cppu::UnoType<sal_Int16>::get(), 0, 0},
+#define GLOW_PROPERTIES \
+ { OUString("GlowEffect"), SDRATTR_GLOW, cppu::UnoType<bool>::get(), 0, 0}, \
+ { OUString{"GlowEffectRad"}, SDRATTR_GLOW_RAD, ::cppu::UnoType<sal_Int32>::get(), 0, 0, PropertyMoreFlags::METRIC_ITEM}, \
+ { OUString{"GlowEffectColor"}, SDRATTR_GLOW_COLOR, ::cppu::UnoType<sal_Int32>::get(), 0, 0},
+
#define SHADOW_PROPERTIES \
{ OUString(UNO_NAME_SHADOW), SDRATTR_SHADOW, cppu::UnoType<bool>::get(), 0, 0}, \
{ OUString(UNO_NAME_SHADOWCOLOR), SDRATTR_SHADOWCOLOR, ::cppu::UnoType<sal_Int32>::get(), 0, 0}, \
diff --git a/include/vcl/BitmapFilterStackBlur.hxx b/include/vcl/BitmapFilterStackBlur.hxx
new file mode 100644
index 000000000000..425420ded3c2
--- /dev/null
+++ b/include/vcl/BitmapFilterStackBlur.hxx
@@ -0,0 +1,34 @@
+/* -*- 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/.
+ *
+ */
+
+#ifndef INCLUDED_VCL_BITMAPFILTERSTACKBLUR_HXX
+#define INCLUDED_VCL_BITMAPFILTERSTACKBLUR_HXX
+
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/BitmapFilter.hxx>
+
+class VCL_DLLPUBLIC BitmapFilterStackBlur : public BitmapFilter
+{
+ sal_Int32 mnRadius;
+ bool mbExtend;
+
+public:
+ BitmapFilterStackBlur(sal_Int32 nRadius, bool bExtend = true);
+ virtual ~BitmapFilterStackBlur();
+
+ virtual BitmapEx execute(BitmapEx const& rBitmap) const override;
+
+ Bitmap filter(Bitmap const& rBitmap) const;
+};
+
+#endif // INCLUDED_VCL_BITMAPFILTERSTACKBLUR_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index 7289d72e5e61..ba4a588d85eb 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -925,6 +925,9 @@ namespace xmloff { namespace token {
XML_GCD,
XML_GENERATOR,
XML_GEQ,
+ XML_GLOW,
+ XML_GLOW_RADIUS,
+ XML_GLOW_COLOR,
XML_GOURAUD,
XML_GRADIENT,
XML_GRADIENT_ANGLE,
diff --git a/oox/source/drawingml/effectproperties.cxx b/oox/source/drawingml/effectproperties.cxx
index 2ca45bae05a8..e4e9eaddcb32 100644
--- a/oox/source/drawingml/effectproperties.cxx
+++ b/oox/source/drawingml/effectproperties.cxx
@@ -18,6 +18,12 @@
namespace oox::drawingml {
+void EffectGlowProperties ::assignUsed(const EffectGlowProperties& rSourceProps)
+{
+ moGlowRad.assignIfUsed( rSourceProps.moGlowRad );
+ moGlowColor.assignIfUsed( rSourceProps.moGlowColor );
+}
+
void EffectShadowProperties::assignUsed(const EffectShadowProperties& rSourceProps)
{
moShadowDist.assignIfUsed( rSourceProps.moShadowDist );
@@ -28,6 +34,7 @@ void EffectShadowProperties::assignUsed(const EffectShadowProperties& rSourcePro
void EffectProperties::assignUsed( const EffectProperties& rSourceProps )
{
maShadow.assignUsed(rSourceProps.maShadow);
+ maGlow.assignUsed(rSourceProps.maGlow);
if (!rSourceProps.m_Effects.empty())
{
m_Effects.clear();
diff --git a/oox/source/drawingml/effectproperties.hxx b/oox/source/drawingml/effectproperties.hxx
index 146214cc9191..c4f39ac8803b 100644
--- a/oox/source/drawingml/effectproperties.hxx
+++ b/oox/source/drawingml/effectproperties.hxx
@@ -20,6 +20,15 @@
namespace oox {
namespace drawingml {
+struct EffectGlowProperties
+{
+ OptValue< sal_Int64 > moGlowRad; // size of glow effect
+ Color moGlowColor;
+ // TODO saturation and luminance missing
+
+ void assignUsed( const EffectGlowProperties& rSourceProps );
+};
+
struct EffectShadowProperties
{
OptValue< sal_Int64 > moShadowDist;
@@ -42,6 +51,7 @@ struct Effect
struct EffectProperties
{
EffectShadowProperties maShadow;
+ EffectGlowProperties maGlow;
/** Stores all effect properties, including those not supported by core yet */
std::vector<std::unique_ptr<Effect>> m_Effects;
diff --git a/oox/source/drawingml/effectpropertiescontext.cxx b/oox/source/drawingml/effectpropertiescontext.cxx
index 7941920ed370..6424e99d8458 100644
--- a/oox/source/drawingml/effectpropertiescontext.cxx
+++ b/oox/source/drawingml/effectpropertiescontext.cxx
@@ -15,6 +15,8 @@
#include <oox/token/namespaces.hxx>
#include <oox/token/tokens.hxx>
+#include <sal/log.hxx>
+
using namespace ::oox::core;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::xml::sax;
@@ -97,13 +99,18 @@ ContextHandlerRef EffectPropertiesContext::onCreateContext( sal_Int32 nElement,
}
break;
case A_TOKEN( glow ):
+ {
+ mrEffectProperties.maGlow.moGlowRad = rAttribs.getInteger( XML_rad, 0 );
+ // undo push_back to effects
+ mrEffectProperties.m_Effects.pop_back();
+ return new ColorContext(*this, mrEffectProperties.maGlow.moGlowColor);
+
+ }
case A_TOKEN( softEdge ):
case A_TOKEN( reflection ):
case A_TOKEN( blur ):
{
- if( nElement == A_TOKEN( glow ) )
- mrEffectProperties.m_Effects[nPos]->msName = "glow";
- else if( nElement == A_TOKEN( softEdge ) )
+ if( nElement == A_TOKEN( softEdge ) )
mrEffectProperties.m_Effects[nPos]->msName = "softEdge";
else if( nElement == A_TOKEN( reflection ) )
mrEffectProperties.m_Effects[nPos]->msName = "reflection";
diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx
index 0cf633369959..1c307ff38371 100644
--- a/oox/source/drawingml/shape.cxx
+++ b/oox/source/drawingml/shape.cxx
@@ -1215,6 +1215,7 @@ Reference< XShape > const & Shape::createAndInsert(
aFormat.ShadowWidth = *oShadowDistance;
aShapeProps.setProperty(PROP_ShadowFormat, aFormat);
}
+
}
else if (mbTextBox)
{
@@ -1464,6 +1465,15 @@ Reference< XShape > const & Shape::createAndInsert(
aPropertySet.setAnyProperty(PROP_CharColor, uno::makeAny(nCharColor));
}
}
+
+ // Set glow effect properties
+ if ( aEffectProperties.maGlow.moGlowRad.has() )
+ {
+ uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
+ propertySet->setPropertyValue("GlowEffect", makeAny(true));
+ propertySet->setPropertyValue("GlowEffectRad", makeAny(static_cast<sal_Int32>(aEffectProperties.maGlow.moGlowRad.get())));
+ propertySet->setPropertyValue("GlowEffectColor", makeAny(aEffectProperties.maGlow.moGlowColor.getColor(rGraphicHelper)));
+ }
}
if( mxShape.is() )
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index b4c37d514ece..d80b6a3bea7e 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -3719,29 +3719,38 @@ void DrawingML::WriteShapeEffects( const Reference< XPropertySet >& rXPropSet )
bool bHasShadow = false;
if( GetProperty( rXPropSet, "Shadow" ) )
mAny >>= bHasShadow;
- if( bHasShadow )
+ bool bHasGlow = false;
+ if( GetProperty( rXPropSet, "GlowEffect") )
+ mAny >>= bHasGlow;
+ //rXPropSet->getPropertyValue("GlowEffect") >>= bHasGlow;
+
+ if( bHasShadow || bHasGlow )
{
- Sequence< PropertyValue > aShadowGrabBag( 3 );
- Sequence< PropertyValue > aShadowAttribsGrabBag( 2 );
+ mpFS->startElementNS(XML_a, XML_effectLst);
+ if( bHasShadow )
+ {
+ Sequence< PropertyValue > aShadowGrabBag( 3 );
+ Sequence< PropertyValue > aShadowAttribsGrabBag( 2 );
- double dX = +0.0, dY = +0.0;
- rXPropSet->getPropertyValue( "ShadowXDistance" ) >>= dX;
- rXPropSet->getPropertyValue( "ShadowYDistance" ) >>= dY;
+ double dX = +0.0, dY = +0.0;
+ rXPropSet->getPropertyValue( "ShadowXDistance" ) >>= dX;
+ rXPropSet->getPropertyValue( "ShadowYDistance" ) >>= dY;
- aShadowAttribsGrabBag[0].Name = "dist";
- aShadowAttribsGrabBag[0].Value <<= lcl_CalculateDist(dX, dY);
- aShadowAttribsGrabBag[1].Name = "dir";
- aShadowAttribsGrabBag[1].Value <<= lcl_CalculateDir(dX, dY);
+ aShadowAttribsGrabBag[0].Name = "dist";
+ aShadowAttribsGrabBag[0].Value <<= lcl_CalculateDist(dX, dY);
+ aShadowAttribsGrabBag[1].Name = "dir";
+ aShadowAttribsGrabBag[1].Value <<= lcl_CalculateDir(dX, dY);
- aShadowGrabBag[0].Name = "Attribs";
- aShadowGrabBag[0].Value <<= aShadowAttribsGrabBag;
- aShadowGrabBag[1].Name = "RgbClr";
- aShadowGrabBag[1].Value = rXPropSet->getPropertyValue( "ShadowColor" );
- aShadowGrabBag[2].Name = "RgbClrTransparency";
- aShadowGrabBag[2].Value = rXPropSet->getPropertyValue( "ShadowTransparence" );
+ aShadowGrabBag[0].Name = "Attribs";
+ aShadowGrabBag[0].Value <<= aShadowAttribsGrabBag;
+ aShadowGrabBag[1].Name = "RgbClr";
+ aShadowGrabBag[1].Value = rXPropSet->getPropertyValue( "ShadowColor" );
+ aShadowGrabBag[2].Name = "RgbClrTransparency";
+ aShadowGrabBag[2].Value = rXPropSet->getPropertyValue( "ShadowTransparence" );
- mpFS->startElementNS(XML_a, XML_effectLst);
- WriteShapeEffect( "outerShdw", aShadowGrabBag );
+ WriteShapeEffect( "outerShdw", aShadowGrabBag );
+ }
+ WriteGlowEffect(rXPropSet);
mpFS->endElementNS(XML_a, XML_effectLst);
}
}
@@ -3796,10 +3805,32 @@ void DrawingML::WriteShapeEffects( const Reference< XPropertySet >& rXPropSet )
WriteShapeEffect( rEffect.Name, aEffectProps );
}
}
+ WriteGlowEffect(rXPropSet);
+
mpFS->endElementNS(XML_a, XML_effectLst);
}
}
+void DrawingML::WriteGlowEffect(const Reference< XPropertySet >& rXPropSet)
+{
+ bool hasGlow = false;
+ rXPropSet->getPropertyValue("GlowEffect") >>= hasGlow;
+ if(!hasGlow)
+ return;
+
+ Sequence< PropertyValue > aGlowAttribs(1);
+ aGlowAttribs[0].Name = "rad";
+ aGlowAttribs[0].Value = rXPropSet->getPropertyValue("GlowEffectRad");
+ Sequence< PropertyValue > aGlowProps(2);
+ aGlowProps[0].Name = "Attribs";
+ aGlowProps[0].Value <<= aGlowAttribs;
+ aGlowProps[1].Name = "RgbClr";
+ aGlowProps[1].Value = rXPropSet->getPropertyValue("GlowEffectColor");
+ // TODO other stuff like saturation or luminance
+
+ WriteShapeEffect("glow", aGlowProps);
+}
+
void DrawingML::WriteShape3DEffects( const Reference< XPropertySet >& xPropSet )
{
// check existence of the grab bag
diff --git a/oox/source/token/properties.txt b/oox/source/token/properties.txt
index 4fc0c5b47c57..4624573d579b 100644
--- a/oox/source/token/properties.txt
+++ b/oox/source/token/properties.txt
@@ -207,6 +207,8 @@ Function
GapwidthSequence
GenerateVbaEvents
Geometry3D
+GlowEffect
+GlowEffectRad
GradientName
HatchName
Graphic
diff --git a/sd/qa/unit/data/pptx/shape-glow-effect.pptx b/sd/qa/unit/data/pptx/shape-glow-effect.pptx
new file mode 100755
index 000000000000..6a33aa58ffaa
--- /dev/null
+++ b/sd/qa/unit/data/pptx/shape-glow-effect.pptx
Binary files differ
diff --git a/sd/qa/unit/export-tests-ooxml2.cxx b/sd/qa/unit/export-tests-ooxml2.cxx
index 2a1802f138ab..2befeb024d9b 100644
--- a/sd/qa/unit/export-tests-ooxml2.cxx
+++ b/sd/qa/unit/export-tests-ooxml2.cxx
@@ -182,6 +182,7 @@ public:
void testTdf127372();
void testTdf127379();
void testTdf98603();
+ void testShapeGlowEffect();
CPPUNIT_TEST_SUITE(SdOOXMLExportTest2);
@@ -282,6 +283,7 @@ public:
CPPUNIT_TEST(testTdf127372);
CPPUNIT_TEST(testTdf127379);
CPPUNIT_TEST(testTdf98603);
+ CPPUNIT_TEST(testShapeGlowEffect);
CPPUNIT_TEST_SUITE_END();
@@ -2633,6 +2635,22 @@ void SdOOXMLExportTest2::testTdf98603()
CPPUNIT_ASSERT_EQUAL(OUString("IL"), aLocale.Country);
}
+void SdOOXMLExportTest2::testShapeGlowEffect()
+{
+ ::sd::DrawDocShellRef xDocShRef = loadURL( m_directories.getURLFromSrc("sd/qa/unit/data/pptx/shape-glow-effect.pptx"), PPTX);
+ xDocShRef = saveAndReload( xDocShRef.get(), PPTX );
+ uno::Reference<beans::XPropertySet> xShape(getShapeFromPage(0, 0, xDocShRef));
+ bool bHasGlow = false;
+ xShape->getPropertyValue("GlowEffect") >>= bHasGlow;
+ CPPUNIT_ASSERT(bHasGlow);
+ sal_Int64 nRadius = -1;
+ xShape->getPropertyValue("GlowEffectRad") >>= nRadius;
+ CPPUNIT_ASSERT_EQUAL(sal_Int64(139700l), nRadius);
+ Color nColor;
+ xShape->getPropertyValue("GlowEffectColor") >>= nColor;
+ CPPUNIT_ASSERT_EQUAL(Color(0xFFC000), nColor);
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(SdOOXMLExportTest2);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx
index 9dfdb35c4fb4..85b7f5fa0cdf 100644
--- a/sd/qa/unit/import-tests.cxx
+++ b/sd/qa/unit/import-tests.cxx
@@ -209,6 +209,7 @@ public:
void testTdf116266();
void testTdf126324();
void testTdf128684();
+ void testShapeGlowEffectPPTXImpoer();
bool checkPattern(sd::DrawDocShellRef const & rDocRef, int nShapeNumber, std::vector<sal_uInt8>& rExpected);
void testPatternImport();
@@ -332,6 +333,7 @@ public:
CPPUNIT_TEST(testTdf106638);
CPPUNIT_TEST(testTdf128684);
CPPUNIT_TEST(testTdf113198);
+ CPPUNIT_TEST(testShapeGlowEffectPPTXImpoer);
CPPUNIT_TEST_SUITE_END();
};
@@ -3145,6 +3147,23 @@ void SdImportTest::testTdf113198()
CPPUNIT_ASSERT_EQUAL(style::ParagraphAdjust_CENTER, static_cast<style::ParagraphAdjust>(nParaAdjust));
}
+void SdImportTest::testShapeGlowEffectPPTXImpoer()
+{
+ sd::DrawDocShellRef xDocShRef
+ = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/pptx/shape-glow-effect.pptx"), PPTX);
+
+ uno::Reference<beans::XPropertySet> xShape(getShapeFromPage(0, 0, xDocShRef));
+ bool bHasGlow = false;
+ xShape->getPropertyValue("GlowEffect") >>= bHasGlow;
+ CPPUNIT_ASSERT(bHasGlow);
+ sal_Int64 nRadius = -1;
+ xShape->getPropertyValue("GlowEffectRad") >>= nRadius;
+ CPPUNIT_ASSERT_EQUAL(sal_Int64(139700l), nRadius);
+ Color nColor;
+ xShape->getPropertyValue("GlowEffectColor") >>= nColor;
+ CPPUNIT_ASSERT_EQUAL(Color(0xFFC000), nColor);
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(SdImportTest);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/svx/inc/sdr/attribute/sdrlinefillshadowtextattribute.hxx b/svx/inc/sdr/attribute/sdrlinefillshadowtextattribute.hxx
index 519800e7dd02..f9d7969e519a 100644
--- a/svx/inc/sdr/attribute/sdrlinefillshadowtextattribute.hxx
+++ b/svx/inc/sdr/attribute/sdrlinefillshadowtextattribute.hxx
@@ -41,7 +41,8 @@ namespace drawinglayer
const SdrLineStartEndAttribute& rLineStartEnd,
const SdrShadowAttribute& rShadow,
const FillGradientAttribute& rFillFloatTransGradient,
- const SdrTextAttribute& rTextAttribute);
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow);
SdrLineFillShadowTextAttribute();
SdrLineFillShadowTextAttribute(const SdrLineFillShadowTextAttribute& rCandidate);
SdrLineFillShadowTextAttribute& operator=(const SdrLineFillShadowTextAttribute& rCandidate);
diff --git a/svx/inc/sdr/attribute/sdrlineshadowtextattribute.hxx b/svx/inc/sdr/attribute/sdrlineshadowtextattribute.hxx
index af7df7982422..840b20e44cc9 100644
--- a/svx/inc/sdr/attribute/sdrlineshadowtextattribute.hxx
+++ b/svx/inc/sdr/attribute/sdrlineshadowtextattribute.hxx
@@ -20,6 +20,7 @@
#pragma once
#include <sdr/attribute/sdrshadowtextattribute.hxx>
+#include <drawinglayer/attribute/sdrglowattribute.hxx>
#include <drawinglayer/attribute/sdrlineattribute.hxx>
#include <drawinglayer/attribute/sdrlinestartendattribute.hxx>
@@ -39,7 +40,8 @@ namespace drawinglayer
const SdrLineAttribute& rLine,
const SdrLineStartEndAttribute& rLineStartEnd,
const SdrShadowAttribute& rShadow,
- const SdrTextAttribute& rTextAttribute);
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow);
SdrLineShadowTextAttribute();
SdrLineShadowTextAttribute(const SdrLineShadowTextAttribute& rCandidate);
SdrLineShadowTextAttribute& operator=(const SdrLineShadowTextAttribute& rCandidate);
diff --git a/svx/inc/sdr/attribute/sdrshadowtextattribute.hxx b/svx/inc/sdr/attribute/sdrshadowtextattribute.hxx
index c58437b70928..bbcd7e95a501 100644
--- a/svx/inc/sdr/attribute/sdrshadowtextattribute.hxx
+++ b/svx/inc/sdr/attribute/sdrshadowtextattribute.hxx
@@ -21,6 +21,7 @@
#include <drawinglayer/attribute/sdrshadowattribute.hxx>
#include <sdr/attribute/sdrtextattribute.hxx>
+#include <drawinglayer/attribute/sdrglowattribute.hxx>
namespace drawinglayer
@@ -33,10 +34,14 @@ namespace drawinglayer
SdrShadowAttribute maShadow; // shadow attributes (if used)
SdrTextAttribute maTextAttribute; // text and text attributes (if used)
+ // glow effect
+ SdrGlowAttribute maGlow;
+
public:
SdrShadowTextAttribute(
const SdrShadowAttribute& rShadow,
- const SdrTextAttribute& rTextAttribute);
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow);
SdrShadowTextAttribute();
SdrShadowTextAttribute(const SdrShadowTextAttribute& rCandidate);
SdrShadowTextAttribute& operator=(const SdrShadowTextAttribute& rCandidate);
@@ -50,6 +55,7 @@ namespace drawinglayer
// data access
const SdrShadowAttribute& getShadow() const { return maShadow; }
const SdrTextAttribute& getText() const { return maTextAttribute; }
+ const SdrGlowAttribute& getGlow() const { return maGlow; }
};
} // end of namespace attribute
} // end of namespace drawinglayer
diff --git a/svx/inc/sdr/primitive2d/sdrattributecreator.hxx b/svx/inc/sdr/primitive2d/sdrattributecreator.hxx
index 1d9e17d60d2a..da0242eed3a5 100644
--- a/svx/inc/sdr/primitive2d/sdrattributecreator.hxx
+++ b/svx/inc/sdr/primitive2d/sdrattributecreator.hxx
@@ -31,6 +31,7 @@ namespace drawinglayer { namespace attribute {
class SdrLineAttribute;
class SdrLineStartEndAttribute;
class SdrShadowAttribute;
+ class SdrGlowAttribute;
class SdrFillAttribute;
class SdrTextAttribute;
class FillGradientAttribute;
@@ -67,6 +68,9 @@ namespace drawinglayer
attribute::SdrFillAttribute SVXCORE_DLLPUBLIC createNewSdrFillAttribute(
const SfxItemSet& rSet);
+ attribute::SdrGlowAttribute createNewSdrGlowAttribute(
+ const SfxItemSet& rSet);
+
// #i101508# Support handing over given text-to-border distances
attribute::SdrTextAttribute createNewSdrTextAttribute(
const SfxItemSet& rSet,
diff --git a/svx/inc/sdr/primitive2d/sdrdecompositiontools.hxx b/svx/inc/sdr/primitive2d/sdrdecompositiontools.hxx
index f55edda1b7c1..6a2cf1993305 100644
--- a/svx/inc/sdr/primitive2d/sdrdecompositiontools.hxx
+++ b/svx/inc/sdr/primitive2d/sdrdecompositiontools.hxx
@@ -20,6 +20,8 @@
#pragma once
#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
+#include <drawinglayer/attribute/sdrglowattribute.hxx>
+
#include <svx/svxdllapi.h>
// predefines
@@ -71,6 +73,10 @@ namespace drawinglayer
const Primitive2DContainer& rContent,
const attribute::SdrShadowAttribute& rShadow);
+ Primitive2DContainer SVXCORE_DLLPUBLIC createEmbeddedGlowPrimitive(
+ const Primitive2DContainer& rContent,
+ const attribute::SdrGlowAttribute& rGlow);
+
} // end of namespace primitive2d
} // end of namespace drawinglayer
diff --git a/svx/source/sdr/attribute/sdrlinefillshadowtextattribute.cxx b/svx/source/sdr/attribute/sdrlinefillshadowtextattribute.cxx
index 6ab08fcba99f..9ecbf331961e 100644
--- a/svx/source/sdr/attribute/sdrlinefillshadowtextattribute.cxx
+++ b/svx/source/sdr/attribute/sdrlinefillshadowtextattribute.cxx
@@ -29,8 +29,9 @@ namespace drawinglayer::attribute
const SdrLineStartEndAttribute& rLineStartEnd,
const SdrShadowAttribute& rShadow,
const FillGradientAttribute& rFillFloatTransGradient,
- const SdrTextAttribute& rTextAttribute)
- : SdrLineShadowTextAttribute(rLine, rLineStartEnd, rShadow, rTextAttribute),
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow)
+ : SdrLineShadowTextAttribute(rLine, rLineStartEnd, rShadow, rTextAttribute, rGlow),
maFill(rFill),
maFillFloatTransGradient(rFillFloatTransGradient)
{
diff --git a/svx/source/sdr/attribute/sdrlineshadowtextattribute.cxx b/svx/source/sdr/attribute/sdrlineshadowtextattribute.cxx
index bc15ad8473e4..667a996d1379 100644
--- a/svx/source/sdr/attribute/sdrlineshadowtextattribute.cxx
+++ b/svx/source/sdr/attribute/sdrlineshadowtextattribute.cxx
@@ -27,8 +27,9 @@ namespace drawinglayer::attribute
const SdrLineAttribute& rLine,
const SdrLineStartEndAttribute& rLineStartEnd,
const SdrShadowAttribute& rShadow,
- const SdrTextAttribute& rTextAttribute)
- : SdrShadowTextAttribute(rShadow, rTextAttribute),
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow)
+ : SdrShadowTextAttribute(rShadow, rTextAttribute, rGlow),
maLine(rLine),
maLineStartEnd(rLineStartEnd)
{
diff --git a/svx/source/sdr/attribute/sdrshadowtextattribute.cxx b/svx/source/sdr/attribute/sdrshadowtextattribute.cxx
index 8d08b770a7a0..705981a62c16 100644
--- a/svx/source/sdr/attribute/sdrshadowtextattribute.cxx
+++ b/svx/source/sdr/attribute/sdrshadowtextattribute.cxx
@@ -25,9 +25,11 @@ namespace drawinglayer::attribute
{
SdrShadowTextAttribute::SdrShadowTextAttribute(
const SdrShadowAttribute& rShadow,
- const SdrTextAttribute& rTextAttribute)
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow)
: maShadow(rShadow),
- maTextAttribute(rTextAttribute)
+ maTextAttribute(rTextAttribute),
+ maGlow(rGlow)
{
}
@@ -39,7 +41,8 @@ namespace drawinglayer::attribute
SdrShadowTextAttribute::SdrShadowTextAttribute(const SdrShadowTextAttribute& rCandidate)
: maShadow(rCandidate.getShadow()),
- maTextAttribute(rCandidate.getText())
+ maTextAttribute(rCandidate.getText()),
+ maGlow(rCandidate.maGlow)
{
}
@@ -47,6 +50,7 @@ namespace drawinglayer::attribute
{
maShadow = rCandidate.getShadow();
maTextAttribute = rCandidate.getText();
+ maGlow = rCandidate.maGlow;
return *this;
}
@@ -54,13 +58,14 @@ namespace drawinglayer::attribute
bool SdrShadowTextAttribute::isDefault() const
{
return (getShadow().isDefault()
- && getText().isDefault());
+ && getText().isDefault() && maGlow.isDefault());
}
bool SdrShadowTextAttribute::operator==(const SdrShadowTextAttribute& rCandidate) const
{
return (getShadow() == rCandidate.getShadow()
- && getText() == rCandidate.getText());
+ && getText() == rCandidate.getText()
+ && maGlow.isDefault());
}
} // end of namespace
diff --git a/svx/source/sdr/primitive2d/sdrattributecreator.cxx b/svx/source/sdr/primitive2d/sdrattributecreator.cxx
index 7afbada0c1be..18f5aae3e884 100644
--- a/svx/source/sdr/primitive2d/sdrattributecreator.cxx
+++ b/svx/source/sdr/primitive2d/sdrattributecreator.cxx
@@ -75,12 +75,15 @@
#include <sdr/attribute/sdrlineshadowtextattribute.hxx>
#include <sdr/attribute/sdrformtextattribute.hxx>
#include <sdr/attribute/sdrlinefillshadowtextattribute.hxx>
+#include <drawinglayer/attribute/sdrglowattribute.hxx>
#include <drawinglayer/attribute/sdrsceneattribute3d.hxx>
#include <drawinglayer/attribute/sdrlightingattribute3d.hxx>
#include <drawinglayer/attribute/sdrlightattribute3d.hxx>
#include <sdr/attribute/sdrfilltextattribute.hxx>
#include <com/sun/star/drawing/LineCap.hpp>
+#include <sal/log.hxx>
+
using namespace com::sun::star;
namespace drawinglayer
@@ -332,6 +335,18 @@ namespace drawinglayer::primitive2d
return attribute::SdrLineStartEndAttribute();
}
+ attribute::SdrGlowAttribute createNewSdrGlowAttribute( const SfxItemSet& rSet)
+ {
+ const bool bGlow(rSet.Get(SDRATTR_GLOW).GetValue());
+ if(!bGlow)
+ return attribute::SdrGlowAttribute();
+ sal_Int32 nRadius = rSet.Get(SDRATTR_GLOW_RAD).GetValue();
+ const Color aColor(rSet.Get(SDRATTR_GLOW_COLOR).GetColorValue());
+
+ attribute::SdrGlowAttribute glowAttr{ nRadius, aColor.getBColor() };
+ return glowAttr;
+ }
+
attribute::SdrShadowAttribute createNewSdrShadowAttribute(const SfxItemSet& rSet)
{
const bool bShadow(rSet.Get(SDRATTR_SHADOW).GetValue());
@@ -724,8 +739,9 @@ namespace drawinglayer::primitive2d
// try shadow
const attribute::SdrShadowAttribute aShadow(createNewSdrShadowAttribute(rSet));
+ const attribute::SdrGlowAttribute aGlow(createNewSdrGlowAttribute(rSet));
- return attribute::SdrShadowTextAttribute(aShadow, aText);
+ return attribute::SdrShadowTextAttribute(aShadow, aText, aGlow);
}
attribute::SdrLineShadowTextAttribute createNewSdrLineShadowTextAttribute(
@@ -735,6 +751,7 @@ namespace drawinglayer::primitive2d
attribute::SdrLineAttribute aLine;
attribute::SdrLineStartEndAttribute aLineStartEnd;
attribute::SdrTextAttribute aText;
+ attribute::SdrGlowAttribute aGlow;
bool bFontworkHideContour(false);
// look for text first
@@ -768,8 +785,9 @@ namespace drawinglayer::primitive2d
{
// try shadow
const attribute::SdrShadowAttribute aShadow(createNewSdrShadowAttribute(rSet));
+ aGlow = createNewSdrGlowAttribute(rSet);
- return attribute::SdrLineShadowTextAttribute(aLine, aLineStartEnd, aShadow, aText);
+ return attribute::SdrLineShadowTextAttribute(aLine, aLineStartEnd, aShadow, aText, aGlow);
}
return attribute::SdrLineShadowTextAttribute();
@@ -786,6 +804,7 @@ namespace drawinglayer::primitive2d
attribute::SdrShadowAttribute aShadow;
attribute::FillGradientAttribute aFillFloatTransGradient;
attribute::SdrTextAttribute aText;
+ attribute::SdrGlowAttribute aGlow;
bool bFontworkHideContour(false);
// look for text first
@@ -831,8 +850,11 @@ namespace drawinglayer::primitive2d
// try shadow
aShadow = createNewSdrShadowAttribute(rSet);
+ // glow
+ aGlow = createNewSdrGlowAttribute(rSet);
+
return attribute::SdrLineFillShadowTextAttribute(
- aLine, aFill, aLineStartEnd, aShadow, aFillFloatTransGradient, aText);
+ aLine, aFill, aLineStartEnd, aShadow, aFillFloatTransGradient, aText, aGlow);
}
return attribute::SdrLineFillShadowTextAttribute();
diff --git a/svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx
index 7d32c753151f..804a653c86b2 100644
--- a/svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx
+++ b/svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx
@@ -25,6 +25,8 @@
#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
#include <drawinglayer/attribute/sdrlineattribute.hxx>
+#include <sal/log.hxx>
+
using namespace com::sun::star;
@@ -69,6 +71,12 @@ namespace drawinglayer::primitive2d
}
}
+ if(!aRetval.empty() && !getSdrSTAttribute().getGlow().isDefault())
+ {
+ // glow
+ aRetval = createEmbeddedGlowPrimitive(aRetval, getSdrSTAttribute().getGlow());
+ }
+
rContainer.insert(rContainer.end(), aRetval.begin(), aRetval.end());
}
diff --git a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
index 9aaf398030f5..e89b2a537b21 100644
--- a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
+++ b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
@@ -31,6 +31,7 @@
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
#include <sdr/attribute/sdrtextattribute.hxx>
+#include <drawinglayer/primitive2d/glowprimitive2d.hxx>
#include <sdr/primitive2d/sdrtextprimitive2d.hxx>
#include <svx/svdotext.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
@@ -43,6 +44,7 @@
#include <drawinglayer/attribute/sdrlineattribute.hxx>
#include <drawinglayer/attribute/sdrlinestartendattribute.hxx>
#include <drawinglayer/attribute/sdrshadowattribute.hxx>
+#include <drawinglayer/attribute/sdrglowattribute.hxx>
using namespace com::sun::star;
@@ -514,6 +516,25 @@ namespace drawinglayer::primitive2d
return rContent;
}
}
+
+ Primitive2DContainer createEmbeddedGlowPrimitive(
+ const Primitive2DContainer& rContent,
+ const attribute::SdrGlowAttribute& rGlow)
+ {
+ if(rContent.empty())
+ return rContent;
+ Primitive2DContainer aRetval(2);
+ const uno::Sequence< beans::PropertyValue > xViewParameters;
+ geometry::ViewInformation2D aViewInformation2D(xViewParameters);
+ aRetval[0] = Primitive2DReference(
+ new GlowPrimitive2D(
+ rGlow.GetTransfMatrix(rContent.getB2DRange(aViewInformation2D)),
+ rGlow.getColor(),
+ rContent));
+ aRetval[1] = Primitive2DReference(new GroupPrimitive2D(rContent));
+ return aRetval;
+ }
+
} // end of namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/customshapeproperties.cxx b/svx/source/sdr/properties/customshapeproperties.cxx
index cb9425754e39..f9da077101ee 100644
--- a/svx/source/sdr/properties/customshapeproperties.cxx
+++ b/svx/source/sdr/properties/customshapeproperties.cxx
@@ -28,6 +28,8 @@
#include <svl/whiter.hxx>
#include <svl/hint.hxx>
+#include <sal/log.hxx>
+
namespace sdr::properties
{
@@ -71,6 +73,7 @@ namespace sdr::properties
// Graphic attributes, 3D properties, CustomShape
// properties:
SDRATTR_GRAF_FIRST, SDRATTR_CUSTOMSHAPE_LAST,
+ SDRATTR_GLOW_FIRST, SDRATTR_GLOW_LAST,
// Range from SdrTextObj:
EE_ITEMS_START, EE_ITEMS_END>{});
}
diff --git a/svx/source/svdraw/svdattr.cxx b/svx/source/svdraw/svdattr.cxx
index e1d56b706b25..af8d7f7d45b9 100644
--- a/svx/source/svdraw/svdattr.cxx
+++ b/svx/source/svdraw/svdattr.cxx
@@ -326,6 +326,10 @@ SdrItemPool::SdrItemPool(
rPoolDefaults[ SDRATTR_TABLE_BORDER_BLTR - SDRATTR_START ] = new SvxLineItem( SDRATTR_TABLE_BORDER_BLTR );
rPoolDefaults[ SDRATTR_TABLE_TEXT_ROTATION - SDRATTR_START ] = new SvxTextRotateItem(0, SDRATTR_TABLE_TEXT_ROTATION);
+ rPoolDefaults[ SDRATTR_GLOW - SDRATTR_START ] = new SdrOnOffItem(SDRATTR_GLOW, false);
+ rPoolDefaults[ SDRATTR_GLOW_RAD - SDRATTR_START ] = new SdrMetricItem(SDRATTR_GLOW_RAD, 0);
+ rPoolDefaults[ SDRATTR_GLOW_COLOR - SDRATTR_START ] = new XColorItem(SDRATTR_GLOW_COLOR, aNullCol);
+
// set own ItemInfos
mpLocalItemInfos[SDRATTR_SHADOW-SDRATTR_START]._nSID=SID_ATTR_FILL_SHADOW;
mpLocalItemInfos[SDRATTR_SHADOWCOLOR-SDRATTR_START]._nSID=SID_ATTR_SHADOW_COLOR;
@@ -446,6 +450,10 @@ OUString SdrItemPool::GetItemName(sal_uInt16 nWhich)
case SDRATTR_SHADOW3D : pResId = SIP_SA_SHADOW3D;break;
case SDRATTR_SHADOWPERSP : pResId = SIP_SA_SHADOWPERSP;break;
+ case SDRATTR_GLOW : pResId = SIP_SA_GLOW;break;
+ case SDRATTR_GLOW_RAD : pResId = SIP_SA_GLOW_RAD;break;
+ case SDRATTR_GLOW_COLOR : pResId = SIP_SA_GLOW_COLOR;break;
+
case SDRATTR_CAPTIONTYPE : pResId = SIP_SA_CAPTIONTYPE;break;
case SDRATTR_CAPTIONFIXEDANGLE: pResId = SIP_SA_CAPTIONFIXEDANGLE;break;
case SDRATTR_CAPTIONANGLE : pResId = SIP_SA_CAPTIONANGLE;break;
diff --git a/svx/source/unodraw/unoprov.cxx b/svx/source/unodraw/unoprov.cxx
index 639b8c798d39..67406c63ba40 100644
--- a/svx/source/unodraw/unoprov.cxx
+++ b/svx/source/unodraw/unoprov.cxx
@@ -68,6 +68,7 @@ static SfxItemPropertyMapEntry const * ImplGetSvxShapePropertyMap()
SHAPE_DESCRIPTOR_PROPERTIES
MISC_OBJ_PROPERTIES
LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
SHADOW_PROPERTIES
TEXT_PROPERTIES
// #FontWork#
@@ -91,6 +92,7 @@ static SfxItemPropertyMapEntry const * ImplGetSvxTextShapePropertyMap()
SHAPE_DESCRIPTOR_PROPERTIES
MISC_OBJ_PROPERTIES_NO_SHEAR
LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
SHADOW_PROPERTIES
TEXT_PROPERTIES
// #FontWork#
@@ -115,6 +117,7 @@ static SfxItemPropertyMapEntry const * ImplGetSvxConnectorPropertyMap()
SHAPE_DESCRIPTOR_PROPERTIES
MISC_OBJ_PROPERTIES
LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
SHADOW_PROPERTIES
TEXT_PROPERTIES
// #FontWork#
@@ -139,6 +142,7 @@ static SfxItemPropertyMapEntry const * ImplGetSvxDimensioningPropertyMap()
SHAPE_DESCRIPTOR_PROPERTIES
MISC_OBJ_PROPERTIES
LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
SHADOW_PROPERTIES
TEXT_PROPERTIES
// #FontWork#
@@ -163,6 +167,7 @@ static SfxItemPropertyMapEntry const * ImplGetSvxCirclePropertyMap()
SHAPE_DESCRIPTOR_PROPERTIES
MISC_OBJ_PROPERTIES
LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
SHADOW_PROPERTIES
TEXT_PROPERTIES
// #FontWork#
@@ -189,6 +194,7 @@ static SfxItemPropertyMapEntry const * ImplGetSvxPolyPolygonPropertyMap()
SHAPE_DESCRIPTOR_PROPERTIES
MISC_OBJ_PROPERTIES
LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
SHADOW_PROPERTIES
TEXT_PROPERTIES
// #FontWork#
@@ -218,6 +224,7 @@ static SfxItemPropertyMapEntry const * ImplGetSvxGraphicObjectPropertyMap()
MISC_OBJ_PROPERTIES
LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
SHADOW_PROPERTIES
TEXT_PROPERTIES
// #FontWork#
@@ -368,6 +375,7 @@ static SfxItemPropertyMapEntry const * ImplGetSvxAllPropertyMap()
{
static SfxItemPropertyMapEntry const aAllPropertyMap_Impl[] =
{
+ GLOW_PROPERTIES
SHADOW_PROPERTIES
LINE_PROPERTIES
LINE_PROPERTIES_START_END
@@ -430,6 +438,7 @@ static SfxItemPropertyMapEntry const * ImplGetSvxOle2PropertyMap()
SHAPE_DESCRIPTOR_PROPERTIES
MISC_OBJ_PROPERTIES
LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
SHADOW_PROPERTIES
TEXT_PROPERTIES
FONTWORK_PROPERTIES
@@ -681,6 +690,7 @@ static SfxItemPropertyMapEntry const * ImplGetSvxCustomShapePropertyMap()
SHAPE_DESCRIPTOR_PROPERTIES
MISC_OBJ_PROPERTIES
LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
SHADOW_PROPERTIES
TEXT_PROPERTIES
{OUString("UserDefinedAttributes"), SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
@@ -759,6 +769,7 @@ static comphelper::PropertyMapEntry const * ImplGetSvxDrawingDefaultsPropertyMap
{
static comphelper::PropertyMapEntry const aSvxDrawingDefaultsPropertyMap_Impl[] =
{
+ GLOW_PROPERTIES
SHADOW_PROPERTIES
LINE_PROPERTIES_DEFAULTS
FILL_PROPERTIES_BMP
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx
index 344b493dae4b..721f1292e8d5 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx
@@ -215,20 +215,6 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testShapeEffectPreservation, "shape-effect-p
"wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:softEdge/*",
0 ); // should not be present
- // 5th shape with glow effect, scheme color
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[6]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:glow",
- "rad", "101600");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[6]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:glow/a:schemeClr",
- "val", "accent2");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[6]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:glow/a:schemeClr/a:satMod",
- "val", "175000");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[6]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:glow/a:schemeClr/a:alpha",
- "val", "40000");
-
// 6th shape with reflection
assertXPath(pXmlDoc, "/w:document/w:body/w:p[7]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
"wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:reflection",
@@ -246,34 +232,6 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testShapeEffectPreservation, "shape-effect-p
"wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:reflection/*",
0 ); // should not be present
- // 7th shape with several effects: glow, inner shadow and reflection
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[8]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:glow",
- "rad", "63500");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[8]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:glow/a:schemeClr",
- "val", "accent2");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[8]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:glow/a:schemeClr/*",
- 2);
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[8]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:innerShdw",
- "blurRad", "63500");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[8]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:innerShdw",
- "dir", "2700000");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[8]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:innerShdw/a:srgbClr",
- "val", "000000");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[8]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:innerShdw/a:srgbClr/a:alpha",
- "val", "50000");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[8]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:reflection",
- "blurRad", "6350");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[8]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:reflection",
- "stA", "52000");
}
DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testShape3DEffectPreservation, "shape-3d-effect-preservation.docx")
@@ -389,17 +347,6 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testPictureEffectPreservation, "picture-effe
{
xmlDocPtr pXmlDoc = parseExport("word/document.xml");
- // first picture: glow effect with theme color and transformations, 3d rotation and extrusion
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/pic:pic/pic:spPr/a:effectLst/a:glow",
- "rad", "228600");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/pic:pic/pic:spPr/a:effectLst/a:glow/a:schemeClr",
- "val", "accent1");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
- "wp:anchor/a:graphic/a:graphicData/pic:pic/pic:spPr/a:effectLst/a:glow/a:schemeClr/*",
- 2);
-
assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
"wp:anchor/a:graphic/a:graphicData/pic:pic/pic:spPr/a:scene3d/a:camera",
"prst", "isometricRightUp");
diff --git a/vcl/CppunitTest_vcl_bitmap_test.mk b/vcl/CppunitTest_vcl_bitmap_test.mk
index 9ebef12dcfb2..dca63852a8af 100644
--- a/vcl/CppunitTest_vcl_bitmap_test.mk
+++ b/vcl/CppunitTest_vcl_bitmap_test.mk
@@ -15,6 +15,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,vcl_bitmap_test, \
vcl/qa/cppunit/bitmapcolor \
vcl/qa/cppunit/ScanlineToolsTest \
vcl/qa/cppunit/BitmapScaleTest \
+ vcl/qa/cppunit/BitmapFilterTest \
))
$(eval $(call gb_CppunitTest_use_externals,vcl_bitmap_test,\
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 79f2002c8c9d..70c23d0d1a71 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -367,6 +367,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/image/ImageRepository \
vcl/source/image/ImplImage \
vcl/source/image/ImplImageTree \
+ vcl/source/bitmap/BitmapFilterStackBlur \
vcl/source/helper/canvasbitmap \
vcl/source/helper/canvastools \
vcl/source/helper/commandinfoprovider \
diff --git a/vcl/qa/cppunit/BitmapFilterTest.cxx b/vcl/qa/cppunit/BitmapFilterTest.cxx
new file mode 100644
index 000000000000..732c0c2dfb0b
--- /dev/null
+++ b/vcl/qa/cppunit/BitmapFilterTest.cxx
@@ -0,0 +1,159 @@
+/* -*- 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 <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmapaccess.hxx>
+#include <bitmapwriteaccess.hxx>
+
+#include <tools/stream.hxx>
+#include <vcl/graphicfilter.hxx>
+
+#include <vcl/BitmapFilterStackBlur.hxx>
+#include <BitmapSymmetryCheck.hxx>
+
+#include <chrono>
+
+namespace
+{
+constexpr bool constWriteResultBitmap(false);
+constexpr bool constEnablePerformanceTest(false);
+
+class BitmapFilterTest : public CppUnit::TestFixture
+{
+ void testBlurCorrectness();
+ void testPerformance();
+
+ CPPUNIT_TEST_SUITE(BitmapFilterTest);
+ CPPUNIT_TEST(testBlurCorrectness);
+ CPPUNIT_TEST(testPerformance);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+void BitmapFilterTest::testBlurCorrectness()
+{
+ // Setup test bitmap
+ Size aSize(41, 31);
+ Bitmap aBitmap24Bit(aSize, 24);
+
+ ScanlineFormat scanlineFormat = ScanlineFormat::NONE;
+ sal_uInt16 nBPP = aBitmap24Bit.GetBitCount();
+
+ {
+ long aMargin1 = 1;
+ long aMargin2 = 3;
+ BitmapScopedWriteAccess aWriteAccess(aBitmap24Bit);
+ scanlineFormat = aWriteAccess->GetScanlineFormat();
+ aWriteAccess->Erase(COL_WHITE);
+ aWriteAccess->SetLineColor(COL_BLACK);
+
+ tools::Rectangle aRectangle1(aMargin1, aMargin1, aSize.Width() - 1 - aMargin1,
+ aSize.Height() - 1 - aMargin1);
+
+ tools::Rectangle aRectangle2(aMargin2, aMargin2, aSize.Width() - 1 - aMargin2,
+ aSize.Height() - 1 - aMargin2);
+
+ tools::Rectangle aRectangle3(aSize.Width() / 2, aSize.Height() / 2, aSize.Width() / 2,
+ aSize.Height() / 2);
+
+ aWriteAccess->DrawRect(aRectangle1);
+ aWriteAccess->DrawRect(aRectangle2);
+ aWriteAccess->DrawRect(aRectangle3);
+ }
+
+ if (constWriteResultBitmap)
+ {
+ SvFileStream aStream("~/blurBefore.png", StreamMode::WRITE | StreamMode::TRUNC);
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ rFilter.compressAsPNG(aBitmap24Bit, aStream);
+ }
+
+ // Perform blur
+ BitmapFilterStackBlur aBlurFilter(2);
+ aBitmap24Bit = aBlurFilter.filter(aBitmap24Bit);
+
+ // Check the result
+
+ if (constWriteResultBitmap)
+ {
+ SvFileStream aStream("~/blurAfter.png", StreamMode::WRITE | StreamMode::TRUNC);
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ rFilter.compressAsPNG(aBitmap24Bit, aStream);
+ }
+
+ // Check blurred bitmap parameters
+ CPPUNIT_ASSERT_EQUAL(static_cast<long>(45), aBitmap24Bit.GetSizePixel().Width());
+ CPPUNIT_ASSERT_EQUAL(static_cast<long>(35), aBitmap24Bit.GetSizePixel().Height());
+
+ CPPUNIT_ASSERT_EQUAL(nBPP, aBitmap24Bit.GetBitCount());
+
+ // Check that the bitmap is horizontally and vertically symmetrical
+ CPPUNIT_ASSERT(BitmapSymmetryCheck::check(aBitmap24Bit));
+
+ {
+ Bitmap::ScopedReadAccess aReadAccess(aBitmap24Bit);
+ CPPUNIT_ASSERT_EQUAL(scanlineFormat, aReadAccess->GetScanlineFormat());
+ }
+}
+
+void BitmapFilterTest::testPerformance()
+{
+ if (!constEnablePerformanceTest)
+ return;
+
+ Size aSize(4000, 3000); // A rather common picture size
+
+ // Prepare bitmap
+ Bitmap aBigBitmap(aSize, 24);
+ {
+ long aMargin = 500;
+ BitmapScopedWriteAccess aWriteAccess(aBigBitmap);
+ aWriteAccess->Erase(COL_WHITE);
+ aWriteAccess->SetLineColor(COL_BLACK);
+ aWriteAccess->SetFillColor(COL_BLACK);
+ tools::Rectangle aRectangle(aMargin, aMargin, aSize.Width() - 1 - aMargin,
+ aSize.Height() - 1 - aMargin);
+
+ aWriteAccess->DrawRect(aRectangle);
+ }
+
+ int nIterations = 10;
+ auto start = std::chrono::high_resolution_clock::now();
+ for (int i = 0; i < nIterations; i++)
+ {
+ BitmapFilterStackBlur aBlurFilter(250, false); // don't extend the image
+ aBlurFilter.filter(aBigBitmap);
+ }
+ auto end = std::chrono::high_resolution_clock::now();
+ auto elapsed = (end - start) / nIterations;
+
+ if (constWriteResultBitmap)
+ {
+ std::unique_ptr<SvFileStream> pStream(
+ new SvFileStream("~/BlurBigPerformance.png", StreamMode::WRITE | StreamMode::TRUNC));
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ rFilter.compressAsPNG(aBigBitmap, *pStream);
+
+ pStream.reset(new SvFileStream("~/BlurBigPerformance.txt", StreamMode::WRITE));
+ pStream->WriteOString("Blur average time: ");
+ pStream->WriteOString(OString::number(
+ std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count()));
+ pStream->WriteOString("\n");
+ }
+}
+
+} // namespace
+
+CPPUNIT_TEST_SUITE_REGISTRATION(BitmapFilterTest);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/bitmap/BitmapFilterStackBlur.cxx b/vcl/source/bitmap/BitmapFilterStackBlur.cxx
new file mode 100644
index 000000000000..d88480787b8b
--- /dev/null
+++ b/vcl/source/bitmap/BitmapFilterStackBlur.cxx
@@ -0,0 +1,554 @@
+/* -*- 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 <vcl/BitmapFilterStackBlur.hxx>
+#include <vcl/bitmapaccess.hxx>
+#include <bitmapwriteaccess.hxx>
+
+namespace
+{
+static const sal_Int16 constMultiplyTable[255]
+ = { 512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512, 454,
+ 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512, 482, 454,
+ 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456, 437, 420, 404,
+ 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512, 497, 482, 468, 454,
+ 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328, 320, 312, 305, 298, 291,
+ 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456, 446, 437, 428, 420, 412, 404,
+ 396, 388, 381, 374, 367, 360, 354, 347, 341, 335, 329, 323, 318, 312, 307, 302, 297,
+ 292, 287, 282, 278, 273, 269, 265, 261, 512, 505, 497, 489, 482, 475, 468, 461, 454,
+ 447, 441, 435, 428, 422, 417, 411, 405, 399, 394, 389, 383, 378, 373, 368, 364, 359,
+ 354, 350, 345, 341, 337, 332, 328, 324, 320, 316, 312, 309, 305, 301, 298, 294, 291,
+ 287, 284, 281, 278, 274, 271, 268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480,
+ 475, 470, 465, 460, 456, 451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404,
+ 400, 396, 392, 388, 385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344,
+ 341, 338, 335, 332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297,
+ 294, 292, 289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259 };
+
+static const sal_Int16 constShiftTable[255]
+ = { 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 };
+
+class BlurSharedData
+{
+public:
+ long mnRadius;
+ long mnComponentWidth;
+ long mnColorChannels;
+ long mnDiv;
+ std::vector<sal_uInt8> maStackBuffer;
+ std::vector<long> maPositionTable;
+ std::vector<long> maWeightTable;
+
+ std::vector<long> mnSumVector;
+ std::vector<long> mnInSumVector;
+ std::vector<long> mnOutSumVector;
+
+ BlurSharedData(long aRadius, long nComponentWidth, long nColorChannels)
+ : mnRadius(aRadius)
+ , mnComponentWidth(nComponentWidth)
+ , mnColorChannels(nColorChannels)
+ , mnDiv(aRadius + aRadius + 1)
+ , maStackBuffer(mnDiv * mnComponentWidth)
+ , maPositionTable(mnDiv)
+ , maWeightTable(mnDiv)
+ , mnSumVector(mnColorChannels)
+ , mnInSumVector(mnColorChannels)
+ , mnOutSumVector(mnColorChannels)
+ {
+ }
+
+ void calculateWeightAndPositions(long nLastIndex)
+ {
+ for (long i = 0; i < mnDiv; i++)
+ {
+ maPositionTable[i] = std::min(nLastIndex, std::max(0L, i - mnRadius));
+ maWeightTable[i] = mnRadius + 1 - std::abs(i - mnRadius);
+ }
+ }
+
+ long getMultiplyValue() { return static_cast<long>(constMultiplyTable[mnRadius]); }
+
+ long getShiftValue() { return static_cast<long>(constShiftTable[mnRadius]); }
+};
+
+struct SumFunction24
+{
+ static inline void add(long*& pValue1, long nConstant)
+ {
+ pValue1[0] += nConstant;
+ pValue1[1] += nConstant;
+ pValue1[2] += nConstant;
+ }
+
+ static inline void set(long*& pValue1, long nConstant)
+ {
+ pValue1[0] = nConstant;
+ pValue1[1] = nConstant;
+ pValue1[2] = nConstant;
+ }
+
+ static inline void add(long*& pValue1, sal_uInt8*& pValue2)
+ {
+ pValue1[0] += pValue2[0];
+ pValue1[1] += pValue2[1];
+ pValue1[2] += pValue2[2];
+ }
+
+ static inline void add(long*& pValue1, long*& pValue2)
+ {
+ pValue1[0] += pValue2[0];
+ pValue1[1] += pValue2[1];
+ pValue1[2] += pValue2[2];
+ }
+
+ static inline void sub(long*& pValue1, sal_uInt8*& pValue2)
+ {
+ pValue1[0] -= pValue2[0];
+ pValue1[1] -= pValue2[1];
+ pValue1[2] -= pValue2[2];
+ }
+
+ static inline void sub(long*& pValue1, long*& pValue2)
+ {
+ pValue1[0] -= pValue2[0];
+ pValue1[1] -= pValue2[1];
+ pValue1[2] -= pValue2[2];
+ }
+
+ static inline void assignPtr(sal_uInt8*& pValue1, sal_uInt8*& pValue2)
+ {
+ pValue1[0] = pValue2[0];
+ pValue1[1] = pValue2[1];
+ pValue1[2] = pValue2[2];
+ }
+
+ static inline void assignMulAndShr(sal_uInt8*& result, long*& sum, long multiply, long shift)
+ {
+ result[0] = (multiply * sum[0]) >> shift;
+ result[1] = (multiply * sum[1]) >> shift;
+ result[2] = (multiply * sum[2]) >> shift;
+ }
+};
+
+struct SumFunction8
+{
+ static inline void add(long*& pValue1, long nConstant) { pValue1[0] += nConstant; }
+
+ static inline void set(long*& pValue1, long nConstant) { pValue1[0] = nConstant; }
+
+ static inline void add(long*& pValue1, sal_uInt8*& pValue2) { pValue1[0] += pValue2[0]; }
+
+ static inline void add(long*& pValue1, long*& pValue2) { pValue1[0] += pValue2[0]; }
+
+ static inline void sub(long*& pValue1, sal_uInt8*& pValue2) { pValue1[0] -= pValue2[0]; }
+
+ static inline void sub(long*& pValue1, long*& pValue2) { pValue1[0] -= pValue2[0]; }
+
+ static inline void assignPtr(sal_uInt8*& pValue1, sal_uInt8*& pValue2)
+ {
+ pValue1[0] = pValue2[0];
+ }
+
+ static inline void assignMulAndShr(sal_uInt8*& result, long*& sum, long multiply, long shift)
+ {
+ result[0] = (multiply * sum[0]) >> shift;
+ }
+};
+
+template <typename SumFunction>
+void stackBlurHorizontal(BitmapReadAccess* pReadAccess, BitmapWriteAccess* pWriteAccess,
+ BlurSharedData& rShared)
+{
+ long nWidth = pReadAccess->Width();
+ long nHeight = pReadAccess->Height();
+
+ sal_uInt8* pStack = rShared.maStackBuffer.data();
+ sal_uInt8* pStackPtr;
+
+ long nLastIndexX = nWidth - 1;
+
+ long nMultiplyValue = rShared.getMultiplyValue();
+ long nShiftValue = rShared.getShiftValue();
+
+ long nRadius = rShared.mnRadius;
+ long nComponentWidth = rShared.mnComponentWidth;
+ long nDiv = rShared.mnDiv;
+
+ Scanline pSourcePointer;
+ Scanline pDestinationPointer;
+
+ long nXPosition;
+ long nStackIndex;
+ long nStackIndexStart;
+ long nWeight;
+
+ long* nSum = rShared.mnSumVector.data();
+ long* nInSum = rShared.mnInSumVector.data();
+ long* nOutSum = rShared.mnOutSumVector.data();
+
+ rShared.calculateWeightAndPositions(nLastIndexX);
+ long* pPositionPointer = rShared.maPositionTable.data();
+ long* pWeightPointer = rShared.maWeightTable.data();
+
+ for (long y = 0; y < nHeight; y++)
+ {
+ SumFunction::set(nSum, 0L);
+ SumFunction::set(nInSum, 0L);
+ SumFunction::set(nOutSum, 0L);
+
+ for (long i = 0; i < nDiv; i++)
+ {
+ pSourcePointer = pReadAccess->GetScanline(pPositionPointer[i]);
+
+ pStackPtr = &pStack[nComponentWidth * i];
+
+ SumFunction::assignPtr(pStackPtr, pSourcePointer);
+
+ nWeight = pWeightPointer[i];
+
+ SumFunction::add(nSum, pSourcePointer[0] * nWeight);
+
+ if (i - nRadius > 0)
+ {
+ SumFunction::add(nInSum, pSourcePointer);
+ }
+ else
+ {
+ SumFunction::add(nOutSum, pSourcePointer);
+ }
+ }
+
+ nStackIndex = nRadius;
+ nXPosition = std::min(nRadius, nLastIndexX);
+
+ pSourcePointer = pReadAccess->GetScanline(y) + nComponentWidth * nXPosition;
+
+ for (long x = 0; x < nWidth; x++)
+ {
+ pDestinationPointer = pWriteAccess->GetScanline(y) + nComponentWidth * x;
+
+ SumFunction::assignMulAndShr(pDestinationPointer, nSum, nMultiplyValue, nShiftValue);
+
+ SumFunction::sub(nSum, nOutSum);
+
+ nStackIndexStart = nStackIndex + nDiv - nRadius;
+ if (nStackIndexStart >= nDiv)
+ {
+ nStackIndexStart -= nDiv;
+ }
+ pStackPtr = &pStack[nComponentWidth * nStackIndexStart];
+
+ SumFunction::sub(nOutSum, pStackPtr);
+
+ if (nXPosition < nLastIndexX)
+ {
+ nXPosition++;
+ pSourcePointer = pReadAccess->GetScanline(y) + nComponentWidth * nXPosition;
+ }
+
+ SumFunction::assignPtr(pStackPtr, pSourcePointer);
+
+ SumFunction::add(nInSum, pSourcePointer);
+
+ SumFunction::add(nSum, nInSum);
+
+ nStackIndex++;
+ if (nStackIndex >= nDiv)
+ {
+ nStackIndex = 0;
+ }
+
+ pStackPtr = &pStack[nStackIndex * nComponentWidth];
+
+ SumFunction::add(nOutSum, pStackPtr);
+ SumFunction::sub(nInSum, pStackPtr);
+ }
+ }
+}
+
+template <typename SumFunction>
+void stackBlurVertical(BitmapReadAccess* pReadAccess, BitmapWriteAccess* pWriteAccess,
+ BlurSharedData& rShared)
+{
+ long nWidth = pReadAccess->Width();
+ long nHeight = pReadAccess->Height();
+
+ sal_uInt8* pStack = rShared.maStackBuffer.data();
+ sal_uInt8* pStackPtr;
+
+ long nLastIndexY = nHeight - 1;
+
+ long nMultiplyValue = rShared.getMultiplyValue();
+ long nShiftValue = rShared.getShiftValue();
+
+ long nRadius = rShared.mnRadius;
+ long nComponentWidth = rShared.mnComponentWidth;
+ long nDiv = rShared.mnDiv;
+
+ Scanline pSourcePointer;
+ Scanline pDestinationPointer;
+
+ long nYPosition;
+ long nStackIndex;
+ long nStackIndexStart;
+ long nWeight;
+
+ long* nSum = rShared.mnSumVector.data();
+ long* nInSum = rShared.mnInSumVector.data();
+ long* nOutSum = rShared.mnOutSumVector.data();
+
+ rShared.calculateWeightAndPositions(nLastIndexY);
+ long* pPositionPointer = rShared.maPositionTable.data();
+ long* pWeightPointer = rShared.maWeightTable.data();
+
+ for (long x = 0; x < nWidth; x++)
+ {
+ SumFunction::set(nSum, 0L);
+ SumFunction::set(nInSum, 0L);
+ SumFunction::set(nOutSum, 0L);
+
+ for (long i = 0; i < nDiv; i++)
+ {
+ pSourcePointer = pReadAccess->GetScanline(pPositionPointer[i]);
+
+ pStackPtr = &pStack[nComponentWidth * i];
+
+ SumFunction::assignPtr(pStackPtr, pSourcePointer);
+
+ nWeight = pWeightPointer[i];
+
+ SumFunction::add(nSum, pSourcePointer[0] * nWeight);
+
+ if (i - nRadius > 0)
+ {
+ SumFunction::add(nInSum, pSourcePointer);
+ }
+ else
+ {
+ SumFunction::add(nOutSum, pSourcePointer);
+ }
+ }
+
+ nStackIndex = nRadius;
+ nYPosition = std::min(nRadius, nLastIndexY);
+
+ pSourcePointer = pReadAccess->GetScanline(nYPosition) + nComponentWidth * x;
+
+ for (long y = 0; y < nHeight; y++)
+ {
+ pDestinationPointer = pWriteAccess->GetScanline(y) + nComponentWidth * x;
+
+ SumFunction::assignMulAndShr(pDestinationPointer, nSum, nMultiplyValue, nShiftValue);
+
+ SumFunction::sub(nSum, nOutSum);
+
+ nStackIndexStart = nStackIndex + nDiv - nRadius;
+ if (nStackIndexStart >= nDiv)
+ {
+ nStackIndexStart -= nDiv;
+ }
+ pStackPtr = &pStack[nComponentWidth * nStackIndexStart];
+
+ SumFunction::sub(nOutSum, pStackPtr);
+
+ if (nYPosition < nLastIndexY)
+ {
+ nYPosition++;
+ pSourcePointer = pReadAccess->GetScanline(nYPosition) + nComponentWidth * x;
+ }
+
+ SumFunction::assignPtr(pStackPtr, pSourcePointer);
+
+ SumFunction::add(nInSum, pSourcePointer);
+
+ SumFunction::add(nSum, nInSum);
+
+ nStackIndex++;
+ if (nStackIndex >= nDiv)
+ {
+ nStackIndex = 0;
+ }
+
+ pStackPtr = &pStack[nStackIndex * nComponentWidth];
+
+ SumFunction::add(nOutSum, pStackPtr);
+
+ SumFunction::sub(nInSum, pStackPtr);
+ }
+ }
+}
+
+void stackBlur24(Bitmap& rBitmap, sal_Int32 nRadius, sal_Int32 nComponentWidth)
+{
+ // Limit radius
+ nRadius = std::clamp<sal_Int32>(nRadius, 2, 254);
+ const long nColorChannels = 3; // 3 color channel
+ BlurSharedData aData(nRadius, nComponentWidth, nColorChannels);
+
+ {
+ Bitmap::ScopedReadAccess pReadAccess(rBitmap);
+ BitmapScopedWriteAccess pWriteAccess(rBitmap);
+
+ stackBlurHorizontal<SumFunction24>(pReadAccess.get(), pWriteAccess.get(), aData);
+ }
+
+ {
+ Bitmap::ScopedReadAccess pReadAccess(rBitmap);
+ BitmapScopedWriteAccess pWriteAccess(rBitmap);
+
+ stackBlurVertical<SumFunction24>(pReadAccess.get(), pWriteAccess.get(), aData);
+ }
+}
+
+void stackBlur8(Bitmap& rBitmap, sal_Int32 nRadius, sal_Int32 nComponentWidth)
+{
+ // Limit radius
+ nRadius = std::clamp<sal_Int32>(nRadius, 2, 254);
+ const long nColorChannels = 1; // 1 color channel
+ BlurSharedData aData(nRadius, nComponentWidth, nColorChannels);
+
+ {
+ Bitmap::ScopedReadAccess pReadAccess(rBitmap);
+ BitmapScopedWriteAccess pWriteAccess(rBitmap);
+
+ stackBlurHorizontal<SumFunction8>(pReadAccess.get(), pWriteAccess.get(), aData);
+ }
+
+ {
+ Bitmap::ScopedReadAccess pReadAccess(rBitmap);
+ BitmapScopedWriteAccess pWriteAccess(rBitmap);
+
+ stackBlurVertical<SumFunction8>(pReadAccess.get(), pWriteAccess.get(), aData);
+ }
+}
+
+void centerExtendBitmap(Bitmap& rBitmap, sal_Int32 nExtendSize, Color aColor)
+{
+ const Size& rSize = rBitmap.GetSizePixel();
+ const Size aNewSize(rSize.Width() + nExtendSize * 2, rSize.Height() + nExtendSize * 2);
+
+ Bitmap aNewBitmap(aNewSize, rBitmap.GetBitCount());
+
+ {
+ Bitmap::ScopedReadAccess pReadAccess(rBitmap);
+ BitmapScopedWriteAccess pWriteAccess(aNewBitmap);
+
+ long nWidthBorder = nExtendSize + rSize.Width();
+ long nHeightBorder = nExtendSize + rSize.Height();
+
+ for (long y = 0; y < aNewSize.Height(); y++)
+ {
+ for (long x = 0; x < aNewSize.Width(); x++)
+ {
+ if (y < nExtendSize || y >= nHeightBorder || x < nExtendSize || x >= nWidthBorder)
+ {
+ pWriteAccess->SetPixel(y, x, aColor);
+ }
+ else
+ {
+ pWriteAccess->SetPixel(y, x,
+ pReadAccess->GetPixel(y - nExtendSize, x - nExtendSize));
+ }
+ }
+ }
+ }
+ rBitmap = aNewBitmap;
+}
+
+} // end anonymous namespace
+
+/**
+ * Implementation of stack blur - a fast Gaussian blur approximation.
+ * nRadius - blur radious, valid values are between 2 and 254
+ * bExtend - extend the bitmap in all directions by the radius
+ *
+ * Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
+ * (http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html)
+ *
+ * Additionally eferences and implementations:
+ * - Blur.js by Jacob Kelley
+ * (http://www.blurjs.com)
+ * - BlurEffectForAndroidDesign by Nicolas Pomepuy
+ * (https://github.com/PomepuyN/BlurEffectForAndroidDesign)
+ * - StackBluriOS by Thomas Landspurg
+ * (https://github.com/tomsoft1/StackBluriOS)
+ * - stackblur.cpp by Benjamin Yates
+ * (https://gist.github.com/benjamin9999/3809142)
+ * - stack blur in fog 2D graphic library by Petr Kobalicek
+ * (https://code.google.com/p/fog/)
+ *
+ */
+BitmapFilterStackBlur::BitmapFilterStackBlur(sal_Int32 nRadius, bool bExtend)
+ : mnRadius(nRadius)
+ , mbExtend(bExtend)
+{
+}
+
+BitmapFilterStackBlur::~BitmapFilterStackBlur() {}
+
+BitmapEx BitmapFilterStackBlur::execute(BitmapEx const& rBitmapEx) const
+{
+ Bitmap aBitmap = rBitmapEx.GetBitmap();
+ Bitmap result = filter(aBitmap);
+ return BitmapEx(result, rBitmapEx.GetMask());
+}
+
+Bitmap BitmapFilterStackBlur::filter(Bitmap const& rBitmap) const
+{
+ Bitmap bitmapCopy(rBitmap);
+ ScanlineFormat nScanlineFormat;
+ {
+ Bitmap::ScopedReadAccess pReadAccess(bitmapCopy);
+ nScanlineFormat = pReadAccess->GetScanlineFormat();
+ }
+
+ if (nScanlineFormat == ScanlineFormat::N24BitTcRgb
+ || nScanlineFormat == ScanlineFormat::N24BitTcBgr
+ || nScanlineFormat == ScanlineFormat::N32BitTcMask
+ || nScanlineFormat == ScanlineFormat::N32BitTcBgra)
+ {
+ int nComponentWidth = (nScanlineFormat == ScanlineFormat::N32BitTcMask
+ || nScanlineFormat == ScanlineFormat::N32BitTcBgra)
+ ? 4
+ : 3;
+
+ if (mbExtend)
+ {
+ centerExtendBitmap(bitmapCopy, mnRadius, COL_WHITE);
+ }
+
+ stackBlur24(bitmapCopy, mnRadius, nComponentWidth);
+ }
+ else if (nScanlineFormat == ScanlineFormat::N8BitPal)
+ {
+ int nComponentWidth = 1;
+
+ if (mbExtend)
+ {
+ centerExtendBitmap(bitmapCopy, mnRadius, COL_WHITE);
+ }
+
+ stackBlur8(bitmapCopy, mnRadius, nComponentWidth);
+ }
+
+ return bitmapCopy;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/outdev/bitmap.cxx b/vcl/source/outdev/bitmap.cxx
index 0e1f3979e5ba..6e707e953ab1 100644
--- a/vcl/source/outdev/bitmap.cxx
+++ b/vcl/source/outdev/bitmap.cxx
@@ -21,6 +21,7 @@
#include <vcl/bitmap.hxx>
#include <vcl/bitmapex.hxx>
+#include <vcl/BitmapFilterStackBlur.hxx>
#include <vcl/bitmapaccess.hxx>
#include <vcl/canvastools.hxx>
#include <vcl/gdimtf.hxx>
@@ -48,6 +49,9 @@
#include <tools/helpers.hxx>
#include <tools/debug.hxx>
+#include <vcl/dibtools.hxx>
+#include <tools/stream.hxx>
+
void OutputDevice::DrawBitmap( const Point& rDestPt, const Bitmap& rBitmap )
{
assert(!is_double_buffered_window());
diff --git a/xmloff/inc/xmlsdtypes.hxx b/xmloff/inc/xmlsdtypes.hxx
index b49639d43a94..6b060d322f7c 100644
--- a/xmloff/inc/xmlsdtypes.hxx
+++ b/xmloff/inc/xmlsdtypes.hxx
@@ -68,6 +68,7 @@
#define XML_SD_TYPE_IMAGE_SCALE_MODE (XML_SD_TYPES_START + 34 )
#define XML_SD_TYPE_LINECAP (XML_SD_TYPES_START + 35 )
#define XML_SD_TYPE_FITTOSIZE_AUTOFIT (XML_SD_TYPES_START + 36 )
+#define XML_SD_TYPE_GLOW (XML_SD_TYPES_START + 37 )
//////////////////////////////////////////////////////////////////////////////
// 3D property types
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index 2005e929a684..46125e067982 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -929,6 +929,9 @@ namespace xmloff::token {
TOKEN( "gcd", XML_GCD ),
TOKEN( "generator", XML_GENERATOR ),
TOKEN( "geq", XML_GEQ ),
+ TOKEN( "glow", XML_GLOW ),
+ TOKEN( "glow-radius", XML_GLOW_RADIUS ),
+ TOKEN( "glow-color", XML_GLOW_COLOR ),
TOKEN( "gouraud", XML_GOURAUD ),
TOKEN( "gradient", XML_GRADIENT ),
TOKEN( "angle", XML_GRADIENT_ANGLE ),
diff --git a/xmloff/source/draw/sdpropls.cxx b/xmloff/source/draw/sdpropls.cxx
index 19b325f8e1c5..4cedc7c148c0 100644
--- a/xmloff/source/draw/sdpropls.cxx
+++ b/xmloff/source/draw/sdpropls.cxx
@@ -152,6 +152,11 @@ const XMLPropertyMapEntry aXMLSDProperties[] =
GMAP( "ShadowColor", XML_NAMESPACE_DRAW, XML_SHADOW_COLOR, XML_TYPE_COLOR, 0 ),
GMAP( "ShadowTransparence", XML_NAMESPACE_DRAW, XML_SHADOW_OPACITY, XML_TYPE_NEG_PERCENT, 0 ),
+ // glow attributes
+ GMAPV( "GlowEffect", XML_NAMESPACE_LO_EXT, XML_GLOW, XML_SD_TYPE_GLOW , 0, SvtSaveOptions::ODFVER_012_EXT_COMPAT ),
+ GMAPV( "GlowEffectRad", XML_NAMESPACE_LO_EXT, XML_GLOW_RADIUS, XML_TYPE_MEASURE , 0, SvtSaveOptions::ODFVER_012_EXT_COMPAT ),
+ GMAPV( "GlowEffectColor", XML_NAMESPACE_LO_EXT, XML_GLOW_COLOR, XML_TYPE_COLOR , 0, SvtSaveOptions::ODFVER_012_EXT_COMPAT ),
+
// graphic attributes
GMAP( "GraphicColorMode", XML_NAMESPACE_DRAW, XML_COLOR_MODE, XML_TYPE_COLOR_MODE, 0 ), // exists in SW, too, with same property name
GMAP( "AdjustLuminance", XML_NAMESPACE_DRAW, XML_LUMINANCE, XML_TYPE_PERCENT16, 0 ), // signed? exists in SW, too, with same property name
@@ -1019,6 +1024,11 @@ const XMLPropertyHandler* XMLSdPropHdlFactory::GetPropertyHandler( sal_Int32 nTy
pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_VISIBLE), GetXMLToken(XML_HIDDEN) );
break;
}
+ case XML_SD_TYPE_GLOW :
+ {
+ pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_VISIBLE), GetXMLToken(XML_HIDDEN) );
+ break;
+ }
case XML_TYPE_SD_MIRROR:
{
pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_HORIZONTAL), GetXMLToken(XML_NONE) );
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index 34e145b30e46..31dae860a15e 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -847,6 +847,9 @@ gap-width
gcd
generator
geq
+glow
+glow-radius
+glow-color
gouraud
gradient
angle