summaryrefslogtreecommitdiffstats
path: root/oox/source/drawingml/fillproperties.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'oox/source/drawingml/fillproperties.cxx')
-rw-r--r--oox/source/drawingml/fillproperties.cxx1065
1 files changed, 1065 insertions, 0 deletions
diff --git a/oox/source/drawingml/fillproperties.cxx b/oox/source/drawingml/fillproperties.cxx
new file mode 100644
index 0000000000..dec9ab9672
--- /dev/null
+++ b/oox/source/drawingml/fillproperties.cxx
@@ -0,0 +1,1065 @@
+/* -*- 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 <drawingml/fillproperties.hxx>
+
+#include <iterator>
+
+#include <comphelper/propertyvalue.hxx>
+#include <drawingml/graphicproperties.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/BitmapFilter.hxx>
+#include <vcl/BitmapMonochromeFilter.hxx>
+#include <docmodel/uno/UnoComplexColor.hxx>
+#include <docmodel/uno/UnoGradientTools.hxx>
+#include <basegfx/utils/gradienttools.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/Gradient2.hpp>
+#include <com/sun/star/text/GraphicCrop.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/drawing/BitmapMode.hpp>
+#include <com/sun/star/drawing/ColorMode.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/RectanglePoint.hpp>
+#include <com/sun/star/graphic/XGraphicTransformer.hpp>
+#include <oox/helper/graphichelper.hxx>
+#include <oox/drawingml/drawingmltypes.hxx>
+#include <oox/drawingml/shapepropertymap.hxx>
+#include <drawingml/hatchmap.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/token/properties.hxx>
+#include <oox/token/tokens.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+
+#include <frozen/bits/defines.h>
+#include <frozen/bits/elsa_std.h>
+#include <frozen/unordered_map.h>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::graphic;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::geometry::IntegerRectangle2D;
+
+namespace oox::drawingml {
+
+namespace {
+
+Reference< XGraphic > lclCheckAndApplyDuotoneTransform(const BlipFillProperties& aBlipProps, uno::Reference<graphic::XGraphic> const & xGraphic,
+ const GraphicHelper& rGraphicHelper, const ::Color nPhClr)
+{
+ if (aBlipProps.maDuotoneColors[0].isUsed() && aBlipProps.maDuotoneColors[1].isUsed())
+ {
+ ::Color nColor1 = aBlipProps.maDuotoneColors[0].getColor( rGraphicHelper, nPhClr );
+ ::Color nColor2 = aBlipProps.maDuotoneColors[1].getColor( rGraphicHelper, nPhClr );
+
+ uno::Reference<graphic::XGraphicTransformer> xTransformer(aBlipProps.mxFillGraphic, uno::UNO_QUERY);
+ if (xTransformer.is())
+ return xTransformer->applyDuotone(xGraphic, sal_Int32(nColor1), sal_Int32(nColor2));
+ }
+ return xGraphic;
+}
+
+Reference< XGraphic > lclRotateGraphic(uno::Reference<graphic::XGraphic> const & xGraphic, Degree10 nRotation)
+{
+ ::Graphic aGraphic(xGraphic);
+ ::Graphic aReturnGraphic;
+
+ assert (aGraphic.GetType() == GraphicType::Bitmap);
+
+ BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
+ const ::Color& aColor = ::Color(0x00);
+ aBitmapEx.Rotate(nRotation, aColor);
+ aReturnGraphic = ::Graphic(aBitmapEx);
+ aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
+
+ return aReturnGraphic.GetXGraphic();
+}
+
+using Quotients = std::tuple<double, double, double, double>;
+Quotients getQuotients(geometry::IntegerRectangle2D aRelRect, double hDiv, double vDiv)
+{
+ return { aRelRect.X1 / hDiv, aRelRect.Y1 / vDiv, aRelRect.X2 / hDiv, aRelRect.Y2 / vDiv };
+}
+
+// ECMA-376 Part 1 20.1.8.55 srcRect (Source Rectangle)
+std::optional<Quotients> CropQuotientsFromSrcRect(geometry::IntegerRectangle2D aSrcRect)
+{
+ aSrcRect.X1 = std::max(aSrcRect.X1, sal_Int32(0));
+ aSrcRect.X2 = std::max(aSrcRect.X2, sal_Int32(0));
+ aSrcRect.Y1 = std::max(aSrcRect.Y1, sal_Int32(0));
+ aSrcRect.Y2 = std::max(aSrcRect.Y2, sal_Int32(0));
+ if (aSrcRect.X1 + aSrcRect.X2 >= MAX_PERCENT || aSrcRect.Y1 + aSrcRect.Y2 >= MAX_PERCENT)
+ return {}; // Cropped everything
+ return getQuotients(aSrcRect, MAX_PERCENT, MAX_PERCENT);
+}
+
+// ECMA-376 Part 1 20.1.8.30 fillRect (Fill Rectangle)
+std::optional<Quotients> CropQuotientsFromFillRect(geometry::IntegerRectangle2D aFillRect)
+{
+ aFillRect.X1 = std::min(aFillRect.X1, sal_Int32(0));
+ aFillRect.X2 = std::min(aFillRect.X2, sal_Int32(0));
+ aFillRect.Y1 = std::min(aFillRect.Y1, sal_Int32(0));
+ aFillRect.Y2 = std::min(aFillRect.Y2, sal_Int32(0));
+ // Negative divisor and negative relative offset give positive value wanted in lclCropGraphic
+ return getQuotients(aFillRect, -MAX_PERCENT + aFillRect.X1 + aFillRect.X2,
+ -MAX_PERCENT + aFillRect.Y1 + aFillRect.Y2);
+}
+
+// Crops a piece of the bitmap. lclCropGraphic doesn't handle growing.
+Reference<XGraphic> lclCropGraphic(uno::Reference<graphic::XGraphic> const& xGraphic,
+ std::optional<Quotients> quotients)
+{
+ ::Graphic aGraphic(xGraphic);
+ assert (aGraphic.GetType() == GraphicType::Bitmap);
+
+ BitmapEx aBitmapEx;
+ if (quotients)
+ {
+ aBitmapEx = aGraphic.GetBitmapEx();
+
+ const Size bmpSize = aBitmapEx.GetSizePixel();
+ const auto& [qx1, qy1, qx2, qy2] = *quotients;
+ const tools::Long l = std::round(bmpSize.Width() * qx1);
+ const tools::Long t = std::round(bmpSize.Height() * qy1);
+ const tools::Long r = std::round(bmpSize.Width() * qx2);
+ const tools::Long b = std::round(bmpSize.Height() * qy2);
+
+ aBitmapEx.Crop({ l, t, bmpSize.Width() - r - 1, bmpSize.Height() - b - 1 });
+ }
+
+ ::Graphic aReturnGraphic(aBitmapEx);
+ aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
+
+ return aReturnGraphic.GetXGraphic();
+}
+
+Reference< XGraphic > lclMirrorGraphic(uno::Reference<graphic::XGraphic> const & xGraphic, bool bFlipH, bool bFlipV)
+{
+ ::Graphic aGraphic(xGraphic);
+ ::Graphic aReturnGraphic;
+
+ assert (aGraphic.GetType() == GraphicType::Bitmap);
+
+ BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
+ BmpMirrorFlags nMirrorFlags = BmpMirrorFlags::NONE;
+
+ if(bFlipH)
+ nMirrorFlags |= BmpMirrorFlags::Horizontal;
+ if(bFlipV)
+ nMirrorFlags |= BmpMirrorFlags::Vertical;
+
+ aBitmapEx.Mirror(nMirrorFlags);
+
+ aReturnGraphic = ::Graphic(aBitmapEx);
+ aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
+
+ return aReturnGraphic.GetXGraphic();
+}
+
+Reference< XGraphic > lclGreysScaleGraphic(uno::Reference<graphic::XGraphic> const & xGraphic)
+{
+ ::Graphic aGraphic(xGraphic);
+ ::Graphic aReturnGraphic;
+
+ assert (aGraphic.GetType() == GraphicType::Bitmap);
+
+ BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
+ aBitmapEx.Convert(BmpConversion::N8BitGreys);
+
+ aReturnGraphic = ::Graphic(aBitmapEx);
+ aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
+
+ return aReturnGraphic.GetXGraphic();
+}
+
+/// Applies the graphic Black&White (Monochrome) effect with the imported threshold
+Reference<XGraphic> lclApplyBlackWhiteEffect(const BlipFillProperties& aBlipProps,
+ const uno::Reference<graphic::XGraphic>& xGraphic)
+{
+ const auto& oBiLevelThreshold = aBlipProps.moBiLevelThreshold;
+ if (oBiLevelThreshold.has_value())
+ {
+ sal_uInt8 nThreshold
+ = static_cast<sal_uInt8>(oBiLevelThreshold.value() * 255 / MAX_PERCENT);
+
+ ::Graphic aGraphic(xGraphic);
+ ::Graphic aReturnGraphic;
+
+ BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
+ AlphaMask aMask(aBitmapEx.GetAlphaMask());
+
+ BitmapEx aTmpBmpEx(aBitmapEx.GetBitmap());
+ BitmapFilter::Filter(aTmpBmpEx, BitmapMonochromeFilter{ nThreshold });
+
+ aReturnGraphic = ::Graphic(BitmapEx(aTmpBmpEx.GetBitmap(), aMask));
+ aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
+ return aReturnGraphic.GetXGraphic();
+ }
+ return xGraphic;
+}
+
+Reference< XGraphic > lclCheckAndApplyChangeColorTransform(const BlipFillProperties &aBlipProps, uno::Reference<graphic::XGraphic> const & xGraphic,
+ const GraphicHelper& rGraphicHelper, const ::Color nPhClr)
+{
+ if( aBlipProps.maColorChangeFrom.isUsed() && aBlipProps.maColorChangeTo.isUsed() )
+ {
+ ::Color nFromColor = aBlipProps.maColorChangeFrom.getColor( rGraphicHelper, nPhClr );
+ ::Color nToColor = aBlipProps.maColorChangeTo.getColor( rGraphicHelper, nPhClr );
+ if ( (nFromColor != nToColor) || aBlipProps.maColorChangeTo.hasTransparency() )
+ {
+ sal_Int16 nToTransparence = aBlipProps.maColorChangeTo.getTransparency();
+ sal_Int8 nToAlpha = static_cast< sal_Int8 >( (100 - nToTransparence) * 2.55 );
+
+ sal_uInt8 nTolerance = 9;
+ Graphic aGraphic{ xGraphic };
+ if( aGraphic.IsGfxLink() )
+ {
+ // tdf#149670: Try to guess tolerance depending on image format
+ switch (aGraphic.GetGfxLink().GetType())
+ {
+ case GfxLinkType::NativeJpg:
+ nTolerance = 15;
+ break;
+ case GfxLinkType::NativePng:
+ case GfxLinkType::NativeTif:
+ nTolerance = 1;
+ break;
+ case GfxLinkType::NativeBmp:
+ nTolerance = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ uno::Reference<graphic::XGraphicTransformer> xTransformer(aBlipProps.mxFillGraphic, uno::UNO_QUERY);
+ if (xTransformer.is())
+ return xTransformer->colorChange(xGraphic, sal_Int32(nFromColor), nTolerance, sal_Int32(nToColor), nToAlpha);
+ }
+ }
+ return xGraphic;
+}
+
+uno::Reference<graphic::XGraphic> applyBrightnessContrast(uno::Reference<graphic::XGraphic> const & xGraphic, sal_Int32 brightness, sal_Int32 contrast)
+{
+ uno::Reference<graphic::XGraphicTransformer> xTransformer(xGraphic, uno::UNO_QUERY);
+ if (xTransformer.is())
+ return xTransformer->applyBrightnessContrast(xGraphic, brightness, contrast, true);
+ return xGraphic;
+}
+
+BitmapMode lclGetBitmapMode( sal_Int32 nToken )
+{
+ OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
+ switch( nToken )
+ {
+ case XML_tile: return BitmapMode_REPEAT;
+ case XML_stretch: return BitmapMode_STRETCH;
+ }
+
+ // tdf#128596 Default value is XML_tile for MSO.
+ return BitmapMode_REPEAT;
+}
+
+RectanglePoint lclGetRectanglePoint( sal_Int32 nToken )
+{
+ OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
+ switch( nToken )
+ {
+ case XML_tl: return RectanglePoint_LEFT_TOP;
+ case XML_t: return RectanglePoint_MIDDLE_TOP;
+ case XML_tr: return RectanglePoint_RIGHT_TOP;
+ case XML_l: return RectanglePoint_LEFT_MIDDLE;
+ case XML_ctr: return RectanglePoint_MIDDLE_MIDDLE;
+ case XML_r: return RectanglePoint_RIGHT_MIDDLE;
+ case XML_bl: return RectanglePoint_LEFT_BOTTOM;
+ case XML_b: return RectanglePoint_MIDDLE_BOTTOM;
+ case XML_br: return RectanglePoint_RIGHT_BOTTOM;
+ }
+ return RectanglePoint_LEFT_TOP;
+}
+
+awt::Size lclGetOriginalSize( const GraphicHelper& rGraphicHelper, const Reference< XGraphic >& rxGraphic )
+{
+ awt::Size aSizeHmm( 0, 0 );
+ try
+ {
+ Reference< beans::XPropertySet > xGraphicPropertySet( rxGraphic, UNO_QUERY_THROW );
+ if( xGraphicPropertySet->getPropertyValue( "Size100thMM" ) >>= aSizeHmm )
+ {
+ if( !aSizeHmm.Width && !aSizeHmm.Height )
+ { // MAPMODE_PIXEL USED :-(
+ awt::Size aSourceSizePixel( 0, 0 );
+ if( xGraphicPropertySet->getPropertyValue( "SizePixel" ) >>= aSourceSizePixel )
+ aSizeHmm = rGraphicHelper.convertScreenPixelToHmm( aSourceSizePixel );
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ }
+ return aSizeHmm;
+}
+
+} // namespace
+
+void GradientFillProperties::assignUsed( const GradientFillProperties& rSourceProps )
+{
+ if( !rSourceProps.maGradientStops.empty() )
+ maGradientStops = rSourceProps.maGradientStops;
+ assignIfUsed( moFillToRect, rSourceProps.moFillToRect );
+ assignIfUsed( moTileRect, rSourceProps.moTileRect );
+ assignIfUsed( moGradientPath, rSourceProps.moGradientPath );
+ assignIfUsed( moShadeAngle, rSourceProps.moShadeAngle );
+ assignIfUsed( moShadeFlip, rSourceProps.moShadeFlip );
+ assignIfUsed( moShadeScaled, rSourceProps.moShadeScaled );
+ assignIfUsed( moRotateWithShape, rSourceProps.moRotateWithShape );
+}
+
+void PatternFillProperties::assignUsed( const PatternFillProperties& rSourceProps )
+{
+ maPattFgColor.assignIfUsed( rSourceProps.maPattFgColor );
+ maPattBgColor.assignIfUsed( rSourceProps.maPattBgColor );
+ assignIfUsed( moPattPreset, rSourceProps.moPattPreset );
+}
+
+void BlipFillProperties::assignUsed( const BlipFillProperties& rSourceProps )
+{
+ if(rSourceProps.mxFillGraphic.is())
+ mxFillGraphic = rSourceProps.mxFillGraphic;
+ assignIfUsed( moBitmapMode, rSourceProps.moBitmapMode );
+ assignIfUsed( moFillRect, rSourceProps.moFillRect );
+ assignIfUsed( moTileOffsetX, rSourceProps.moTileOffsetX );
+ assignIfUsed( moTileOffsetY, rSourceProps.moTileOffsetY );
+ assignIfUsed( moTileScaleX, rSourceProps.moTileScaleX );
+ assignIfUsed( moTileScaleY, rSourceProps.moTileScaleY );
+ assignIfUsed( moTileAlign, rSourceProps.moTileAlign );
+ assignIfUsed( moTileFlip, rSourceProps.moTileFlip );
+ assignIfUsed( moRotateWithShape, rSourceProps.moRotateWithShape );
+ assignIfUsed( moColorEffect, rSourceProps.moColorEffect );
+ assignIfUsed( moBrightness, rSourceProps.moBrightness );
+ assignIfUsed( moContrast, rSourceProps.moContrast );
+ assignIfUsed( moBiLevelThreshold, rSourceProps.moBiLevelThreshold );
+ maColorChangeFrom.assignIfUsed( rSourceProps.maColorChangeFrom );
+ maColorChangeTo.assignIfUsed( rSourceProps.maColorChangeTo );
+ maDuotoneColors[0].assignIfUsed( rSourceProps.maDuotoneColors[0] );
+ maDuotoneColors[1].assignIfUsed( rSourceProps.maDuotoneColors[1] );
+ maEffect.assignUsed( rSourceProps.maEffect );
+ assignIfUsed(moAlphaModFix, rSourceProps.moAlphaModFix);
+}
+
+void FillProperties::assignUsed( const FillProperties& rSourceProps )
+{
+ assignIfUsed( moFillType, rSourceProps.moFillType );
+ maFillColor.assignIfUsed( rSourceProps.maFillColor );
+ assignIfUsed( moUseBgFill, rSourceProps.moUseBgFill );
+ maGradientProps.assignUsed( rSourceProps.maGradientProps );
+ maPatternProps.assignUsed( rSourceProps.maPatternProps );
+ maBlipProps.assignUsed( rSourceProps.maBlipProps );
+}
+
+Color FillProperties::getBestSolidColor() const
+{
+ Color aSolidColor;
+ if( moFillType.has_value() ) switch( moFillType.value() )
+ {
+ case XML_solidFill:
+ aSolidColor = maFillColor;
+ break;
+ case XML_gradFill:
+ if( !maGradientProps.maGradientStops.empty() )
+ {
+ GradientFillProperties::GradientStopMap::const_iterator aGradientStop =
+ maGradientProps.maGradientStops.begin();
+ if (maGradientProps.maGradientStops.size() > 2)
+ ++aGradientStop;
+ aSolidColor = aGradientStop->second;
+ }
+ break;
+ case XML_pattFill:
+ aSolidColor = maPatternProps.maPattBgColor.isUsed() ? maPatternProps.maPattBgColor : maPatternProps.maPattFgColor;
+ break;
+ }
+ return aSolidColor;
+}
+
+void FillProperties::pushToPropMap(ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper,
+ sal_Int32 nShapeRotation, ::Color nPhClr,
+ const css::awt::Size& rSize, sal_Int16 nPhClrTheme, bool bFlipH,
+ bool bFlipV, bool bIsCustomShape) const
+{
+ if( !moFillType.has_value() )
+ return;
+
+ FillStyle eFillStyle = FillStyle_NONE;
+ OSL_ASSERT((moFillType.value() & sal_Int32(0xFFFF0000))==0);
+ switch( moFillType.value() )
+ {
+ case XML_noFill:
+ {
+ eFillStyle = FillStyle_NONE;
+ rPropMap.setProperty(ShapeProperty::FillUseSlideBackground, moUseBgFill.value_or(false));
+ }
+ break;
+
+ case XML_solidFill:
+ if( maFillColor.isUsed() )
+ {
+ ::Color aFillColor = maFillColor.getColor(rGraphicHelper, nPhClr);
+ rPropMap.setProperty(ShapeProperty::FillColor, aFillColor);
+ if( maFillColor.hasTransparency() )
+ rPropMap.setProperty( ShapeProperty::FillTransparency, maFillColor.getTransparency() );
+
+ model::ComplexColor aComplexColor;
+ if (aFillColor == nPhClr)
+ {
+ aComplexColor.setThemeColor(model::convertToThemeColorType(nPhClrTheme));
+ }
+ else
+ {
+ aComplexColor = maFillColor.getComplexColor();
+ }
+ rPropMap.setProperty(PROP_FillComplexColor, model::color::createXComplexColor(aComplexColor));
+
+ eFillStyle = FillStyle_SOLID;
+ }
+ break;
+
+ case XML_gradFill:
+ // do not create gradient struct if property is not supported...
+ if( rPropMap.supportsProperty( ShapeProperty::FillGradient ) )
+ {
+ // prepare ColorStops
+ basegfx::BColorStops aColorStops;
+ basegfx::BColorStops aTransparencyStops;
+ bool bContainsTransparency(false);
+
+ // convert to BColorStops, check for contained transparency
+ for (const auto& rCandidate : maGradientProps.maGradientStops)
+ {
+ const ::Color aColor(rCandidate.second.getColor(rGraphicHelper, nPhClr));
+ aColorStops.emplace_back(rCandidate.first, aColor.getBColor());
+ bContainsTransparency = bContainsTransparency || rCandidate.second.hasTransparency();
+ }
+
+ // if we have transparency, convert to BColorStops
+ if (bContainsTransparency)
+ {
+ for (const auto& rCandidate : maGradientProps.maGradientStops)
+ {
+ const double fTrans(rCandidate.second.getTransparency() * (1.0/100.0));
+ aTransparencyStops.emplace_back(rCandidate.first, basegfx::BColor(fTrans, fTrans, fTrans));
+ }
+ }
+
+ // prepare BGradient with some defaults
+ // CAUTION: This used awt::Gradient2 before who's empty constructor
+ // (see workdir/UnoApiHeadersTarget/offapi/normal/com/sun/
+ // star/awt/Gradient.hpp) initializes all to zeros, so reflect
+ // this here. OTOH set all that were set, e.g. Start/EndIntens
+ // were set to 100, so just use default of BGradient constructor
+ basegfx::BGradient aGradient(
+ aColorStops,
+ awt::GradientStyle_LINEAR,
+ Degree10(900),
+ 0, // border
+ 0, // OfsX -> 0, not 50 (!)
+ 0); // OfsY -> 0, not 50 (!)
+
+ // "rotate with shape" set to false -> do not rotate
+ if (!maGradientProps.moRotateWithShape.value_or(true))
+ {
+ nShapeRotation = 0;
+ }
+
+ if (maGradientProps.moGradientPath.has_value())
+ {
+ IntegerRectangle2D aFillToRect = maGradientProps.moFillToRect.value_or( IntegerRectangle2D( 0, 0, MAX_PERCENT, MAX_PERCENT ) );
+ sal_Int32 nCenterX = (MAX_PERCENT + aFillToRect.X1 - aFillToRect.X2) / 2;
+ aGradient.SetXOffset(getLimitedValue<sal_Int16, sal_Int32>(
+ nCenterX / PER_PERCENT, 0, 100));
+ sal_Int32 nCenterY = (MAX_PERCENT + aFillToRect.Y1 - aFillToRect.Y2) / 2;
+ aGradient.SetYOffset(getLimitedValue<sal_Int16, sal_Int32>(
+ nCenterY / PER_PERCENT, 0, 100));
+
+ if( maGradientProps.moGradientPath.value() == XML_circle )
+ {
+ // Style should be radial at least when the horizontal center is at 50%.
+ // Otherwise import as a linear gradient, because it is the most similar to the MSO radial style.
+ // aGradient.SetGradientStyle(awt::GradientStyle_LINEAR);
+ if( 100 == aGradient.GetXOffset() && 100 == aGradient.GetYOffset() )
+ aGradient.SetAngle( Degree10(450) );
+ else if( 0 == aGradient.GetXOffset() && 100 == aGradient.GetYOffset() )
+ aGradient.SetAngle( Degree10(3150) );
+ else if( 100 == aGradient.GetXOffset() && 0 == aGradient.GetYOffset() )
+ aGradient.SetAngle( Degree10(1350) );
+ else if( 0 == aGradient.GetXOffset() && 0 == aGradient.GetYOffset() )
+ aGradient.SetAngle( Degree10(2250) );
+ else
+ aGradient.SetGradientStyle(awt::GradientStyle_RADIAL);
+ }
+ else
+ {
+ aGradient.SetGradientStyle(awt::GradientStyle_RECT);
+ }
+
+ aColorStops.reverseColorStops();
+ aGradient.SetColorStops(aColorStops);
+ aTransparencyStops.reverseColorStops();
+ }
+ else if (!maGradientProps.maGradientStops.empty())
+ {
+ // aGradient.SetGradientStyle(awt::GradientStyle_LINEAR);
+ sal_Int32 nShadeAngle(maGradientProps.moShadeAngle.value_or( 0 ));
+ // Adjust for flips
+ if ( bFlipH )
+ nShadeAngle = 180*60000 - nShadeAngle;
+ if ( bFlipV )
+ nShadeAngle = -nShadeAngle;
+ const sal_Int32 nDmlAngle = nShadeAngle + nShapeRotation;
+
+ // convert DrawingML angle (in 1/60000 degrees) to API angle (in 1/10 degrees)
+ aGradient.SetAngle(Degree10(static_cast< sal_Int16 >( (8100 - (nDmlAngle / (PER_DEGREE / 10))) % 3600 )));
+ }
+
+ if (awt::GradientStyle_RECT == aGradient.GetGradientStyle())
+ {
+ // MCGR: tdf#155362: better support border
+ // CAUTION: Need to handle TransparencyStops if used
+ aGradient.tryToRecreateBorder(aTransparencyStops.empty() ? nullptr : &aTransparencyStops);
+ }
+
+ // push gradient or named gradient to property map
+ if (rPropMap.setProperty(ShapeProperty::FillGradient, model::gradient::createUnoGradient2(aGradient)))
+ {
+ eFillStyle = FillStyle_GRADIENT;
+ }
+
+ // push gradient transparency to property map if it exists
+ if (!aTransparencyStops.empty())
+ {
+ aGradient.SetColorStops(aTransparencyStops);
+ rPropMap.setProperty(ShapeProperty::GradientTransparency, model::gradient::createUnoGradient2(aGradient));
+ }
+ }
+ break;
+
+ case XML_blipFill:
+ // do not start complex graphic transformation if property is not supported...
+ if (maBlipProps.mxFillGraphic.is() && rPropMap.supportsProperty(ShapeProperty::FillBitmap))
+ {
+ uno::Reference<graphic::XGraphic> xGraphic = lclCheckAndApplyDuotoneTransform(maBlipProps, maBlipProps.mxFillGraphic, rGraphicHelper, nPhClr);
+ // TODO: "rotate with shape" is not possible with our current core
+
+ if (xGraphic.is())
+ {
+ if (maBlipProps.moColorEffect.value_or(XML_TOKEN_INVALID) == XML_grayscl)
+ xGraphic = lclGreysScaleGraphic(xGraphic);
+
+ if (rPropMap.supportsProperty(ShapeProperty::FillBitmapName) &&
+ rPropMap.setProperty(ShapeProperty::FillBitmapName, xGraphic))
+ {
+ eFillStyle = FillStyle_BITMAP;
+ }
+ else if (rPropMap.setProperty(ShapeProperty::FillBitmap, xGraphic))
+ {
+ eFillStyle = FillStyle_BITMAP;
+ }
+ }
+
+ // set other bitmap properties, if bitmap has been inserted into the map
+ if( eFillStyle == FillStyle_BITMAP )
+ {
+ // bitmap mode (single, repeat, stretch)
+ BitmapMode eBitmapMode = lclGetBitmapMode( maBlipProps.moBitmapMode.value_or( XML_TOKEN_INVALID ) );
+
+ // additional settings for repeated bitmap
+ if( eBitmapMode == BitmapMode_REPEAT )
+ {
+ // anchor position inside bitmap
+ RectanglePoint eRectPoint = lclGetRectanglePoint( maBlipProps.moTileAlign.value_or( XML_tl ) );
+ rPropMap.setProperty( ShapeProperty::FillBitmapRectanglePoint, eRectPoint );
+
+ awt::Size aOriginalSize = lclGetOriginalSize(rGraphicHelper, maBlipProps.mxFillGraphic);
+ if( (aOriginalSize.Width > 0) && (aOriginalSize.Height > 0) )
+ {
+ // size of one bitmap tile (given as 1/1000 percent of bitmap size), convert to 1/100 mm
+ double fScaleX = maBlipProps.moTileScaleX.value_or( MAX_PERCENT ) / static_cast< double >( MAX_PERCENT );
+ sal_Int32 nFillBmpSizeX = getLimitedValue< sal_Int32, double >( aOriginalSize.Width * fScaleX, 1, SAL_MAX_INT32 );
+ rPropMap.setProperty( ShapeProperty::FillBitmapSizeX, nFillBmpSizeX );
+ double fScaleY = maBlipProps.moTileScaleY.value_or( MAX_PERCENT ) / static_cast< double >( MAX_PERCENT );
+ sal_Int32 nFillBmpSizeY = getLimitedValue< sal_Int32, double >( aOriginalSize.Height * fScaleY, 1, SAL_MAX_INT32 );
+ rPropMap.setProperty( ShapeProperty::FillBitmapSizeY, nFillBmpSizeY );
+
+ awt::Size aBmpSize(nFillBmpSizeX, nFillBmpSizeY);
+ // offset of the first bitmap tile (given as EMUs), convert to percent
+ sal_Int16 nTileOffsetX = getDoubleIntervalValue< sal_Int16 >(std::round(maBlipProps.moTileOffsetX.value_or( 0 ) / 3.6 / aBmpSize.Width), 0, 100 );
+ rPropMap.setProperty( ShapeProperty::FillBitmapOffsetX, nTileOffsetX );
+ sal_Int16 nTileOffsetY = getDoubleIntervalValue< sal_Int16 >(std::round(maBlipProps.moTileOffsetY.value_or( 0 ) / 3.6 / aBmpSize.Height), 0, 100 );
+ rPropMap.setProperty( ShapeProperty::FillBitmapOffsetY, nTileOffsetY );
+ }
+ }
+ else if ( eBitmapMode == BitmapMode_STRETCH && maBlipProps.moFillRect.has_value() )
+ {
+ geometry::IntegerRectangle2D aFillRect( maBlipProps.moFillRect.value() );
+ awt::Size aOriginalSize( rGraphicHelper.getOriginalSize( xGraphic ) );
+ if ( aOriginalSize.Width && aOriginalSize.Height )
+ {
+ text::GraphicCrop aGraphCrop( 0, 0, 0, 0 );
+ if ( aFillRect.X1 )
+ aGraphCrop.Left = o3tl::convert(aFillRect.X1, aOriginalSize.Width, MAX_PERCENT);
+ if ( aFillRect.Y1 )
+ aGraphCrop.Top = o3tl::convert(aFillRect.Y1, aOriginalSize.Height, MAX_PERCENT);
+ if ( aFillRect.X2 )
+ aGraphCrop.Right = o3tl::convert(aFillRect.X2, aOriginalSize.Width, MAX_PERCENT);
+ if ( aFillRect.Y2 )
+ aGraphCrop.Bottom = o3tl::convert(aFillRect.Y2, aOriginalSize.Height, MAX_PERCENT);
+
+ bool bHasCropValues = aGraphCrop.Left != 0 || aGraphCrop.Right !=0 || aGraphCrop.Top != 0 || aGraphCrop.Bottom != 0;
+ // Negative GraphicCrop values means "crop" here.
+ bool bNeedCrop = aGraphCrop.Left <= 0 && aGraphCrop.Right <= 0 && aGraphCrop.Top <= 0 && aGraphCrop.Bottom <= 0;
+
+ if (bHasCropValues)
+ {
+ if (bIsCustomShape && bNeedCrop)
+ {
+ // Physically crop the image
+ // In this case, don't set the PROP_GraphicCrop because that
+ // would lead to applying the crop twice after roundtrip
+ xGraphic = lclCropGraphic(xGraphic, CropQuotientsFromFillRect(aFillRect));
+ if (rPropMap.supportsProperty(ShapeProperty::FillBitmapName))
+ rPropMap.setProperty(ShapeProperty::FillBitmapName, xGraphic);
+ else
+ rPropMap.setProperty(ShapeProperty::FillBitmap, xGraphic);
+ }
+ else if ((aFillRect.X1 != 0 && aFillRect.X2 != 0
+ && aFillRect.X1 != aFillRect.X2)
+ || (aFillRect.Y1 != 0 && aFillRect.Y2 != 0
+ && aFillRect.Y1 != aFillRect.Y2))
+ {
+ rPropMap.setProperty(PROP_GraphicCrop, aGraphCrop);
+ }
+ else
+ {
+ double nL = aFillRect.X1 / static_cast<double>(MAX_PERCENT);
+ double nT = aFillRect.Y1 / static_cast<double>(MAX_PERCENT);
+ double nR = aFillRect.X2 / static_cast<double>(MAX_PERCENT);
+ double nB = aFillRect.Y2 / static_cast<double>(MAX_PERCENT);
+
+ sal_Int32 nSizeX;
+ if (nL || nR)
+ nSizeX = rSize.Width * (1 - (nL + nR));
+ else
+ nSizeX = rSize.Width;
+ rPropMap.setProperty(ShapeProperty::FillBitmapSizeX, nSizeX);
+
+ sal_Int32 nSizeY;
+ if (nT || nB)
+ nSizeY = rSize.Height * (1 - (nT + nB));
+ else
+ nSizeY = rSize.Height;
+ rPropMap.setProperty(ShapeProperty::FillBitmapSizeY, nSizeY);
+
+ RectanglePoint eRectPoint;
+ if (!aFillRect.X1 && aFillRect.X2)
+ {
+ if (!aFillRect.Y1 && aFillRect.Y2)
+ eRectPoint = lclGetRectanglePoint(XML_tl);
+ else if (aFillRect.Y1 && !aFillRect.Y2)
+ eRectPoint = lclGetRectanglePoint(XML_bl);
+ else
+ eRectPoint = lclGetRectanglePoint(XML_l);
+ }
+ else if (aFillRect.X1 && !aFillRect.X2)
+ {
+ if (!aFillRect.Y1 && aFillRect.Y2)
+ eRectPoint = lclGetRectanglePoint(XML_tr);
+ else if (aFillRect.Y1 && !aFillRect.Y2)
+ eRectPoint = lclGetRectanglePoint(XML_br);
+ else
+ eRectPoint = lclGetRectanglePoint(XML_r);
+ }
+ else
+ {
+ if (!aFillRect.Y1 && aFillRect.Y2)
+ eRectPoint = lclGetRectanglePoint(XML_t);
+ else if (aFillRect.Y1 && !aFillRect.Y2)
+ eRectPoint = lclGetRectanglePoint(XML_b);
+ else
+ eRectPoint = lclGetRectanglePoint(XML_ctr);
+ }
+ rPropMap.setProperty(ShapeProperty::FillBitmapRectanglePoint, eRectPoint);
+ eBitmapMode = BitmapMode_NO_REPEAT;
+ }
+ }
+ }
+ }
+ rPropMap.setProperty(ShapeProperty::FillBitmapMode, eBitmapMode);
+ }
+
+ if (maBlipProps.moAlphaModFix.has_value())
+ rPropMap.setProperty(ShapeProperty::FillTransparency, static_cast<sal_Int16>(100 - (maBlipProps.moAlphaModFix.value() / PER_PERCENT)));
+ }
+ break;
+
+ case XML_pattFill:
+ {
+ if( rPropMap.supportsProperty( ShapeProperty::FillHatch ) )
+ {
+ Color aColor( maPatternProps.maPattFgColor );
+ if( aColor.isUsed() && maPatternProps.moPattPreset.has_value() )
+ {
+ eFillStyle = FillStyle_HATCH;
+ rPropMap.setProperty( ShapeProperty::FillHatch, createHatch( maPatternProps.moPattPreset.value(), aColor.getColor( rGraphicHelper, nPhClr ) ) );
+ if( aColor.hasTransparency() )
+ rPropMap.setProperty( ShapeProperty::FillTransparency, aColor.getTransparency() );
+
+ // Set background color for hatch
+ if(maPatternProps.maPattBgColor.isUsed())
+ {
+ aColor = maPatternProps.maPattBgColor;
+ rPropMap.setProperty( ShapeProperty::FillBackground, aColor.getTransparency() != 100 );
+ rPropMap.setProperty( ShapeProperty::FillColor, aColor.getColor( rGraphicHelper, nPhClr ) );
+ }
+ }
+ else if ( maPatternProps.maPattBgColor.isUsed() )
+ {
+ aColor = maPatternProps.maPattBgColor;
+ rPropMap.setProperty( ShapeProperty::FillColor, aColor.getColor( rGraphicHelper, nPhClr ) );
+ if( aColor.hasTransparency() )
+ rPropMap.setProperty( ShapeProperty::FillTransparency, aColor.getTransparency() );
+ eFillStyle = FillStyle_SOLID;
+ }
+ }
+ }
+ break;
+
+ case XML_grpFill:
+ // todo
+ eFillStyle = FillStyle_NONE;
+ break;
+ }
+
+ // set final fill style property
+ rPropMap.setProperty( ShapeProperty::FillStyle, eFillStyle );
+}
+
+void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const GraphicHelper& rGraphicHelper, bool bFlipH, bool bFlipV) const
+{
+ sal_Int16 nBrightness = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moBrightness.value_or( 0 ) / PER_PERCENT, -100, 100 );
+ sal_Int16 nContrast = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moContrast.value_or( 0 ) / PER_PERCENT, -100, 100 );
+ ColorMode eColorMode = ColorMode_STANDARD;
+
+ switch( maBlipProps.moColorEffect.value_or( XML_TOKEN_INVALID ) )
+ {
+ case XML_biLevel: eColorMode = ColorMode_MONO; break;
+ case XML_grayscl: eColorMode = ColorMode_GREYS; break;
+ }
+
+ if (maBlipProps.mxFillGraphic.is())
+ {
+ // created transformed graphic
+ uno::Reference<graphic::XGraphic> xGraphic = lclCheckAndApplyChangeColorTransform(maBlipProps, maBlipProps.mxFillGraphic, rGraphicHelper, API_RGB_TRANSPARENT);
+ xGraphic = lclCheckAndApplyDuotoneTransform(maBlipProps, xGraphic, rGraphicHelper, API_RGB_TRANSPARENT);
+
+ if( eColorMode == ColorMode_MONO )
+ {
+ // ColorMode_MONO is the same with MSO's biLevel with 50000 (50%) threshold,
+ // when threshold isn't 50000 bake the effect instead.
+ if( maBlipProps.moBiLevelThreshold != 50000 )
+ {
+ xGraphic = lclApplyBlackWhiteEffect(maBlipProps, xGraphic);
+ eColorMode = ColorMode_STANDARD;
+ }
+ }
+
+ if (eColorMode == ColorMode_STANDARD && nBrightness == 70 && nContrast == -70)
+ {
+ // map MSO 'washout' to our Watermark colormode
+ eColorMode = ColorMode_WATERMARK;
+ nBrightness = 0;
+ nContrast = 0;
+ }
+ else if( nBrightness != 0 && nContrast != 0 )
+ {
+ // MSO uses a different algorithm for contrast+brightness, LO applies contrast before brightness,
+ // while MSO apparently applies half of brightness before contrast and half after. So if only
+ // contrast or brightness need to be altered, the result is the same, but if both are involved,
+ // there's no way to map that, so just force a conversion of the image.
+ xGraphic = applyBrightnessContrast( xGraphic, nBrightness, nContrast );
+ nBrightness = 0;
+ nContrast = 0;
+ }
+
+ // cropping
+ if ( maBlipProps.moClipRect.has_value() )
+ {
+ geometry::IntegerRectangle2D oClipRect( maBlipProps.moClipRect.value() );
+ awt::Size aOriginalSize( rGraphicHelper.getOriginalSize( xGraphic ) );
+ if ( aOriginalSize.Width && aOriginalSize.Height )
+ {
+ text::GraphicCrop aGraphCrop( 0, 0, 0, 0 );
+ if ( oClipRect.X1 )
+ aGraphCrop.Left = o3tl::convert(oClipRect.X1, aOriginalSize.Width, MAX_PERCENT);
+ if ( oClipRect.Y1 )
+ aGraphCrop.Top = o3tl::convert(oClipRect.Y1, aOriginalSize.Height, MAX_PERCENT);
+ if ( oClipRect.X2 )
+ aGraphCrop.Right = o3tl::convert(oClipRect.X2, aOriginalSize.Width, MAX_PERCENT);
+ if ( oClipRect.Y2 )
+ aGraphCrop.Bottom = o3tl::convert(oClipRect.Y2, aOriginalSize.Height, MAX_PERCENT);
+ rPropMap.setProperty(PROP_GraphicCrop, aGraphCrop);
+
+ if(mbIsCustomShape)
+ {
+ // Positive GraphicCrop values means "crop" here.
+ if (aGraphCrop.Left > 0 || aGraphCrop.Right > 0 || aGraphCrop.Top > 0 || aGraphCrop.Bottom > 0)
+ xGraphic = lclCropGraphic(xGraphic, CropQuotientsFromSrcRect(oClipRect));
+ }
+ }
+ }
+
+ if(mbIsCustomShape)
+ {
+ // it is a cropped graphic.
+ rPropMap.setProperty(PROP_FillStyle, FillStyle_BITMAP);
+ rPropMap.setProperty(PROP_FillBitmapMode, BitmapMode_STRETCH);
+
+ // It is a bitmap filled and rotated graphic.
+ // When custom shape is rotated, bitmap have to be rotated too.
+ if(rPropMap.hasProperty(PROP_RotateAngle))
+ {
+ tools::Long nAngle = rPropMap.getProperty(PROP_RotateAngle).get<tools::Long>();
+ xGraphic = lclRotateGraphic(xGraphic, Degree10(nAngle/10) );
+ }
+
+ // We have not core feature that flips graphic in the shape.
+ // Here we are applying flip property to bitmap directly.
+ if(bFlipH || bFlipV)
+ xGraphic = lclMirrorGraphic(xGraphic, bFlipH, bFlipV );
+
+ if(eColorMode == ColorMode_GREYS)
+ xGraphic = lclGreysScaleGraphic( xGraphic );
+
+ rPropMap.setProperty(PROP_FillBitmap, xGraphic);
+ }
+ else
+ rPropMap.setProperty(PROP_Graphic, xGraphic);
+
+
+ if ( maBlipProps.moAlphaModFix.has_value() )
+ {
+ rPropMap.setProperty(
+ mbIsCustomShape ? PROP_FillTransparence : PROP_Transparency,
+ static_cast<sal_Int16>(100 - (maBlipProps.moAlphaModFix.value() / PER_PERCENT)));
+ }
+ }
+ rPropMap.setProperty(PROP_GraphicColorMode, eColorMode);
+
+ // brightness and contrast
+ if( nBrightness != 0 )
+ rPropMap.setProperty(PROP_AdjustLuminance, nBrightness);
+ if( nContrast != 0 )
+ rPropMap.setProperty(PROP_AdjustContrast, nContrast);
+
+ // Media content
+ if (!m_sMediaPackageURL.isEmpty())
+ {
+ rPropMap.setProperty(PROP_MediaURL, m_sMediaPackageURL);
+ if (m_xMediaStream.is())
+ rPropMap.setProperty(PROP_PrivateStream, m_xMediaStream);
+ }
+}
+
+bool ArtisticEffectProperties::isEmpty() const
+{
+ return msName.isEmpty();
+}
+
+css::beans::PropertyValue ArtisticEffectProperties::getEffect()
+{
+ css::beans::PropertyValue aRet;
+ if( msName.isEmpty() )
+ return aRet;
+
+ css::uno::Sequence< css::beans::PropertyValue > aSeq( maAttribs.size() + 1 );
+ auto pSeq = aSeq.getArray();
+ sal_uInt32 i = 0;
+ for (auto const& attrib : maAttribs)
+ {
+ pSeq[i].Name = attrib.first;
+ pSeq[i].Value = attrib.second;
+ i++;
+ }
+
+ if( mrOleObjectInfo.maEmbeddedData.hasElements() )
+ {
+ css::uno::Sequence< css::beans::PropertyValue > aGraphicSeq{
+ comphelper::makePropertyValue("Id", mrOleObjectInfo.maProgId),
+ comphelper::makePropertyValue("Data", mrOleObjectInfo.maEmbeddedData)
+ };
+
+ pSeq[i].Name = "OriginalGraphic";
+ pSeq[i].Value <<= aGraphicSeq;
+ }
+
+ aRet.Name = msName;
+ aRet.Value <<= aSeq;
+
+ return aRet;
+}
+
+void ArtisticEffectProperties::assignUsed( const ArtisticEffectProperties& rSourceProps )
+{
+ if( !rSourceProps.isEmpty() )
+ {
+ msName = rSourceProps.msName;
+ maAttribs = rSourceProps.maAttribs;
+ }
+}
+
+OUString ArtisticEffectProperties::getEffectString( sal_Int32 nToken )
+{
+ switch( nToken )
+ {
+ // effects
+ case OOX_TOKEN( a14, artisticBlur ): return "artisticBlur";
+ case OOX_TOKEN( a14, artisticCement ): return "artisticCement";
+ case OOX_TOKEN( a14, artisticChalkSketch ): return "artisticChalkSketch";
+ case OOX_TOKEN( a14, artisticCrisscrossEtching ): return "artisticCrisscrossEtching";
+ case OOX_TOKEN( a14, artisticCutout ): return "artisticCutout";
+ case OOX_TOKEN( a14, artisticFilmGrain ): return "artisticFilmGrain";
+ case OOX_TOKEN( a14, artisticGlass ): return "artisticGlass";
+ case OOX_TOKEN( a14, artisticGlowDiffused ): return "artisticGlowDiffused";
+ case OOX_TOKEN( a14, artisticGlowEdges ): return "artisticGlowEdges";
+ case OOX_TOKEN( a14, artisticLightScreen ): return "artisticLightScreen";
+ case OOX_TOKEN( a14, artisticLineDrawing ): return "artisticLineDrawing";
+ case OOX_TOKEN( a14, artisticMarker ): return "artisticMarker";
+ case OOX_TOKEN( a14, artisticMosiaicBubbles ): return "artisticMosiaicBubbles";
+ case OOX_TOKEN( a14, artisticPaintStrokes ): return "artisticPaintStrokes";
+ case OOX_TOKEN( a14, artisticPaintBrush ): return "artisticPaintBrush";
+ case OOX_TOKEN( a14, artisticPastelsSmooth ): return "artisticPastelsSmooth";
+ case OOX_TOKEN( a14, artisticPencilGrayscale ): return "artisticPencilGrayscale";
+ case OOX_TOKEN( a14, artisticPencilSketch ): return "artisticPencilSketch";
+ case OOX_TOKEN( a14, artisticPhotocopy ): return "artisticPhotocopy";
+ case OOX_TOKEN( a14, artisticPlasticWrap ): return "artisticPlasticWrap";
+ case OOX_TOKEN( a14, artisticTexturizer ): return "artisticTexturizer";
+ case OOX_TOKEN( a14, artisticWatercolorSponge ): return "artisticWatercolorSponge";
+ case OOX_TOKEN( a14, brightnessContrast ): return "brightnessContrast";
+ case OOX_TOKEN( a14, colorTemperature ): return "colorTemperature";
+ case OOX_TOKEN( a14, saturation ): return "saturation";
+ case OOX_TOKEN( a14, sharpenSoften ): return "sharpenSoften";
+
+ // attributes
+ case XML_visible: return "visible";
+ case XML_trans: return "trans";
+ case XML_crackSpacing: return "crackSpacing";
+ case XML_pressure: return "pressure";
+ case XML_numberOfShades: return "numberOfShades";
+ case XML_grainSize: return "grainSize";
+ case XML_intensity: return "intensity";
+ case XML_smoothness: return "smoothness";
+ case XML_gridSize: return "gridSize";
+ case XML_pencilSize: return "pencilSize";
+ case XML_size: return "size";
+ case XML_brushSize: return "brushSize";
+ case XML_scaling: return "scaling";
+ case XML_detail: return "detail";
+ case XML_bright: return "bright";
+ case XML_contrast: return "contrast";
+ case XML_colorTemp: return "colorTemp";
+ case XML_sat: return "sat";
+ case XML_amount: return "amount";
+ }
+ SAL_WARN( "oox.drawingml", "ArtisticEffectProperties::getEffectString: unexpected token " << nToken );
+ return OUString();
+}
+
+constexpr auto constEffectTokenForEffectNameMap = frozen::make_unordered_map<std::u16string_view, sal_Int32>(
+{
+ // effects
+ { u"artisticBlur", XML_artisticBlur },
+ { u"artisticCement", XML_artisticCement },
+ { u"artisticChalkSketch", XML_artisticChalkSketch },
+ { u"artisticCrisscrossEtching", XML_artisticCrisscrossEtching },
+ { u"artisticCutout", XML_artisticCutout },
+ { u"artisticFilmGrain", XML_artisticFilmGrain },
+ { u"artisticGlass", XML_artisticGlass },
+ { u"artisticGlowDiffused", XML_artisticGlowDiffused },
+ { u"artisticGlowEdges", XML_artisticGlowEdges },
+ { u"artisticLightScreen", XML_artisticLightScreen },
+ { u"artisticLineDrawing", XML_artisticLineDrawing },
+ { u"artisticMarker", XML_artisticMarker },
+ { u"artisticMosiaicBubbles", XML_artisticMosiaicBubbles },
+ { u"artisticPaintStrokes", XML_artisticPaintStrokes },
+ { u"artisticPaintBrush", XML_artisticPaintBrush },
+ { u"artisticPastelsSmooth", XML_artisticPastelsSmooth },
+ { u"artisticPencilGrayscale", XML_artisticPencilGrayscale },
+ { u"artisticPencilSketch", XML_artisticPencilSketch },
+ { u"artisticPhotocopy", XML_artisticPhotocopy },
+ { u"artisticPlasticWrap", XML_artisticPlasticWrap },
+ { u"artisticTexturizer", XML_artisticTexturizer },
+ { u"artisticWatercolorSponge", XML_artisticWatercolorSponge },
+ { u"brightnessContrast", XML_brightnessContrast },
+ { u"colorTemperature", XML_colorTemperature },
+ { u"saturation", XML_saturation },
+ { u"sharpenSoften", XML_sharpenSoften },
+
+ // attributes
+ { u"visible", XML_visible },
+ { u"trans", XML_trans },
+ { u"crackSpacing", XML_crackSpacing },
+ { u"pressure", XML_pressure },
+ { u"numberOfShades", XML_numberOfShades },
+ { u"grainSize", XML_grainSize },
+ { u"intensity", XML_intensity },
+ { u"smoothness", XML_smoothness },
+ { u"gridSize", XML_gridSize },
+ { u"pencilSize", XML_pencilSize },
+ { u"size", XML_size },
+ { u"brushSize", XML_brushSize },
+ { u"scaling", XML_scaling },
+ { u"detail", XML_detail },
+ { u"bright", XML_bright },
+ { u"contrast", XML_contrast },
+ { u"colorTemp", XML_colorTemp },
+ { u"sat", XML_sat },
+ { u"amount", XML_amount }
+});
+
+sal_Int32 ArtisticEffectProperties::getEffectToken(const OUString& sName)
+{
+ auto const aIterator = constEffectTokenForEffectNameMap.find(sName);
+
+ if (aIterator != constEffectTokenForEffectNameMap.end())
+ return aIterator->second;
+
+ SAL_WARN( "oox.drawingml", "ArtisticEffectProperties::getEffectToken - unexpected token name: " << sName );
+ return XML_none;
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */