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 <sdr/primitive2d/sdrattributecreator.hxx>
21 #include <svl/itemset.hxx>
22 #include <svx/sdmetitm.hxx>
23 #include <svx/sdooitm.hxx>
24 #include <svx/sdprcitm.hxx>
25 #include <svx/xdef.hxx>
26 #include <basegfx/polygon/b2dpolygon.hxx>
27 #include <svx/xlineit0.hxx>
28 #include <svx/xfillit0.hxx>
29 #include <svx/xflbmpit.hxx>
30 #include <svx/xlntrit.hxx>
31 #include <svx/xlnwtit.hxx>
32 #include <svx/xlinjoit.hxx>
33 #include <svx/xlncapit.hxx>
34 #include <svx/xlnclit.hxx>
35 #include <svx/xlnstwit.hxx>
36 #include <svx/xlnedwit.hxx>
37 #include <svx/xlnstit.hxx>
38 #include <svx/xlnstcit.hxx>
39 #include <svx/xlnedit.hxx>
40 #include <svx/xlnedcit.hxx>
41 #include <svx/xdash.hxx>
42 #include <svx/xlndsit.hxx>
43 #include <svx/xfilluseslidebackgrounditem.hxx>
44 #include <svx/xfltrit.hxx>
45 #include <svx/xflftrit.hxx>
46 #include <svx/xflclit.hxx>
47 #include <svx/xgrscit.hxx>
48 #include <svx/xflhtit.hxx>
49 #include <svx/xflbckit.hxx>
50 #include <svx/xflbmsxy.hxx>
51 #include <svx/xflbtoxy.hxx>
52 #include <svx/xflboxy.hxx>
53 #include <svx/xflbmtit.hxx>
54 #include <svx/xflbstit.hxx>
55 #include <svx/xtextit0.hxx>
56 #include <svx/RectangleAlignmentItem.hxx>
57 #include <drawinglayer/attribute/sdrfillgraphicattribute.hxx>
58 #include <svx/svdotext.hxx>
59 #include <sdr/attribute/sdrtextattribute.hxx>
60 #include <svx/xbtmpit.hxx>
61 #include <svl/itempool.hxx>
62 #include <vcl/svapp.hxx>
63 #include <vcl/GraphicLoader.hxx>
64 #include <basegfx/range/b2drange.hxx>
65 #include <basegfx/utils/gradienttools.hxx>
66 #include <svx/svx3ditems.hxx>
67 #include <com/sun/star/drawing/ProjectionMode.hpp>
68 #include <com/sun/star/drawing/ShadeMode.hpp>
69 #include <drawinglayer/attribute/sdrallattribute3d.hxx>
70 #include <svx/rectenum.hxx>
71 #include <svx/sdtfchim.hxx>
72 #include <svx/svdoutl.hxx>
73 #include <svx/svdmodel.hxx>
74 #include <svx/xflbmsli.hxx>
75 #include <editeng/editstat.hxx>
76 #include <osl/diagnose.h>
77 #include <drawinglayer/attribute/fillhatchattribute.hxx>
78 #include <drawinglayer/attribute/fillgradientattribute.hxx>
79 #include <sdr/attribute/sdreffectstextattribute.hxx>
80 #include <sdr/attribute/sdrlineeffectstextattribute.hxx>
81 #include <sdr/attribute/sdrformtextattribute.hxx>
82 #include <sdr/attribute/sdrlinefilleffectstextattribute.hxx>
83 #include <drawinglayer/attribute/sdrglowattribute.hxx>
84 #include <drawinglayer/attribute/sdrsceneattribute3d.hxx>
85 #include <drawinglayer/attribute/sdrlightingattribute3d.hxx>
86 #include <drawinglayer/attribute/sdrlightattribute3d.hxx>
87 #include <sdr/attribute/sdrfilltextattribute.hxx>
88 #include <com/sun/star/drawing/LineCap.hpp>
89 
90 using namespace com::sun::star;
91 
92 namespace drawinglayer
93 {
94     namespace
95     {
96         attribute::HatchStyle XHatchStyleToHatchStyle(css::drawing::HatchStyle eStyle)
97         {
98             switch(eStyle)
99             {
100                 case css::drawing::HatchStyle_SINGLE :
101                 {
102                     return attribute::HatchStyle::Single;
103                 }
104                 case css::drawing::HatchStyle_DOUBLE :
105                 {
106                     return attribute::HatchStyle::Double;
107                 }
108                 default :
109                 {
110                     return attribute::HatchStyle::Triple; // css::drawing::HatchStyle_TRIPLE
111                 }
112             }
113         }
114 
115         basegfx::B2DLineJoin LineJointToB2DLineJoin(css::drawing::LineJoint eLineJoint)
116         {
117             switch(eLineJoint)
118             {
119                 case css::drawing::LineJoint_BEVEL :
120                 {
121                     return basegfx::B2DLineJoin::Bevel;
122                 }
123                 case css::drawing::LineJoint_MIDDLE :
124                 case css::drawing::LineJoint_MITER :
125                 {
126                     return basegfx::B2DLineJoin::Miter;
127                 }
128                 case css::drawing::LineJoint_ROUND :
129                 {
130                     return basegfx::B2DLineJoin::Round;
131                 }
132                 default : // css::drawing::LineJoint_NONE
133                 {
134                     return basegfx::B2DLineJoin::NONE;
135                 }
136             }
137         }
138 
139         basegfx::B2DVector RectPointToB2DVector(RectPoint eRectPoint)
140         {
141             basegfx::B2DVector aRetval(0.0, 0.0);
142 
143             // position changes X
144             switch(eRectPoint)
145             {
146                 case RectPoint::LT: case RectPoint::LM: case RectPoint::LB:
147                 {
148                     aRetval.setX(-1.0);
149                     break;
150                 }
151 
152                 case RectPoint::RT: case RectPoint::RM: case RectPoint::RB:
153                 {
154                     aRetval.setX(1.0);
155                     break;
156                 }
157 
158                 default :
159                 {
160                     break;
161                 }
162             }
163 
164             // position changes Y
165             switch(eRectPoint)
166             {
167                 case RectPoint::LT: case RectPoint::MT: case RectPoint::RT:
168                 {
169                     aRetval.setY(-1.0);
170                     break;
171                 }
172 
173                 case RectPoint::LB: case RectPoint::MB: case RectPoint::RB:
174                 {
175                     aRetval.setY(1.0);
176                     break;
177                 }
178 
179                 default :
180                 {
181                     break;
182                 }
183             }
184 
185             return aRetval;
186         }
187 
188         attribute::SdrGlowAttribute createNewSdrGlowAttribute(const SfxItemSet& rSet)
189         {
190             sal_Int32 nRadius = rSet.Get(SDRATTR_GLOW_RADIUS).GetValue();
191             if (!nRadius)
192                 return attribute::SdrGlowAttribute();
193             Color aColor(rSet.Get(SDRATTR_GLOW_COLOR).GetColorValue());
194             sal_uInt16 nTransparency(rSet.Get(SDRATTR_GLOW_TRANSPARENCY).GetValue());
195             if (nTransparency)
196                 aColor.SetAlpha(255 - std::round(nTransparency / 100.0 * 255.0));
197 
198             attribute::SdrGlowAttribute glowAttr{ nRadius, aColor };
199             return glowAttr;
200         }
201 
202         sal_Int32 getSoftEdgeRadius(const SfxItemSet& rSet)
203         {
204             return rSet.Get(SDRATTR_SOFTEDGE_RADIUS).GetValue();
205         }
206     } // end of anonymous namespace
207 } // end of namespace drawinglayer
208 
209 
210 namespace drawinglayer::primitive2d
211 {
212         attribute::SdrLineAttribute createNewSdrLineAttribute(const SfxItemSet& rSet)
213         {
214             const css::drawing::LineStyle eStyle(rSet.Get(XATTR_LINESTYLE).GetValue());
215 
216             if(drawing::LineStyle_NONE != eStyle)
217             {
218                 sal_uInt16 nTransparence(rSet.Get(XATTR_LINETRANSPARENCE).GetValue());
219 
220                 if(nTransparence > 100)
221                 {
222                     nTransparence = 100;
223                 }
224 
225                 if(100 != nTransparence)
226                 {
227                     const sal_uInt32 nWidth(rSet.Get(XATTR_LINEWIDTH).GetValue());
228                     const Color aColor(rSet.Get(XATTR_LINECOLOR).GetColorValue());
229                     const css::drawing::LineJoint eJoint(rSet.Get(XATTR_LINEJOINT).GetValue());
230                     const css::drawing::LineCap eCap(rSet.Get(XATTR_LINECAP).GetValue());
231                     ::std::vector< double > aDotDashArray;
232                     double fFullDotDashLen(0.0);
233 
234                     if(drawing::LineStyle_DASH == eStyle)
235                     {
236                         const XDash& rDash = rSet.Get(XATTR_LINEDASH).GetDashValue();
237 
238                         if(rDash.GetDots() || rDash.GetDashes())
239                         {
240                             fFullDotDashLen = rDash.CreateDotDashArray(aDotDashArray, static_cast<double>(nWidth));
241                         }
242                     }
243 
244                     return attribute::SdrLineAttribute(
245                         LineJointToB2DLineJoin(eJoint),
246                         static_cast<double>(nWidth),
247                         static_cast<double>(nTransparence) * 0.01,
248                         aColor.getBColor(),
249                         eCap,
250                         std::move(aDotDashArray),
251                         fFullDotDashLen);
252                 }
253             }
254 
255             return attribute::SdrLineAttribute();
256         }
257 
258         attribute::SdrLineStartEndAttribute createNewSdrLineStartEndAttribute(
259             const SfxItemSet& rSet,
260             double fWidth)
261         {
262             const sal_Int32 nTempStartWidth(rSet.Get(XATTR_LINESTARTWIDTH).GetValue());
263             const sal_Int32 nTempEndWidth(rSet.Get(XATTR_LINEENDWIDTH).GetValue());
264             basegfx::B2DPolyPolygon aStartPolyPolygon;
265             basegfx::B2DPolyPolygon aEndPolyPolygon;
266             double fStartWidth(0.0);
267             double fEndWidth(0.0);
268             bool bStartActive(false);
269             bool bEndActive(false);
270             bool bStartCentered(true);
271             bool bEndCentered(true);
272 
273             if(nTempStartWidth)
274             {
275                 if(nTempStartWidth < 0)
276                 {
277                     fStartWidth = (static_cast<double>(-nTempStartWidth) * fWidth) * 0.01;
278                 }
279                 else
280                 {
281                     fStartWidth = static_cast<double>(nTempStartWidth);
282                 }
283 
284                 if(0.0 != fStartWidth)
285                 {
286                     aStartPolyPolygon = rSet.Get(XATTR_LINESTART).GetLineStartValue();
287 
288                     if(aStartPolyPolygon.count() && aStartPolyPolygon.getB2DPolygon(0).count())
289                     {
290                         bStartActive = true;
291                         bStartCentered = rSet.Get(XATTR_LINESTARTCENTER).GetValue();
292                     }
293                 }
294             }
295 
296             if(nTempEndWidth)
297             {
298                 if(nTempEndWidth < 0)
299                 {
300                     fEndWidth = (static_cast<double>(-nTempEndWidth) * fWidth) * 0.01;
301                 }
302                 else
303                 {
304                     fEndWidth = static_cast<double>(nTempEndWidth);
305                 }
306 
307                 if(0.0 != fEndWidth)
308                 {
309                     aEndPolyPolygon = rSet.Get(XATTR_LINEEND).GetLineEndValue();
310 
311                     if(aEndPolyPolygon.count() && aEndPolyPolygon.getB2DPolygon(0).count())
312                     {
313                         bEndActive = true;
314                         bEndCentered = rSet.Get(XATTR_LINEENDCENTER).GetValue();
315                     }
316                 }
317             }
318 
319             if(bStartActive || bEndActive)
320             {
321                 return attribute::SdrLineStartEndAttribute(
322                     aStartPolyPolygon, aEndPolyPolygon, fStartWidth, fEndWidth,
323                     bStartActive, bEndActive, bStartCentered, bEndCentered);
324             }
325 
326             return attribute::SdrLineStartEndAttribute();
327         }
328 
329         attribute::SdrShadowAttribute createNewSdrShadowAttribute(const SfxItemSet& rSet)
330         {
331             const bool bShadow(rSet.Get(SDRATTR_SHADOW).GetValue());
332 
333             if(bShadow)
334             {
335                 sal_uInt16 nTransparence(rSet.Get(SDRATTR_SHADOWTRANSPARENCE).GetValue());
336 
337                 if(nTransparence > 100)
338                 {
339                     nTransparence = 100;
340                 }
341 
342                 if(nTransparence)
343                 {
344                     sal_uInt16 nFillTransparence(rSet.Get(XATTR_FILLTRANSPARENCE).GetValue());
345 
346                     if(nFillTransparence > 100)
347                     {
348                         nFillTransparence = 100;
349                     }
350 
351                     if(nTransparence == nFillTransparence)
352                     {
353                         // shadow does not really have an own transparence, but the application
354                         // sets the shadow transparence equal to the object transparence for
355                         // convenience. This is not useful for primitive creation, so take
356                         // this as no shadow transparence
357                         nTransparence = 0;
358                     }
359                 }
360 
361                 if(100 != nTransparence)
362                 {
363                     const basegfx::B2DVector aOffset(
364                         static_cast<double>(rSet.Get(SDRATTR_SHADOWXDIST).GetValue()),
365                         static_cast<double>(rSet.Get(SDRATTR_SHADOWYDIST).GetValue()));
366 
367                     const basegfx::B2DVector aSize(
368                         static_cast<double>(rSet.Get(SDRATTR_SHADOWSIZEX).GetValue()),
369                         static_cast<double>(rSet.Get(SDRATTR_SHADOWSIZEY).GetValue()));
370 
371                     const Color aColor(rSet.Get(SDRATTR_SHADOWCOLOR).GetColorValue());
372 
373                     sal_Int32 nBlur(rSet.Get(SDRATTR_SHADOWBLUR).GetValue());
374 
375                     model::RectangleAlignment eAlignment{rSet.Get(SDRATTR_SHADOWALIGNMENT).GetValue()};
376 
377                     return attribute::SdrShadowAttribute(aOffset, aSize, static_cast<double>(nTransparence) * 0.01, nBlur, eAlignment, aColor.getBColor());
378                 }
379             }
380 
381             return attribute::SdrShadowAttribute();
382         }
383 
384         attribute::SdrFillAttribute createNewSdrFillAttribute(const SfxItemSet& rSet)
385         {
386             const drawing::FillStyle eStyle(rSet.Get(XATTR_FILLSTYLE).GetValue());
387 
388             sal_uInt16 nTransparence(rSet.Get(XATTR_FILLTRANSPARENCE).GetValue());
389 
390             if(nTransparence > 100)
391             {
392                 nTransparence = 100;
393             }
394 
395             if(drawing::FillStyle_NONE == eStyle)
396             {
397                 XFillUseSlideBackgroundItem aBckItem(rSet.Get(XATTR_FILLUSESLIDEBACKGROUND));
398                 const bool bSlideBackgroundFill(aBckItem.GetValue());
399 
400                 if(bSlideBackgroundFill)
401                 {
402                     // we have SlideBackgroundFill mode, create a
403                     // SdrFillAttribute accordingly
404                     return attribute::SdrFillAttribute(true);
405                 }
406             }
407 
408             if(drawing::FillStyle_NONE != eStyle)
409             {
410                 if(100 != nTransparence)
411                 {
412                     // need to check XFillFloatTransparence, object fill may still be completely transparent
413                     const XFillFloatTransparenceItem* pGradientItem;
414 
415                     if((pGradientItem = rSet.GetItemIfSet(XATTR_FILLFLOATTRANSPARENCE, true))
416                         && pGradientItem->IsEnabled())
417                     {
418                         const basegfx::BGradient& rGradient = pGradientItem->GetGradientValue();
419                         basegfx::BColor aSingleColor;
420                         const bool bSingleColor(rGradient.GetColorStops().isSingleColor(aSingleColor));
421                         const bool bCompletelyTransparent(bSingleColor && basegfx::fTools::equal(aSingleColor.luminance(), 1.0));
422 
423                         if(bCompletelyTransparent)
424                         {
425                             nTransparence = 100;
426                         }
427                     }
428                 }
429 
430                 if(100 != nTransparence)
431                 {
432                     const Color aColor(rSet.Get(XATTR_FILLCOLOR).GetColorValue());
433                     attribute::FillGradientAttribute aGradient;
434                     attribute::FillHatchAttribute aHatch;
435                     attribute::SdrFillGraphicAttribute aFillGraphic;
436 
437                     switch(eStyle)
438                     {
439                         default:
440                         {
441                             // nothing to do, color is defined
442                             break;
443                         }
444                         case drawing::FillStyle_GRADIENT :
445                         {
446                             basegfx::BGradient aBGradient(rSet.Get(XATTR_FILLGRADIENT).GetGradientValue());
447                             basegfx::BColorStops aColorStops(aBGradient.GetColorStops());
448 
449 
450                             if (aBGradient.GetStartIntens() != 100 || aBGradient.GetEndIntens() != 100)
451                             {
452                                 // Need to do the (old, crazy) blend against black for a
453                                 // used intensity, but now for all ColorStops relative to their
454                                 // offsets, where 0 means black and 100 means original color
455                                 aColorStops.blendToIntensity(
456                                     aBGradient.GetStartIntens() * 0.01,
457                                     aBGradient.GetEndIntens() * 0.01,
458                                     basegfx::BColor()); // COL_BLACK
459                             }
460 
461                             aGradient = attribute::FillGradientAttribute(
462                                 aBGradient.GetGradientStyle(),
463                                 static_cast<double>(aBGradient.GetBorder()) * 0.01,
464                                 static_cast<double>(aBGradient.GetXOffset()) * 0.01,
465                                 static_cast<double>(aBGradient.GetYOffset()) * 0.01,
466                                 toRadians(aBGradient.GetAngle()),
467                                 aColorStops,
468                                 rSet.Get(XATTR_GRADIENTSTEPCOUNT).GetValue());
469 
470                             break;
471                         }
472                         case drawing::FillStyle_HATCH :
473                         {
474                             const XHatch& rHatch(rSet.Get(XATTR_FILLHATCH).GetHatchValue());
475                             const Color aColorB(rHatch.GetColor());
476 
477                             aHatch = attribute::FillHatchAttribute(
478                                 XHatchStyleToHatchStyle(rHatch.GetHatchStyle()),
479                                 static_cast<double>(rHatch.GetDistance()),
480                                 toRadians(rHatch.GetAngle()),
481                                 aColorB.getBColor(),
482                                 3, // same default as VCL, a minimum of three discrete units (pixels) offset
483                                 rSet.Get(XATTR_FILLBACKGROUND).GetValue());
484 
485                             break;
486                         }
487                         case drawing::FillStyle_BITMAP :
488                         {
489                             aFillGraphic = createNewSdrFillGraphicAttribute(rSet);
490                             break;
491                         }
492                     }
493 
494                     return attribute::SdrFillAttribute(
495                         static_cast<double>(nTransparence) * 0.01,
496                         aColor.getBColor(),
497                         aGradient,
498                         aHatch,
499                         aFillGraphic);
500                 }
501             }
502 
503             if(nTransparence == 100)
504             {
505                 attribute::FillGradientAttribute aGradient;
506                 attribute::FillHatchAttribute aHatch;
507                 attribute::SdrFillGraphicAttribute aFillGraphic;
508                 return attribute::SdrFillAttribute(
509                         1,
510                         basegfx::BColor( 0, 0, 0 ),
511                         aGradient,
512                         aHatch,
513                         aFillGraphic);
514             }
515 
516             return attribute::SdrFillAttribute();
517         }
518 
519         // #i101508# Support handing over given text-to-border distances
520         attribute::SdrTextAttribute createNewSdrTextAttribute(
521             const SfxItemSet& rSet,
522             const SdrText& rText,
523             const sal_Int32* pLeft,
524             const sal_Int32* pUpper,
525             const sal_Int32* pRight,
526             const sal_Int32* pLower)
527         {
528             const SdrTextObj& rTextObj = rText.GetObject();
529 
530             // Save chaining attributes
531             bool bChainable = rTextObj.IsChainable();
532 
533 
534             if(rText.GetOutlinerParaObject())
535             {
536                 // added TextEdit text suppression
537                 bool bInEditMode(false);
538 
539                 if(rText.GetObject().getTextCount() > 1)
540                 {
541                     bInEditMode = rTextObj.IsInEditMode() && rText.GetObject().getActiveText() == &rText;
542                 }
543                 else
544                 {
545                     bInEditMode = rTextObj.IsInEditMode();
546                 }
547 
548                 OutlinerParaObject aOutlinerParaObject(*rText.GetOutlinerParaObject());
549 
550                 if(bInEditMode)
551                 {
552                     std::optional<OutlinerParaObject> pTempObj = rTextObj.CreateEditOutlinerParaObject();
553 
554                     if(pTempObj)
555                     {
556                         aOutlinerParaObject = *pTempObj;
557                     }
558                     else
559                     {
560                         // #i100537#
561                         // CreateEditOutlinerParaObject() returning no object does not mean that
562                         // text edit mode is not active. Do not reset the flag here
563                         // bInEditMode = false;
564                     }
565                 }
566 
567                 const SdrTextAniKind eAniKind(rTextObj.GetTextAniKind());
568 
569                 // #i107346#
570                 const SdrOutliner& rDrawTextOutliner(rText.GetObject().getSdrModelFromSdrObject().GetDrawOutliner(&rTextObj));
571                 const bool bWrongSpell(rDrawTextOutliner.GetControlWord() & EEControlBits::ONLINESPELLING);
572 
573                 return attribute::SdrTextAttribute(
574                     rText,
575                     aOutlinerParaObject,
576                     rSet.Get(XATTR_FORMTXTSTYLE).GetValue(),
577                     pLeft ? *pLeft : rTextObj.GetTextLeftDistance(),
578                     pUpper ? *pUpper : rTextObj.GetTextUpperDistance(),
579                     pRight ? *pRight : rTextObj.GetTextRightDistance(),
580                     pLower ? *pLower : rTextObj.GetTextLowerDistance(),
581                     rTextObj.GetTextHorizontalAdjust(rSet),
582                     rTextObj.GetTextVerticalAdjust(rSet),
583                     rSet.Get(SDRATTR_TEXT_CONTOURFRAME).GetValue(),
584                     rTextObj.IsFitToSize(),
585                     rTextObj.IsAutoFit(),
586                     rSet.Get(XATTR_FORMTXTHIDEFORM).GetValue(),
587                     SdrTextAniKind::Blink == eAniKind,
588                     SdrTextAniKind::Scroll == eAniKind || SdrTextAniKind::Alternate == eAniKind || SdrTextAniKind::Slide == eAniKind,
589                     bInEditMode,
590                     rSet.Get(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue(),
591                     bWrongSpell,
592                     bChainable);
593             }
594 
595             return attribute::SdrTextAttribute();
596         }
597 
598         attribute::FillGradientAttribute createNewTransparenceGradientAttribute(const SfxItemSet& rSet)
599         {
600             const XFillFloatTransparenceItem* pGradientItem;
601 
602             if((pGradientItem = rSet.GetItemIfSet(XATTR_FILLFLOATTRANSPARENCE))
603                 && pGradientItem->IsEnabled())
604             {
605                 // test if float transparency is completely transparent
606                 const basegfx::BGradient& rGradient(pGradientItem->GetGradientValue());
607                 basegfx::BColor aSingleColor;
608                 const bool bSingleColor(rGradient.GetColorStops().isSingleColor(aSingleColor));
609                 const bool bCompletelyTransparent(bSingleColor && basegfx::fTools::equal(aSingleColor.luminance(), 1.0));
610                 const bool bNotTransparent(bSingleColor && basegfx::fTools::equalZero(aSingleColor.luminance()));
611 
612                 // create nothing when completely transparent: This case is already checked for the
613                 // normal fill attributes, XFILL_NONE will be used.
614                 // create nothing when not transparent: use normal fill, no need t create a FillGradientAttribute.
615                 // Both cases are optimizations, always creating FillGradientAttribute will work, too
616                 if (!bNotTransparent && !bCompletelyTransparent)
617                 {
618                     basegfx::BColorStops aColorStops(rGradient.GetColorStops());
619 
620                     if (rGradient.GetStartIntens() != 100 || rGradient.GetEndIntens() != 100)
621                     {
622                         // this may also be set for transparence, so need to take care of it
623                         aColorStops.blendToIntensity(
624                             rGradient.GetStartIntens() * 0.01,
625                             rGradient.GetEndIntens() * 0.01,
626                             basegfx::BColor()); // COL_BLACK
627                     }
628 
629                     return attribute::FillGradientAttribute(
630                         rGradient.GetGradientStyle(),
631                         static_cast<double>(rGradient.GetBorder()) * 0.01,
632                         static_cast<double>(rGradient.GetXOffset()) * 0.01,
633                         static_cast<double>(rGradient.GetYOffset()) * 0.01,
634                         toRadians(rGradient.GetAngle()),
635                         aColorStops,
636                         // oops - the gradientStepCount was missing here. If we want to use
637                         // a combination of gradient & transparencyGradient to represent
638                         // imported gradients of formats which do originally support transparency
639                         // in gradients, then the gradient has to be exactly defined the same,
640                         // including the (evtl. used) gradientStepCount
641                         rSet.Get(XATTR_GRADIENTSTEPCOUNT).GetValue());
642                 }
643             }
644 
645             return attribute::FillGradientAttribute();
646         }
647 
648         attribute::SdrFillGraphicAttribute createNewSdrFillGraphicAttribute(const SfxItemSet& rSet)
649         {
650             Graphic aGraphic(rSet.Get(XATTR_FILLBITMAP).GetGraphicObject().GetGraphic());
651 
652             OUString aOriginURL = aGraphic.getOriginURL();
653             if (aGraphic.GetType() == GraphicType::Default && !aOriginURL.isEmpty())
654             {
655                 aGraphic = vcl::graphic::loadFromURL(aGraphic.getOriginURL());
656                 aGraphic.setOriginURL(aOriginURL);
657             }
658 
659             if(GraphicType::Bitmap != aGraphic.GetType() && GraphicType::GdiMetafile != aGraphic.GetType())
660             {
661                 // no content if not bitmap or metafile
662                 OSL_ENSURE(false, "No fill graphic in SfxItemSet (!)");
663                 return attribute::SdrFillGraphicAttribute();
664             }
665 
666             Size aPrefSize(aGraphic.GetPrefSize());
667 
668             if(!aPrefSize.Width() || !aPrefSize.Height())
669             {
670                 // if there is no logical size, create a size from pixel size and set MapMode accordingly
671                 if(GraphicType::Bitmap == aGraphic.GetType())
672                 {
673                     aGraphic.SetPrefSize(aGraphic.GetBitmapEx().GetSizePixel());
674                     aGraphic.SetPrefMapMode(MapMode(MapUnit::MapPixel));
675                     aPrefSize = aGraphic.GetPrefSize();
676                 }
677             }
678 
679             if(!aPrefSize.Width() || !aPrefSize.Height())
680             {
681                 // no content if no size
682                 OSL_ENSURE(false, "Graphic has no size in SfxItemSet (!)");
683                 return attribute::SdrFillGraphicAttribute();
684             }
685 
686             // convert size and MapMode to destination logical size and MapMode
687             const MapUnit aDestinationMapUnit(rSet.GetPool()->GetMetric(0));
688             basegfx::B2DVector aGraphicLogicSize(aGraphic.GetPrefSize().Width(), aGraphic.GetPrefSize().Height());
689 
690             if (aGraphic.GetPrefMapMode().GetMapUnit() != aDestinationMapUnit)
691             {
692                 // #i100360# for MapUnit::MapPixel, LogicToLogic will not work properly,
693                 // so fallback to Application::GetDefaultDevice()
694                 Size aNewSize(0, 0);
695 
696                 if(MapUnit::MapPixel == aGraphic.GetPrefMapMode().GetMapUnit())
697                 {
698                     aNewSize = Application::GetDefaultDevice()->PixelToLogic(
699                         aGraphic.GetPrefSize(),
700                         MapMode(aDestinationMapUnit));
701                 }
702                 else
703                 {
704                     aNewSize = OutputDevice::LogicToLogic(
705                         aGraphic.GetPrefSize(),
706                         aGraphic.GetPrefMapMode(),
707                         MapMode(aDestinationMapUnit));
708                 }
709 
710                 // #i124002# do not set new size using SetPrefSize at the graphic, this will lead to problems.
711                 // Instead, adapt the GraphicLogicSize which will be used for further decompositions
712                 aGraphicLogicSize = basegfx::B2DVector(aNewSize.Width(), aNewSize.Height());
713             }
714 
715             // get size
716             const basegfx::B2DVector aSize(
717                 static_cast<double>(rSet.Get(XATTR_FILLBMP_SIZEX).GetValue()),
718                 static_cast<double>(rSet.Get(XATTR_FILLBMP_SIZEY).GetValue()));
719             const basegfx::B2DVector aOffset(
720                 static_cast<double>(rSet.Get(XATTR_FILLBMP_TILEOFFSETX).GetValue()),
721                 static_cast<double>(rSet.Get(XATTR_FILLBMP_TILEOFFSETY).GetValue()));
722             const basegfx::B2DVector aOffsetPosition(
723                 static_cast<double>(rSet.Get(XATTR_FILLBMP_POSOFFSETX).GetValue()),
724                 static_cast<double>(rSet.Get(XATTR_FILLBMP_POSOFFSETY).GetValue()));
725 
726             return attribute::SdrFillGraphicAttribute(
727                 aGraphic,
728                 aGraphicLogicSize,
729                 aSize,
730                 aOffset,
731                 aOffsetPosition,
732                 RectPointToB2DVector(rSet.GetItem<XFillBmpPosItem>(XATTR_FILLBMP_POS)->GetValue()),
733                 rSet.Get(XATTR_FILLBMP_TILE).GetValue(),
734                 rSet.Get(XATTR_FILLBMP_STRETCH).GetValue(),
735                 rSet.Get(XATTR_FILLBMP_SIZELOG).GetValue());
736         }
737 
738         attribute::SdrEffectsTextAttribute createNewSdrEffectsTextAttribute(
739             const SfxItemSet& rSet,
740             const SdrText* pText,
741             bool bSuppressText)
742         {
743             attribute::SdrTextAttribute aText;
744 
745             // #i98072# added option to suppress text
746             // look for text first
747             if(!bSuppressText && pText)
748             {
749                 aText = createNewSdrTextAttribute(rSet, *pText);
750             }
751 
752             // try shadow
753             const attribute::SdrShadowAttribute aShadow(createNewSdrShadowAttribute(rSet));
754             const attribute::SdrGlowAttribute aGlow(createNewSdrGlowAttribute(rSet));
755             const sal_Int32 nSoftEdgeRadius(getSoftEdgeRadius(rSet));
756 
757             return attribute::SdrEffectsTextAttribute(aShadow, aText, aGlow, nSoftEdgeRadius);
758         }
759 
760         attribute::SdrLineEffectsTextAttribute createNewSdrLineEffectsTextAttribute(
761             const SfxItemSet& rSet,
762             const SdrText* pText)
763         {
764             attribute::SdrLineAttribute aLine;
765             attribute::SdrLineStartEndAttribute aLineStartEnd;
766             attribute::SdrTextAttribute aText;
767             bool bFontworkHideContour(false);
768 
769             // look for text first
770             if(pText)
771             {
772                 aText = createNewSdrTextAttribute(rSet, *pText);
773 
774                 // when object has text and text is fontwork and hide contour is set for fontwork, force
775                 // line and fill style to empty
776                 if(!aText.isDefault()
777                     && !aText.getSdrFormTextAttribute().isDefault()
778                     && aText.isHideContour())
779                 {
780                     bFontworkHideContour = true;
781                 }
782             }
783 
784             // try line style
785             if(!bFontworkHideContour)
786             {
787                 aLine = createNewSdrLineAttribute(rSet);
788 
789                 if(!aLine.isDefault())
790                 {
791                     // try LineStartEnd
792                     aLineStartEnd = createNewSdrLineStartEndAttribute(rSet, aLine.getWidth());
793                 }
794             }
795 
796             if(!aLine.isDefault() || !aText.isDefault())
797             {
798                 // try shadow
799                 const attribute::SdrShadowAttribute aShadow(createNewSdrShadowAttribute(rSet));
800                 const attribute::SdrGlowAttribute aGlow = createNewSdrGlowAttribute(rSet);
801                 const sal_Int32 nSoftEdgeRadius(getSoftEdgeRadius(rSet));
802 
803                 return attribute::SdrLineEffectsTextAttribute(aLine, aLineStartEnd, aShadow, aText,
804                                                               aGlow, nSoftEdgeRadius);
805             }
806 
807             return attribute::SdrLineEffectsTextAttribute();
808         }
809 
810         attribute::SdrLineFillEffectsTextAttribute createNewSdrLineFillEffectsTextAttribute(
811             const SfxItemSet& rSet,
812             const SdrText* pText,
813             bool bHasContent,
814             bool bSuppressShadow)
815         {
816             attribute::SdrLineAttribute aLine;
817             attribute::SdrFillAttribute aFill;
818             attribute::SdrLineStartEndAttribute aLineStartEnd;
819             attribute::FillGradientAttribute aFillFloatTransGradient;
820             attribute::SdrTextAttribute aText;
821             bool bFontworkHideContour(false);
822 
823             // look for text first
824             if(pText)
825             {
826                 aText = createNewSdrTextAttribute(rSet, *pText);
827 
828                 // when object has text and text is fontwork and hide contour is set for fontwork, force
829                 // line and fill style to empty
830                 if(!aText.getSdrFormTextAttribute().isDefault() && aText.isHideContour())
831                 {
832                     bFontworkHideContour = true;
833                 }
834             }
835 
836             if(!bFontworkHideContour)
837             {
838                 // try line style
839                 aLine = createNewSdrLineAttribute(rSet);
840 
841                 if(!aLine.isDefault())
842                 {
843                     // try LineStartEnd
844                     aLineStartEnd = createNewSdrLineStartEndAttribute(rSet, aLine.getWidth());
845                 }
846 
847                 // try fill style
848                 aFill = createNewSdrFillAttribute(rSet);
849 
850                 if(!aFill.isDefault())
851                 {
852                     // try fillfloattransparence
853                     aFillFloatTransGradient = createNewTransparenceGradientAttribute(rSet);
854                 }
855             }
856 
857             // bHasContent is used from OLE and graphic objects. Normally a possible shadow
858             // depends on line, fill or text to be set, but for these objects it is possible
859             // to have none of these, but still content which needs to have a shadow (if set),
860             // so shadow needs to be tried
861             if(bHasContent || !aLine.isDefault() || !aFill.isDefault() || !aText.isDefault())
862             {
863                 // try shadow
864                 const attribute::SdrShadowAttribute aShadow = !bSuppressShadow ?
865                     createNewSdrShadowAttribute(rSet) : attribute::SdrShadowAttribute();
866 
867                 // glow
868                 const attribute::SdrGlowAttribute aGlow = createNewSdrGlowAttribute(rSet);
869 
870                 const sal_Int32 nSoftEdgeRadius(getSoftEdgeRadius(rSet));
871 
872                 return attribute::SdrLineFillEffectsTextAttribute(aLine, aFill, aLineStartEnd,
873                                                                   aShadow, aFillFloatTransGradient,
874                                                                   aText, aGlow, nSoftEdgeRadius);
875             }
876 
877             return attribute::SdrLineFillEffectsTextAttribute();
878         }
879 
880         attribute::SdrLineFillShadowAttribute3D createNewSdrLineFillShadowAttribute(const SfxItemSet& rSet, bool bSuppressFill)
881         {
882             attribute::SdrFillAttribute aFill;
883             attribute::SdrLineStartEndAttribute aLineStartEnd;
884             attribute::SdrShadowAttribute aShadow;
885             attribute::FillGradientAttribute aFillFloatTransGradient;
886 
887             // try line style
888             const attribute::SdrLineAttribute aLine(createNewSdrLineAttribute(rSet));
889 
890             if(!aLine.isDefault())
891             {
892                 // try LineStartEnd
893                 aLineStartEnd = createNewSdrLineStartEndAttribute(rSet, aLine.getWidth());
894             }
895 
896             // try fill style
897             if(!bSuppressFill)
898             {
899                 aFill = createNewSdrFillAttribute(rSet);
900 
901                 if(!aFill.isDefault())
902                 {
903                     // try fillfloattransparence
904                     aFillFloatTransGradient = createNewTransparenceGradientAttribute(rSet);
905                 }
906             }
907 
908             if(!aLine.isDefault() || !aFill.isDefault())
909             {
910                 // try shadow
911                 aShadow = createNewSdrShadowAttribute(rSet);
912 
913                 return attribute::SdrLineFillShadowAttribute3D(
914                     aLine, aFill, aLineStartEnd, aShadow, aFillFloatTransGradient);
915             }
916 
917             return attribute::SdrLineFillShadowAttribute3D();
918         }
919 
920         attribute::SdrSceneAttribute createNewSdrSceneAttribute(const SfxItemSet& rSet)
921         {
922             // get perspective
923             css::drawing::ProjectionMode aProjectionMode(css::drawing::ProjectionMode_PARALLEL);
924             const sal_uInt16 nProjectionValue(rSet.Get(SDRATTR_3DSCENE_PERSPECTIVE).GetValue());
925 
926             if(1 == nProjectionValue)
927             {
928                 aProjectionMode = css::drawing::ProjectionMode_PERSPECTIVE;
929             }
930 
931             // get distance
932             const double fDistance(rSet.Get(SDRATTR_3DSCENE_DISTANCE).GetValue());
933 
934             // get shadow slant
935             const double fShadowSlant(
936                 basegfx::deg2rad(rSet.Get(SDRATTR_3DSCENE_SHADOW_SLANT).GetValue()));
937 
938             // get shade mode
939             css::drawing::ShadeMode aShadeMode(css::drawing::ShadeMode_FLAT);
940             const sal_uInt16 nShadeValue(rSet.Get(SDRATTR_3DSCENE_SHADE_MODE).GetValue());
941 
942             if(1 == nShadeValue)
943             {
944                 aShadeMode = css::drawing::ShadeMode_PHONG;
945             }
946             else if(2 == nShadeValue)
947             {
948                 aShadeMode = css::drawing::ShadeMode_SMOOTH;
949             }
950             else if(3 == nShadeValue)
951             {
952                 aShadeMode = css::drawing::ShadeMode_DRAFT;
953             }
954 
955             // get two sided lighting
956             const bool bTwoSidedLighting(rSet.Get(SDRATTR_3DSCENE_TWO_SIDED_LIGHTING).GetValue());
957 
958             return attribute::SdrSceneAttribute(fDistance, fShadowSlant, aProjectionMode, aShadeMode, bTwoSidedLighting);
959         }
960 
961         attribute::SdrLightingAttribute createNewSdrLightingAttribute(const SfxItemSet& rSet)
962         {
963             // extract lights from given SfxItemSet (from scene)
964             ::std::vector< attribute::Sdr3DLightAttribute > aLightVector;
965 
966             if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_1).GetValue())
967             {
968                 const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_1).GetValue().getBColor());
969                 const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_1).GetValue());
970                 aLightVector.emplace_back(aColor, aDirection, true);
971             }
972 
973             if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_2).GetValue())
974             {
975                 const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_2).GetValue().getBColor());
976                 const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_2).GetValue());
977                 aLightVector.emplace_back(aColor, aDirection, false);
978             }
979 
980             if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_3).GetValue())
981             {
982                 const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_3).GetValue().getBColor());
983                 const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_3).GetValue());
984                 aLightVector.emplace_back(aColor, aDirection, false);
985             }
986 
987             if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_4).GetValue())
988             {
989                 const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_4).GetValue().getBColor());
990                 const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_4).GetValue());
991                 aLightVector.emplace_back(aColor, aDirection, false);
992             }
993 
994             if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_5).GetValue())
995             {
996                 const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_5).GetValue().getBColor());
997                 const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_5).GetValue());
998                 aLightVector.emplace_back(aColor, aDirection, false);
999             }
1000 
1001             if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_6).GetValue())
1002             {
1003                 const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_6).GetValue().getBColor());
1004                 const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_6).GetValue());
1005                 aLightVector.emplace_back(aColor, aDirection, false);
1006             }
1007 
1008             if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_7).GetValue())
1009             {
1010                 const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_7).GetValue().getBColor());
1011                 const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_7).GetValue());
1012                 aLightVector.emplace_back(aColor, aDirection, false);
1013             }
1014 
1015             if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_8).GetValue())
1016             {
1017                 const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_8).GetValue().getBColor());
1018                 const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_8).GetValue());
1019                 aLightVector.emplace_back(aColor, aDirection, false);
1020             }
1021 
1022             // get ambient color
1023             const Color aAmbientValue(rSet.Get(SDRATTR_3DSCENE_AMBIENTCOLOR).GetValue());
1024             const basegfx::BColor aAmbientLight(aAmbientValue.getBColor());
1025 
1026             return attribute::SdrLightingAttribute(aAmbientLight, std::move(aLightVector));
1027         }
1028 
1029         void calculateRelativeCornerRadius(sal_Int32 nRadius, const basegfx::B2DRange& rObjectRange, double& rfCornerRadiusX, double& rfCornerRadiusY)
1030         {
1031             rfCornerRadiusX = rfCornerRadiusY = static_cast<double>(nRadius);
1032 
1033             if(0.0 != rfCornerRadiusX)
1034             {
1035                 const double fHalfObjectWidth(rObjectRange.getWidth() * 0.5);
1036 
1037                 if(0.0 != fHalfObjectWidth)
1038                 {
1039                     if(rfCornerRadiusX < 0.0)
1040                     {
1041                         rfCornerRadiusX = 0.0;
1042                     }
1043 
1044                     if(rfCornerRadiusX > fHalfObjectWidth)
1045                     {
1046                         rfCornerRadiusX = fHalfObjectWidth;
1047                     }
1048 
1049                     rfCornerRadiusX /= fHalfObjectWidth;
1050                 }
1051                 else
1052                 {
1053                     rfCornerRadiusX = 0.0;
1054                 }
1055             }
1056 
1057             if(0.0 == rfCornerRadiusY)
1058                 return;
1059 
1060             const double fHalfObjectHeight(rObjectRange.getHeight() * 0.5);
1061 
1062             if(0.0 != fHalfObjectHeight)
1063             {
1064                 if(rfCornerRadiusY < 0.0)
1065                 {
1066                     rfCornerRadiusY = 0.0;
1067                 }
1068 
1069                 if(rfCornerRadiusY > fHalfObjectHeight)
1070                 {
1071                     rfCornerRadiusY = fHalfObjectHeight;
1072                 }
1073 
1074                 rfCornerRadiusY /= fHalfObjectHeight;
1075             }
1076             else
1077             {
1078                 rfCornerRadiusY = 0.0;
1079             }
1080         }
1081 
1082         // #i101508# Support handing over given text-to-border distances
1083         attribute::SdrFillTextAttribute createNewSdrFillTextAttribute(
1084             const SfxItemSet& rSet,
1085             const SdrText* pText,
1086             const sal_Int32* pLeft,
1087             const sal_Int32* pUpper,
1088             const sal_Int32* pRight,
1089             const sal_Int32* pLower)
1090         {
1091             attribute::SdrFillAttribute aFill;
1092             attribute::FillGradientAttribute aFillFloatTransGradient;
1093             attribute::SdrTextAttribute aText;
1094             bool bFontworkHideContour(false);
1095 
1096             // look for text first
1097             if(pText)
1098             {
1099                 aText = createNewSdrTextAttribute(rSet, *pText, pLeft, pUpper, pRight, pLower);
1100 
1101                 // when object has text and text is fontwork and hide contour is set for fontwork, force
1102                 // fill style to empty
1103                 if(!aText.getSdrFormTextAttribute().isDefault() && aText.isHideContour())
1104                 {
1105                     bFontworkHideContour = true;
1106                 }
1107             }
1108 
1109             if(!bFontworkHideContour)
1110             {
1111                 // try fill style
1112                 aFill = createNewSdrFillAttribute(rSet);
1113 
1114                 if(!aFill.isDefault())
1115                 {
1116                     // try fillfloattransparence
1117                     aFillFloatTransGradient = createNewTransparenceGradientAttribute(rSet);
1118                 }
1119             }
1120 
1121             if(!aFill.isDefault() || !aText.isDefault())
1122             {
1123                 return attribute::SdrFillTextAttribute(aFill, aFillFloatTransGradient, aText);
1124             }
1125 
1126             return attribute::SdrFillTextAttribute();
1127         }
1128 
1129 } // end of namespace
1130 
1131 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1132