1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <drawingml/fillproperties.hxx>
21
22 #include <iterator>
23
24 #include <comphelper/propertyvalue.hxx>
25 #include <drawingml/graphicproperties.hxx>
26 #include <vcl/graph.hxx>
27 #include <vcl/bitmap/BitmapMonochromeFilter.hxx>
28 #include <docmodel/uno/UnoComplexColor.hxx>
29 #include <docmodel/uno/UnoGradientTools.hxx>
30 #include <basegfx/utils/gradienttools.hxx>
31
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/awt/Gradient2.hpp>
34 #include <com/sun/star/text/GraphicCrop.hpp>
35 #include <com/sun/star/awt/Size.hpp>
36 #include <com/sun/star/drawing/BitmapMode.hpp>
37 #include <com/sun/star/drawing/ColorMode.hpp>
38 #include <com/sun/star/drawing/FillStyle.hpp>
39 #include <com/sun/star/drawing/RectanglePoint.hpp>
40 #include <com/sun/star/graphic/XGraphicTransformer.hpp>
41 #include <oox/helper/graphichelper.hxx>
42 #include <oox/drawingml/drawingmltypes.hxx>
43 #include <oox/drawingml/shapepropertymap.hxx>
44 #include <drawingml/hatchmap.hxx>
45 #include <oox/token/namespaces.hxx>
46 #include <oox/token/properties.hxx>
47 #include <oox/token/tokens.hxx>
48 #include <osl/diagnose.h>
49 #include <sal/log.hxx>
50
51 #include <frozen/bits/defines.h>
52 #include <frozen/bits/elsa_std.h>
53 #include <frozen/unordered_map.h>
54
55
56 using namespace ::com::sun::star;
57 using namespace ::com::sun::star::drawing;
58 using namespace ::com::sun::star::graphic;
59
60 using ::com::sun::star::uno::Reference;
61 using ::com::sun::star::uno::Exception;
62 using ::com::sun::star::uno::UNO_QUERY_THROW;
63 using ::com::sun::star::geometry::IntegerRectangle2D;
64
65 namespace oox::drawingml {
66
67 namespace {
68
lclCheckAndApplyDuotoneTransform(const BlipFillProperties & aBlipProps,uno::Reference<graphic::XGraphic> const & xGraphic,const GraphicHelper & rGraphicHelper,const::Color nPhClr)69 Reference< XGraphic > lclCheckAndApplyDuotoneTransform(const BlipFillProperties& aBlipProps, uno::Reference<graphic::XGraphic> const & xGraphic,
70 const GraphicHelper& rGraphicHelper, const ::Color nPhClr)
71 {
72 if (aBlipProps.maDuotoneColors[0].isUsed() && aBlipProps.maDuotoneColors[1].isUsed())
73 {
74 ::Color nColor1 = aBlipProps.maDuotoneColors[0].getColor( rGraphicHelper, nPhClr );
75 ::Color nColor2 = aBlipProps.maDuotoneColors[1].getColor( rGraphicHelper, nPhClr );
76
77 uno::Reference<graphic::XGraphicTransformer> xTransformer(aBlipProps.mxFillGraphic, uno::UNO_QUERY);
78 if (xTransformer.is())
79 return xTransformer->applyDuotone(xGraphic, sal_Int32(nColor1), sal_Int32(nColor2));
80 }
81 return xGraphic;
82 }
83
lclRotateGraphic(uno::Reference<graphic::XGraphic> const & xGraphic,Degree10 nRotation)84 Reference< XGraphic > lclRotateGraphic(uno::Reference<graphic::XGraphic> const & xGraphic, Degree10 nRotation)
85 {
86 ::Graphic aGraphic(xGraphic);
87 ::Graphic aReturnGraphic;
88
89 assert (aGraphic.GetType() == GraphicType::Bitmap);
90
91 Bitmap aBitmap(aGraphic.GetBitmap());
92 const ::Color aColor(0x00);
93 aBitmap.Rotate(nRotation, aColor);
94 aReturnGraphic = ::Graphic(aBitmap);
95 aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
96
97 return aReturnGraphic.GetXGraphic();
98 }
99
100 using Quotients = std::tuple<double, double, double, double>;
getQuotients(geometry::IntegerRectangle2D aRelRect,double hDiv,double vDiv)101 Quotients getQuotients(geometry::IntegerRectangle2D aRelRect, double hDiv, double vDiv)
102 {
103 return { aRelRect.X1 / hDiv, aRelRect.Y1 / vDiv, aRelRect.X2 / hDiv, aRelRect.Y2 / vDiv };
104 }
105
106 // ECMA-376 Part 1 20.1.8.55 srcRect (Source Rectangle)
CropQuotientsFromSrcRect(geometry::IntegerRectangle2D aSrcRect)107 std::optional<Quotients> CropQuotientsFromSrcRect(geometry::IntegerRectangle2D aSrcRect)
108 {
109 aSrcRect.X1 = std::max(aSrcRect.X1, sal_Int32(0));
110 aSrcRect.X2 = std::max(aSrcRect.X2, sal_Int32(0));
111 aSrcRect.Y1 = std::max(aSrcRect.Y1, sal_Int32(0));
112 aSrcRect.Y2 = std::max(aSrcRect.Y2, sal_Int32(0));
113 if (aSrcRect.X1 + aSrcRect.X2 >= MAX_PERCENT || aSrcRect.Y1 + aSrcRect.Y2 >= MAX_PERCENT)
114 return {}; // Cropped everything
115 return getQuotients(aSrcRect, MAX_PERCENT, MAX_PERCENT);
116 }
117
118 // ECMA-376 Part 1 20.1.8.30 fillRect (Fill Rectangle)
CropQuotientsFromFillRect(geometry::IntegerRectangle2D aFillRect)119 std::optional<Quotients> CropQuotientsFromFillRect(geometry::IntegerRectangle2D aFillRect)
120 {
121 aFillRect.X1 = std::min(aFillRect.X1, sal_Int32(0));
122 aFillRect.X2 = std::min(aFillRect.X2, sal_Int32(0));
123 aFillRect.Y1 = std::min(aFillRect.Y1, sal_Int32(0));
124 aFillRect.Y2 = std::min(aFillRect.Y2, sal_Int32(0));
125 // Negative divisor and negative relative offset give positive value wanted in lclCropGraphic
126 return getQuotients(aFillRect, -MAX_PERCENT + aFillRect.X1 + aFillRect.X2,
127 -MAX_PERCENT + aFillRect.Y1 + aFillRect.Y2);
128 }
129
130 // Crops a piece of the bitmap. lclCropGraphic doesn't handle growing.
lclCropGraphic(uno::Reference<graphic::XGraphic> const & xGraphic,std::optional<Quotients> quotients)131 Reference<XGraphic> lclCropGraphic(uno::Reference<graphic::XGraphic> const& xGraphic,
132 std::optional<Quotients> quotients)
133 {
134 ::Graphic aGraphic(xGraphic);
135 assert (aGraphic.GetType() == GraphicType::Bitmap);
136
137 Bitmap aBitmap;
138 if (quotients)
139 {
140 aBitmap = aGraphic.GetBitmap();
141
142 const Size bmpSize = aBitmap.GetSizePixel();
143 const auto& [qx1, qy1, qx2, qy2] = *quotients;
144 const tools::Long l = std::round(bmpSize.Width() * qx1);
145 const tools::Long t = std::round(bmpSize.Height() * qy1);
146 const tools::Long r = std::round(bmpSize.Width() * qx2);
147 const tools::Long b = std::round(bmpSize.Height() * qy2);
148
149 aBitmap.Crop({ l, t, bmpSize.Width() - r - 1, bmpSize.Height() - b - 1 });
150 }
151
152 ::Graphic aReturnGraphic(aBitmap);
153 aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
154
155 return aReturnGraphic.GetXGraphic();
156 }
157
lclMirrorGraphic(uno::Reference<graphic::XGraphic> const & xGraphic,bool bFlipH,bool bFlipV)158 Reference< XGraphic > lclMirrorGraphic(uno::Reference<graphic::XGraphic> const & xGraphic, bool bFlipH, bool bFlipV)
159 {
160 ::Graphic aGraphic(xGraphic);
161 ::Graphic aReturnGraphic;
162
163 assert (aGraphic.GetType() == GraphicType::Bitmap);
164
165 Bitmap aBitmap(aGraphic.GetBitmap());
166 BmpMirrorFlags nMirrorFlags = BmpMirrorFlags::NONE;
167
168 if(bFlipH)
169 nMirrorFlags |= BmpMirrorFlags::Horizontal;
170 if(bFlipV)
171 nMirrorFlags |= BmpMirrorFlags::Vertical;
172
173 aBitmap.Mirror(nMirrorFlags);
174
175 aReturnGraphic = ::Graphic(aBitmap);
176 aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
177
178 return aReturnGraphic.GetXGraphic();
179 }
180
lclGreysScaleGraphic(uno::Reference<graphic::XGraphic> const & xGraphic)181 Reference< XGraphic > lclGreysScaleGraphic(uno::Reference<graphic::XGraphic> const & xGraphic)
182 {
183 ::Graphic aGraphic(xGraphic);
184 ::Graphic aReturnGraphic;
185
186 assert (aGraphic.GetType() == GraphicType::Bitmap);
187
188 Bitmap aBitmap(aGraphic.GetBitmap());
189 aBitmap.Convert(BmpConversion::N8BitGreys);
190
191 aReturnGraphic = ::Graphic(aBitmap);
192 aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
193
194 return aReturnGraphic.GetXGraphic();
195 }
196
197 /// Applies the graphic Black&White (Monochrome) effect with the imported threshold
lclApplyBlackWhiteEffect(const BlipFillProperties & aBlipProps,const uno::Reference<graphic::XGraphic> & xGraphic)198 Reference<XGraphic> lclApplyBlackWhiteEffect(const BlipFillProperties& aBlipProps,
199 const uno::Reference<graphic::XGraphic>& xGraphic)
200 {
201 const auto& oBiLevelThreshold = aBlipProps.moBiLevelThreshold;
202 if (oBiLevelThreshold.has_value())
203 {
204 sal_uInt8 nThreshold
205 = static_cast<sal_uInt8>(oBiLevelThreshold.value() * 255 / MAX_PERCENT);
206
207 ::Graphic aGraphic(xGraphic);
208 ::Graphic aReturnGraphic;
209
210 Bitmap aBitmap(aGraphic.GetBitmap());
211 if (aBitmap.HasAlpha())
212 {
213 const AlphaMask aMask(aBitmap.CreateAlphaMask());
214
215 Bitmap aTmpBmp(aBitmap.CreateColorBitmap());
216 BitmapFilter::Filter(aTmpBmp, BitmapMonochromeFilter{ nThreshold });
217
218 aReturnGraphic = ::Graphic(BitmapEx(aTmpBmp, aMask));
219 }
220 else
221 {
222 BitmapFilter::Filter(aBitmap, BitmapMonochromeFilter{ nThreshold });
223 aReturnGraphic = ::Graphic(aBitmap);
224 }
225 aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
226 return aReturnGraphic.GetXGraphic();
227 }
228 return xGraphic;
229 }
230
lclCheckAndApplyChangeColorTransform(const BlipFillProperties & aBlipProps,uno::Reference<graphic::XGraphic> const & xGraphic,const GraphicHelper & rGraphicHelper,const::Color nPhClr)231 Reference< XGraphic > lclCheckAndApplyChangeColorTransform(const BlipFillProperties &aBlipProps, uno::Reference<graphic::XGraphic> const & xGraphic,
232 const GraphicHelper& rGraphicHelper, const ::Color nPhClr)
233 {
234 if( aBlipProps.maColorChangeFrom.isUsed() && aBlipProps.maColorChangeTo.isUsed() )
235 {
236 ::Color nFromColor = aBlipProps.maColorChangeFrom.getColor( rGraphicHelper, nPhClr );
237 ::Color nToColor = aBlipProps.maColorChangeTo.getColor( rGraphicHelper, nPhClr );
238 if ( (nFromColor != nToColor) || aBlipProps.maColorChangeTo.hasTransparency() )
239 {
240 sal_Int16 nToTransparence = aBlipProps.maColorChangeTo.getTransparency();
241 sal_Int8 nToAlpha = static_cast< sal_Int8 >( (100 - nToTransparence) * 2.55 );
242
243 sal_uInt8 nTolerance = 9;
244 Graphic aGraphic{ xGraphic };
245 if( aGraphic.IsGfxLink() )
246 {
247 // tdf#149670: Try to guess tolerance depending on image format
248 switch (aGraphic.GetGfxLink().GetType())
249 {
250 case GfxLinkType::NativeJpg:
251 nTolerance = 15;
252 break;
253 case GfxLinkType::NativePng:
254 case GfxLinkType::NativeTif:
255 nTolerance = 1;
256 break;
257 case GfxLinkType::NativeBmp:
258 nTolerance = 0;
259 break;
260 default:
261 break;
262 }
263 }
264
265 uno::Reference<graphic::XGraphicTransformer> xTransformer(aBlipProps.mxFillGraphic, uno::UNO_QUERY);
266 if (xTransformer.is())
267 return xTransformer->colorChange(xGraphic, sal_Int32(nFromColor), nTolerance, sal_Int32(nToColor), nToAlpha);
268 }
269 }
270 return xGraphic;
271 }
272
applyBrightnessContrast(uno::Reference<graphic::XGraphic> const & xGraphic,sal_Int32 brightness,sal_Int32 contrast)273 uno::Reference<graphic::XGraphic> applyBrightnessContrast(uno::Reference<graphic::XGraphic> const & xGraphic, sal_Int32 brightness, sal_Int32 contrast)
274 {
275 uno::Reference<graphic::XGraphicTransformer> xTransformer(xGraphic, uno::UNO_QUERY);
276 if (xTransformer.is())
277 return xTransformer->applyBrightnessContrast(xGraphic, brightness, contrast, true);
278 return xGraphic;
279 }
280
lclGetBitmapMode(sal_Int32 nToken)281 BitmapMode lclGetBitmapMode( sal_Int32 nToken )
282 {
283 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
284 switch( nToken )
285 {
286 case XML_tile: return BitmapMode_REPEAT;
287 case XML_stretch: return BitmapMode_STRETCH;
288 }
289
290 // tdf#128596 Default value is XML_tile for MSO.
291 return BitmapMode_REPEAT;
292 }
293
lclGetRectanglePoint(sal_Int32 nToken)294 RectanglePoint lclGetRectanglePoint( sal_Int32 nToken )
295 {
296 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
297 switch( nToken )
298 {
299 case XML_tl: return RectanglePoint_LEFT_TOP;
300 case XML_t: return RectanglePoint_MIDDLE_TOP;
301 case XML_tr: return RectanglePoint_RIGHT_TOP;
302 case XML_l: return RectanglePoint_LEFT_MIDDLE;
303 case XML_ctr: return RectanglePoint_MIDDLE_MIDDLE;
304 case XML_r: return RectanglePoint_RIGHT_MIDDLE;
305 case XML_bl: return RectanglePoint_LEFT_BOTTOM;
306 case XML_b: return RectanglePoint_MIDDLE_BOTTOM;
307 case XML_br: return RectanglePoint_RIGHT_BOTTOM;
308 }
309 return RectanglePoint_LEFT_TOP;
310 }
311
lclGetOriginalSize(const GraphicHelper & rGraphicHelper,const Reference<XGraphic> & rxGraphic)312 awt::Size lclGetOriginalSize( const GraphicHelper& rGraphicHelper, const Reference< XGraphic >& rxGraphic )
313 {
314 awt::Size aSizeHmm( 0, 0 );
315 try
316 {
317 Reference< beans::XPropertySet > xGraphicPropertySet( rxGraphic, UNO_QUERY_THROW );
318 if( xGraphicPropertySet->getPropertyValue( u"Size100thMM"_ustr ) >>= aSizeHmm )
319 {
320 if( !aSizeHmm.Width && !aSizeHmm.Height )
321 { // MAPMODE_PIXEL USED :-(
322 awt::Size aSourceSizePixel( 0, 0 );
323 if( xGraphicPropertySet->getPropertyValue( u"SizePixel"_ustr ) >>= aSourceSizePixel )
324 aSizeHmm = rGraphicHelper.convertScreenPixelToHmm( aSourceSizePixel );
325 }
326 }
327 }
328 catch( Exception& )
329 {
330 }
331 return aSizeHmm;
332 }
333
334 } // namespace
335
assignUsed(const GradientFillProperties & rSourceProps)336 void GradientFillProperties::assignUsed( const GradientFillProperties& rSourceProps )
337 {
338 if( !rSourceProps.maGradientStops.empty() )
339 maGradientStops = rSourceProps.maGradientStops;
340 assignIfUsed( moFillToRect, rSourceProps.moFillToRect );
341 assignIfUsed( moTileRect, rSourceProps.moTileRect );
342 assignIfUsed( moGradientPath, rSourceProps.moGradientPath );
343 assignIfUsed( moShadeAngle, rSourceProps.moShadeAngle );
344 assignIfUsed( moShadeFlip, rSourceProps.moShadeFlip );
345 assignIfUsed( moShadeScaled, rSourceProps.moShadeScaled );
346 assignIfUsed( moRotateWithShape, rSourceProps.moRotateWithShape );
347 }
348
assignUsed(const PatternFillProperties & rSourceProps)349 void PatternFillProperties::assignUsed( const PatternFillProperties& rSourceProps )
350 {
351 maPattFgColor.assignIfUsed( rSourceProps.maPattFgColor );
352 maPattBgColor.assignIfUsed( rSourceProps.maPattBgColor );
353 assignIfUsed( moPattPreset, rSourceProps.moPattPreset );
354 }
355
assignUsed(const BlipFillProperties & rSourceProps)356 void BlipFillProperties::assignUsed( const BlipFillProperties& rSourceProps )
357 {
358 if(rSourceProps.mxFillGraphic.is())
359 mxFillGraphic = rSourceProps.mxFillGraphic;
360 assignIfUsed( moBitmapMode, rSourceProps.moBitmapMode );
361 assignIfUsed( moFillRect, rSourceProps.moFillRect );
362 assignIfUsed( moTileOffsetX, rSourceProps.moTileOffsetX );
363 assignIfUsed( moTileOffsetY, rSourceProps.moTileOffsetY );
364 assignIfUsed( moTileScaleX, rSourceProps.moTileScaleX );
365 assignIfUsed( moTileScaleY, rSourceProps.moTileScaleY );
366 assignIfUsed( moTileAlign, rSourceProps.moTileAlign );
367 assignIfUsed( moTileFlip, rSourceProps.moTileFlip );
368 assignIfUsed( moRotateWithShape, rSourceProps.moRotateWithShape );
369 assignIfUsed( moColorEffect, rSourceProps.moColorEffect );
370 assignIfUsed( moBrightness, rSourceProps.moBrightness );
371 assignIfUsed( moContrast, rSourceProps.moContrast );
372 assignIfUsed( moBiLevelThreshold, rSourceProps.moBiLevelThreshold );
373 maColorChangeFrom.assignIfUsed( rSourceProps.maColorChangeFrom );
374 maColorChangeTo.assignIfUsed( rSourceProps.maColorChangeTo );
375 maDuotoneColors[0].assignIfUsed( rSourceProps.maDuotoneColors[0] );
376 maDuotoneColors[1].assignIfUsed( rSourceProps.maDuotoneColors[1] );
377 maEffect.assignUsed( rSourceProps.maEffect );
378 assignIfUsed(moAlphaModFix, rSourceProps.moAlphaModFix);
379 }
380
assignUsed(const FillProperties & rSourceProps)381 void FillProperties::assignUsed( const FillProperties& rSourceProps )
382 {
383 assignIfUsed( moFillType, rSourceProps.moFillType );
384 maFillColor.assignIfUsed( rSourceProps.maFillColor );
385 assignIfUsed( moUseBgFill, rSourceProps.moUseBgFill );
386 maGradientProps.assignUsed( rSourceProps.maGradientProps );
387 maPatternProps.assignUsed( rSourceProps.maPatternProps );
388 maBlipProps.assignUsed( rSourceProps.maBlipProps );
389 }
390
getBestSolidColor() const391 Color FillProperties::getBestSolidColor() const
392 {
393 Color aSolidColor;
394 if( moFillType.has_value() ) switch( moFillType.value() )
395 {
396 case XML_solidFill:
397 aSolidColor = maFillColor;
398 break;
399 case XML_gradFill:
400 if( !maGradientProps.maGradientStops.empty() )
401 {
402 GradientFillProperties::GradientStopMap::const_iterator aGradientStop =
403 maGradientProps.maGradientStops.begin();
404 if (maGradientProps.maGradientStops.size() > 2)
405 ++aGradientStop;
406 aSolidColor = aGradientStop->second;
407 }
408 break;
409 case XML_pattFill:
410 aSolidColor = maPatternProps.maPattBgColor.isUsed() ? maPatternProps.maPattBgColor : maPatternProps.maPattFgColor;
411 break;
412 }
413 return aSolidColor;
414 }
415
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) const416 void FillProperties::pushToPropMap(ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper,
417 sal_Int32 nShapeRotation, ::Color nPhClr,
418 const css::awt::Size& rSize, sal_Int16 nPhClrTheme, bool bFlipH,
419 bool bFlipV, bool bIsCustomShape) const
420 {
421 if( !moFillType.has_value() )
422 return;
423
424 FillStyle eFillStyle = FillStyle_NONE;
425 OSL_ASSERT((moFillType.value() & sal_Int32(0xFFFF0000))==0);
426 switch( moFillType.value() )
427 {
428 case XML_noFill:
429 {
430 eFillStyle = FillStyle_NONE;
431 rPropMap.setProperty(ShapeProperty::FillUseSlideBackground, moUseBgFill.value_or(false));
432 }
433 break;
434
435 case XML_solidFill:
436 if( maFillColor.isUsed() )
437 {
438 ::Color aFillColor = maFillColor.getColor(rGraphicHelper, nPhClr);
439 rPropMap.setProperty(ShapeProperty::FillColor, aFillColor);
440 if( maFillColor.hasTransparency() )
441 rPropMap.setProperty( ShapeProperty::FillTransparency, maFillColor.getTransparency() );
442
443 model::ComplexColor aComplexColor;
444 if (aFillColor == nPhClr)
445 {
446 aComplexColor.setThemeColor(model::convertToThemeColorType(nPhClrTheme));
447 }
448 else
449 {
450 aComplexColor = maFillColor.getComplexColor();
451 OUString sColorName = getBestSolidColor().getSchemeColorName();
452 sal_Int32 nToken = Color::getColorMapToken(sColorName);
453 if (nToken != -1)
454 {
455 rGraphicHelper.getSchemeColorToken(nToken);
456 model::ThemeColorType eThemeColorType = schemeTokenToThemeColorType(nToken);
457 aComplexColor.setThemeColor(eThemeColorType);
458 }
459 }
460 rPropMap.setProperty(PROP_FillComplexColor, model::color::createXComplexColor(aComplexColor));
461
462 eFillStyle = FillStyle_SOLID;
463 }
464 break;
465
466 case XML_gradFill:
467 // do not create gradient struct if property is not supported...
468 if( rPropMap.supportsProperty( ShapeProperty::FillGradient ) )
469 {
470 // prepare ColorStops
471 basegfx::BColorStops aColorStops;
472 basegfx::BColorStops aTransparencyStops;
473 bool bContainsTransparency(false);
474
475 // convert to BColorStops, check for contained transparency
476 for (const auto& rCandidate : maGradientProps.maGradientStops)
477 {
478 const ::Color aColor(rCandidate.second.getColor(rGraphicHelper, nPhClr));
479 aColorStops.emplace_back(rCandidate.first, aColor.getBColor());
480 bContainsTransparency = bContainsTransparency || rCandidate.second.hasTransparency();
481 }
482
483 // if we have transparency, convert to BColorStops
484 if (bContainsTransparency)
485 {
486 for (const auto& rCandidate : maGradientProps.maGradientStops)
487 {
488 const double fTrans(rCandidate.second.getTransparency() * (1.0/100.0));
489 aTransparencyStops.emplace_back(rCandidate.first, basegfx::BColor(fTrans, fTrans, fTrans));
490 }
491 }
492
493 // prepare BGradient with some defaults
494 // CAUTION: This used awt::Gradient2 before who's empty constructor
495 // (see workdir/UnoApiHeadersTarget/offapi/normal/com/sun/
496 // star/awt/Gradient.hpp) initializes all to zeros, so reflect
497 // this here. OTOH set all that were set, e.g. Start/EndIntens
498 // were set to 100, so just use default of BGradient constructor
499 basegfx::BGradient aGradient(
500 aColorStops,
501 awt::GradientStyle_LINEAR,
502 Degree10(900),
503 0, // border
504 0, // OfsX -> 0, not 50 (!)
505 0); // OfsY -> 0, not 50 (!)
506
507 // "rotate with shape" set to false -> do not rotate
508 if (!maGradientProps.moRotateWithShape.value_or(true))
509 {
510 nShapeRotation = 0;
511 }
512
513 if (maGradientProps.moGradientPath.has_value())
514 {
515 IntegerRectangle2D aFillToRect = maGradientProps.moFillToRect.value_or( IntegerRectangle2D( 0, 0, MAX_PERCENT, MAX_PERCENT ) );
516 sal_Int32 nCenterX = (MAX_PERCENT + aFillToRect.X1 - aFillToRect.X2) / 2;
517 aGradient.SetXOffset(getLimitedValue<sal_Int16, sal_Int32>(
518 nCenterX / PER_PERCENT, 0, 100));
519 sal_Int32 nCenterY = (MAX_PERCENT + aFillToRect.Y1 - aFillToRect.Y2) / 2;
520 aGradient.SetYOffset(getLimitedValue<sal_Int16, sal_Int32>(
521 nCenterY / PER_PERCENT, 0, 100));
522
523 // FIXME tdf#166140: Size of gradient is smaller than in MSO
524 if( maGradientProps.moGradientPath.value() == XML_circle )
525 {
526 aGradient.SetGradientStyle(awt::GradientStyle_RADIAL);
527 }
528 else
529 {
530 // XML_rect or XML_shape, but the latter is not implemented.
531 aGradient.SetGradientStyle(awt::GradientStyle_RECT);
532 }
533
534 aColorStops.reverseColorStops();
535 aGradient.SetColorStops(aColorStops);
536 aTransparencyStops.reverseColorStops();
537 }
538 else if (!maGradientProps.maGradientStops.empty())
539 {
540 // aGradient.SetGradientStyle(awt::GradientStyle_LINEAR);
541 sal_Int32 nShadeAngle(maGradientProps.moShadeAngle.value_or( 0 ));
542 // Adjust for flips
543 if ( bFlipH )
544 nShadeAngle = 180*60000 - nShadeAngle;
545 if ( bFlipV )
546 nShadeAngle = -nShadeAngle;
547 const sal_Int32 nDmlAngle = nShadeAngle + nShapeRotation;
548
549 // convert DrawingML angle (in 1/60000 degrees) to API angle (in 1/10 degrees)
550 aGradient.SetAngle(Degree10(static_cast< sal_Int16 >( (8100 - (nDmlAngle / (PER_DEGREE / 10))) % 3600 )));
551
552 // If this is symmetrical, set it as an axial gradient for better UI/export.
553 // There were chart2 unit test failures when doing this to transparent gradients
554 // so just avoid that case.
555 if (!bContainsTransparency)
556 aGradient.tryToConvertToAxial();
557 }
558
559 if (awt::GradientStyle_RECT == aGradient.GetGradientStyle())
560 {
561 // MCGR: tdf#155362: better support border
562 // CAUTION: Need to handle TransparencyStops if used
563 aGradient.tryToRecreateBorder(aTransparencyStops.empty() ? nullptr : &aTransparencyStops);
564 }
565
566 // push gradient or named gradient to property map
567 if (rPropMap.setProperty(ShapeProperty::FillGradient, model::gradient::createUnoGradient2(aGradient)))
568 {
569 eFillStyle = FillStyle_GRADIENT;
570 }
571
572 // push gradient transparency to property map if it exists
573 if (!aTransparencyStops.empty())
574 {
575 aGradient.SetColorStops(aTransparencyStops);
576 rPropMap.setProperty(ShapeProperty::GradientTransparency, model::gradient::createUnoGradient2(aGradient));
577 }
578 }
579 break;
580
581 case XML_blipFill:
582 // do not start complex graphic transformation if property is not supported...
583 if (maBlipProps.mxFillGraphic.is() && rPropMap.supportsProperty(ShapeProperty::FillBitmap))
584 {
585 uno::Reference<graphic::XGraphic> xGraphic = lclCheckAndApplyDuotoneTransform(maBlipProps, maBlipProps.mxFillGraphic, rGraphicHelper, nPhClr);
586 // TODO: "rotate with shape" is not possible with our current core
587
588 if (xGraphic.is())
589 {
590 if (maBlipProps.moColorEffect.value_or(XML_TOKEN_INVALID) == XML_grayscl)
591 xGraphic = lclGreysScaleGraphic(xGraphic);
592
593 if (rPropMap.supportsProperty(ShapeProperty::FillBitmapName) &&
594 rPropMap.setProperty(ShapeProperty::FillBitmapName, xGraphic))
595 {
596 eFillStyle = FillStyle_BITMAP;
597 }
598 else if (rPropMap.setProperty(ShapeProperty::FillBitmap, xGraphic))
599 {
600 eFillStyle = FillStyle_BITMAP;
601 }
602 }
603
604 // set other bitmap properties, if bitmap has been inserted into the map
605 if( eFillStyle == FillStyle_BITMAP )
606 {
607 // bitmap mode (single, repeat, stretch)
608 BitmapMode eBitmapMode = lclGetBitmapMode( maBlipProps.moBitmapMode.value_or( XML_TOKEN_INVALID ) );
609
610 // additional settings for repeated bitmap
611 if( eBitmapMode == BitmapMode_REPEAT )
612 {
613 // anchor position inside bitmap
614 RectanglePoint eRectPoint = lclGetRectanglePoint( maBlipProps.moTileAlign.value_or( XML_tl ) );
615 rPropMap.setProperty( ShapeProperty::FillBitmapRectanglePoint, eRectPoint );
616
617 awt::Size aOriginalSize = lclGetOriginalSize(rGraphicHelper, maBlipProps.mxFillGraphic);
618 if( (aOriginalSize.Width > 0) && (aOriginalSize.Height > 0) )
619 {
620 // size of one bitmap tile (given as 1/1000 percent of bitmap size), convert to 1/100 mm
621 double fScaleX = maBlipProps.moTileScaleX.value_or( MAX_PERCENT ) / static_cast< double >( MAX_PERCENT );
622 sal_Int32 nFillBmpSizeX = getLimitedValue< sal_Int32, double >( aOriginalSize.Width * fScaleX, 1, SAL_MAX_INT32 );
623 rPropMap.setProperty( ShapeProperty::FillBitmapSizeX, nFillBmpSizeX );
624 double fScaleY = maBlipProps.moTileScaleY.value_or( MAX_PERCENT ) / static_cast< double >( MAX_PERCENT );
625 sal_Int32 nFillBmpSizeY = getLimitedValue< sal_Int32, double >( aOriginalSize.Height * fScaleY, 1, SAL_MAX_INT32 );
626 rPropMap.setProperty( ShapeProperty::FillBitmapSizeY, nFillBmpSizeY );
627
628 awt::Size aBmpSize(nFillBmpSizeX, nFillBmpSizeY);
629 // offset of the first bitmap tile (given as EMUs), convert to percent
630 sal_Int16 nTileOffsetX = getDoubleIntervalValue< sal_Int16 >(std::round(maBlipProps.moTileOffsetX.value_or( 0 ) / 3.6 / aBmpSize.Width), 0, 100 );
631 rPropMap.setProperty( ShapeProperty::FillBitmapOffsetX, nTileOffsetX );
632 sal_Int16 nTileOffsetY = getDoubleIntervalValue< sal_Int16 >(std::round(maBlipProps.moTileOffsetY.value_or( 0 ) / 3.6 / aBmpSize.Height), 0, 100 );
633 rPropMap.setProperty( ShapeProperty::FillBitmapOffsetY, nTileOffsetY );
634 }
635 }
636 else if ( eBitmapMode == BitmapMode_STRETCH && maBlipProps.moFillRect.has_value() )
637 {
638 geometry::IntegerRectangle2D aFillRect( maBlipProps.moFillRect.value() );
639 awt::Size aOriginalSize( rGraphicHelper.getOriginalSize( xGraphic ) );
640 if ( aOriginalSize.Width && aOriginalSize.Height )
641 {
642 text::GraphicCrop aGraphCrop( 0, 0, 0, 0 );
643 if ( aFillRect.X1 )
644 aGraphCrop.Left = o3tl::convert(aFillRect.X1, aOriginalSize.Width, MAX_PERCENT);
645 if ( aFillRect.Y1 )
646 aGraphCrop.Top = o3tl::convert(aFillRect.Y1, aOriginalSize.Height, MAX_PERCENT);
647 if ( aFillRect.X2 )
648 aGraphCrop.Right = o3tl::convert(aFillRect.X2, aOriginalSize.Width, MAX_PERCENT);
649 if ( aFillRect.Y2 )
650 aGraphCrop.Bottom = o3tl::convert(aFillRect.Y2, aOriginalSize.Height, MAX_PERCENT);
651
652 bool bHasCropValues = aGraphCrop.Left != 0 || aGraphCrop.Right !=0 || aGraphCrop.Top != 0 || aGraphCrop.Bottom != 0;
653 // Negative GraphicCrop values means "crop" here.
654 bool bNeedCrop = aGraphCrop.Left <= 0 && aGraphCrop.Right <= 0 && aGraphCrop.Top <= 0 && aGraphCrop.Bottom <= 0;
655
656 if (bHasCropValues)
657 {
658 if (bIsCustomShape && bNeedCrop)
659 {
660 // Physically crop the image
661 // In this case, don't set the PROP_GraphicCrop because that
662 // would lead to applying the crop twice after roundtrip
663 xGraphic = lclCropGraphic(xGraphic, CropQuotientsFromFillRect(aFillRect));
664 if (rPropMap.supportsProperty(ShapeProperty::FillBitmapName))
665 rPropMap.setProperty(ShapeProperty::FillBitmapName, xGraphic);
666 else
667 rPropMap.setProperty(ShapeProperty::FillBitmap, xGraphic);
668 }
669 else if ((aFillRect.X1 != 0 && aFillRect.X2 != 0
670 && aFillRect.X1 != aFillRect.X2)
671 || (aFillRect.Y1 != 0 && aFillRect.Y2 != 0
672 && aFillRect.Y1 != aFillRect.Y2))
673 {
674 rPropMap.setProperty(PROP_GraphicCrop, aGraphCrop);
675 }
676 else
677 {
678 double nL = aFillRect.X1 / static_cast<double>(MAX_PERCENT);
679 double nT = aFillRect.Y1 / static_cast<double>(MAX_PERCENT);
680 double nR = aFillRect.X2 / static_cast<double>(MAX_PERCENT);
681 double nB = aFillRect.Y2 / static_cast<double>(MAX_PERCENT);
682
683 sal_Int32 nSizeX;
684 if (nL || nR)
685 nSizeX = rSize.Width * (1 - (nL + nR));
686 else
687 nSizeX = rSize.Width;
688 rPropMap.setProperty(ShapeProperty::FillBitmapSizeX, nSizeX);
689
690 sal_Int32 nSizeY;
691 if (nT || nB)
692 nSizeY = rSize.Height * (1 - (nT + nB));
693 else
694 nSizeY = rSize.Height;
695 rPropMap.setProperty(ShapeProperty::FillBitmapSizeY, nSizeY);
696
697 RectanglePoint eRectPoint;
698 if (!aFillRect.X1 && aFillRect.X2)
699 {
700 if (!aFillRect.Y1 && aFillRect.Y2)
701 eRectPoint = lclGetRectanglePoint(XML_tl);
702 else if (aFillRect.Y1 && !aFillRect.Y2)
703 eRectPoint = lclGetRectanglePoint(XML_bl);
704 else
705 eRectPoint = lclGetRectanglePoint(XML_l);
706 }
707 else if (aFillRect.X1 && !aFillRect.X2)
708 {
709 if (!aFillRect.Y1 && aFillRect.Y2)
710 eRectPoint = lclGetRectanglePoint(XML_tr);
711 else if (aFillRect.Y1 && !aFillRect.Y2)
712 eRectPoint = lclGetRectanglePoint(XML_br);
713 else
714 eRectPoint = lclGetRectanglePoint(XML_r);
715 }
716 else
717 {
718 if (!aFillRect.Y1 && aFillRect.Y2)
719 eRectPoint = lclGetRectanglePoint(XML_t);
720 else if (aFillRect.Y1 && !aFillRect.Y2)
721 eRectPoint = lclGetRectanglePoint(XML_b);
722 else
723 eRectPoint = lclGetRectanglePoint(XML_ctr);
724 }
725 rPropMap.setProperty(ShapeProperty::FillBitmapRectanglePoint, eRectPoint);
726 eBitmapMode = BitmapMode_NO_REPEAT;
727 }
728 }
729 }
730 }
731 rPropMap.setProperty(ShapeProperty::FillBitmapMode, eBitmapMode);
732 }
733
734 if (maBlipProps.moAlphaModFix.has_value())
735 rPropMap.setProperty(ShapeProperty::FillTransparency, static_cast<sal_Int16>(100 - (maBlipProps.moAlphaModFix.value() / PER_PERCENT)));
736 }
737 break;
738
739 case XML_pattFill:
740 {
741 if( rPropMap.supportsProperty( ShapeProperty::FillHatch ) )
742 {
743 Color aColor( maPatternProps.maPattFgColor );
744 if( aColor.isUsed() && maPatternProps.moPattPreset.has_value() )
745 {
746 eFillStyle = FillStyle_HATCH;
747 rPropMap.setProperty( ShapeProperty::FillHatch, createHatch( maPatternProps.moPattPreset.value(), aColor.getColor( rGraphicHelper, nPhClr ) ) );
748 if( aColor.hasTransparency() )
749 rPropMap.setProperty( ShapeProperty::FillTransparency, aColor.getTransparency() );
750
751 // Set background color for hatch
752 if(maPatternProps.maPattBgColor.isUsed())
753 {
754 aColor = maPatternProps.maPattBgColor;
755 rPropMap.setProperty( ShapeProperty::FillBackground, aColor.getTransparency() != 100 );
756 rPropMap.setProperty( ShapeProperty::FillColor, aColor.getColor( rGraphicHelper, nPhClr ) );
757 }
758 }
759 else if ( maPatternProps.maPattBgColor.isUsed() )
760 {
761 aColor = maPatternProps.maPattBgColor;
762 rPropMap.setProperty( ShapeProperty::FillColor, aColor.getColor( rGraphicHelper, nPhClr ) );
763 if( aColor.hasTransparency() )
764 rPropMap.setProperty( ShapeProperty::FillTransparency, aColor.getTransparency() );
765 eFillStyle = FillStyle_SOLID;
766 }
767 }
768 }
769 break;
770
771 case XML_grpFill:
772 // todo
773 eFillStyle = FillStyle_NONE;
774 break;
775 }
776
777 // set final fill style property
778 rPropMap.setProperty( ShapeProperty::FillStyle, eFillStyle );
779 }
780
pushToPropMap(PropertyMap & rPropMap,const GraphicHelper & rGraphicHelper,bool bFlipH,bool bFlipV) const781 void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const GraphicHelper& rGraphicHelper, bool bFlipH, bool bFlipV) const
782 {
783 sal_Int16 nBrightness = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moBrightness.value_or( 0 ) / PER_PERCENT, -100, 100 );
784 sal_Int16 nContrast = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moContrast.value_or( 0 ) / PER_PERCENT, -100, 100 );
785 ColorMode eColorMode = ColorMode_STANDARD;
786
787 switch( maBlipProps.moColorEffect.value_or( XML_TOKEN_INVALID ) )
788 {
789 case XML_biLevel: eColorMode = ColorMode_MONO; break;
790 case XML_grayscl: eColorMode = ColorMode_GREYS; break;
791 }
792
793 if (maBlipProps.mxFillGraphic.is())
794 {
795 // created transformed graphic
796 uno::Reference<graphic::XGraphic> xGraphic = lclCheckAndApplyChangeColorTransform(maBlipProps, maBlipProps.mxFillGraphic, rGraphicHelper, API_RGB_TRANSPARENT);
797 xGraphic = lclCheckAndApplyDuotoneTransform(maBlipProps, xGraphic, rGraphicHelper, API_RGB_TRANSPARENT);
798
799 if( eColorMode == ColorMode_MONO )
800 {
801 // ColorMode_MONO is the same with MSO's biLevel with 50000 (50%) threshold,
802 // when threshold isn't 50000 bake the effect instead.
803 if( maBlipProps.moBiLevelThreshold != 50000 )
804 {
805 xGraphic = lclApplyBlackWhiteEffect(maBlipProps, xGraphic);
806 eColorMode = ColorMode_STANDARD;
807 }
808 }
809
810 if (eColorMode == ColorMode_STANDARD && nBrightness == 70 && nContrast == -70)
811 {
812 // map MSO 'washout' to our Watermark colormode
813 eColorMode = ColorMode_WATERMARK;
814 nBrightness = 0;
815 nContrast = 0;
816 }
817 else if( nBrightness != 0 && nContrast != 0 )
818 {
819 // MSO uses a different algorithm for contrast+brightness, LO applies contrast before brightness,
820 // while MSO apparently applies half of brightness before contrast and half after. So if only
821 // contrast or brightness need to be altered, the result is the same, but if both are involved,
822 // there's no way to map that, so just force a conversion of the image.
823 xGraphic = applyBrightnessContrast( xGraphic, nBrightness, nContrast );
824 nBrightness = 0;
825 nContrast = 0;
826 }
827
828 // cropping
829 if ( maBlipProps.moClipRect.has_value() )
830 {
831 geometry::IntegerRectangle2D oClipRect( maBlipProps.moClipRect.value() );
832 awt::Size aOriginalSize( rGraphicHelper.getOriginalSize( xGraphic ) );
833
834 if (aOriginalSize.Width <= 0 || aOriginalSize.Height <= 0)
835 {
836 // VectorGraphic Objects need the correct object size for cropping
837 Graphic aGraphic(xGraphic);
838 if (aGraphic.getVectorGraphicData())
839 {
840 Size aPrefSize = aGraphic.GetPrefSize();
841 aOriginalSize.Height = static_cast<sal_Int32>(aPrefSize.getHeight());
842 aOriginalSize.Width = static_cast<sal_Int32>(aPrefSize.getWidth());
843 }
844 }
845
846 if (aOriginalSize.Width > 0 && aOriginalSize.Height > 0)
847 {
848 text::GraphicCrop aGraphCrop( 0, 0, 0, 0 );
849 if ( oClipRect.X1 )
850 aGraphCrop.Left = o3tl::convert(oClipRect.X1, aOriginalSize.Width, MAX_PERCENT);
851 if ( oClipRect.Y1 )
852 aGraphCrop.Top = o3tl::convert(oClipRect.Y1, aOriginalSize.Height, MAX_PERCENT);
853 if ( oClipRect.X2 )
854 aGraphCrop.Right = o3tl::convert(oClipRect.X2, aOriginalSize.Width, MAX_PERCENT);
855 if ( oClipRect.Y2 )
856 aGraphCrop.Bottom = o3tl::convert(oClipRect.Y2, aOriginalSize.Height, MAX_PERCENT);
857 rPropMap.setProperty(PROP_GraphicCrop, aGraphCrop);
858
859 if(mbIsCustomShape)
860 {
861 // Positive GraphicCrop values means "crop" here.
862 if (aGraphCrop.Left > 0 || aGraphCrop.Right > 0 || aGraphCrop.Top > 0 || aGraphCrop.Bottom > 0)
863 xGraphic = lclCropGraphic(xGraphic, CropQuotientsFromSrcRect(oClipRect));
864 }
865 }
866 }
867
868 if(mbIsCustomShape)
869 {
870 // it is a cropped graphic.
871 rPropMap.setProperty(PROP_FillStyle, FillStyle_BITMAP);
872 rPropMap.setProperty(PROP_FillBitmapMode, BitmapMode_STRETCH);
873
874 // It is a bitmap filled and rotated graphic.
875 // When custom shape is rotated, bitmap have to be rotated too.
876 // Only in extruded mode the bitmap is transformed together with the shape
877 if(rPropMap.hasProperty(PROP_RotateAngle) && !mbIsExtruded)
878 {
879 tools::Long nAngle = rPropMap.getProperty(PROP_RotateAngle).get<tools::Long>();
880 xGraphic = lclRotateGraphic(xGraphic, Degree10(nAngle/10) );
881 }
882
883 // We have not core feature that flips graphic in the shape.
884 // Here we are applying flip property to bitmap directly.
885 if((bFlipH || bFlipV) && !mbIsExtruded)
886 xGraphic = lclMirrorGraphic(xGraphic, bFlipH, bFlipV );
887
888 if(eColorMode == ColorMode_GREYS)
889 xGraphic = lclGreysScaleGraphic( xGraphic );
890
891 rPropMap.setProperty(PROP_FillBitmap, xGraphic);
892 }
893 else
894 rPropMap.setProperty(PROP_Graphic, xGraphic);
895
896
897 if ( maBlipProps.moAlphaModFix.has_value() )
898 {
899 rPropMap.setProperty(
900 mbIsCustomShape ? PROP_FillTransparence : PROP_Transparency,
901 static_cast<sal_Int16>(100 - (maBlipProps.moAlphaModFix.value() / PER_PERCENT)));
902 }
903 }
904 rPropMap.setProperty(PROP_GraphicColorMode, eColorMode);
905
906 // brightness and contrast
907 if( nBrightness != 0 )
908 rPropMap.setProperty(PROP_AdjustLuminance, nBrightness);
909 if( nContrast != 0 )
910 rPropMap.setProperty(PROP_AdjustContrast, nContrast);
911
912 // Media content
913 if (!m_sMediaPackageURL.isEmpty())
914 {
915 rPropMap.setProperty(PROP_MediaURL, m_sMediaPackageURL);
916 if (m_xMediaStream.is())
917 rPropMap.setProperty(PROP_PrivateStream, m_xMediaStream);
918 }
919 }
920
isEmpty() const921 bool ArtisticEffectProperties::isEmpty() const
922 {
923 return msName.isEmpty();
924 }
925
getEffect()926 css::beans::PropertyValue ArtisticEffectProperties::getEffect()
927 {
928 css::beans::PropertyValue aRet;
929 if( msName.isEmpty() )
930 return aRet;
931
932 css::uno::Sequence< css::beans::PropertyValue > aSeq( maAttribs.size() + 1 );
933 auto pSeq = aSeq.getArray();
934 sal_uInt32 i = 0;
935 for (auto const& attrib : maAttribs)
936 {
937 pSeq[i].Name = attrib.first;
938 pSeq[i].Value = attrib.second;
939 i++;
940 }
941
942 if( mrOleObjectInfo.maEmbeddedData.hasElements() )
943 {
944 css::uno::Sequence< css::beans::PropertyValue > aGraphicSeq{
945 comphelper::makePropertyValue(u"Id"_ustr, mrOleObjectInfo.maProgId),
946 comphelper::makePropertyValue(u"Data"_ustr, mrOleObjectInfo.maEmbeddedData)
947 };
948
949 pSeq[i].Name = "OriginalGraphic";
950 pSeq[i].Value <<= aGraphicSeq;
951 }
952
953 aRet.Name = msName;
954 aRet.Value <<= aSeq;
955
956 return aRet;
957 }
958
assignUsed(const ArtisticEffectProperties & rSourceProps)959 void ArtisticEffectProperties::assignUsed( const ArtisticEffectProperties& rSourceProps )
960 {
961 if( !rSourceProps.isEmpty() )
962 {
963 msName = rSourceProps.msName;
964 maAttribs = rSourceProps.maAttribs;
965 }
966 }
967
getEffectString(sal_Int32 nToken)968 OUString ArtisticEffectProperties::getEffectString( sal_Int32 nToken )
969 {
970 switch( nToken )
971 {
972 // effects
973 case OOX_TOKEN( a14, artisticBlur ): return u"artisticBlur"_ustr;
974 case OOX_TOKEN( a14, artisticCement ): return u"artisticCement"_ustr;
975 case OOX_TOKEN( a14, artisticChalkSketch ): return u"artisticChalkSketch"_ustr;
976 case OOX_TOKEN( a14, artisticCrisscrossEtching ): return u"artisticCrisscrossEtching"_ustr;
977 case OOX_TOKEN( a14, artisticCutout ): return u"artisticCutout"_ustr;
978 case OOX_TOKEN( a14, artisticFilmGrain ): return u"artisticFilmGrain"_ustr;
979 case OOX_TOKEN( a14, artisticGlass ): return u"artisticGlass"_ustr;
980 case OOX_TOKEN( a14, artisticGlowDiffused ): return u"artisticGlowDiffused"_ustr;
981 case OOX_TOKEN( a14, artisticGlowEdges ): return u"artisticGlowEdges"_ustr;
982 case OOX_TOKEN( a14, artisticLightScreen ): return u"artisticLightScreen"_ustr;
983 case OOX_TOKEN( a14, artisticLineDrawing ): return u"artisticLineDrawing"_ustr;
984 case OOX_TOKEN( a14, artisticMarker ): return u"artisticMarker"_ustr;
985 case OOX_TOKEN( a14, artisticMosiaicBubbles ): return u"artisticMosiaicBubbles"_ustr;
986 case OOX_TOKEN( a14, artisticPaintStrokes ): return u"artisticPaintStrokes"_ustr;
987 case OOX_TOKEN( a14, artisticPaintBrush ): return u"artisticPaintBrush"_ustr;
988 case OOX_TOKEN( a14, artisticPastelsSmooth ): return u"artisticPastelsSmooth"_ustr;
989 case OOX_TOKEN( a14, artisticPencilGrayscale ): return u"artisticPencilGrayscale"_ustr;
990 case OOX_TOKEN( a14, artisticPencilSketch ): return u"artisticPencilSketch"_ustr;
991 case OOX_TOKEN( a14, artisticPhotocopy ): return u"artisticPhotocopy"_ustr;
992 case OOX_TOKEN( a14, artisticPlasticWrap ): return u"artisticPlasticWrap"_ustr;
993 case OOX_TOKEN( a14, artisticTexturizer ): return u"artisticTexturizer"_ustr;
994 case OOX_TOKEN( a14, artisticWatercolorSponge ): return u"artisticWatercolorSponge"_ustr;
995 case OOX_TOKEN( a14, brightnessContrast ): return u"brightnessContrast"_ustr;
996 case OOX_TOKEN( a14, colorTemperature ): return u"colorTemperature"_ustr;
997 case OOX_TOKEN( a14, saturation ): return u"saturation"_ustr;
998 case OOX_TOKEN( a14, sharpenSoften ): return u"sharpenSoften"_ustr;
999
1000 // attributes
1001 case XML_visible: return u"visible"_ustr;
1002 case XML_trans: return u"trans"_ustr;
1003 case XML_crackSpacing: return u"crackSpacing"_ustr;
1004 case XML_pressure: return u"pressure"_ustr;
1005 case XML_numberOfShades: return u"numberOfShades"_ustr;
1006 case XML_grainSize: return u"grainSize"_ustr;
1007 case XML_intensity: return u"intensity"_ustr;
1008 case XML_smoothness: return u"smoothness"_ustr;
1009 case XML_gridSize: return u"gridSize"_ustr;
1010 case XML_pencilSize: return u"pencilSize"_ustr;
1011 case XML_size: return u"size"_ustr;
1012 case XML_brushSize: return u"brushSize"_ustr;
1013 case XML_scaling: return u"scaling"_ustr;
1014 case XML_detail: return u"detail"_ustr;
1015 case XML_bright: return u"bright"_ustr;
1016 case XML_contrast: return u"contrast"_ustr;
1017 case XML_colorTemp: return u"colorTemp"_ustr;
1018 case XML_sat: return u"sat"_ustr;
1019 case XML_amount: return u"amount"_ustr;
1020 }
1021 SAL_WARN( "oox.drawingml", "ArtisticEffectProperties::getEffectString: unexpected token " << nToken );
1022 return OUString();
1023 }
1024
1025 constexpr auto constEffectTokenForEffectNameMap = frozen::make_unordered_map<std::u16string_view, sal_Int32>(
1026 {
1027 // effects
1028 { u"artisticBlur", XML_artisticBlur },
1029 { u"artisticCement", XML_artisticCement },
1030 { u"artisticChalkSketch", XML_artisticChalkSketch },
1031 { u"artisticCrisscrossEtching", XML_artisticCrisscrossEtching },
1032 { u"artisticCutout", XML_artisticCutout },
1033 { u"artisticFilmGrain", XML_artisticFilmGrain },
1034 { u"artisticGlass", XML_artisticGlass },
1035 { u"artisticGlowDiffused", XML_artisticGlowDiffused },
1036 { u"artisticGlowEdges", XML_artisticGlowEdges },
1037 { u"artisticLightScreen", XML_artisticLightScreen },
1038 { u"artisticLineDrawing", XML_artisticLineDrawing },
1039 { u"artisticMarker", XML_artisticMarker },
1040 { u"artisticMosiaicBubbles", XML_artisticMosiaicBubbles },
1041 { u"artisticPaintStrokes", XML_artisticPaintStrokes },
1042 { u"artisticPaintBrush", XML_artisticPaintBrush },
1043 { u"artisticPastelsSmooth", XML_artisticPastelsSmooth },
1044 { u"artisticPencilGrayscale", XML_artisticPencilGrayscale },
1045 { u"artisticPencilSketch", XML_artisticPencilSketch },
1046 { u"artisticPhotocopy", XML_artisticPhotocopy },
1047 { u"artisticPlasticWrap", XML_artisticPlasticWrap },
1048 { u"artisticTexturizer", XML_artisticTexturizer },
1049 { u"artisticWatercolorSponge", XML_artisticWatercolorSponge },
1050 { u"brightnessContrast", XML_brightnessContrast },
1051 { u"colorTemperature", XML_colorTemperature },
1052 { u"saturation", XML_saturation },
1053 { u"sharpenSoften", XML_sharpenSoften },
1054
1055 // attributes
1056 { u"visible", XML_visible },
1057 { u"trans", XML_trans },
1058 { u"crackSpacing", XML_crackSpacing },
1059 { u"pressure", XML_pressure },
1060 { u"numberOfShades", XML_numberOfShades },
1061 { u"grainSize", XML_grainSize },
1062 { u"intensity", XML_intensity },
1063 { u"smoothness", XML_smoothness },
1064 { u"gridSize", XML_gridSize },
1065 { u"pencilSize", XML_pencilSize },
1066 { u"size", XML_size },
1067 { u"brushSize", XML_brushSize },
1068 { u"scaling", XML_scaling },
1069 { u"detail", XML_detail },
1070 { u"bright", XML_bright },
1071 { u"contrast", XML_contrast },
1072 { u"colorTemp", XML_colorTemp },
1073 { u"sat", XML_sat },
1074 { u"amount", XML_amount }
1075 });
1076
getEffectToken(const OUString & sName)1077 sal_Int32 ArtisticEffectProperties::getEffectToken(const OUString& sName)
1078 {
1079 auto const aIterator = constEffectTokenForEffectNameMap.find(sName);
1080
1081 if (aIterator != constEffectTokenForEffectNameMap.end())
1082 return aIterator->second;
1083
1084 SAL_WARN( "oox.drawingml", "ArtisticEffectProperties::getEffectToken - unexpected token name: " << sName );
1085 return XML_none;
1086 }
1087
1088 } // namespace oox
1089
1090 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1091