Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/svdraw/svdoashp.cxx
Line
Count
Source
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 <vcl/bitmap/BitmapShadowFilter.hxx>
21
#include <svx/svdoashp.hxx>
22
#include <svx/unoapi.hxx>
23
#include <com/sun/star/loader/CannotActivateFactoryException.hpp>
24
#include <com/sun/star/drawing/XShape.hpp>
25
#include <com/sun/star/drawing/XCustomShapeEngine.hpp>
26
#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
27
#include <com/sun/star/beans/PropertyValue.hpp>
28
#include <com/sun/star/awt/Rectangle.hpp>
29
#include <com/sun/star/uno/XComponentContext.hpp>
30
#include <comphelper/processfactory.hxx>
31
#include <comphelper/propertyvalue.hxx>
32
#include <comphelper/sequenceashashmap.hxx>
33
#include <com/sun/star/uno/Sequence.h>
34
#include <tools/helpers.hxx>
35
#include <svx/svddrag.hxx>
36
#include <svx/svddrgmt.hxx>
37
#include <svx/svdmodel.hxx>
38
#include <svx/svdpage.hxx>
39
#include <svx/svditer.hxx>
40
#include <svx/svdobj.hxx>
41
#include <svx/svdtrans.hxx>
42
#include <svx/dialmgr.hxx>
43
#include <svx/strings.hrc>
44
#include <editeng/eeitem.hxx>
45
#include <editeng/editstat.hxx>
46
#include <editeng/adjustitem.hxx>
47
#include <svx/svdoutl.hxx>
48
#include <editeng/outlobj.hxx>
49
#include <svx/sdtfchim.hxx>
50
#include <svx/EnhancedCustomShapeGeometry.hxx>
51
#include <svx/EnhancedCustomShapeTypeNames.hxx>
52
#include <svx/EnhancedCustomShape2d.hxx>
53
#include <com/sun/star/beans/PropertyValues.hpp>
54
#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
55
#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
56
#include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
57
#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
58
#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
59
#include <editeng/writingmodeitem.hxx>
60
#include <svx/xlineit0.hxx>
61
#include <svx/xlnclit.hxx>
62
#include <sdr/properties/customshapeproperties.hxx>
63
#include <sdr/contact/viewcontactofsdrobjcustomshape.hxx>
64
#include <svx/xlntrit.hxx>
65
#include <svx/xfillit0.hxx>
66
#include <svx/xfltrit.hxx>
67
#include <svx/xflclit.hxx>
68
#include <svx/xflgrit.hxx>
69
#include <svx/xflhtit.hxx>
70
#include <svx/xbtmpit.hxx>
71
#include <vcl/virdev.hxx>
72
#include <svx/svdview.hxx>
73
#include <svx/sdmetitm.hxx>
74
#include <svx/sdprcitm.hxx>
75
#include <svx/sdshitm.hxx>
76
#include <svx/sdsxyitm.hxx>
77
#include <svx/sdtmfitm.hxx>
78
#include <svx/sdasitm.hxx>
79
#include <svx/diagram/IDiagramHelper.hxx>
80
#include <basegfx/polygon/b2dpolypolygontools.hxx>
81
#include <basegfx/matrix/b2dhommatrix.hxx>
82
#include <basegfx/matrix/b2dhommatrixtools.hxx>
83
#include <basegfx/polygon/b2dpolygon.hxx>
84
#include <basegfx/polygon/b2dpolygontools.hxx>
85
#include <basegfx/range/b2drange.hxx>
86
#include <svdobjplusdata.hxx>
87
#include <sal/log.hxx>
88
#include <tools/debug.hxx>
89
#include <o3tl/string_view.hxx>
90
#include "presetooxhandleadjustmentrelations.hxx"
91
#include <editeng/frmdiritem.hxx>
92
#include <EnhancedCustomShapeEngine.hxx>
93
94
using namespace ::com::sun::star;
95
96
static void lcl_ShapeSegmentFromBinary( drawing::EnhancedCustomShapeSegment& rSegInfo, sal_uInt16 nSDat )
97
189k
{
98
189k
    switch( nSDat >> 8 )
99
189k
    {
100
46.9k
        case 0x00 :
101
46.9k
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::LINETO;
102
46.9k
            rSegInfo.Count   = nSDat & 0xff;
103
46.9k
            if ( !rSegInfo.Count )
104
0
                rSegInfo.Count = 1;
105
46.9k
            break;
106
2.31k
        case 0x20 :
107
2.31k
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::CURVETO;
108
2.31k
            rSegInfo.Count   = nSDat & 0xff;
109
2.31k
            if ( !rSegInfo.Count )
110
0
                rSegInfo.Count = 1;
111
2.31k
            break;
112
26.6k
        case 0x40 :
113
26.6k
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::MOVETO;
114
26.6k
            rSegInfo.Count   = nSDat & 0xff;
115
26.6k
            if ( !rSegInfo.Count )
116
26.6k
                rSegInfo.Count = 1;
117
26.6k
            break;
118
18.0k
        case 0x60 :
119
18.0k
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
120
18.0k
            rSegInfo.Count   = 0;
121
18.0k
            break;
122
38.3k
        case 0x80 :
123
38.3k
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
124
38.3k
            rSegInfo.Count   = 0;
125
38.3k
            break;
126
0
        case 0xa1 :
127
0
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO;
128
0
            rSegInfo.Count   = ( nSDat & 0xff ) / 3;
129
0
            break;
130
1.19k
        case 0xa2 :
131
1.19k
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE;
132
1.19k
            rSegInfo.Count   = ( nSDat & 0xff ) / 3;
133
1.19k
            break;
134
519
        case 0xa3 :
135
519
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::ARCTO;
136
519
            rSegInfo.Count   = ( nSDat & 0xff ) >> 2;
137
519
            break;
138
439
        case 0xa4 :
139
439
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::ARC;
140
439
            rSegInfo.Count   = ( nSDat & 0xff ) >> 2;
141
439
            break;
142
810
        case 0xa5 :
143
810
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO;
144
810
            rSegInfo.Count   = ( nSDat & 0xff ) >> 2;
145
810
            break;
146
9.82k
        case 0xa6 :
147
9.82k
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC;
148
9.82k
            rSegInfo.Count   = ( nSDat & 0xff ) >> 2;
149
9.82k
            break;
150
17.0k
        case 0xa7 :
151
17.0k
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX;
152
17.0k
            rSegInfo.Count   = nSDat & 0xff;
153
17.0k
            break;
154
17.1k
        case 0xa8 :
155
17.1k
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY;
156
17.1k
            rSegInfo.Count   = nSDat & 0xff;
157
17.1k
            break;
158
5.22k
        case 0xaa :
159
5.22k
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::NOFILL;
160
5.22k
            rSegInfo.Count   = 0;
161
5.22k
            break;
162
4.87k
        case 0xab :
163
4.87k
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE;
164
4.87k
            rSegInfo.Count   = 0;
165
4.87k
            break;
166
0
        default:
167
0
        case 0xf8 :
168
0
            rSegInfo.Command = drawing::EnhancedCustomShapeSegmentCommand::UNKNOWN;
169
0
            rSegInfo.Count   = nSDat;
170
0
            break;
171
189k
    }
172
189k
}
173
174
static MSO_SPT ImpGetCustomShapeType( const SdrObjCustomShape& rCustoShape )
175
22
{
176
22
    MSO_SPT eRetValue = mso_sptNil;
177
178
22
    OUString aEngine( rCustoShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE ).GetValue() );
179
22
    if ( aEngine.isEmpty() || aEngine == "com.sun.star.drawing.EnhancedCustomShapeEngine" )
180
22
    {
181
22
        OUString sShapeType;
182
22
        const SdrCustomShapeGeometryItem& rGeometryItem( rCustoShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
183
22
        const uno::Any* pAny = rGeometryItem.GetPropertyValueByName( u"Type"_ustr );
184
22
        if ( pAny && ( *pAny >>= sShapeType ) )
185
22
            eRetValue = EnhancedCustomShapeTypeNames::Get( sShapeType );
186
22
    }
187
22
    return eRetValue;
188
22
};
189
190
static bool ImpVerticalSwitch( const SdrObjCustomShape& rCustoShape )
191
0
{
192
0
    bool bRet = false;
193
0
    MSO_SPT eShapeType( ImpGetCustomShapeType( rCustoShape ) );
194
0
    switch( eShapeType )
195
0
    {
196
0
        case mso_sptAccentBorderCallout90 :     // 2 ortho
197
0
        case mso_sptBorderCallout1 :            // 2 diag
198
0
        case mso_sptBorderCallout2 :            // 3
199
0
        {
200
0
            bRet = true;
201
0
        }
202
0
        break;
203
0
        default: break;
204
0
    }
205
0
    return bRet;
206
0
}
207
208
// #i37011# create a clone with all attributes changed to shadow attributes
209
// and translation executed, too.
210
static rtl::Reference<SdrObject> ImpCreateShadowObjectClone(const SdrObject& rOriginal, const SfxItemSet& rOriginalSet)
211
0
{
212
0
    rtl::Reference<SdrObject> pRetval;
213
0
    const bool bShadow(rOriginalSet.Get(SDRATTR_SHADOW).GetValue());
214
215
0
    if(bShadow)
216
0
    {
217
        // create a shadow representing object
218
0
        const sal_Int32 nXDist(rOriginalSet.Get(SDRATTR_SHADOWXDIST).GetValue());
219
0
        const sal_Int32 nYDist(rOriginalSet.Get(SDRATTR_SHADOWYDIST).GetValue());
220
0
        const ::Color aShadowColor(rOriginalSet.Get(SDRATTR_SHADOWCOLOR).GetColorValue());
221
0
        const sal_uInt16 nShadowTransparence(rOriginalSet.Get(SDRATTR_SHADOWTRANSPARENCE).GetValue());
222
0
        pRetval = rOriginal.CloneSdrObject(rOriginal.getSdrModelFromSdrObject());
223
0
        DBG_ASSERT(pRetval, "ImpCreateShadowObjectClone: Could not clone object (!)");
224
225
        // look for used stuff
226
0
        SdrObjListIter aIterator(rOriginal);
227
0
        bool bLineUsed(false);
228
0
        bool bAllFillUsed(false);
229
0
        bool bSolidFillUsed(false);
230
0
        bool bGradientFillUsed(false);
231
0
        bool bHatchFillUsed(false);
232
0
        bool bBitmapFillUsed(false);
233
234
0
        while(aIterator.IsMore())
235
0
        {
236
0
            SdrObject* pObj = aIterator.Next();
237
0
            drawing::FillStyle eFillStyle = pObj->GetMergedItem(XATTR_FILLSTYLE).GetValue();
238
239
0
            if(!bLineUsed)
240
0
            {
241
0
                drawing::LineStyle eLineStyle = pObj->GetMergedItem(XATTR_LINESTYLE).GetValue();
242
243
0
                if(drawing::LineStyle_NONE != eLineStyle)
244
0
                {
245
0
                    bLineUsed = true;
246
0
                }
247
0
            }
248
249
0
            if(!bAllFillUsed)
250
0
            {
251
0
                if(!bSolidFillUsed && drawing::FillStyle_SOLID == eFillStyle)
252
0
                {
253
0
                    bSolidFillUsed = true;
254
0
                    bAllFillUsed = (bSolidFillUsed && bGradientFillUsed && bHatchFillUsed && bBitmapFillUsed);
255
0
                }
256
0
                if(!bGradientFillUsed && drawing::FillStyle_GRADIENT == eFillStyle)
257
0
                {
258
0
                    bGradientFillUsed = true;
259
0
                    bAllFillUsed = (bSolidFillUsed && bGradientFillUsed && bHatchFillUsed && bBitmapFillUsed);
260
0
                }
261
0
                if(!bHatchFillUsed && drawing::FillStyle_HATCH == eFillStyle)
262
0
                {
263
0
                    bHatchFillUsed = true;
264
0
                    bAllFillUsed = (bSolidFillUsed && bGradientFillUsed && bHatchFillUsed && bBitmapFillUsed);
265
0
                }
266
0
                if(!bBitmapFillUsed && drawing::FillStyle_BITMAP == eFillStyle)
267
0
                {
268
0
                    bBitmapFillUsed = true;
269
0
                    bAllFillUsed = (bSolidFillUsed && bGradientFillUsed && bHatchFillUsed && bBitmapFillUsed);
270
0
                }
271
0
            }
272
0
        }
273
274
        // translate to shadow coordinates
275
0
        pRetval->NbcMove(Size(nXDist, nYDist));
276
277
        // set items as needed
278
0
        SfxItemSet aTempSet(rOriginalSet);
279
280
        // if a SvxWritingModeItem (Top->Bottom) is set the text object
281
        // is creating a paraobject, but paraobjects can not be created without model. So
282
        // we are preventing the crash by setting the writing mode always left to right,
283
        // this is not bad since our shadow geometry does not contain text.
284
0
        aTempSet.Put(SvxWritingModeItem(text::WritingMode_LR_TB, SDRATTR_TEXTDIRECTION));
285
286
        // no shadow
287
0
        aTempSet.Put(makeSdrShadowItem(false));
288
0
        aTempSet.Put(makeSdrShadowXDistItem(0));
289
0
        aTempSet.Put(makeSdrShadowYDistItem(0));
290
291
        // line color and transparency like shadow
292
0
        if(bLineUsed)
293
0
        {
294
0
            aTempSet.Put(XLineColorItem(OUString(), aShadowColor));
295
0
            aTempSet.Put(XLineTransparenceItem(nShadowTransparence));
296
0
        }
297
298
        // fill color and transparency like shadow
299
0
        if(bSolidFillUsed)
300
0
        {
301
0
            aTempSet.Put(XFillColorItem(OUString(), aShadowColor));
302
0
            aTempSet.Put(XFillTransparenceItem(nShadowTransparence));
303
0
        }
304
305
        // gradient and transparency like shadow
306
0
        if(bGradientFillUsed)
307
0
        {
308
0
            basegfx::BGradient aGradient(rOriginalSet.Get(XATTR_FILLGRADIENT).GetGradientValue());
309
0
            sal_uInt8 nStartLuminance(Color(aGradient.GetColorStops().front().getStopColor()).GetLuminance());
310
0
            sal_uInt8 nEndLuminance(Color(aGradient.GetColorStops().back().getStopColor()).GetLuminance());
311
312
0
            if(aGradient.GetStartIntens() != 100)
313
0
            {
314
0
                nStartLuminance = static_cast<sal_uInt8>(nStartLuminance * (static_cast<double>(aGradient.GetStartIntens()) / 100.0));
315
0
            }
316
317
0
            if(aGradient.GetEndIntens() != 100)
318
0
            {
319
0
                nEndLuminance = static_cast<sal_uInt8>(nEndLuminance * (static_cast<double>(aGradient.GetEndIntens()) / 100.0));
320
0
            }
321
322
0
            ::Color aStartColor(
323
0
                static_cast<sal_uInt8>((nStartLuminance * aShadowColor.GetRed()) / 256),
324
0
                static_cast<sal_uInt8>((nStartLuminance * aShadowColor.GetGreen()) / 256),
325
0
                static_cast<sal_uInt8>((nStartLuminance * aShadowColor.GetBlue()) / 256));
326
327
0
            ::Color aEndColor(
328
0
                static_cast<sal_uInt8>((nEndLuminance * aShadowColor.GetRed()) / 256),
329
0
                static_cast<sal_uInt8>((nEndLuminance * aShadowColor.GetGreen()) / 256),
330
0
                static_cast<sal_uInt8>((nEndLuminance * aShadowColor.GetBlue()) / 256));
331
332
0
            aGradient.SetColorStops(
333
0
                basegfx::BColorStops(
334
0
                    aStartColor.getBColor(),
335
0
                    aEndColor.getBColor()));
336
0
            aTempSet.Put(XFillGradientItem(aGradient));
337
0
            aTempSet.Put(XFillTransparenceItem(nShadowTransparence));
338
0
        }
339
340
        // hatch and transparency like shadow
341
0
        if(bHatchFillUsed)
342
0
        {
343
0
            XHatch aHatch(rOriginalSet.Get(XATTR_FILLHATCH).GetHatchValue());
344
0
            aHatch.SetColor(aShadowColor);
345
0
            aTempSet.Put(XFillHatchItem(aHatch));
346
0
            aTempSet.Put(XFillTransparenceItem(nShadowTransparence));
347
0
        }
348
349
        // bitmap and transparency like shadow
350
0
        if(bBitmapFillUsed)
351
0
        {
352
0
            GraphicObject aGraphicObject(rOriginalSet.Get(XATTR_FILLBITMAP).GetGraphicObject());
353
0
            Bitmap aBitmap(aGraphicObject.GetGraphic().GetBitmap());
354
355
0
            if(!aBitmap.IsEmpty())
356
0
            {
357
0
                ScopedVclPtr<VirtualDevice> pVirDev(VclPtr<VirtualDevice>::Create());
358
0
                pVirDev->SetOutputSizePixel(aBitmap.GetSizePixel());
359
0
                BitmapFilter::Filter(aBitmap, BitmapShadowFilter(aShadowColor));
360
0
                pVirDev->DrawBitmap(Point(), aBitmap);
361
0
                aGraphicObject.SetGraphic(Graphic(pVirDev->GetBitmap(Point(0,0), aBitmap.GetSizePixel())));
362
0
            }
363
364
0
            aTempSet.Put(XFillBitmapItem(aGraphicObject));
365
0
            aTempSet.Put(XFillTransparenceItem(nShadowTransparence));
366
0
        }
367
368
        // set attributes and paint shadow object
369
0
        pRetval->SetMergedItemSet( aTempSet );
370
0
    }
371
0
    return pRetval;
372
0
}
373
374
375
rtl::Reference<EnhancedCustomShapeEngine> const & SdrObjCustomShape::GetCustomShapeEngine() const
376
451k
{
377
451k
    if (mxCustomShapeEngine.is())
378
122k
        return mxCustomShapeEngine;
379
380
328k
    OUString aEngine(GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE ).GetValue());
381
328k
    if ( aEngine.isEmpty() || aEngine == "com.sun.star.drawing.EnhancedCustomShapeEngine")
382
328k
    {
383
328k
        mxCustomShapeEngine = new EnhancedCustomShapeEngine(*const_cast<SdrObjCustomShape*>(this));
384
328k
    }
385
386
328k
    return mxCustomShapeEngine;
387
451k
}
388
389
const SdrObject* SdrObjCustomShape::GetSdrObjectFromCustomShape() const
390
240k
{
391
240k
    if ( !mXRenderedCustomShape.is() )
392
82.7k
    {
393
82.7k
        rtl::Reference<EnhancedCustomShapeEngine> xCustomShapeEngine( GetCustomShapeEngine() );
394
82.7k
        if ( xCustomShapeEngine.is() )
395
82.7k
            mXRenderedCustomShape = xCustomShapeEngine->render2();
396
82.7k
    }
397
240k
    return mXRenderedCustomShape.get();
398
240k
}
399
400
// #i37011# Shadow geometry creation
401
const SdrObject* SdrObjCustomShape::GetSdrObjectShadowFromCustomShape() const
402
0
{
403
0
    if(!mpLastShadowGeometry)
404
0
    {
405
0
        const SdrObject* pSdrObject = GetSdrObjectFromCustomShape();
406
0
        if(pSdrObject)
407
0
        {
408
0
            const SfxItemSet& rOriginalSet = GetObjectItemSet();
409
0
            const bool bShadow(rOriginalSet.Get( SDRATTR_SHADOW ).GetValue());
410
411
0
            if(bShadow)
412
0
            {
413
                // create a clone with all attributes changed to shadow attributes
414
                // and translation executed, too.
415
0
                const_cast<SdrObjCustomShape*>(this)->mpLastShadowGeometry =
416
0
                    ImpCreateShadowObjectClone(*pSdrObject, rOriginalSet);
417
0
            }
418
0
        }
419
0
    }
420
421
0
    return mpLastShadowGeometry.get();
422
0
}
423
424
bool SdrObjCustomShape::IsTextPath() const
425
1.41k
{
426
1.41k
    static constexpr OUString sTextPath( u"TextPath"_ustr );
427
1.41k
    bool bTextPathOn = false;
428
1.41k
    const SdrCustomShapeGeometryItem& rGeometryItem = GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
429
1.41k
    const uno::Any* pAny = rGeometryItem.GetPropertyValueByName( sTextPath, sTextPath );
430
1.41k
    if ( pAny )
431
0
        *pAny >>= bTextPathOn;
432
1.41k
    return bTextPathOn;
433
1.41k
}
434
435
bool SdrObjCustomShape::UseNoFillStyle() const
436
0
{
437
0
    bool bRet = false;
438
0
    OUString sShapeType;
439
0
    static constexpr OUString sType( u"Type"_ustr );
440
0
    const SdrCustomShapeGeometryItem& rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
441
0
    const uno::Any* pAny = rGeometryItem.GetPropertyValueByName( sType );
442
0
    if ( pAny )
443
0
        *pAny >>= sShapeType;
444
0
    bRet = !IsCustomShapeFilledByDefault( EnhancedCustomShapeTypeNames::Get( sType ) );
445
446
0
    return bRet;
447
0
}
448
449
bool SdrObjCustomShape::IsMirroredX() const
450
170k
{
451
170k
    bool bMirroredX = false;
452
170k
    const SdrCustomShapeGeometryItem & rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
453
170k
    const uno::Any* pAny = rGeometryItem.GetPropertyValueByName( u"MirroredX"_ustr );
454
170k
    if ( pAny )
455
33.8k
        *pAny >>= bMirroredX;
456
170k
    return bMirroredX;
457
170k
}
458
bool SdrObjCustomShape::IsMirroredY() const
459
175k
{
460
175k
    bool bMirroredY = false;
461
175k
    const SdrCustomShapeGeometryItem & rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
462
175k
    const uno::Any* pAny = rGeometryItem.GetPropertyValueByName( u"MirroredY"_ustr );
463
175k
    if ( pAny )
464
37.3k
        *pAny >>= bMirroredY;
465
175k
    return bMirroredY;
466
175k
}
467
void SdrObjCustomShape::SetMirroredX( const bool bMirrorX )
468
7.70k
{
469
7.70k
    SdrCustomShapeGeometryItem aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
470
7.70k
    beans::PropertyValue aPropVal;
471
7.70k
    aPropVal.Name = "MirroredX";
472
7.70k
    aPropVal.Value <<= bMirrorX;
473
7.70k
    aGeometryItem.SetPropertyValue( aPropVal );
474
7.70k
    SetMergedItem( aGeometryItem );
475
7.70k
}
476
void SdrObjCustomShape::SetMirroredY( const bool bMirrorY )
477
10.9k
{
478
10.9k
    SdrCustomShapeGeometryItem aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
479
10.9k
    beans::PropertyValue aPropVal;
480
10.9k
    aPropVal.Name = "MirroredY";
481
10.9k
    aPropVal.Value <<= bMirrorY;
482
10.9k
    aGeometryItem.SetPropertyValue( aPropVal );
483
10.9k
    SetMergedItem( aGeometryItem );
484
10.9k
}
485
486
double SdrObjCustomShape::GetExtraTextRotation( const bool bPreRotation ) const
487
12.9k
{
488
12.9k
    double fExtraTextRotateAngle = 0.0;
489
12.9k
    if (bPreRotation)
490
740
    {
491
        // textPreRotateAngle might be set by macro or diagram (SmartArt) import
492
740
        const uno::Any* pAny;
493
740
        const SdrCustomShapeGeometryItem& rGeometryItem = GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
494
740
        pAny = rGeometryItem.GetPropertyValueByName(u"TextPreRotateAngle"_ustr);
495
740
        if ( pAny )
496
728
            *pAny >>= fExtraTextRotateAngle;
497
498
        // As long as the edit engine is not able to render these text directions we
499
        // emulate them by setting a suitable text pre-rotation.
500
740
        const SvxFrameDirectionItem& rDirectionItem = GetMergedItem(SDRATTR_WRITINGMODE2);
501
740
        if (rDirectionItem.GetValue() == SvxFrameDirection::Vertical_RL_TB90)
502
0
            fExtraTextRotateAngle -= 90;
503
740
        else if (rDirectionItem.GetValue() == SvxFrameDirection::Vertical_LR_BT)
504
76
            fExtraTextRotateAngle -=270;
505
740
    }
506
12.2k
    else
507
12.2k
    {
508
12.2k
        const uno::Any* pAny;
509
12.2k
        const SdrCustomShapeGeometryItem& rGeometryItem = GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
510
12.2k
        pAny = rGeometryItem.GetPropertyValueByName(u"TextRotateAngle"_ustr);
511
12.2k
        if ( pAny )
512
143
            *pAny >>= fExtraTextRotateAngle;
513
12.2k
    }
514
12.9k
    return fExtraTextRotateAngle;
515
12.9k
}
516
517
bool SdrObjCustomShape::GetTextBounds( tools::Rectangle& rTextBound ) const
518
357k
{
519
357k
    bool bRet = false;
520
521
357k
    rtl::Reference<EnhancedCustomShapeEngine> xCustomShapeEngine( GetCustomShapeEngine() );
522
357k
    if ( xCustomShapeEngine.is() )
523
357k
    {
524
357k
        tools::Rectangle aR( xCustomShapeEngine->getTextBounds() );
525
357k
        if ( aR.GetWidth() > 1 && aR.GetHeight() > 1 )
526
200k
        {
527
200k
            rTextBound = aR;
528
200k
            bRet = true;
529
200k
        }
530
357k
    }
531
357k
    return bRet;
532
357k
}
533
basegfx::B2DPolyPolygon SdrObjCustomShape::GetLineGeometry( const bool bBezierAllowed ) const
534
9.64k
{
535
9.64k
    basegfx::B2DPolyPolygon aRetval;
536
9.64k
    rtl::Reference<EnhancedCustomShapeEngine> xCustomShapeEngine( GetCustomShapeEngine() );
537
9.64k
    if ( xCustomShapeEngine.is() )
538
9.64k
    {
539
9.64k
        aRetval = xCustomShapeEngine->getB2DLineGeometry();
540
9.64k
        try
541
9.64k
        {
542
9.64k
            if ( !bBezierAllowed && aRetval.areControlPointsUsed())
543
0
            {
544
0
                aRetval = basegfx::utils::adaptiveSubdivideByAngle(aRetval);
545
0
            }
546
9.64k
        }
547
9.64k
        catch ( const lang::IllegalArgumentException & )
548
9.64k
        {
549
0
        }
550
9.64k
    }
551
9.64k
    return aRetval;
552
9.64k
}
553
554
std::vector< SdrCustomShapeInteraction > SdrObjCustomShape::GetInteractionHandles() const
555
1.76k
{
556
1.76k
    std::vector< SdrCustomShapeInteraction > aRet;
557
1.76k
    try
558
1.76k
    {
559
1.76k
        rtl::Reference<EnhancedCustomShapeEngine> xCustomShapeEngine( GetCustomShapeEngine() );
560
1.76k
        if ( !xCustomShapeEngine.is() )
561
0
            return aRet;
562
563
1.76k
        std::vector<uno::Reference<drawing::XCustomShapeHandle>> xInteractionHandles( xCustomShapeEngine->getInteraction() );
564
1.78k
        for ( size_t i = 0; i < xInteractionHandles.size(); i++ )
565
22
        {
566
22
            SdrCustomShapeInteraction aSdrCustomShapeInteraction;
567
22
            aSdrCustomShapeInteraction.xInteraction = xInteractionHandles[ i ];
568
22
            aSdrCustomShapeInteraction.aPosition = xInteractionHandles[ i ]->getPosition();
569
570
22
            CustomShapeHandleModes nMode = CustomShapeHandleModes::NONE;
571
22
            switch( ImpGetCustomShapeType( *this ) )
572
22
            {
573
0
                case mso_sptAccentBorderCallout90 :     // 2 ortho
574
0
                {
575
0
                    if (i == 0)
576
0
                        nMode |= CustomShapeHandleModes::RESIZE_FIXED | CustomShapeHandleModes::CREATE_FIXED;
577
0
                    else if (i == 1)
578
0
                        nMode |= CustomShapeHandleModes::RESIZE_ABSOLUTE_X | CustomShapeHandleModes::RESIZE_ABSOLUTE_Y | CustomShapeHandleModes::MOVE_SHAPE | CustomShapeHandleModes::ORTHO4;
579
0
                }
580
0
                break;
581
582
0
                case mso_sptChevron :
583
0
                case mso_sptHomePlate :
584
0
                     nMode |= CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX;
585
0
                break;
586
587
0
                case mso_sptWedgeRectCallout :
588
0
                case mso_sptWedgeRRectCallout :
589
0
                case mso_sptCloudCallout :
590
0
                case mso_sptWedgeEllipseCallout :
591
0
                {
592
0
                    if (i == 0)
593
0
                        nMode |= CustomShapeHandleModes::RESIZE_FIXED;
594
0
                }
595
0
                break;
596
597
0
                case mso_sptBorderCallout1 :            // 2 diag
598
0
                {
599
0
                    if (i == 0)
600
0
                        nMode |= CustomShapeHandleModes::RESIZE_FIXED | CustomShapeHandleModes::CREATE_FIXED;
601
0
                    else if (i == 1)
602
0
                        nMode |= CustomShapeHandleModes::RESIZE_ABSOLUTE_X | CustomShapeHandleModes::RESIZE_ABSOLUTE_Y | CustomShapeHandleModes::MOVE_SHAPE;
603
0
                }
604
0
                break;
605
0
                case mso_sptBorderCallout2 :            // 3
606
0
                {
607
0
                    if (i == 0)
608
0
                        nMode |= CustomShapeHandleModes::RESIZE_FIXED | CustomShapeHandleModes::CREATE_FIXED;
609
0
                    else if (i == 2)
610
0
                        nMode |= CustomShapeHandleModes::RESIZE_ABSOLUTE_X | CustomShapeHandleModes::RESIZE_ABSOLUTE_Y | CustomShapeHandleModes::MOVE_SHAPE;
611
0
                }
612
0
                break;
613
0
                case mso_sptCallout90 :
614
0
                case mso_sptAccentCallout90 :
615
0
                case mso_sptBorderCallout90 :
616
0
                case mso_sptCallout1 :
617
0
                case mso_sptCallout2 :
618
0
                case mso_sptCallout3 :
619
0
                case mso_sptAccentCallout1 :
620
0
                case mso_sptAccentCallout2 :
621
0
                case mso_sptAccentCallout3 :
622
0
                case mso_sptBorderCallout3 :
623
0
                case mso_sptAccentBorderCallout1 :
624
0
                case mso_sptAccentBorderCallout2 :
625
0
                case mso_sptAccentBorderCallout3 :
626
0
                {
627
0
                    if (i == 0)
628
0
                        nMode |= CustomShapeHandleModes::RESIZE_FIXED | CustomShapeHandleModes::CREATE_FIXED;
629
0
                }
630
0
                break;
631
22
                default: break;
632
22
            }
633
22
            aSdrCustomShapeInteraction.nMode = nMode;
634
22
            aRet.push_back( aSdrCustomShapeInteraction );
635
22
        }
636
1.76k
    }
637
1.76k
    catch( const uno::RuntimeException& )
638
1.76k
    {
639
0
    }
640
1.76k
    return aRet;
641
1.76k
}
642
643
644
// BaseProperties section
645
334k
#define DEFAULT_MINIMUM_SIGNED_COMPARE  (sal_Int32(0x80000000))
646
95.6k
#define DEFAULT_MAXIMUM_SIGNED_COMPARE  (sal_Int32(0x7fffffff))
647
648
static sal_Int32 GetNumberOfProperties ( const SvxMSDffHandle* pData )
649
35.1k
{
650
35.1k
    sal_Int32           nPropertiesNeeded=1;  // position is always needed
651
35.1k
    SvxMSDffHandleFlags nFlags = pData->nFlags;
652
653
35.1k
    if ( nFlags & SvxMSDffHandleFlags::MIRRORED_X )
654
0
        nPropertiesNeeded++;
655
35.1k
    if ( nFlags & SvxMSDffHandleFlags::MIRRORED_Y )
656
0
        nPropertiesNeeded++;
657
35.1k
    if ( nFlags & SvxMSDffHandleFlags::SWITCHED )
658
8.54k
        nPropertiesNeeded++;
659
35.1k
    if ( nFlags & SvxMSDffHandleFlags::POLAR )
660
10.1k
    {
661
10.1k
        nPropertiesNeeded++;
662
10.1k
        if ( nFlags & SvxMSDffHandleFlags::RADIUS_RANGE )
663
10.0k
        {
664
10.0k
            if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
665
10.0k
                nPropertiesNeeded++;
666
10.0k
            if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
667
10.0k
                nPropertiesNeeded++;
668
10.0k
        }
669
10.1k
    }
670
25.0k
    else if ( nFlags & SvxMSDffHandleFlags::RANGE )
671
18.8k
    {
672
18.8k
        if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
673
12.5k
            nPropertiesNeeded++;
674
18.8k
        if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
675
12.5k
            nPropertiesNeeded++;
676
18.8k
        if ( pData->nRangeYMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
677
3.24k
            nPropertiesNeeded++;
678
18.8k
        if ( pData->nRangeYMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
679
3.24k
            nPropertiesNeeded++;
680
18.8k
    }
681
682
35.1k
    return nPropertiesNeeded;
683
35.1k
}
684
685
static void lcl_ShapePropertiesFromDFF( const SvxMSDffHandle* pData, beans::PropertyValues& rPropValues )
686
35.1k
{
687
35.1k
    SvxMSDffHandleFlags nFlags = pData->nFlags;
688
35.1k
    sal_Int32 n=0;
689
35.1k
    auto pPropValues = rPropValues.getArray();
690
691
    // POSITION
692
35.1k
    {
693
35.1k
        drawing::EnhancedCustomShapeParameterPair aPosition;
694
35.1k
        EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.First, pData->nPositionX, true, true );
695
35.1k
        EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.Second, pData->nPositionY, true, false );
696
35.1k
        pPropValues[ n ].Name = "Position";
697
35.1k
        pPropValues[ n++ ].Value <<= aPosition;
698
35.1k
    }
699
35.1k
    if ( nFlags & SvxMSDffHandleFlags::MIRRORED_X )
700
0
    {
701
0
        pPropValues[ n ].Name = "MirroredX";
702
0
        pPropValues[ n++ ].Value <<= true;
703
0
    }
704
35.1k
    if ( nFlags & SvxMSDffHandleFlags::MIRRORED_Y )
705
0
    {
706
0
        pPropValues[ n ].Name = "MirroredY";
707
0
        pPropValues[ n++ ].Value <<= true;
708
0
    }
709
35.1k
    if ( nFlags & SvxMSDffHandleFlags::SWITCHED )
710
8.54k
    {
711
8.54k
        pPropValues[ n ].Name = "Switched";
712
8.54k
        pPropValues[ n++ ].Value <<= true;
713
8.54k
    }
714
35.1k
    if ( nFlags & SvxMSDffHandleFlags::POLAR )
715
10.1k
    {
716
10.1k
        drawing::EnhancedCustomShapeParameterPair aCenter;
717
10.1k
        EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aCenter.First, pData->nCenterX,
718
10.1k
                           bool( nFlags & SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL ), true  );
719
10.1k
        EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aCenter.Second, pData->nCenterY,
720
10.1k
                           bool( nFlags & SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL ), false );
721
10.1k
        pPropValues[ n ].Name = "Polar";
722
10.1k
        pPropValues[ n++ ].Value <<= aCenter;
723
10.1k
        if ( nFlags & SvxMSDffHandleFlags::RADIUS_RANGE )
724
10.0k
        {
725
10.0k
            if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
726
10.0k
            {
727
10.0k
                drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum;
728
10.0k
                EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMinimum, pData->nRangeXMin,
729
10.0k
                           bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true  );
730
10.0k
                pPropValues[ n ].Name = "RadiusRangeMinimum";
731
10.0k
                pPropValues[ n++ ].Value <<= aRadiusRangeMinimum;
732
10.0k
            }
733
10.0k
            if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
734
10.0k
            {
735
10.0k
                drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum;
736
10.0k
                EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMaximum, pData->nRangeXMax,
737
10.0k
                           bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false );
738
10.0k
                pPropValues[ n ].Name = "RadiusRangeMaximum";
739
10.0k
                pPropValues[ n++ ].Value <<= aRadiusRangeMaximum;
740
10.0k
            }
741
10.0k
        }
742
10.1k
    }
743
25.0k
    else if ( nFlags & SvxMSDffHandleFlags::RANGE )
744
18.8k
    {
745
18.8k
        if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
746
12.5k
        {
747
12.5k
            drawing::EnhancedCustomShapeParameter aRangeXMinimum;
748
12.5k
            EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMinimum, pData->nRangeXMin,
749
12.5k
                           bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true  );
750
12.5k
            pPropValues[ n ].Name = "RangeXMinimum";
751
12.5k
            pPropValues[ n++ ].Value <<= aRangeXMinimum;
752
12.5k
        }
753
18.8k
        if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
754
12.5k
        {
755
12.5k
            drawing::EnhancedCustomShapeParameter aRangeXMaximum;
756
12.5k
            EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMaximum, pData->nRangeXMax,
757
12.5k
                           bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false );
758
12.5k
            pPropValues[ n ].Name = "RangeXMaximum";
759
12.5k
            pPropValues[ n++ ].Value <<= aRangeXMaximum;
760
12.5k
        }
761
18.8k
        if ( pData->nRangeYMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
762
3.24k
        {
763
3.24k
            drawing::EnhancedCustomShapeParameter aRangeYMinimum;
764
3.24k
            EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMinimum, pData->nRangeYMin,
765
3.24k
                             bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL ), true );
766
3.24k
            pPropValues[ n ].Name = "RangeYMinimum";
767
3.24k
            pPropValues[ n++ ].Value <<= aRangeYMinimum;
768
3.24k
        }
769
18.8k
        if ( pData->nRangeYMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
770
3.24k
        {
771
3.24k
            drawing::EnhancedCustomShapeParameter aRangeYMaximum;
772
3.24k
            EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMaximum, pData->nRangeYMax,
773
3.24k
                             bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL ), false );
774
3.24k
            pPropValues[ n ].Name = "RangeYMaximum";
775
3.24k
            pPropValues[ n++ ].Value <<= aRangeYMaximum;
776
3.24k
        }
777
18.8k
    }
778
35.1k
}
779
780
std::unique_ptr<sdr::properties::BaseProperties> SdrObjCustomShape::CreateObjectSpecificProperties()
781
147k
{
782
147k
    return std::make_unique<sdr::properties::CustomShapeProperties>(*this);
783
147k
}
784
785
SdrObjCustomShape::SdrObjCustomShape(SdrModel& rSdrModel)
786
147k
:   SdrTextObj(rSdrModel)
787
147k
    , m_fObjectRotation(0.0)
788
147k
    , mbAdjustingTextFrameWidthAndHeight(false)
789
147k
{
790
147k
    m_bClosedObj = true; // custom shapes may be filled
791
147k
    mbTextFrame = true;
792
147k
}
793
794
SdrObjCustomShape::SdrObjCustomShape(SdrModel& rSdrModel, SdrObjCustomShape const & rSource)
795
5.49k
:   SdrTextObj(rSdrModel, rSource)
796
5.49k
    , m_fObjectRotation(0.0)
797
5.49k
    , mbAdjustingTextFrameWidthAndHeight(false)
798
5.49k
{
799
5.49k
    m_bClosedObj = true; // custom shapes may be filled
800
5.49k
    mbTextFrame = true;
801
802
5.49k
    m_fObjectRotation = rSource.m_fObjectRotation;
803
5.49k
    mbAdjustingTextFrameWidthAndHeight = rSource.mbAdjustingTextFrameWidthAndHeight;
804
5.49k
    assert(!mbAdjustingTextFrameWidthAndHeight);
805
5.49k
    InvalidateRenderGeometry();
806
5.49k
}
807
808
SdrObjCustomShape::~SdrObjCustomShape()
809
152k
{
810
    // delete buffered display geometry
811
152k
    InvalidateRenderGeometry();
812
152k
}
813
814
void SdrObjCustomShape::MergeDefaultAttributes( const OUString* pType )
815
147k
{
816
147k
    beans::PropertyValue aPropVal;
817
147k
    OUString sShapeType;
818
147k
    static constexpr OUString sType( u"Type"_ustr );
819
147k
    SdrCustomShapeGeometryItem aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
820
147k
    if ( pType && !pType->isEmpty() )
821
961
    {
822
961
        sal_Int32 nType = pType->toInt32();
823
961
        if ( nType )
824
222
            sShapeType = EnhancedCustomShapeTypeNames::Get( static_cast< MSO_SPT >( nType ) );
825
739
        else
826
739
            sShapeType = *pType;
827
828
961
        aPropVal.Name = sType;
829
961
        aPropVal.Value <<= sShapeType;
830
961
        aGeometryItem.SetPropertyValue( aPropVal );
831
961
    }
832
146k
    else
833
146k
    {
834
146k
        uno::Any *pAny = aGeometryItem.GetPropertyValueByName( sType );
835
146k
        if ( pAny )
836
125k
            *pAny >>= sShapeType;
837
146k
    }
838
147k
    MSO_SPT eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );
839
840
147k
    const sal_Int32* pDefData = nullptr;
841
147k
    const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( eSpType );
842
147k
    if ( pDefCustomShape )
843
120k
        pDefData = pDefCustomShape->pDefData;
844
845
147k
    uno::Sequence<drawing::EnhancedCustomShapeAdjustmentValue> seqAdjustmentValues;
846
847
848
    // AdjustmentValues
849
850
147k
    static constexpr OUString sAdjustmentValues( u"AdjustmentValues"_ustr );
851
147k
    const uno::Any* pAny = aGeometryItem.GetPropertyValueByName( sAdjustmentValues );
852
147k
    if ( pAny )
853
19.2k
        *pAny >>= seqAdjustmentValues;
854
147k
    if ( pDefCustomShape && pDefData )  // now check if we have to default some adjustment values
855
24.7k
    {
856
        // first check if there are adjustment values are to be appended
857
24.7k
        sal_Int32 i, nAdjustmentValues = seqAdjustmentValues.getLength();
858
24.7k
        sal_Int32 nAdjustmentDefaults = *pDefData++;
859
24.7k
        if ( nAdjustmentDefaults > nAdjustmentValues )
860
11.2k
            seqAdjustmentValues.realloc( nAdjustmentDefaults );
861
24.7k
        auto pseqAdjustmentValues = seqAdjustmentValues.getArray();
862
46.5k
        for ( i = nAdjustmentValues; i < nAdjustmentDefaults; i++ )
863
21.8k
        {
864
21.8k
            pseqAdjustmentValues[ i ].Value <<= pDefData[ i ];
865
21.8k
            pseqAdjustmentValues[ i ].State = beans::PropertyState_DIRECT_VALUE;
866
21.8k
        }
867
        // check if there are defaulted adjustment values that should be filled the hard coded defaults (pDefValue)
868
24.7k
        sal_Int32 nCount = std::min(nAdjustmentValues, nAdjustmentDefaults);
869
45.3k
        for ( i = 0; i < nCount; i++ )
870
20.6k
        {
871
20.6k
            if ( seqAdjustmentValues[ i ].State != beans::PropertyState_DIRECT_VALUE )
872
1.12k
            {
873
1.12k
                pseqAdjustmentValues[ i ].Value <<= pDefData[ i ];
874
1.12k
                pseqAdjustmentValues[ i ].State = beans::PropertyState_DIRECT_VALUE;
875
1.12k
            }
876
20.6k
        }
877
24.7k
    }
878
147k
    aPropVal.Name = sAdjustmentValues;
879
147k
    aPropVal.Value <<= seqAdjustmentValues;
880
147k
    aGeometryItem.SetPropertyValue( aPropVal );
881
882
883
    // Coordsize
884
885
147k
    static constexpr OUString sViewBox( u"ViewBox"_ustr );
886
147k
    const uno::Any* pViewBox = aGeometryItem.GetPropertyValueByName( sViewBox );
887
147k
    awt::Rectangle aViewBox;
888
147k
    if ( !pViewBox || !(*pViewBox >>= aViewBox ) )
889
140k
    {
890
140k
        if ( pDefCustomShape )
891
118k
        {
892
118k
            aViewBox.X = 0;
893
118k
            aViewBox.Y = 0;
894
118k
            aViewBox.Width = pDefCustomShape->nCoordWidth;
895
118k
            aViewBox.Height= pDefCustomShape->nCoordHeight;
896
118k
            aPropVal.Name = sViewBox;
897
118k
            aPropVal.Value <<= aViewBox;
898
118k
            aGeometryItem.SetPropertyValue( aPropVal );
899
118k
        }
900
140k
    }
901
902
147k
    static constexpr OUString sPath( u"Path"_ustr );
903
904
905
    // Path/Coordinates
906
907
147k
    static constexpr OUString sCoordinates( u"Coordinates"_ustr );
908
147k
    pAny = aGeometryItem.GetPropertyValueByName( sPath, sCoordinates );
909
147k
    if (!pAny && pDefCustomShape && !pDefCustomShape->pVertices.empty())
910
119k
    {
911
119k
        sal_Int32 i, nCount = pDefCustomShape->pVertices.size();
912
119k
        uno::Sequence<drawing::EnhancedCustomShapeParameterPair> seqCoordinates( nCount );
913
119k
        auto pseqCoordinates = seqCoordinates.getArray();
914
782k
        for ( i = 0; i < nCount; i++ )
915
663k
        {
916
663k
            EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqCoordinates[ i ].First, pDefCustomShape->pVertices[ i ].nValA );
917
663k
            EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqCoordinates[ i ].Second, pDefCustomShape->pVertices[ i ].nValB );
918
663k
        }
919
119k
        aPropVal.Name = sCoordinates;
920
119k
        aPropVal.Value <<= seqCoordinates;
921
119k
        aGeometryItem.SetPropertyValue( sPath, aPropVal );
922
119k
    }
923
924
    // Path/GluePoints
925
147k
    static constexpr OUString sGluePoints( u"GluePoints"_ustr );
926
147k
    pAny = aGeometryItem.GetPropertyValueByName( sPath, sGluePoints );
927
147k
    if (!pAny && pDefCustomShape && !pDefCustomShape->pGluePoints.empty())
928
3.67k
    {
929
3.67k
        sal_Int32 i, nCount = pDefCustomShape->pGluePoints.size();
930
3.67k
        uno::Sequence<drawing::EnhancedCustomShapeParameterPair> seqGluePoints( nCount );
931
3.67k
        auto pseqGluePoints = seqGluePoints.getArray();
932
25.4k
        for ( i = 0; i < nCount; i++ )
933
21.7k
        {
934
21.7k
            EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqGluePoints[ i ].First, pDefCustomShape->pGluePoints[ i ].nValA );
935
21.7k
            EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqGluePoints[ i ].Second, pDefCustomShape->pGluePoints[ i ].nValB );
936
21.7k
        }
937
3.67k
        aPropVal.Name = sGluePoints;
938
3.67k
        aPropVal.Value <<= seqGluePoints;
939
3.67k
        aGeometryItem.SetPropertyValue( sPath, aPropVal );
940
3.67k
    }
941
942
    // Path/Segments
943
147k
    static constexpr OUString sSegments( u"Segments"_ustr );
944
147k
    pAny = aGeometryItem.GetPropertyValueByName( sPath, sSegments );
945
147k
    if ( !pAny && pDefCustomShape && pDefCustomShape->nElements && pDefCustomShape->pElements )
946
27.6k
    {
947
27.6k
        sal_Int32 i, nCount = pDefCustomShape->nElements;
948
27.6k
        uno::Sequence<drawing::EnhancedCustomShapeSegment> seqSegments( nCount );
949
27.6k
        auto pseqSegments = seqSegments.getArray();
950
216k
        for ( i = 0; i < nCount; i++ )
951
189k
        {
952
189k
            drawing::EnhancedCustomShapeSegment& rSegInfo = pseqSegments[ i ];
953
189k
            sal_uInt16 nSDat = pDefCustomShape->pElements[ i ];
954
189k
            lcl_ShapeSegmentFromBinary( rSegInfo, nSDat );
955
189k
        }
956
27.6k
        aPropVal.Name = sSegments;
957
27.6k
        aPropVal.Value <<= seqSegments;
958
27.6k
        aGeometryItem.SetPropertyValue( sPath, aPropVal );
959
27.6k
    }
960
961
    // Path/StretchX
962
147k
    static constexpr OUString sStretchX( u"StretchX"_ustr );
963
147k
    pAny = aGeometryItem.GetPropertyValueByName( sPath, sStretchX );
964
147k
    if ( !pAny && pDefCustomShape )
965
118k
    {
966
118k
        sal_Int32 nXRef = pDefCustomShape->nXRef;
967
118k
        if ( nXRef != DEFAULT_MINIMUM_SIGNED_COMPARE )
968
8.56k
        {
969
8.56k
            aPropVal.Name = sStretchX;
970
8.56k
            aPropVal.Value <<= nXRef;
971
8.56k
            aGeometryItem.SetPropertyValue( sPath, aPropVal );
972
8.56k
        }
973
118k
    }
974
975
    // Path/StretchY
976
147k
    static constexpr OUString sStretchY( u"StretchY"_ustr );
977
147k
    pAny = aGeometryItem.GetPropertyValueByName( sPath, sStretchY );
978
147k
    if ( !pAny && pDefCustomShape )
979
120k
    {
980
120k
        sal_Int32 nYRef = pDefCustomShape->nYRef;
981
120k
        if ( nYRef != DEFAULT_MINIMUM_SIGNED_COMPARE )
982
8.55k
        {
983
8.55k
            aPropVal.Name = sStretchY;
984
8.55k
            aPropVal.Value <<= nYRef;
985
8.55k
            aGeometryItem.SetPropertyValue( sPath, aPropVal );
986
8.55k
        }
987
120k
    }
988
989
    // Path/TextFrames
990
147k
    static constexpr OUString sTextFrames( u"TextFrames"_ustr );
991
147k
    pAny = aGeometryItem.GetPropertyValueByName( sPath, sTextFrames );
992
147k
    if (!pAny && pDefCustomShape && !pDefCustomShape->pTextRect.empty())
993
15.0k
    {
994
15.0k
        sal_Int32 i, nCount = pDefCustomShape->pTextRect.size();
995
15.0k
        uno::Sequence<drawing::EnhancedCustomShapeTextFrame> seqTextFrames( nCount );
996
15.0k
        auto pseqTextFrames = seqTextFrames.getArray();
997
30.3k
        for (i = 0; i < nCount; i++)
998
15.2k
        {
999
15.2k
            const SvxMSDffTextRectangles* pRectangles = &pDefCustomShape->pTextRect[i];
1000
15.2k
            EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames[ i ].TopLeft.First,     pRectangles->nPairA.nValA );
1001
15.2k
            EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames[ i ].TopLeft.Second,    pRectangles->nPairA.nValB );
1002
15.2k
            EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames[ i ].BottomRight.First,  pRectangles->nPairB.nValA );
1003
15.2k
            EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames[ i ].BottomRight.Second, pRectangles->nPairB.nValB );
1004
15.2k
        }
1005
15.0k
        aPropVal.Name = sTextFrames;
1006
15.0k
        aPropVal.Value <<= seqTextFrames;
1007
15.0k
        aGeometryItem.SetPropertyValue( sPath, aPropVal );
1008
15.0k
    }
1009
1010
    // Equations
1011
147k
    static constexpr OUString sEquations(  u"Equations"_ustr  );
1012
147k
    pAny = aGeometryItem.GetPropertyValueByName( sEquations );
1013
147k
    if (!pAny && pDefCustomShape && !pDefCustomShape->pCalculation.empty() )
1014
24.2k
    {
1015
24.2k
        sal_Int32 i, nCount = pDefCustomShape->pCalculation.size();
1016
24.2k
        uno::Sequence< OUString > seqEquations( nCount );
1017
24.2k
        auto pseqEquations = seqEquations.getArray();
1018
257k
        for (i = 0; i < nCount; i++)
1019
232k
        {
1020
232k
            const SvxMSDffCalculationData* pData = &pDefCustomShape->pCalculation[i];
1021
232k
            pseqEquations[ i ] = EnhancedCustomShape2d::GetEquation( pData->nFlags, pData->nVal[ 0 ], pData->nVal[ 1 ], pData->nVal[ 2 ] );
1022
232k
        }
1023
24.2k
        aPropVal.Name = sEquations;
1024
24.2k
        aPropVal.Value <<= seqEquations;
1025
24.2k
        aGeometryItem.SetPropertyValue( aPropVal );
1026
24.2k
    }
1027
1028
    // Handles
1029
147k
    static constexpr OUString sHandles(  u"Handles"_ustr  );
1030
147k
    pAny = aGeometryItem.GetPropertyValueByName( sHandles );
1031
147k
    if  (!pAny && pDefCustomShape && !pDefCustomShape->pHandles.empty())
1032
24.4k
    {
1033
24.4k
        sal_Int32 i, nCount = pDefCustomShape->pHandles.size();
1034
24.4k
        uno::Sequence<beans::PropertyValues> seqHandles( nCount );
1035
24.4k
        auto pseqHandles = seqHandles.getArray();
1036
59.6k
        for (i = 0; i < nCount; i++)
1037
35.1k
        {
1038
35.1k
            const SvxMSDffHandle* pData = &pDefCustomShape->pHandles[i];
1039
35.1k
            sal_Int32 nPropertiesNeeded;
1040
35.1k
            beans::PropertyValues& rPropValues = pseqHandles[ i ];
1041
35.1k
            nPropertiesNeeded = GetNumberOfProperties( pData );
1042
35.1k
            rPropValues.realloc( nPropertiesNeeded );
1043
35.1k
            lcl_ShapePropertiesFromDFF( pData, rPropValues );
1044
35.1k
        }
1045
24.4k
        aPropVal.Name = sHandles;
1046
24.4k
        aPropVal.Value <<= seqHandles;
1047
24.4k
        aGeometryItem.SetPropertyValue( aPropVal );
1048
24.4k
    }
1049
123k
    else if (pAny && sShapeType.startsWith("ooxml-") && sShapeType != "ooxml-non-primitive")
1050
0
    {
1051
        // ODF is not able to store the ooxml way of connecting handle to an adjustment
1052
        // value by name, e.g. attribute RefX="adj". So the information is lost, when exporting
1053
        // a pptx to odp, for example. This part reconstructs this information for the
1054
        // ooxml preset shapes from their definition.
1055
0
        uno::Sequence<beans::PropertyValues> seqHandles;
1056
0
        *pAny >>= seqHandles;
1057
0
        auto seqHandlesRange = asNonConstRange(seqHandles);
1058
0
        bool bChanged(false);
1059
0
        for (sal_Int32 i = 0; i < seqHandles.getLength(); i++)
1060
0
        {
1061
0
            comphelper::SequenceAsHashMap aHandleProps(seqHandles[i]);
1062
0
            OUString sFirstRefType;
1063
0
            sal_Int32 nFirstAdjRef;
1064
0
            OUString sSecondRefType;
1065
0
            sal_Int32 nSecondAdjRef;
1066
0
            PresetOOXHandleAdj::GetOOXHandleAdjRelation(sShapeType, i, sFirstRefType, nFirstAdjRef,
1067
0
                                                        sSecondRefType, nSecondAdjRef);
1068
0
            if (sFirstRefType != "na" && 0 <= nFirstAdjRef
1069
0
                && nFirstAdjRef < seqAdjustmentValues.getLength())
1070
0
            {
1071
0
                bChanged |= aHandleProps.createItemIfMissing(sFirstRefType, nFirstAdjRef);
1072
0
            }
1073
0
            if (sSecondRefType != "na" && 0 <= nSecondAdjRef
1074
0
                && nSecondAdjRef < seqAdjustmentValues.getLength())
1075
0
            {
1076
0
                bChanged |= aHandleProps.createItemIfMissing(sSecondRefType, nSecondAdjRef);
1077
0
            }
1078
0
            aHandleProps >> seqHandlesRange[i];
1079
0
        }
1080
0
        if (bChanged)
1081
0
        {
1082
0
            aPropVal.Name = sHandles;
1083
0
            aPropVal.Value <<= seqHandles;
1084
0
            aGeometryItem.SetPropertyValue(aPropVal);
1085
0
        }
1086
0
    }
1087
1088
147k
    SetMergedItem( aGeometryItem );
1089
147k
}
1090
1091
bool SdrObjCustomShape::IsDefaultGeometry( const DefaultType eDefaultType ) const
1092
0
{
1093
0
    bool bIsDefaultGeometry = false;
1094
1095
0
    OUString sShapeType;
1096
0
    const SdrCustomShapeGeometryItem & rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
1097
1098
0
    const uno::Any *pAny = rGeometryItem.GetPropertyValueByName( u"Type"_ustr );
1099
0
    if ( pAny )
1100
0
        *pAny >>= sShapeType;
1101
1102
0
    MSO_SPT eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );
1103
1104
0
    const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( eSpType );
1105
0
    static constexpr OUString sPath( u"Path"_ustr );
1106
0
    switch( eDefaultType )
1107
0
    {
1108
0
        case DefaultType::Viewbox :
1109
0
        {
1110
0
            const uno::Any* pViewBox = rGeometryItem.GetPropertyValueByName( u"ViewBox"_ustr );
1111
0
            awt::Rectangle aViewBox;
1112
0
            if (pViewBox && (*pViewBox >>= aViewBox) && pDefCustomShape)
1113
0
            {
1114
0
                if ( ( aViewBox.Width == pDefCustomShape->nCoordWidth )
1115
0
                    && ( aViewBox.Height == pDefCustomShape->nCoordHeight ) )
1116
0
                    bIsDefaultGeometry = true;
1117
0
            }
1118
0
        }
1119
0
        break;
1120
1121
0
        case DefaultType::Path :
1122
0
        {
1123
0
            pAny = rGeometryItem.GetPropertyValueByName( sPath, u"Coordinates"_ustr );
1124
0
            if (pAny && pDefCustomShape && !pDefCustomShape->pVertices.empty())
1125
0
            {
1126
0
                uno::Sequence<drawing::EnhancedCustomShapeParameterPair> seqCoordinates1;
1127
0
                if ( *pAny >>= seqCoordinates1 )
1128
0
                {
1129
0
                    sal_Int32 i, nCount = pDefCustomShape->pVertices.size();
1130
0
                    uno::Sequence<drawing::EnhancedCustomShapeParameterPair> seqCoordinates2( nCount );
1131
0
                    auto pseqCoordinates2 = seqCoordinates2.getArray();
1132
0
                    for ( i = 0; i < nCount; i++ )
1133
0
                    {
1134
0
                        EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqCoordinates2[ i ].First, pDefCustomShape->pVertices[ i ].nValA );
1135
0
                        EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqCoordinates2[ i ].Second, pDefCustomShape->pVertices[ i ].nValB );
1136
0
                    }
1137
0
                    if ( seqCoordinates1 == seqCoordinates2 )
1138
0
                        bIsDefaultGeometry = true;
1139
0
                }
1140
0
            }
1141
0
            else if (pDefCustomShape && pDefCustomShape->pVertices.empty())
1142
0
                bIsDefaultGeometry = true;
1143
0
        }
1144
0
        break;
1145
1146
0
        case DefaultType::Gluepoints :
1147
0
        {
1148
0
            pAny = rGeometryItem.GetPropertyValueByName( sPath, u"GluePoints"_ustr );
1149
0
            if (pAny && pDefCustomShape && !pDefCustomShape->pGluePoints.empty())
1150
0
            {
1151
0
                uno::Sequence<drawing::EnhancedCustomShapeParameterPair> seqGluePoints1;
1152
0
                if ( *pAny >>= seqGluePoints1 )
1153
0
                {
1154
0
                    sal_Int32 i, nCount = pDefCustomShape->pGluePoints.size();
1155
0
                    uno::Sequence<drawing::EnhancedCustomShapeParameterPair> seqGluePoints2( nCount );
1156
0
                    auto pseqGluePoints2 = seqGluePoints2.getArray();
1157
0
                    for ( i = 0; i < nCount; i++ )
1158
0
                    {
1159
0
                        EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqGluePoints2[ i ].First, pDefCustomShape->pGluePoints[ i ].nValA );
1160
0
                        EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqGluePoints2[ i ].Second, pDefCustomShape->pGluePoints[ i ].nValB );
1161
0
                    }
1162
0
                    if ( seqGluePoints1 == seqGluePoints2 )
1163
0
                        bIsDefaultGeometry = true;
1164
0
                }
1165
0
            }
1166
0
            else if (pDefCustomShape && pDefCustomShape->pGluePoints.empty())
1167
0
                bIsDefaultGeometry = true;
1168
0
        }
1169
0
        break;
1170
1171
0
        case DefaultType::Segments :
1172
0
        {
1173
            // Path/Segments
1174
0
            pAny = rGeometryItem.GetPropertyValueByName( sPath, u"Segments"_ustr );
1175
0
            if ( pAny )
1176
0
            {
1177
0
                uno::Sequence<drawing::EnhancedCustomShapeSegment> seqSegments1;
1178
0
                if ( *pAny >>= seqSegments1 )
1179
0
                {
1180
0
                    if ( pDefCustomShape && pDefCustomShape->nElements && pDefCustomShape->pElements )
1181
0
                    {
1182
0
                        sal_Int32 i, nCount = pDefCustomShape->nElements;
1183
0
                        if ( nCount )
1184
0
                        {
1185
0
                            uno::Sequence<drawing::EnhancedCustomShapeSegment> seqSegments2( nCount );
1186
0
                            auto pseqSegments2 = seqSegments2.getArray();
1187
0
                            for ( i = 0; i < nCount; i++ )
1188
0
                            {
1189
0
                                drawing::EnhancedCustomShapeSegment& rSegInfo = pseqSegments2[ i ];
1190
0
                                sal_uInt16 nSDat = pDefCustomShape->pElements[ i ];
1191
0
                                lcl_ShapeSegmentFromBinary( rSegInfo, nSDat );
1192
0
                            }
1193
0
                            if ( seqSegments1 == seqSegments2 )
1194
0
                                bIsDefaultGeometry = true;
1195
0
                        }
1196
0
                    }
1197
0
                    else
1198
0
                    {
1199
                        // check if it's the default segment description ( M L Z N )
1200
0
                        if ( seqSegments1.getLength() == 4 )
1201
0
                        {
1202
0
                            if ( ( seqSegments1[ 0 ].Command == drawing::EnhancedCustomShapeSegmentCommand::MOVETO )
1203
0
                                && ( seqSegments1[ 1 ].Command == drawing::EnhancedCustomShapeSegmentCommand::LINETO )
1204
0
                                && ( seqSegments1[ 2 ].Command == drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH )
1205
0
                                && ( seqSegments1[ 3 ].Command == drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH ) )
1206
0
                                bIsDefaultGeometry = true;
1207
0
                        }
1208
0
                    }
1209
0
                }
1210
0
            }
1211
0
            else if ( pDefCustomShape && ( ( pDefCustomShape->nElements == 0 ) || ( pDefCustomShape->pElements == nullptr ) ) )
1212
0
                bIsDefaultGeometry = true;
1213
0
        }
1214
0
        break;
1215
1216
0
        case DefaultType::StretchX :
1217
0
        {
1218
0
            pAny = rGeometryItem.GetPropertyValueByName( sPath, u"StretchX"_ustr );
1219
0
            if ( pAny && pDefCustomShape )
1220
0
            {
1221
0
                sal_Int32 nStretchX = 0;
1222
0
                if ( *pAny >>= nStretchX )
1223
0
                {
1224
0
                    if ( pDefCustomShape->nXRef == nStretchX )
1225
0
                        bIsDefaultGeometry = true;
1226
0
                }
1227
0
            }
1228
0
            else if ( pDefCustomShape && ( pDefCustomShape->nXRef == DEFAULT_MINIMUM_SIGNED_COMPARE ) )
1229
0
                bIsDefaultGeometry = true;
1230
0
        }
1231
0
        break;
1232
1233
0
        case DefaultType::StretchY :
1234
0
        {
1235
0
            pAny = rGeometryItem.GetPropertyValueByName( sPath, u"StretchY"_ustr );
1236
0
            if ( pAny && pDefCustomShape )
1237
0
            {
1238
0
                sal_Int32 nStretchY = 0;
1239
0
                if ( *pAny >>= nStretchY )
1240
0
                {
1241
0
                    if ( pDefCustomShape->nYRef == nStretchY )
1242
0
                        bIsDefaultGeometry = true;
1243
0
                }
1244
0
            }
1245
0
            else if ( pDefCustomShape && ( pDefCustomShape->nYRef == DEFAULT_MINIMUM_SIGNED_COMPARE ) )
1246
0
                bIsDefaultGeometry = true;
1247
0
        }
1248
0
        break;
1249
1250
0
        case DefaultType::Equations :
1251
0
        {
1252
0
            pAny = rGeometryItem.GetPropertyValueByName( u"Equations"_ustr );
1253
0
            if (pAny && pDefCustomShape && !pDefCustomShape->pCalculation.empty())
1254
0
            {
1255
0
                uno::Sequence<OUString> seqEquations1;
1256
0
                if ( *pAny >>= seqEquations1 )
1257
0
                {
1258
0
                    sal_Int32 i, nCount = pDefCustomShape->pCalculation.size();
1259
0
                    uno::Sequence<OUString> seqEquations2( nCount );
1260
0
                    auto pseqEquations2 = seqEquations2.getArray();
1261
1262
0
                    for (i = 0; i < nCount; i++)
1263
0
                    {
1264
0
                        const SvxMSDffCalculationData* pData = &pDefCustomShape->pCalculation[i];
1265
0
                        pseqEquations2[ i ] = EnhancedCustomShape2d::GetEquation( pData->nFlags, pData->nVal[ 0 ], pData->nVal[ 1 ], pData->nVal[ 2 ] );
1266
0
                    }
1267
1268
0
                    if ( seqEquations1 == seqEquations2 )
1269
0
                        bIsDefaultGeometry = true;
1270
0
                }
1271
0
            }
1272
0
            else if (pDefCustomShape && pDefCustomShape->pCalculation.empty())
1273
0
                bIsDefaultGeometry = true;
1274
0
        }
1275
0
        break;
1276
1277
0
        case DefaultType::TextFrames :
1278
0
        {
1279
0
            pAny = rGeometryItem.GetPropertyValueByName( sPath, u"TextFrames"_ustr );
1280
0
            if (pAny && pDefCustomShape && !pDefCustomShape->pTextRect.empty())
1281
0
            {
1282
0
                uno::Sequence<drawing::EnhancedCustomShapeTextFrame> seqTextFrames1;
1283
0
                if ( *pAny >>= seqTextFrames1 )
1284
0
                {
1285
0
                    sal_Int32 i, nCount = pDefCustomShape->pTextRect.size();
1286
0
                    uno::Sequence<drawing::EnhancedCustomShapeTextFrame> seqTextFrames2( nCount );
1287
0
                    auto pseqTextFrames2 = seqTextFrames2.getArray();
1288
0
                    for (i = 0; i < nCount; i++)
1289
0
                    {
1290
0
                        const SvxMSDffTextRectangles* pRectangles = &pDefCustomShape->pTextRect[i];
1291
0
                        EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames2[ i ].TopLeft.First,    pRectangles->nPairA.nValA );
1292
0
                        EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames2[ i ].TopLeft.Second,   pRectangles->nPairA.nValB );
1293
0
                        EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames2[ i ].BottomRight.First,  pRectangles->nPairB.nValA );
1294
0
                        EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames2[ i ].BottomRight.Second, pRectangles->nPairB.nValB );
1295
0
                    }
1296
0
                    if ( seqTextFrames1 == seqTextFrames2 )
1297
0
                        bIsDefaultGeometry = true;
1298
0
                }
1299
0
            }
1300
0
            else if (pDefCustomShape && pDefCustomShape->pTextRect.empty())
1301
0
                bIsDefaultGeometry = true;
1302
0
        }
1303
0
        break;
1304
0
    }
1305
0
    return bIsDefaultGeometry;
1306
0
}
1307
1308
void SdrObjCustomShape::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
1309
0
{
1310
0
    rInfo.bResizeFreeAllowed=m_fObjectRotation == 0.0;
1311
0
    rInfo.bResizePropAllowed=true;
1312
0
    rInfo.bRotateFreeAllowed=true;
1313
0
    rInfo.bRotate90Allowed  =true;
1314
0
    rInfo.bMirrorFreeAllowed=true;
1315
0
    rInfo.bMirror45Allowed  =true;
1316
0
    rInfo.bMirror90Allowed  =true;
1317
0
    rInfo.bTransparenceAllowed = false;
1318
0
    rInfo.bShearAllowed     =true;
1319
0
    rInfo.bEdgeRadiusAllowed=false;
1320
0
    rInfo.bNoContortion     =true;
1321
1322
    // #i37011#
1323
0
    if ( !mXRenderedCustomShape.is() )
1324
0
        return;
1325
1326
    // #i37262#
1327
    // Iterate self over the contained objects, since there are combinations of
1328
    // polygon and curve objects. In that case, aInfo.bCanConvToPath and
1329
    // aInfo.bCanConvToPoly would be false. What is needed here is an or, not an and.
1330
0
    SdrObjListIter aIterator(*mXRenderedCustomShape);
1331
0
    while(aIterator.IsMore())
1332
0
    {
1333
0
        SdrObject* pCandidate = aIterator.Next();
1334
0
        SdrObjTransformInfoRec aInfo;
1335
0
        pCandidate->TakeObjInfo(aInfo);
1336
1337
        // set path and poly conversion if one is possible since
1338
        // this object will first be broken
1339
0
        const bool bCanConvToPathOrPoly(aInfo.bCanConvToPath || aInfo.bCanConvToPoly);
1340
0
        if(rInfo.bCanConvToPath != bCanConvToPathOrPoly)
1341
0
        {
1342
0
            rInfo.bCanConvToPath = bCanConvToPathOrPoly;
1343
0
        }
1344
1345
0
        if(rInfo.bCanConvToPoly != bCanConvToPathOrPoly)
1346
0
        {
1347
0
            rInfo.bCanConvToPoly = bCanConvToPathOrPoly;
1348
0
        }
1349
1350
0
        if(rInfo.bCanConvToContour != aInfo.bCanConvToContour)
1351
0
        {
1352
0
            rInfo.bCanConvToContour = aInfo.bCanConvToContour;
1353
0
        }
1354
1355
0
        if(rInfo.bShearAllowed != aInfo.bShearAllowed)
1356
0
        {
1357
0
            rInfo.bShearAllowed = aInfo.bShearAllowed;
1358
0
        }
1359
0
    }
1360
0
}
1361
1362
SdrObjKind SdrObjCustomShape::GetObjIdentifier() const
1363
1.34M
{
1364
1.34M
    return SdrObjKind::CustomShape;
1365
1.34M
}
1366
1367
// #115391# This implementation is based on the TextFrame size of the CustomShape and the
1368
// state of the ResizeShapeToFitText flag to correctly set TextMinFrameWidth/Height
1369
void SdrObjCustomShape::AdaptTextMinSize()
1370
427k
{
1371
427k
    if (getSdrModelFromSdrObject().IsCreatingDataObj() || getSdrModelFromSdrObject().IsPasteResize())
1372
0
        return;
1373
1374
    // check if we need to change anything before creating an SfxItemSet, because that is expensive
1375
427k
    const bool bResizeShapeToFitText(GetObjectItem(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue());
1376
427k
    tools::Rectangle aTextBound(getRectangle());
1377
427k
    bool bChanged(false);
1378
427k
    if(bResizeShapeToFitText)
1379
95.9k
        bChanged = true;
1380
331k
    else if(GetTextBounds(aTextBound))
1381
175k
        bChanged = true;
1382
427k
    if (!bChanged)
1383
155k
       return;
1384
1385
271k
    SfxItemSetFixed<SDRATTR_TEXT_MINFRAMEHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT,
1386
271k
        SDRATTR_TEXT_MINFRAMEWIDTH, SDRATTR_TEXT_AUTOGROWWIDTH> // contains SDRATTR_TEXT_MAXFRAMEWIDTH
1387
271k
        aSet(*GetObjectItemSet().GetPool());
1388
1389
271k
    if(bResizeShapeToFitText)
1390
95.9k
    {
1391
        // always reset MinWidthHeight to zero to only rely on text size and frame size
1392
        // to allow resizing being completely dependent on text size only
1393
95.9k
        aSet.Put(makeSdrTextMinFrameWidthItem(0));
1394
95.9k
        aSet.Put(makeSdrTextMinFrameHeightItem(0));
1395
95.9k
    }
1396
175k
    else
1397
175k
    {
1398
        // recreate from CustomShape-specific TextBounds
1399
175k
        const tools::Long nHDist(GetTextLeftDistance() + GetTextRightDistance());
1400
175k
        const tools::Long nVDist(GetTextUpperDistance() + GetTextLowerDistance());
1401
175k
        const tools::Long nTWdt(std::max(tools::Long(0), static_cast<tools::Long>(aTextBound.GetWidth() - 1 - nHDist)));
1402
175k
        const tools::Long nTHgt(std::max(tools::Long(0), static_cast<tools::Long>(aTextBound.GetHeight() - 1 - nVDist)));
1403
1404
175k
        aSet.Put(makeSdrTextMinFrameWidthItem(nTWdt));
1405
175k
        aSet.Put(makeSdrTextMinFrameHeightItem(nTHgt));
1406
175k
    }
1407
1408
271k
    SetObjectItemSet(aSet);
1409
271k
}
1410
1411
void SdrObjCustomShape::NbcSetSnapRect(const tools::Rectangle& rRectangle)
1412
241k
{
1413
241k
    tools::Rectangle aRectangle(rRectangle);
1414
241k
    ImpJustifyRect(aRectangle);
1415
241k
    setRectangle(aRectangle);
1416
241k
    InvalidateRenderGeometry();
1417
1418
241k
    AdaptTextMinSize();
1419
1420
241k
    ImpCheckShear();
1421
241k
    SetBoundAndSnapRectsDirty();
1422
241k
    SetChanged();
1423
241k
}
1424
1425
void SdrObjCustomShape::SetSnapRect( const tools::Rectangle& rRect )
1426
126k
{
1427
126k
    tools::Rectangle aBoundRect0;
1428
126k
    if ( m_pUserCall )
1429
0
        aBoundRect0 = GetLastBoundRect();
1430
126k
    NbcSetSnapRect( rRect );
1431
126k
    BroadcastObjectChange();
1432
126k
    SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1433
126k
}
1434
1435
void SdrObjCustomShape::NbcSetLogicRect(const tools::Rectangle& rRectangle, bool bAdaptTextMinSize)
1436
44.0k
{
1437
44.0k
    tools::Rectangle aRectangle(rRectangle);
1438
44.0k
    ImpJustifyRect(aRectangle);
1439
44.0k
    setRectangle(aRectangle);
1440
44.0k
    InvalidateRenderGeometry();
1441
1442
44.0k
    if (bAdaptTextMinSize)
1443
44.0k
        AdaptTextMinSize();
1444
1445
44.0k
    SetBoundAndSnapRectsDirty();
1446
44.0k
    SetChanged();
1447
44.0k
}
1448
1449
void SdrObjCustomShape::SetLogicRect( const tools::Rectangle& rRect )
1450
44.0k
{
1451
44.0k
    tools::Rectangle aBoundRect0;
1452
44.0k
    if ( m_pUserCall )
1453
1.67k
        aBoundRect0 = GetLastBoundRect();
1454
44.0k
    NbcSetLogicRect(rRect);
1455
44.0k
    BroadcastObjectChange();
1456
44.0k
    SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1457
44.0k
}
1458
1459
void SdrObjCustomShape::Move( const Size& rSiz )
1460
42.5k
{
1461
42.5k
    if ( rSiz.Width() || rSiz.Height() )
1462
19.9k
    {
1463
19.9k
        tools::Rectangle aBoundRect0;
1464
19.9k
        if ( m_pUserCall )
1465
684
            aBoundRect0 = GetLastBoundRect();
1466
19.9k
        NbcMove(rSiz);
1467
19.9k
        SetChanged();
1468
19.9k
        BroadcastObjectChange();
1469
19.9k
        SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
1470
19.9k
    }
1471
42.5k
}
1472
void SdrObjCustomShape::NbcMove( const Size& rSiz )
1473
19.9k
{
1474
19.9k
    SdrTextObj::NbcMove( rSiz );
1475
19.9k
    if ( mXRenderedCustomShape.is() )
1476
0
    {
1477
        // #i97149# the visualisation shape needs to be informed
1478
        // about change, too
1479
0
        mXRenderedCustomShape->ActionChanged();
1480
0
        mXRenderedCustomShape->NbcMove( rSiz );
1481
0
    }
1482
1483
    // #i37011# adapt geometry shadow
1484
19.9k
    if(mpLastShadowGeometry)
1485
0
    {
1486
0
        mpLastShadowGeometry->NbcMove( rSiz );
1487
0
    }
1488
19.9k
}
1489
1490
void SdrObjCustomShape::NbcResize( const Point& rRef, const Fraction& rxFact, const Fraction& ryFact )
1491
1.51k
{
1492
    // taking care of handles that should not been changed
1493
1.51k
    tools::Rectangle aOld(getRectangle());
1494
1.51k
    std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles() );
1495
1496
1.51k
    SdrTextObj::NbcResize( rRef, rxFact, ryFact );
1497
1498
1.51k
    if ( ( rxFact.GetNumerator() != rxFact.GetDenominator() )
1499
0
        || ( ryFact.GetNumerator()!= ryFact.GetDenominator() ) )
1500
1.51k
    {
1501
1.51k
        if ( ( ( rxFact.GetNumerator() < 0 ) && ( rxFact.GetDenominator() > 0 ) ) ||
1502
1.51k
            ( ( rxFact.GetNumerator() > 0 ) && ( rxFact.GetDenominator() < 0 ) ) )
1503
0
        {
1504
0
            SetMirroredX( !IsMirroredX() );
1505
0
        }
1506
1.51k
        if ( ( ( ryFact.GetNumerator() < 0 ) && ( ryFact.GetDenominator() > 0 ) ) ||
1507
1.51k
            ( ( ryFact.GetNumerator() > 0 ) && ( ryFact.GetDenominator() < 0 ) ) )
1508
0
        {
1509
0
            SetMirroredY( !IsMirroredY() );
1510
0
        }
1511
1.51k
    }
1512
1513
1.51k
    for (const auto& rInteraction : aInteractionHandles)
1514
0
    {
1515
0
        try
1516
0
        {
1517
0
            if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_FIXED )
1518
0
                rInteraction.xInteraction->setControllerPosition( rInteraction.aPosition );
1519
0
            if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_X )
1520
0
            {
1521
0
                sal_Int32 nX = ( rInteraction.aPosition.X - aOld.Left() ) + getRectangle().Left();
1522
0
                rInteraction.xInteraction->setControllerPosition(awt::Point(nX, rInteraction.xInteraction->getPosition().Y));
1523
0
            }
1524
0
            else if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX )
1525
0
            {
1526
0
                sal_Int32 nX = getRectangle().Right() - (aOld.Right() - rInteraction.aPosition.X);
1527
0
                rInteraction.xInteraction->setControllerPosition(awt::Point(nX, rInteraction.xInteraction->getPosition().Y));
1528
0
            }
1529
0
            if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_Y )
1530
0
            {
1531
0
                sal_Int32 nY = ( rInteraction.aPosition.Y - aOld.Top() ) + getRectangle().Top();
1532
0
                rInteraction.xInteraction->setControllerPosition(awt::Point(rInteraction.xInteraction->getPosition().X, nY));
1533
0
            }
1534
0
        }
1535
0
        catch ( const uno::RuntimeException& )
1536
0
        {
1537
0
        }
1538
0
    }
1539
1540
    // updating fObjectRotation
1541
1.51k
    Degree100 nTextObjRotation = maGeo.m_nRotationAngle;
1542
1.51k
    double fAngle = toDegrees(nTextObjRotation);
1543
1.51k
    if (IsMirroredX())
1544
0
    {
1545
0
        if (IsMirroredY())
1546
0
            m_fObjectRotation = fAngle - 180.0;
1547
0
        else
1548
0
            m_fObjectRotation = -fAngle;
1549
0
    }
1550
1.51k
    else
1551
1.51k
    {
1552
1.51k
        if (IsMirroredY())
1553
0
            m_fObjectRotation = 180.0 - fAngle;
1554
1.51k
        else
1555
1.51k
            m_fObjectRotation = fAngle;
1556
1.51k
    }
1557
1.51k
    while (m_fObjectRotation < 0)
1558
0
        m_fObjectRotation += 360.0;
1559
1.51k
    while (m_fObjectRotation >= 360.0)
1560
0
        m_fObjectRotation -= 360.0;
1561
1562
1.51k
    InvalidateRenderGeometry();
1563
1.51k
}
1564
1565
void SdrObjCustomShape::NbcRotate( const Point& rRef, Degree100 nAngle, double sn, double cs )
1566
16.4k
{
1567
16.4k
    bool bMirroredX = IsMirroredX();
1568
16.4k
    bool bMirroredY = IsMirroredY();
1569
1570
16.4k
    m_fObjectRotation = fmod( m_fObjectRotation, 360.0 );
1571
16.4k
    if ( m_fObjectRotation < 0 )
1572
0
        m_fObjectRotation = 360 + m_fObjectRotation;
1573
1574
    // the rotation angle for ashapes is stored in fObjectRotation, this rotation
1575
    // has to be applied to the text object (which is internally using maGeo.nAngle).
1576
16.4k
    SdrTextObj::NbcRotate( getRectangle().TopLeft(), -maGeo.m_nRotationAngle,        // retrieving the unrotated text object
1577
16.4k
                            -maGeo.mfSinRotationAngle,
1578
16.4k
                            maGeo.mfCosRotationAngle );
1579
16.4k
    maGeo.m_nRotationAngle = 0_deg100;                                             // resetting aGeo data
1580
16.4k
    maGeo.RecalcSinCos();
1581
1582
16.4k
    Degree100 nW(static_cast<sal_Int32>( m_fObjectRotation * 100 ));                      // applying our object rotation
1583
16.4k
    if ( bMirroredX )
1584
86
        nW = 36000_deg100 - nW;
1585
16.4k
    if ( bMirroredY )
1586
115
        nW = 18000_deg100 - nW;
1587
16.4k
    nW = nW % 36000_deg100;
1588
16.4k
    if ( nW < 0_deg100 )
1589
38
        nW = 36000_deg100 + nW;
1590
16.4k
    SdrTextObj::NbcRotate( getRectangle().TopLeft(), nW,                     // applying text rotation
1591
16.4k
                            sin( toRadians(nW) ),
1592
16.4k
                            cos( toRadians(nW) ) );
1593
1594
16.4k
    int nSwap = 0;
1595
16.4k
    if ( bMirroredX )
1596
86
        nSwap ^= 1;
1597
16.4k
    if ( bMirroredY )
1598
115
        nSwap ^= 1;
1599
1600
16.4k
    double fAngle = toDegrees(nAngle);     // updating to our new object rotation
1601
16.4k
    m_fObjectRotation = fmod( nSwap ? m_fObjectRotation - fAngle : m_fObjectRotation + fAngle, 360.0 );
1602
16.4k
    if ( m_fObjectRotation < 0 )
1603
117
        m_fObjectRotation = 360 + m_fObjectRotation;
1604
1605
16.4k
    SdrTextObj::NbcRotate( rRef, nAngle, sn, cs );                           // applying text rotation
1606
16.4k
    InvalidateRenderGeometry();
1607
16.4k
}
1608
1609
void SdrObjCustomShape::NbcMirror( const Point& rRef1, const Point& rRef2 )
1610
18.5k
{
1611
    // TTTT: Fix for old mirroring, can be removed again in aw080
1612
    // storing horizontal and vertical flipping without modifying the rotate angle
1613
    // decompose other flipping to rotation and MirrorX.
1614
18.5k
    tools::Long ndx = rRef2.X()-rRef1.X();
1615
18.5k
    tools::Long ndy = rRef2.Y()-rRef1.Y();
1616
1617
18.5k
    if(!ndx) // MirroredX
1618
7.69k
    {
1619
7.69k
         SetMirroredX(!IsMirroredX());
1620
7.69k
         SdrTextObj::NbcMirror( rRef1, rRef2 );
1621
7.69k
    }
1622
10.8k
    else
1623
10.8k
    {
1624
10.8k
        if(!ndy)  // MirroredY
1625
10.8k
        {
1626
10.8k
            SetMirroredY(!IsMirroredY());
1627
10.8k
            SdrTextObj::NbcMirror( rRef1, rRef2 );
1628
10.8k
        }
1629
0
        else // neither horizontal nor vertical
1630
0
        {
1631
0
            SetMirroredX(!IsMirroredX());
1632
1633
            // call parent
1634
0
            SdrTextObj::NbcMirror( rRef1, rRef2 );
1635
1636
            // update fObjectRotation
1637
0
            Degree100 nTextObjRotation = maGeo.m_nRotationAngle;
1638
0
            double fAngle = toDegrees(nTextObjRotation);
1639
1640
0
            bool bSingleFlip = (IsMirroredX()!= IsMirroredY());
1641
1642
0
            m_fObjectRotation = fmod( bSingleFlip ? -fAngle : fAngle, 360.0 );
1643
1644
0
            if ( m_fObjectRotation < 0 )
1645
0
            {
1646
0
                m_fObjectRotation = 360.0 + m_fObjectRotation;
1647
0
            }
1648
0
         }
1649
10.8k
    }
1650
1651
18.5k
    InvalidateRenderGeometry();
1652
18.5k
}
1653
1654
void SdrObjCustomShape::Shear( const Point& rRef, Degree100 nAngle, double tn, bool bVShear )
1655
0
{
1656
0
    SdrTextObj::Shear( rRef, nAngle, tn, bVShear );
1657
0
    InvalidateRenderGeometry();
1658
0
}
1659
void SdrObjCustomShape::NbcShear( const Point& rRef, Degree100 nAngle, double tn, bool bVShear )
1660
0
{
1661
    // TTTT: Fix for old mirroring, can be removed again in aw080
1662
0
    SdrTextObj::NbcShear(rRef,nAngle,tn,bVShear);
1663
1664
    // updating fObjectRotation
1665
0
    Degree100 nTextObjRotation = maGeo.m_nRotationAngle;
1666
0
    double fAngle = toDegrees(nTextObjRotation);
1667
0
    if (IsMirroredX())
1668
0
    {
1669
0
        if (IsMirroredY())
1670
0
            m_fObjectRotation = fAngle - 180.0;
1671
0
        else
1672
0
            m_fObjectRotation = -fAngle;
1673
0
    }
1674
0
    else
1675
0
    {
1676
0
        if (IsMirroredY())
1677
0
            m_fObjectRotation = 180.0 - fAngle;
1678
0
        else
1679
0
            m_fObjectRotation = fAngle;
1680
0
    }
1681
0
    while (m_fObjectRotation < 0)
1682
0
        m_fObjectRotation += 360.0;
1683
0
    while (m_fObjectRotation >= 360.0)
1684
0
        m_fObjectRotation -= 360.0;
1685
1686
0
    InvalidateRenderGeometry();
1687
0
}
1688
1689
SdrGluePoint SdrObjCustomShape::GetVertexGluePoint(sal_uInt16 nPosNum) const
1690
375
{
1691
375
    sal_Int32 nWdt = ImpGetLineWdt(); // #i25616#
1692
1693
    // #i25616#
1694
375
    if(!LineIsOutsideGeometry())
1695
375
    {
1696
375
        nWdt++;
1697
375
        nWdt /= 2;
1698
375
    }
1699
1700
375
    Point aPt;
1701
375
    tools::Rectangle aRectangle = getRectangle();
1702
375
    switch (nPosNum)
1703
375
    {
1704
45
        case 0: aPt = aRectangle.TopCenter();    aPt.AdjustY( -nWdt ); break;
1705
160
        case 1: aPt = aRectangle.RightCenter();  aPt.AdjustX(nWdt ); break;
1706
45
        case 2: aPt = aRectangle.BottomCenter(); aPt.AdjustY(nWdt ); break;
1707
125
        case 3: aPt = aRectangle.LeftCenter();   aPt.AdjustX( -nWdt ); break;
1708
375
    }
1709
375
    if (maGeo.m_nShearAngle != 0_deg100)
1710
0
        ShearPoint(aPt, aRectangle.TopLeft(), maGeo.mfTanShearAngle);
1711
375
    if (maGeo.m_nRotationAngle != 0_deg100)
1712
0
        RotatePoint(aPt, aRectangle.TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
1713
375
    aPt-=GetSnapRect().Center();
1714
375
    SdrGluePoint aGP(aPt);
1715
375
    aGP.SetPercent(false);
1716
375
    return aGP;
1717
375
}
1718
1719
1720
// #i38892#
1721
void SdrObjCustomShape::ImpCheckCustomGluePointsAreAdded()
1722
239k
{
1723
239k
    const SdrObject* pSdrObject = GetSdrObjectFromCustomShape();
1724
1725
239k
    if(!pSdrObject)
1726
46.8k
        return;
1727
1728
192k
    const SdrGluePointList* pSource = pSdrObject->GetGluePointList();
1729
1730
192k
    if(!(pSource && pSource->GetCount()))
1731
139k
        return;
1732
1733
53.2k
    if(!SdrTextObj::GetGluePointList())
1734
2.87k
    {
1735
2.87k
        SdrTextObj::ForceGluePointList();
1736
2.87k
    }
1737
1738
53.2k
    const SdrGluePointList* pList = SdrTextObj::GetGluePointList();
1739
1740
53.2k
    if(!pList)
1741
0
        return;
1742
1743
53.2k
    SdrGluePointList aNewList;
1744
53.2k
    sal_uInt16 a;
1745
1746
2.68M
    for(a = 0; a < pSource->GetCount(); a++)
1747
2.63M
    {
1748
2.63M
        SdrGluePoint aCopy((*pSource)[a]);
1749
2.63M
        aCopy.SetUserDefined(false);
1750
2.63M
        aNewList.Insert(aCopy);
1751
2.63M
    }
1752
1753
53.2k
    bool bMirroredX = IsMirroredX();
1754
53.2k
    bool bMirroredY = IsMirroredY();
1755
1756
53.2k
    Degree100 nShearAngle = maGeo.m_nShearAngle;
1757
53.2k
    double fTan = maGeo.mfTanShearAngle;
1758
1759
53.2k
    if (maGeo.m_nRotationAngle || nShearAngle || bMirroredX || bMirroredY)
1760
24.1k
    {
1761
24.1k
        tools::Polygon aPoly(getRectangle());
1762
24.1k
        if( nShearAngle )
1763
0
        {
1764
0
            sal_uInt16 nPointCount=aPoly.GetSize();
1765
0
            for (sal_uInt16 i=0; i<nPointCount; i++)
1766
0
                ShearPoint(aPoly[i], getRectangle().Center(), fTan );
1767
0
        }
1768
24.1k
        if (maGeo.m_nRotationAngle)
1769
19.1k
            aPoly.Rotate( getRectangle().Center(), to<Degree10>(maGeo.m_nRotationAngle) );
1770
1771
24.1k
        tools::Rectangle aBoundRect( aPoly.GetBoundRect() );
1772
24.1k
        sal_Int32 nXDiff = aBoundRect.Left() - getRectangle().Left();
1773
24.1k
        sal_Int32 nYDiff = aBoundRect.Top() - getRectangle().Top();
1774
1775
24.1k
        if (nShearAngle && bMirroredX != bMirroredY)
1776
0
        {
1777
0
            nShearAngle = -nShearAngle;
1778
0
            fTan = -fTan;
1779
0
        }
1780
1781
24.1k
        Point aRef( getRectangle().GetWidth() / 2, getRectangle().GetHeight() / 2 );
1782
1.19M
        for ( a = 0; a < aNewList.GetCount(); a++ )
1783
1.16M
        {
1784
1.16M
            SdrGluePoint& rPoint = aNewList[ a ];
1785
1.16M
            Point aGlue( rPoint.GetPos() );
1786
1.16M
            if ( nShearAngle )
1787
0
                ShearPoint( aGlue, aRef, fTan );
1788
1789
1.16M
            RotatePoint(aGlue, aRef, sin(basegfx::deg2rad(m_fObjectRotation)),
1790
1.16M
                        cos(basegfx::deg2rad(m_fObjectRotation)));
1791
1.16M
            if ( bMirroredX )
1792
429k
                aGlue.setX( getRectangle().GetWidth() - aGlue.X() );
1793
1.16M
            if ( bMirroredY )
1794
523k
                aGlue.setY( getRectangle().GetHeight() - aGlue.Y() );
1795
1.16M
            aGlue.AdjustX( -nXDiff );
1796
1.16M
            aGlue.AdjustY( -nYDiff );
1797
1.16M
            rPoint.SetPos( aGlue );
1798
1.16M
        }
1799
24.1k
    }
1800
1801
2.57M
    for(a = 0; a < pList->GetCount(); a++)
1802
2.51M
    {
1803
2.51M
        const SdrGluePoint& rCandidate = (*pList)[a];
1804
1805
2.51M
        if(rCandidate.IsUserDefined())
1806
0
        {
1807
0
            aNewList.Insert(rCandidate);
1808
0
        }
1809
2.51M
    }
1810
1811
    // copy new list to local. This is NOT very convenient behavior, the local
1812
    // GluePointList should not be set, but we delivered by using GetGluePointList(),
1813
    // maybe on demand. Since the local object is changed here, this is assumed to
1814
    // be a result of GetGluePointList and thus the list is copied
1815
53.2k
    if(m_pPlusData)
1816
53.2k
    {
1817
53.2k
        m_pPlusData->SetGluePoints(aNewList);
1818
53.2k
    }
1819
53.2k
}
1820
1821
// #i38892#
1822
const SdrGluePointList* SdrObjCustomShape::GetGluePointList() const
1823
204k
{
1824
204k
    const_cast<SdrObjCustomShape*>(this)->ImpCheckCustomGluePointsAreAdded();
1825
204k
    return SdrTextObj::GetGluePointList();
1826
204k
}
1827
1828
// #i38892#
1829
SdrGluePointList* SdrObjCustomShape::ForceGluePointList()
1830
34.8k
{
1831
34.8k
    if(SdrTextObj::ForceGluePointList())
1832
34.8k
    {
1833
34.8k
        ImpCheckCustomGluePointsAreAdded();
1834
34.8k
        return SdrTextObj::ForceGluePointList();
1835
34.8k
    }
1836
0
    else
1837
0
    {
1838
0
        return nullptr;
1839
0
    }
1840
34.8k
}
1841
1842
1843
sal_uInt32 SdrObjCustomShape::GetHdlCount() const
1844
0
{
1845
0
    const sal_uInt32 nBasicHdlCount(SdrTextObj::GetHdlCount());
1846
0
    return ( GetInteractionHandles().size() + nBasicHdlCount );
1847
0
}
1848
1849
void SdrObjCustomShape::AddToHdlList(SdrHdlList& rHdlList) const
1850
0
{
1851
0
    SdrTextObj::AddToHdlList(rHdlList);
1852
1853
0
    int nCustomShapeHdlNum = 0;
1854
0
    for (SdrCustomShapeInteraction const & rInteraction : GetInteractionHandles())
1855
0
    {
1856
0
        if ( rInteraction.xInteraction.is() )
1857
0
        {
1858
0
            try
1859
0
            {
1860
0
                awt::Point aPosition( rInteraction.xInteraction->getPosition() );
1861
0
                std::unique_ptr<SdrHdl> pH(new SdrHdl( Point( aPosition.X, aPosition.Y ), SdrHdlKind::CustomShape1 ));
1862
0
                pH->SetPointNum( nCustomShapeHdlNum );
1863
0
                pH->SetObj( const_cast<SdrObjCustomShape*>(this) );
1864
0
                rHdlList.AddHdl(std::move(pH));
1865
0
            }
1866
0
            catch ( const uno::RuntimeException& )
1867
0
            {
1868
0
            }
1869
0
        }
1870
0
        ++nCustomShapeHdlNum;
1871
0
    }
1872
0
}
1873
1874
bool SdrObjCustomShape::hasSpecialDrag() const
1875
0
{
1876
0
    return true;
1877
0
}
1878
1879
bool SdrObjCustomShape::beginSpecialDrag(SdrDragStat& rDrag) const
1880
0
{
1881
0
    const SdrHdl* pHdl = rDrag.GetHdl();
1882
1883
0
    if(pHdl && SdrHdlKind::CustomShape1 == pHdl->GetKind())
1884
0
    {
1885
0
        rDrag.SetEndDragChangesAttributes(true);
1886
0
        rDrag.SetNoSnap();
1887
0
    }
1888
0
    else
1889
0
    {
1890
0
        const SdrHdl* pHdl2 = rDrag.GetHdl();
1891
0
        const SdrHdlKind eHdl((pHdl2 == nullptr) ? SdrHdlKind::Move : pHdl2->GetKind());
1892
1893
0
        switch( eHdl )
1894
0
        {
1895
0
            case SdrHdlKind::UpperLeft :
1896
0
            case SdrHdlKind::Upper :
1897
0
            case SdrHdlKind::UpperRight :
1898
0
            case SdrHdlKind::Left  :
1899
0
            case SdrHdlKind::Right :
1900
0
            case SdrHdlKind::LowerLeft :
1901
0
            case SdrHdlKind::Lower :
1902
0
            case SdrHdlKind::LowerRight :
1903
0
            case SdrHdlKind::Move  :
1904
0
            {
1905
0
                break;
1906
0
            }
1907
0
            default:
1908
0
            {
1909
0
                return false;
1910
0
            }
1911
0
        }
1912
0
    }
1913
1914
0
    return true;
1915
0
}
1916
1917
void SdrObjCustomShape::DragResizeCustomShape( const tools::Rectangle& rNewRect )
1918
0
{
1919
0
    tools::Rectangle aOld(getRectangle());
1920
0
    bool    bOldMirroredX( IsMirroredX() );
1921
0
    bool    bOldMirroredY( IsMirroredY() );
1922
1923
0
    tools::Rectangle aNewRect( rNewRect );
1924
0
    aNewRect.Normalize();
1925
1926
0
    std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles() );
1927
1928
0
    GeoStat aGeoStat( GetGeoStat() );
1929
0
    if ( aNewRect.TopLeft() != getRectangle().TopLeft() &&
1930
0
        ( maGeo.m_nRotationAngle || maGeo.m_nShearAngle ) )
1931
0
    {
1932
0
        Point aNewPos( aNewRect.TopLeft() );
1933
0
        if ( maGeo.m_nShearAngle ) ShearPoint( aNewPos, aOld.TopLeft(), aGeoStat.mfTanShearAngle );
1934
0
        if ( maGeo.m_nRotationAngle )  RotatePoint(aNewPos, aOld.TopLeft(), aGeoStat.mfSinRotationAngle, aGeoStat.mfCosRotationAngle );
1935
0
        aNewRect.SetPos( aNewPos );
1936
0
    }
1937
0
    if (aNewRect == getRectangle())
1938
0
        return;
1939
1940
0
    SetLogicRect( aNewRect );
1941
0
    InvalidateRenderGeometry();
1942
1943
0
    if ( rNewRect.Left() > rNewRect.Right() )
1944
0
    {
1945
0
        Point aTop( ( GetSnapRect().Left() + GetSnapRect().Right() ) >> 1, GetSnapRect().Top() );
1946
0
        Point aBottom( aTop.X(), aTop.Y() + 1000 );
1947
0
        NbcMirror( aTop, aBottom );
1948
0
    }
1949
0
    if ( rNewRect.Top() > rNewRect.Bottom() )
1950
0
    {
1951
0
        Point aLeft( GetSnapRect().Left(), ( GetSnapRect().Top() + GetSnapRect().Bottom() ) >> 1 );
1952
0
        Point aRight( aLeft.X() + 1000, aLeft.Y() );
1953
0
        NbcMirror( aLeft, aRight );
1954
0
    }
1955
1956
0
    for (const auto& rInteraction : aInteractionHandles)
1957
0
    {
1958
0
        try
1959
0
        {
1960
0
            if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_FIXED )
1961
0
                rInteraction.xInteraction->setControllerPosition( rInteraction.aPosition );
1962
0
            if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_X ||
1963
0
                 rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX )
1964
0
            {
1965
0
                if (rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX)
1966
0
                    bOldMirroredX = !bOldMirroredX;
1967
1968
0
                sal_Int32 nX;
1969
0
                if ( bOldMirroredX )
1970
0
                {
1971
0
                    nX = ( rInteraction.aPosition.X - aOld.Right() );
1972
0
                    if ( rNewRect.Left() > rNewRect.Right() )
1973
0
                        nX = getRectangle().Left() - nX;
1974
0
                    else
1975
0
                        nX += getRectangle().Right();
1976
0
                }
1977
0
                else
1978
0
                {
1979
0
                    nX = ( rInteraction.aPosition.X - aOld.Left() );
1980
0
                    if ( rNewRect.Left() > rNewRect.Right() )
1981
0
                        nX = getRectangle().Right() - nX;
1982
0
                    else
1983
0
                        nX += getRectangle().Left();
1984
0
                }
1985
0
                rInteraction.xInteraction->setControllerPosition(awt::Point(nX, rInteraction.xInteraction->getPosition().Y));
1986
0
            }
1987
0
            if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_Y )
1988
0
            {
1989
0
                sal_Int32 nY;
1990
0
                if ( bOldMirroredY )
1991
0
                {
1992
0
                    nY = ( rInteraction.aPosition.Y - aOld.Bottom() );
1993
0
                    if ( rNewRect.Top() > rNewRect.Bottom() )
1994
0
                        nY = getRectangle().Top() - nY;
1995
0
                    else
1996
0
                        nY += getRectangle().Bottom();
1997
0
                }
1998
0
                else
1999
0
                {
2000
0
                    nY = ( rInteraction.aPosition.Y - aOld.Top() );
2001
0
                    if ( rNewRect.Top() > rNewRect.Bottom() )
2002
0
                        nY = getRectangle().Bottom() - nY;
2003
0
                    else
2004
0
                        nY += getRectangle().Top();
2005
0
                }
2006
0
                rInteraction.xInteraction->setControllerPosition(awt::Point(rInteraction.xInteraction->getPosition().X, nY));
2007
0
            }
2008
0
        }
2009
0
        catch ( const uno::RuntimeException& )
2010
0
        {
2011
0
        }
2012
0
    }
2013
0
}
2014
2015
void SdrObjCustomShape::DragMoveCustomShapeHdl( const Point& rDestination,
2016
        const sal_uInt16 nCustomShapeHdlNum, bool bMoveCalloutRectangle )
2017
0
{
2018
0
    std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles() );
2019
0
    if ( nCustomShapeHdlNum >= aInteractionHandles.size() )
2020
0
        return;
2021
2022
0
    SdrCustomShapeInteraction aInteractionHandle( aInteractionHandles[ nCustomShapeHdlNum ] );
2023
0
    if ( !aInteractionHandle.xInteraction.is() )
2024
0
        return;
2025
2026
0
    try
2027
0
    {
2028
0
        awt::Point aPt( rDestination.X(), rDestination.Y() );
2029
0
        if ( aInteractionHandle.nMode & CustomShapeHandleModes::MOVE_SHAPE && bMoveCalloutRectangle )
2030
0
        {
2031
0
            sal_Int32 nXDiff = aPt.X - aInteractionHandle.aPosition.X;
2032
0
            sal_Int32 nYDiff = aPt.Y - aInteractionHandle.aPosition.Y;
2033
2034
0
            moveRectangle(nXDiff, nYDiff);
2035
0
            moveOutRectangle(nXDiff, nYDiff);
2036
0
            maSnapRect.Move( nXDiff, nYDiff );
2037
0
            SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
2038
0
            InvalidateRenderGeometry();
2039
2040
0
            for (const auto& rInteraction : aInteractionHandles)
2041
0
            {
2042
0
                if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_FIXED )
2043
0
                {
2044
0
                    if ( rInteraction.xInteraction.is() )
2045
0
                        rInteraction.xInteraction->setControllerPosition( rInteraction.aPosition );
2046
0
                }
2047
0
            }
2048
0
        }
2049
0
        aInteractionHandle.xInteraction->setControllerPosition( aPt );
2050
0
    }
2051
0
    catch ( const uno::RuntimeException& )
2052
0
    {
2053
0
    }
2054
0
}
2055
2056
bool SdrObjCustomShape::applySpecialDrag(SdrDragStat& rDrag)
2057
0
{
2058
0
    const SdrHdl* pHdl = rDrag.GetHdl();
2059
0
    const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());
2060
2061
0
    switch(eHdl)
2062
0
    {
2063
0
        case SdrHdlKind::CustomShape1 :
2064
0
        {
2065
0
            rDrag.SetEndDragChangesGeoAndAttributes(true);
2066
0
            DragMoveCustomShapeHdl( rDrag.GetNow(), static_cast<sal_uInt16>(pHdl->GetPointNum()), !rDrag.GetDragMethod()->IsShiftPressed() );
2067
0
            SetBoundAndSnapRectsDirty();
2068
0
            InvalidateRenderGeometry();
2069
0
            SetChanged();
2070
0
            break;
2071
0
        }
2072
2073
0
        case SdrHdlKind::UpperLeft :
2074
0
        case SdrHdlKind::Upper :
2075
0
        case SdrHdlKind::UpperRight :
2076
0
        case SdrHdlKind::Left  :
2077
0
        case SdrHdlKind::Right :
2078
0
        case SdrHdlKind::LowerLeft :
2079
0
        case SdrHdlKind::Lower :
2080
0
        case SdrHdlKind::LowerRight :
2081
0
        {
2082
0
            DragResizeCustomShape( ImpDragCalcRect(rDrag) );
2083
0
            break;
2084
0
        }
2085
0
        case SdrHdlKind::Move :
2086
0
        {
2087
0
            Move(Size(rDrag.GetDX(), rDrag.GetDY()));
2088
0
            break;
2089
0
        }
2090
0
        default: break;
2091
0
    }
2092
2093
0
    return true;
2094
0
}
2095
2096
2097
void SdrObjCustomShape::DragCreateObject( SdrDragStat& rStat )
2098
0
{
2099
0
    tools::Rectangle aRect1;
2100
0
    rStat.TakeCreateRect( aRect1 );
2101
2102
0
    std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles() );
2103
2104
0
    constexpr sal_uInt32 nDefaultObjectSizeWidth = 3000;      // default width from SDOptions ?
2105
0
    constexpr sal_uInt32 nDefaultObjectSizeHeight= 3000;
2106
2107
0
    if ( ImpVerticalSwitch( *this ) )
2108
0
    {
2109
0
        SetMirroredX( aRect1.Left() > aRect1.Right() );
2110
2111
0
        aRect1 = tools::Rectangle( rStat.GetNow(), Size( nDefaultObjectSizeWidth, nDefaultObjectSizeHeight ) );
2112
        // subtracting the horizontal difference of the latest handle from shape position
2113
0
        if ( !aInteractionHandles.empty() )
2114
0
        {
2115
0
            sal_Int32 nHandlePos = aInteractionHandles[ aInteractionHandles.size() - 1 ].xInteraction->getPosition().X;
2116
0
            aRect1.Move(getRectangle().Left() - nHandlePos, 0);
2117
0
        }
2118
0
    }
2119
0
    ImpJustifyRect( aRect1 );
2120
0
    rStat.SetActionRect( aRect1 );
2121
0
    setRectangle(aRect1);
2122
0
    SetBoundAndSnapRectsDirty();
2123
2124
0
    for (const auto& rInteraction : aInteractionHandles)
2125
0
    {
2126
0
        try
2127
0
        {
2128
0
            if ( rInteraction.nMode & CustomShapeHandleModes::CREATE_FIXED )
2129
0
                rInteraction.xInteraction->setControllerPosition( awt::Point( rStat.GetStart().X(), rStat.GetStart().Y() ) );
2130
0
        }
2131
0
        catch ( const uno::RuntimeException& )
2132
0
        {
2133
0
        }
2134
0
    }
2135
2136
0
    SetBoundRectDirty();
2137
0
    m_bSnapRectDirty=true;
2138
0
}
2139
2140
bool SdrObjCustomShape::MovCreate(SdrDragStat& rStat)
2141
0
{
2142
0
    SdrView* pView = rStat.GetView();       // #i37448#
2143
0
    if( pView && pView->IsSolidDragging() )
2144
0
    {
2145
0
        InvalidateRenderGeometry();
2146
0
    }
2147
0
    DragCreateObject( rStat );
2148
0
    SetBoundAndSnapRectsDirty();
2149
0
    return true;
2150
0
}
2151
2152
bool SdrObjCustomShape::EndCreate( SdrDragStat& rStat, SdrCreateCmd eCmd )
2153
0
{
2154
0
    DragCreateObject( rStat );
2155
2156
0
    AdaptTextMinSize();
2157
2158
0
    SetBoundAndSnapRectsDirty();
2159
0
    return ( eCmd == SdrCreateCmd::ForceEnd || rStat.GetPointCount() >= 2 );
2160
0
}
2161
2162
basegfx::B2DPolyPolygon SdrObjCustomShape::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
2163
0
{
2164
0
    return GetLineGeometry( false );
2165
0
}
2166
2167
2168
// in context with the SdrObjCustomShape the SdrTextAutoGrowHeightItem == true -> Resize Shape to fit text,
2169
//                                     the SdrTextAutoGrowWidthItem  == true -> Word wrap text in Shape
2170
bool SdrObjCustomShape::IsAutoGrowHeight() const
2171
41.2k
{
2172
41.2k
    const SfxItemSet& rSet = GetMergedItemSet();
2173
41.2k
    bool bIsAutoGrowHeight = rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
2174
41.2k
    if ( bIsAutoGrowHeight && IsVerticalWriting() )
2175
4.13k
        bIsAutoGrowHeight = !rSet.Get(SDRATTR_TEXT_WORDWRAP).GetValue();
2176
41.2k
    return bIsAutoGrowHeight;
2177
41.2k
}
2178
bool SdrObjCustomShape::IsAutoGrowWidth() const
2179
2.02k
{
2180
2.02k
    const SfxItemSet& rSet = GetMergedItemSet();
2181
2.02k
    bool bIsAutoGrowWidth = rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
2182
2.02k
    if ( bIsAutoGrowWidth && !IsVerticalWriting() )
2183
237
        bIsAutoGrowWidth = !rSet.Get(SDRATTR_TEXT_WORDWRAP).GetValue();
2184
2.02k
    return bIsAutoGrowWidth;
2185
2.02k
}
2186
2187
/* The following method is identical to the SdrTextObj::SetVerticalWriting method, the only difference
2188
   is that the SdrAutoGrowWidthItem and SdrAutoGrowHeightItem are not exchanged if the vertical writing
2189
   mode has been changed */
2190
2191
void SdrObjCustomShape::SetVerticalWriting( bool bVertical )
2192
174k
{
2193
174k
    ForceOutlinerParaObject();
2194
2195
174k
    OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
2196
2197
174k
    DBG_ASSERT( pOutlinerParaObject, "SdrTextObj::SetVerticalWriting() without OutlinerParaObject!" );
2198
2199
174k
    if( !pOutlinerParaObject ||
2200
174k
        (pOutlinerParaObject->IsEffectivelyVertical() == bVertical) )
2201
173k
        return;
2202
2203
    // get item settings
2204
1.21k
    const SfxItemSet& rSet = GetObjectItemSet();
2205
2206
    // Also exchange horizontal and vertical adjust items
2207
1.21k
    SdrTextHorzAdjust eHorz = rSet.Get(SDRATTR_TEXT_HORZADJUST).GetValue();
2208
1.21k
    SdrTextVertAdjust eVert = rSet.Get(SDRATTR_TEXT_VERTADJUST).GetValue();
2209
2210
    // rescue object size, SetSnapRect below expects logic rect,
2211
    // not snap rect.
2212
1.21k
    tools::Rectangle aObjectRect = GetLogicRect();
2213
2214
    // prepare ItemSet to set exchanged width and height items
2215
1.21k
    SfxItemSetFixed<SDRATTR_TEXT_AUTOGROWHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT,
2216
        // Expanded item ranges to also support horizontal and vertical adjust.
2217
1.21k
        SDRATTR_TEXT_VERTADJUST, SDRATTR_TEXT_VERTADJUST,
2218
1.21k
        SDRATTR_TEXT_AUTOGROWWIDTH, SDRATTR_TEXT_HORZADJUST> aNewSet(*rSet.GetPool());
2219
2220
1.21k
    aNewSet.Put(rSet);
2221
2222
    // Exchange horizontal and vertical adjusts
2223
1.21k
    switch(eVert)
2224
1.21k
    {
2225
1.20k
        case SDRTEXTVERTADJUST_TOP: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT)); break;
2226
4
        case SDRTEXTVERTADJUST_CENTER: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER)); break;
2227
9
        case SDRTEXTVERTADJUST_BOTTOM: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT)); break;
2228
2
        case SDRTEXTVERTADJUST_BLOCK: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_BLOCK)); break;
2229
1.21k
    }
2230
1.21k
    switch(eHorz)
2231
1.21k
    {
2232
0
        case SDRTEXTHORZADJUST_LEFT: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BOTTOM)); break;
2233
0
        case SDRTEXTHORZADJUST_CENTER: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER)); break;
2234
0
        case SDRTEXTHORZADJUST_RIGHT: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP)); break;
2235
1.21k
        case SDRTEXTHORZADJUST_BLOCK: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BLOCK)); break;
2236
1.21k
    }
2237
2238
1.21k
    pOutlinerParaObject = GetOutlinerParaObject();
2239
1.21k
    if ( pOutlinerParaObject )
2240
1.21k
        pOutlinerParaObject->SetVertical(bVertical);
2241
1.21k
    SetObjectItemSet( aNewSet );
2242
2243
    // restore object size
2244
1.21k
    SetSnapRect(aObjectRect);
2245
1.21k
}
2246
2247
void SdrObjCustomShape::SuggestTextFrameSize(Size aSuggestedTextFrameSize)
2248
0
{
2249
0
    m_aSuggestedTextFrameSize = aSuggestedTextFrameSize;
2250
0
}
2251
2252
bool SdrObjCustomShape::AdjustTextFrameWidthAndHeight(tools::Rectangle& rR, bool bHgt, bool bWdt) const
2253
2.09k
{
2254
    // Either we have text or the application has native text and suggested its size to us.
2255
2.09k
    bool bHasText = HasText() || !m_aSuggestedTextFrameSize.IsEmpty();
2256
2.09k
    if ( bHasText && !rR.IsEmpty() )
2257
251
    {
2258
251
        bool bWdtGrow=bWdt && IsAutoGrowWidth();
2259
251
        bool bHgtGrow=bHgt && IsAutoGrowHeight();
2260
251
        if ( bWdtGrow || bHgtGrow )
2261
251
        {
2262
251
            tools::Rectangle aR0(rR);
2263
251
            tools::Long nHgt=0,nMinHgt=0,nMaxHgt=0;
2264
251
            tools::Long nWdt=0,nMinWdt=0,nMaxWdt=0;
2265
251
            Size aSiz(rR.GetSize()); aSiz.AdjustWidth( -1 ); aSiz.AdjustHeight( -1 );
2266
251
            Size aMaxSiz(100000,100000);
2267
251
            Size aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
2268
251
            if (aTmpSiz.Width()!=0) aMaxSiz.setWidth(aTmpSiz.Width() );
2269
251
            if (aTmpSiz.Height()!=0) aMaxSiz.setHeight(aTmpSiz.Height() );
2270
251
            if (bWdtGrow)
2271
213
            {
2272
213
                nMinWdt=GetMinTextFrameWidth();
2273
213
                nMaxWdt=GetMaxTextFrameWidth();
2274
213
                if (nMaxWdt==0 || nMaxWdt>aMaxSiz.Width()) nMaxWdt=aMaxSiz.Width();
2275
213
                if (nMinWdt<=0) nMinWdt=1;
2276
213
                aSiz.setWidth(nMaxWdt );
2277
213
            }
2278
251
            if (bHgtGrow)
2279
237
            {
2280
237
                nMinHgt=GetMinTextFrameHeight();
2281
237
                nMaxHgt=GetMaxTextFrameHeight();
2282
237
                if (nMaxHgt==0 || nMaxHgt>aMaxSiz.Height()) nMaxHgt=aMaxSiz.Height();
2283
237
                if (nMinHgt<=0) nMinHgt=1;
2284
237
                aSiz.setHeight(nMaxHgt );
2285
237
            }
2286
251
            tools::Long nHDist=GetTextLeftDistance()+GetTextRightDistance();
2287
251
            tools::Long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
2288
251
            aSiz.AdjustWidth( -nHDist );
2289
251
            aSiz.AdjustHeight( -nVDist );
2290
251
            if ( aSiz.Width() < 2 )
2291
20
                aSiz.setWidth( 2 );   // minimum size=2
2292
251
            if ( aSiz.Height() < 2 )
2293
10
                aSiz.setHeight( 2 ); // minimum size=2
2294
2295
251
            if (HasText())
2296
251
            {
2297
251
                if(mpEditingOutliner)
2298
0
                {
2299
0
                    mpEditingOutliner->SetMaxAutoPaperSize( aSiz );
2300
0
                    if (bWdtGrow)
2301
0
                    {
2302
0
                        Size aSiz2(mpEditingOutliner->CalcTextSize());
2303
0
                        nWdt=aSiz2.Width()+1; // a little more tolerance
2304
0
                        if (bHgtGrow) nHgt=aSiz2.Height()+1; // a little more tolerance
2305
0
                    } else
2306
0
                    {
2307
0
                        nHgt=mpEditingOutliner->GetTextHeight()+1; // a little more tolerance
2308
0
                    }
2309
0
                }
2310
251
                else
2311
251
                {
2312
251
                    Outliner& rOutliner=ImpGetDrawOutliner();
2313
251
                    rOutliner.SetPaperSize(aSiz);
2314
                    // TODO: add the optimization with bPortionInfoChecked again.
2315
251
                    OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
2316
251
                    if( pOutlinerParaObject != nullptr )
2317
251
                    {
2318
251
                        rOutliner.SetFixedCellHeight(
2319
251
                            GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue());
2320
251
                        rOutliner.SetText(*pOutlinerParaObject);
2321
251
                    }
2322
251
                    rOutliner.SetUpdateLayout(true);
2323
251
                    if ( bWdtGrow )
2324
213
                    {
2325
213
                        Size aSiz2(rOutliner.CalcTextSize());
2326
213
                        nWdt=aSiz2.Width()+1; // a little more tolerance
2327
213
                        if ( bHgtGrow )
2328
199
                            nHgt=aSiz2.Height()+1; // a little more tolerance
2329
213
                    }
2330
38
                    else
2331
38
                    {
2332
38
                        nHgt = rOutliner.GetTextHeight()+1; // a little more tolerance
2333
2334
38
                        sal_Int16 nColumns = GetMergedItem(SDRATTR_TEXTCOLUMNS_NUMBER).GetValue();
2335
38
                        if (bHgtGrow && nColumns > 1)
2336
0
                        {
2337
                            // Both 'resize shape to fix text' and multiple columns are enabled. The
2338
                            // first means a dynamic height, the second expects a fixed height.
2339
                            // Resolve this conflict by going with the original height.
2340
0
                            nHgt = rR.getOpenHeight();
2341
0
                        }
2342
38
                    }
2343
                    // cleanup outliner
2344
251
                    rOutliner.Clear();
2345
251
                    rOutliner.SetFixedCellHeight(false);
2346
251
                }
2347
251
            }
2348
0
            else
2349
0
            {
2350
0
                nHgt = m_aSuggestedTextFrameSize.Height();
2351
0
                nWdt = m_aSuggestedTextFrameSize.Width();
2352
0
            }
2353
251
            if ( nWdt < nMinWdt )
2354
0
                nWdt = nMinWdt;
2355
251
            if ( nWdt > nMaxWdt )
2356
0
                nWdt = nMaxWdt;
2357
251
            nWdt += nHDist;
2358
251
            if ( nWdt < 1 )
2359
0
                nWdt = 1; // nHDist may also be negative
2360
251
            if ( nHgt < nMinHgt )
2361
0
                nHgt = nMinHgt;
2362
251
            if ( nHgt > nMaxHgt )
2363
0
                nHgt = nMaxHgt;
2364
251
            nHgt+=nVDist;
2365
251
            if ( nHgt < 1 )
2366
0
                nHgt = 1; // nVDist may also be negative
2367
251
            tools::Long nWdtGrow = nWdt-(rR.Right()-rR.Left());
2368
251
            tools::Long nHgtGrow = nHgt-(rR.Bottom()-rR.Top());
2369
251
            if ( nWdtGrow == 0 )
2370
7
                bWdtGrow = false;
2371
251
            if ( nHgtGrow == 0 )
2372
2
                bHgtGrow=false;
2373
251
            if ( bWdtGrow || bHgtGrow || !m_aSuggestedTextFrameSize.IsEmpty())
2374
242
            {
2375
242
                if ( bWdtGrow || m_aSuggestedTextFrameSize.Width() )
2376
206
                {
2377
206
                    SdrTextHorzAdjust eHAdj=GetTextHorizontalAdjust();
2378
206
                    if (m_aSuggestedTextFrameSize.Width())
2379
0
                    {
2380
0
                        rR.SetRight(rR.Left() + m_aSuggestedTextFrameSize.Width());
2381
0
                    }
2382
206
                    else if ( eHAdj == SDRTEXTHORZADJUST_LEFT )
2383
196
                        rR.AdjustRight(nWdtGrow );
2384
10
                    else if ( eHAdj == SDRTEXTHORZADJUST_RIGHT )
2385
7
                        rR.AdjustLeft( -nWdtGrow );
2386
3
                    else
2387
3
                    {
2388
3
                        tools::Long nWdtGrow2=nWdtGrow/2;
2389
3
                        rR.AdjustLeft( -nWdtGrow2 );
2390
3
                        rR.SetRight(rR.Left()+nWdt );
2391
3
                    }
2392
206
                }
2393
242
                if ( bHgtGrow || m_aSuggestedTextFrameSize.Height() )
2394
235
                {
2395
235
                    SdrTextVertAdjust eVAdj=GetTextVerticalAdjust();
2396
235
                    if (m_aSuggestedTextFrameSize.Height())
2397
0
                    {
2398
0
                        rR.SetBottom(rR.Top() + m_aSuggestedTextFrameSize.Height());
2399
0
                    }
2400
235
                    else if ( eVAdj == SDRTEXTVERTADJUST_TOP )
2401
232
                        rR.AdjustBottom(nHgtGrow );
2402
3
                    else if ( eVAdj == SDRTEXTVERTADJUST_BOTTOM )
2403
0
                        rR.AdjustTop( -nHgtGrow );
2404
3
                    else
2405
3
                    {
2406
3
                        tools::Long nHgtGrow2=nHgtGrow/2;
2407
3
                        rR.AdjustTop( -nHgtGrow2 );
2408
3
                        rR.SetBottom(rR.Top()+nHgt );
2409
3
                    }
2410
235
                }
2411
242
                if ( maGeo.m_nRotationAngle )
2412
40
                {
2413
40
                    Point aD1(rR.TopLeft());
2414
40
                    aD1-=aR0.TopLeft();
2415
40
                    Point aD2(aD1);
2416
40
                    RotatePoint(aD2,Point(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
2417
40
                    aD2-=aD1;
2418
40
                    rR.Move(aD2.X(),aD2.Y());
2419
40
                }
2420
242
                return true;
2421
242
            }
2422
251
        }
2423
251
    }
2424
1.85k
    return false;
2425
2.09k
}
2426
2427
tools::Rectangle SdrObjCustomShape::ImpCalculateTextFrame( const bool bHgt, const bool bWdt )
2428
2.09k
{
2429
2.09k
    tools::Rectangle aReturnValue;
2430
2431
2.09k
    tools::Rectangle aOldTextRect(getRectangle());        // <- initial text rectangle
2432
2433
2.09k
    tools::Rectangle aNewTextRect(getRectangle());        // <- new text rectangle returned from the custom shape renderer,
2434
2.09k
    GetTextBounds( aNewTextRect );          //    it depends to the current logical shape size
2435
2436
2.09k
    tools::Rectangle aAdjustedTextRect( aNewTextRect );                            // <- new text rectangle is being tested by AdjustTextFrameWidthAndHeight to ensure
2437
2.09k
    if ( AdjustTextFrameWidthAndHeight( aAdjustedTextRect, bHgt, bWdt ) )   //    that the new text rectangle is matching the current text size from the outliner
2438
242
    {
2439
242
        if (aAdjustedTextRect != aNewTextRect && aOldTextRect != aAdjustedTextRect &&
2440
242
            aNewTextRect.GetWidth() && aNewTextRect.GetHeight())
2441
242
        {
2442
242
            aReturnValue = getRectangle();
2443
242
            double fXScale = static_cast<double>(aOldTextRect.GetWidth()) / static_cast<double>(aNewTextRect.GetWidth());
2444
242
            double fYScale = static_cast<double>(aOldTextRect.GetHeight()) / static_cast<double>(aNewTextRect.GetHeight());
2445
242
            double fRightDiff = static_cast<double>( aAdjustedTextRect.Right() - aNewTextRect.Right() ) * fXScale;
2446
242
            double fLeftDiff  = static_cast<double>( aAdjustedTextRect.Left()  - aNewTextRect.Left()  ) * fXScale;
2447
242
            double fTopDiff   = static_cast<double>( aAdjustedTextRect.Top()   - aNewTextRect.Top()   ) * fYScale;
2448
242
            double fBottomDiff= static_cast<double>( aAdjustedTextRect.Bottom()- aNewTextRect.Bottom()) * fYScale;
2449
242
            aReturnValue.AdjustLeft(static_cast<sal_Int32>(fLeftDiff) );
2450
242
            aReturnValue.AdjustRight(static_cast<sal_Int32>(fRightDiff) );
2451
242
            aReturnValue.AdjustTop(static_cast<sal_Int32>(fTopDiff) );
2452
242
            aReturnValue.AdjustBottom(static_cast<sal_Int32>(fBottomDiff) );
2453
242
        }
2454
242
    }
2455
2.09k
    return aReturnValue;
2456
2.09k
}
2457
2458
bool SdrObjCustomShape::NbcAdjustTextFrameWidthAndHeight(bool bHgt, bool bWdt)
2459
2.09k
{
2460
2.09k
    tools::Rectangle aNewTextRect = ImpCalculateTextFrame(bHgt, bWdt);
2461
2.09k
    const bool bRet = !aNewTextRect.IsEmpty() && aNewTextRect != getRectangle();
2462
2.09k
    if (bRet && !mbAdjustingTextFrameWidthAndHeight)
2463
242
    {
2464
242
        mbAdjustingTextFrameWidthAndHeight = true;
2465
2466
        // taking care of handles that should not been changed
2467
242
        std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles() );
2468
2469
242
        setRectangle(aNewTextRect);
2470
242
        SetBoundAndSnapRectsDirty();
2471
242
        SetChanged();
2472
2473
242
        for (const auto& rInteraction : aInteractionHandles)
2474
22
        {
2475
22
            try
2476
22
            {
2477
22
                if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_FIXED )
2478
0
                    rInteraction.xInteraction->setControllerPosition( rInteraction.aPosition );
2479
22
            }
2480
22
            catch ( const uno::RuntimeException& )
2481
22
            {
2482
0
            }
2483
22
        }
2484
242
        InvalidateRenderGeometry();
2485
2486
242
        mbAdjustingTextFrameWidthAndHeight = false;
2487
242
    }
2488
2.09k
    return bRet;
2489
2.09k
}
2490
2491
bool SdrObjCustomShape::AdjustTextFrameWidthAndHeight()
2492
0
{
2493
0
    tools::Rectangle aNewTextRect = ImpCalculateTextFrame( true/*bHgt*/, true/*bWdt*/ );
2494
0
    bool bRet = !aNewTextRect.IsEmpty() && ( aNewTextRect != getRectangle());
2495
0
    if ( bRet )
2496
0
    {
2497
0
        tools::Rectangle aBoundRect0;
2498
0
        if ( m_pUserCall )
2499
0
            aBoundRect0 = GetCurrentBoundRect();
2500
2501
        // taking care of handles that should not been changed
2502
0
        std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles() );
2503
2504
0
        setRectangle(aNewTextRect);
2505
0
        SetBoundAndSnapRectsDirty();
2506
2507
0
        for (const auto& rInteraction : aInteractionHandles)
2508
0
        {
2509
0
            try
2510
0
            {
2511
0
                if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_FIXED )
2512
0
                    rInteraction.xInteraction->setControllerPosition( rInteraction.aPosition );
2513
0
            }
2514
0
            catch ( const uno::RuntimeException& )
2515
0
            {
2516
0
            }
2517
0
        }
2518
2519
0
        InvalidateRenderGeometry();
2520
0
        SetChanged();
2521
0
        BroadcastObjectChange();
2522
0
        SendUserCall(SdrUserCallType::Resize,aBoundRect0);
2523
0
    }
2524
0
    return bRet;
2525
0
}
2526
void SdrObjCustomShape::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const
2527
0
{
2528
0
    tools::Rectangle aViewInit;
2529
0
    TakeTextAnchorRect( aViewInit );
2530
0
    if (maGeo.m_nRotationAngle)
2531
0
    {
2532
0
        Point aCenter(aViewInit.Center());
2533
0
        aCenter-=aViewInit.TopLeft();
2534
0
        Point aCenter0(aCenter);
2535
0
        RotatePoint(aCenter, Point(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
2536
0
        aCenter-=aCenter0;
2537
0
        aViewInit.Move(aCenter.X(),aCenter.Y());
2538
0
    }
2539
0
    Size aAnkSiz(aViewInit.GetSize());
2540
0
    aAnkSiz.AdjustWidth( -1 ); aAnkSiz.AdjustHeight( -1 ); // because GetSize() adds 1
2541
0
    Size aMaxSiz(1000000,1000000);
2542
0
    {
2543
0
        Size aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
2544
0
        if (aTmpSiz.Width()!=0) aMaxSiz.setWidth(aTmpSiz.Width() );
2545
0
        if (aTmpSiz.Height()!=0) aMaxSiz.setHeight(aTmpSiz.Height() );
2546
0
    }
2547
0
    SdrTextHorzAdjust eHAdj(GetTextHorizontalAdjust());
2548
0
    SdrTextVertAdjust eVAdj(GetTextVerticalAdjust());
2549
2550
0
    tools::Long nMinWdt = GetMinTextFrameWidth();
2551
0
    tools::Long nMinHgt = GetMinTextFrameHeight();
2552
0
    tools::Long nMaxWdt = GetMaxTextFrameWidth();
2553
0
    tools::Long nMaxHgt = GetMaxTextFrameHeight();
2554
0
    if (nMinWdt<1) nMinWdt=1;
2555
0
    if (nMinHgt<1) nMinHgt=1;
2556
0
    if ( nMaxWdt == 0 || nMaxWdt > aMaxSiz.Width() )
2557
0
        nMaxWdt = aMaxSiz.Width();
2558
0
    if ( nMaxHgt == 0 || nMaxHgt > aMaxSiz.Height() )
2559
0
        nMaxHgt=aMaxSiz.Height();
2560
2561
0
    if (GetMergedItem(SDRATTR_TEXT_WORDWRAP).GetValue())
2562
0
    {
2563
0
        if ( IsVerticalWriting() )
2564
0
        {
2565
0
            nMaxHgt = aAnkSiz.Height();
2566
0
            nMinHgt = nMaxHgt;
2567
0
        }
2568
0
        else
2569
0
        {
2570
0
            nMaxWdt = aAnkSiz.Width();
2571
0
            nMinWdt = nMaxWdt;
2572
0
        }
2573
0
    }
2574
0
    Size aPaperMax(nMaxWdt, nMaxHgt);
2575
0
    Size aPaperMin(nMinWdt, nMinHgt);
2576
2577
0
    if ( pViewMin )
2578
0
    {
2579
0
        *pViewMin = aViewInit;
2580
2581
0
        tools::Long nXFree = aAnkSiz.Width() - aPaperMin.Width();
2582
0
        if ( eHAdj == SDRTEXTHORZADJUST_LEFT )
2583
0
            pViewMin->AdjustRight( -nXFree );
2584
0
        else if ( eHAdj == SDRTEXTHORZADJUST_RIGHT )
2585
0
            pViewMin->AdjustLeft(nXFree );
2586
0
        else { pViewMin->AdjustLeft(nXFree / 2 ); pViewMin->SetRight( pViewMin->Left() + aPaperMin.Width() ); }
2587
2588
0
        tools::Long nYFree = aAnkSiz.Height() - aPaperMin.Height();
2589
0
        if ( eVAdj == SDRTEXTVERTADJUST_TOP )
2590
0
            pViewMin->AdjustBottom( -nYFree );
2591
0
        else if ( eVAdj == SDRTEXTVERTADJUST_BOTTOM )
2592
0
            pViewMin->AdjustTop(nYFree );
2593
0
        else { pViewMin->AdjustTop(nYFree / 2 ); pViewMin->SetBottom( pViewMin->Top() + aPaperMin.Height() ); }
2594
0
    }
2595
2596
0
    if( IsVerticalWriting() )
2597
0
        aPaperMin.setWidth( 0 );
2598
0
    else
2599
0
        aPaperMin.setHeight( 0 );
2600
2601
0
    if( eHAdj != SDRTEXTHORZADJUST_BLOCK )
2602
0
        aPaperMin.setWidth(0 );
2603
2604
    // For complete vertical adjust support, set paper min height to 0, here.
2605
0
    if(SDRTEXTVERTADJUST_BLOCK != eVAdj )
2606
0
        aPaperMin.setHeight( 0 );
2607
2608
0
    if (pPaperMin!=nullptr) *pPaperMin=aPaperMin;
2609
0
    if (pPaperMax!=nullptr) *pPaperMax=aPaperMax;
2610
0
    if (pViewInit!=nullptr) *pViewInit=aViewInit;
2611
0
}
2612
2613
void SdrObjCustomShape::EndTextEdit( SdrOutliner& rOutl )
2614
0
{
2615
0
    if (!getDiagramDataModelID().isEmpty())
2616
0
    {
2617
0
        std::shared_ptr< svx::diagram::IDiagramHelper > pIDiagramHelper(getDiagramHelperFromDiagramOrMember());
2618
2619
0
        if (pIDiagramHelper)
2620
0
        {
2621
            // try to do the needed changes at the associated DiagramData model
2622
0
            pIDiagramHelper->TextInformationChange(getDiagramDataModelID(), rOutl);
2623
0
        }
2624
0
    }
2625
2626
0
    SdrTextObj::EndTextEdit( rOutl );
2627
0
    InvalidateRenderGeometry();
2628
0
}
2629
void SdrObjCustomShape::TakeTextAnchorRect( tools::Rectangle& rAnchorRect ) const
2630
11.4k
{
2631
11.4k
    if ( GetTextBounds( rAnchorRect ) )
2632
11.4k
    {
2633
11.4k
        Point aRotateRef( maSnapRect.Center() );
2634
11.4k
        const double fExtraTextRotation(GetExtraTextRotation());
2635
11.4k
        AdjustRectToTextDistance(rAnchorRect, fExtraTextRotation);
2636
2637
11.4k
        if ( rAnchorRect.GetWidth() < 2 )
2638
0
            rAnchorRect.SetRight( rAnchorRect.Left() + 1 );   // minimal width is 2
2639
11.4k
        if ( rAnchorRect.GetHeight() < 2 )
2640
0
            rAnchorRect.SetBottom( rAnchorRect.Top() + 1 );   // minimal height is 2
2641
11.4k
        if (maGeo.m_nRotationAngle)
2642
332
        {
2643
332
            Point aP( rAnchorRect.TopLeft() );
2644
332
            RotatePoint(aP, aRotateRef, maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
2645
332
            rAnchorRect.SetPos( aP );
2646
332
        }
2647
11.4k
    }
2648
0
    else
2649
0
        SdrTextObj::TakeTextAnchorRect( rAnchorRect );
2650
11.4k
}
2651
void SdrObjCustomShape::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText,
2652
                               tools::Rectangle* pAnchorRect, bool /*bLineWidth*/) const
2653
0
{
2654
0
    tools::Rectangle aAnkRect; // Rect in which we anchor
2655
0
    TakeTextAnchorRect(aAnkRect);
2656
0
    SdrTextVertAdjust eVAdj=GetTextVerticalAdjust();
2657
0
    SdrTextHorzAdjust eHAdj=GetTextHorizontalAdjust();
2658
0
    EEControlBits nStat0=rOutliner.GetControlWord();
2659
0
    Size aNullSize;
2660
2661
0
    rOutliner.SetControlWord(nStat0|EEControlBits::AUTOPAGESIZE);
2662
0
    rOutliner.SetMinAutoPaperSize(aNullSize);
2663
0
    sal_Int32 nMaxAutoPaperWidth = 1000000;
2664
0
    sal_Int32 nMaxAutoPaperHeight= 1000000;
2665
2666
0
    tools::Long nAnkWdt=aAnkRect.GetWidth();
2667
0
    tools::Long nAnkHgt=aAnkRect.GetHeight();
2668
2669
0
    if (GetMergedItem(SDRATTR_TEXT_WORDWRAP).GetValue())
2670
0
    {
2671
0
        if ( IsVerticalWriting() )
2672
0
            nMaxAutoPaperHeight = nAnkHgt;
2673
0
        else
2674
0
            nMaxAutoPaperWidth = nAnkWdt;
2675
0
    }
2676
0
    if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting())
2677
0
    {
2678
0
        rOutliner.SetMinAutoPaperSize(Size(nAnkWdt, 0));
2679
0
    }
2680
2681
0
    if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting())
2682
0
    {
2683
0
        rOutliner.SetMinAutoPaperSize(Size(0, nAnkHgt));
2684
0
    }
2685
0
    rOutliner.SetMaxAutoPaperSize( Size( nMaxAutoPaperWidth, nMaxAutoPaperHeight ) );
2686
0
    rOutliner.SetPaperSize( aNullSize );
2687
2688
    // put text into the Outliner - if necessary the use the text from the EditOutliner
2689
0
    std::optional<OutlinerParaObject> pPara;
2690
0
    if (GetOutlinerParaObject())
2691
0
        pPara = *GetOutlinerParaObject();
2692
0
    if (mpEditingOutliner && !bNoEditText)
2693
0
        pPara=mpEditingOutliner->CreateParaObject();
2694
2695
0
    if (pPara)
2696
0
    {
2697
0
        bool bHitTest(&getSdrModelFromSdrObject().GetHitTestOutliner() == &rOutliner);
2698
0
        const SdrTextObj* pTestObj = rOutliner.GetTextObj();
2699
2700
0
        if( !pTestObj || !bHitTest || pTestObj != this ||
2701
0
            pTestObj->GetOutlinerParaObject() != GetOutlinerParaObject() )
2702
0
        {
2703
0
            if( bHitTest )
2704
0
                rOutliner.SetTextObj( this );
2705
2706
0
            rOutliner.SetUpdateLayout(true);
2707
0
            rOutliner.SetText(*pPara);
2708
0
        }
2709
0
    }
2710
0
    else
2711
0
    {
2712
0
        rOutliner.SetTextObj( nullptr );
2713
0
    }
2714
2715
0
    rOutliner.SetUpdateLayout(true);
2716
0
    rOutliner.SetControlWord(nStat0);
2717
2718
0
    SdrText* pText = getActiveText();
2719
0
    if( pText )
2720
0
        pText->CheckPortionInfo( rOutliner );
2721
2722
0
    Point aTextPos(aAnkRect.TopLeft());
2723
0
    Size aTextSiz(rOutliner.GetPaperSize()); // GetPaperSize() has a little added tolerance, no?
2724
2725
    // For draw objects containing text correct horizontal/vertical alignment if text is bigger
2726
    // than the object itself. Without that correction, the text would always be
2727
    // formatted to the left edge (or top edge when vertical) of the draw object.
2728
2729
0
    if( !IsTextFrame() )
2730
0
    {
2731
0
        if(aAnkRect.GetWidth() < aTextSiz.Width() && !IsVerticalWriting())
2732
0
        {
2733
            // Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK,
2734
            // else the alignment is wanted.
2735
0
            if(SDRTEXTHORZADJUST_BLOCK == eHAdj)
2736
0
            {
2737
0
                SvxAdjust eAdjust = GetObjectItemSet().Get(EE_PARA_JUST).GetAdjust();
2738
0
                switch (eAdjust)
2739
0
                {
2740
0
                    case SvxAdjust::Left:   eHAdj = SDRTEXTHORZADJUST_LEFT; break;
2741
0
                    case SvxAdjust::Right:  eHAdj = SDRTEXTHORZADJUST_RIGHT; break;
2742
0
                    case SvxAdjust::Center: eHAdj = SDRTEXTHORZADJUST_CENTER; break;
2743
0
                    default: break;
2744
0
                }
2745
0
            }
2746
0
        }
2747
2748
0
        if(aAnkRect.GetHeight() < aTextSiz.Height() && IsVerticalWriting())
2749
0
        {
2750
            // Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK,
2751
            // else the alignment is wanted.
2752
0
            if(SDRTEXTVERTADJUST_BLOCK == eVAdj)
2753
0
            {
2754
0
                eVAdj = SDRTEXTVERTADJUST_CENTER;
2755
0
            }
2756
0
        }
2757
0
    }
2758
2759
0
    if (eHAdj==SDRTEXTHORZADJUST_CENTER || eHAdj==SDRTEXTHORZADJUST_RIGHT)
2760
0
    {
2761
0
        tools::Long nFreeWdt=aAnkRect.GetWidth()-aTextSiz.Width();
2762
0
        if (eHAdj==SDRTEXTHORZADJUST_CENTER)
2763
0
            aTextPos.AdjustX(nFreeWdt/2 );
2764
0
        if (eHAdj==SDRTEXTHORZADJUST_RIGHT)
2765
0
            aTextPos.AdjustX(nFreeWdt );
2766
0
    }
2767
0
    if (eVAdj==SDRTEXTVERTADJUST_CENTER || eVAdj==SDRTEXTVERTADJUST_BOTTOM)
2768
0
    {
2769
0
        tools::Long nFreeHgt=aAnkRect.GetHeight()-aTextSiz.Height();
2770
0
        if (eVAdj==SDRTEXTVERTADJUST_CENTER)
2771
0
            aTextPos.AdjustY(nFreeHgt/2 );
2772
0
        if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
2773
0
            aTextPos.AdjustY(nFreeHgt );
2774
0
    }
2775
0
    if (maGeo.m_nRotationAngle != 0_deg100)
2776
0
        RotatePoint(aTextPos,aAnkRect.TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
2777
2778
0
    if (pAnchorRect)
2779
0
        *pAnchorRect=aAnkRect;
2780
2781
    // using rTextRect together with ContourFrame doesn't always work correctly
2782
0
    rTextRect=tools::Rectangle(aTextPos,aTextSiz);
2783
0
}
2784
2785
void SdrObjCustomShape::NbcSetOutlinerParaObject(std::optional<OutlinerParaObject> pTextObject, bool bAdjustTextFrameWidthAndHeight)
2786
40.1k
{
2787
40.1k
    SdrTextObj::NbcSetOutlinerParaObject( std::move(pTextObject), bAdjustTextFrameWidthAndHeight );
2788
40.1k
    SetBoundRectDirty();
2789
40.1k
    SetBoundAndSnapRectsDirty(true);
2790
40.1k
    InvalidateRenderGeometry();
2791
40.1k
}
2792
2793
rtl::Reference<SdrObject> SdrObjCustomShape::CloneSdrObject(SdrModel& rTargetModel) const
2794
5.49k
{
2795
5.49k
    return new SdrObjCustomShape(rTargetModel, *this);
2796
5.49k
}
2797
2798
OUString SdrObjCustomShape::TakeObjNameSingul() const
2799
0
{
2800
0
    OUString sName(SvxResId(STR_ObjNameSingulCUSTOMSHAPE));
2801
0
    OUString aNm(GetName());
2802
0
    if (!aNm.isEmpty())
2803
0
        sName += " '" + aNm + "'";
2804
0
    return sName;
2805
0
}
2806
2807
OUString SdrObjCustomShape::TakeObjNamePlural() const
2808
0
{
2809
0
    return SvxResId(STR_ObjNamePluralCUSTOMSHAPE);
2810
0
}
2811
2812
basegfx::B2DPolyPolygon SdrObjCustomShape::TakeXorPoly() const
2813
0
{
2814
0
    return GetLineGeometry( false );
2815
0
}
2816
2817
basegfx::B2DPolyPolygon SdrObjCustomShape::TakeContour() const
2818
0
{
2819
0
    const SdrObject* pSdrObject = GetSdrObjectFromCustomShape();
2820
0
    if ( pSdrObject )
2821
0
        return pSdrObject->TakeContour();
2822
0
    return basegfx::B2DPolyPolygon();
2823
0
}
2824
2825
rtl::Reference<SdrObject> SdrObjCustomShape::DoConvertToPolyObj(bool bBezier, bool bAddText) const
2826
0
{
2827
    // #i37011#
2828
0
    rtl::Reference<SdrObject> pRetval;
2829
2830
0
    if ( !mXRenderedCustomShape.is() )
2831
0
    {
2832
        // force CustomShape
2833
0
        GetSdrObjectFromCustomShape();
2834
0
    }
2835
2836
0
    SdrObject* pRenderedCustomShape = mXRenderedCustomShape.get();
2837
0
    if ( pRenderedCustomShape )
2838
0
    {
2839
        // Clone to same SdrModel
2840
0
        rtl::Reference<SdrObject> pCandidate(pRenderedCustomShape->CloneSdrObject(pRenderedCustomShape->getSdrModelFromSdrObject()));
2841
0
        DBG_ASSERT(pCandidate, "SdrObjCustomShape::DoConvertToPolyObj: Could not clone SdrObject (!)");
2842
0
        pRetval = pCandidate->DoConvertToPolyObj(bBezier, bAddText);
2843
0
        pCandidate.clear();
2844
2845
0
        if(pRetval)
2846
0
        {
2847
0
            const bool bShadow(GetMergedItem(SDRATTR_SHADOW).GetValue());
2848
0
            if(bShadow)
2849
0
            {
2850
0
                pRetval->SetMergedItem(makeSdrShadowItem(true));
2851
0
            }
2852
0
        }
2853
2854
0
        if(bAddText && HasText() && !IsTextPath())
2855
0
        {
2856
0
            pRetval = ImpConvertAddText(std::move(pRetval), bBezier);
2857
0
        }
2858
0
    }
2859
2860
0
    return pRetval;
2861
0
}
2862
2863
void SdrObjCustomShape::InternalSetStyleSheet( SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr, bool bBroadcast, bool bAdjustTextFrameWidthAndHeight )
2864
4.07k
{
2865
    // #i40944#
2866
4.07k
    InvalidateRenderGeometry();
2867
4.07k
    SdrObject::InternalSetStyleSheet( pNewStyleSheet, bDontRemoveHardAttr, bBroadcast, bAdjustTextFrameWidthAndHeight );
2868
4.07k
}
2869
2870
void SdrObjCustomShape::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
2871
88.0k
{
2872
    // call parent
2873
88.0k
    SdrTextObj::handlePageChange(pOldPage, pNewPage);
2874
2875
88.0k
    if(nullptr != pNewPage)
2876
80.0k
    {
2877
        // invalidating rectangles by SetRectsDirty is not sufficient,
2878
        // AdjustTextFrameWidthAndHeight() also has to be made, both
2879
        // actions are done by NbcSetSnapRect
2880
80.0k
        tools::Rectangle aRectangle(getRectangle());    //creating temporary rectangle #i61108#
2881
80.0k
        NbcSetSnapRect(aRectangle);
2882
80.0k
    }
2883
88.0k
}
2884
2885
std::unique_ptr<SdrObjGeoData> SdrObjCustomShape::NewGeoData() const
2886
0
{
2887
0
    return std::make_unique<SdrAShapeObjGeoData>();
2888
0
}
2889
2890
void SdrObjCustomShape::SaveGeoData(SdrObjGeoData& rGeo) const
2891
931
{
2892
931
    SdrTextObj::SaveGeoData( rGeo );
2893
931
    SdrAShapeObjGeoData& rAGeo=static_cast<SdrAShapeObjGeoData&>(rGeo);
2894
931
    rAGeo.fObjectRotation = m_fObjectRotation;
2895
931
    rAGeo.bMirroredX = IsMirroredX();
2896
931
    rAGeo.bMirroredY = IsMirroredY();
2897
2898
931
    const uno::Any* pAny = GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ).GetPropertyValueByName( u"AdjustmentValues"_ustr );
2899
931
    if ( pAny )
2900
0
        *pAny >>= rAGeo.aAdjustmentSeq;
2901
931
}
2902
2903
void SdrObjCustomShape::RestoreGeoData(const SdrObjGeoData& rGeo)
2904
0
{
2905
0
    SdrTextObj::RestoreGeoData( rGeo );
2906
0
    const SdrAShapeObjGeoData& rAGeo=static_cast<const SdrAShapeObjGeoData&>(rGeo);
2907
0
    m_fObjectRotation = rAGeo.fObjectRotation;
2908
0
    SetMirroredX( rAGeo.bMirroredX );
2909
0
    SetMirroredY( rAGeo.bMirroredY );
2910
2911
0
    SdrCustomShapeGeometryItem rGeometryItem = GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
2912
0
    beans::PropertyValue aPropVal;
2913
0
    aPropVal.Name = "AdjustmentValues";
2914
0
    aPropVal.Value <<= rAGeo.aAdjustmentSeq;
2915
0
    rGeometryItem.SetPropertyValue( aPropVal );
2916
0
    SetMergedItem( rGeometryItem );
2917
2918
0
    InvalidateRenderGeometry();
2919
0
}
2920
2921
void SdrObjCustomShape::AdjustToMaxRect(const tools::Rectangle& rMaxRect, bool bShrinkOnly /* = false */)
2922
23
{
2923
23
    SAL_INFO_IF(bShrinkOnly, "svx", "Case bShrinkOnly == true is not implemented yet.");
2924
2925
23
    if (rMaxRect.IsEmpty() || rMaxRect == GetSnapRect())
2926
0
        return;
2927
2928
    // Get a matrix, that would produce the existing shape, when applied to a unit square
2929
23
    basegfx::B2DPolyPolygon aPolyPolygon; //not used, but formal needed
2930
23
    basegfx::B2DHomMatrix aMatrix;
2931
23
    TRGetBaseGeometry(aMatrix, aPolyPolygon);
2932
    // Using TRSetBaseGeometry(aMatrix, aPolyPolygon) would regenerate the current shape. But
2933
    // applying aMatrix to a unit square will not generate the current shape. Scaling,
2934
    // rotation and translation are correct, but shear angle has wrong sign. So break up
2935
    // matrix and create a mathematically correct new one.
2936
23
    basegfx::B2DTuple aScale;
2937
23
    basegfx::B2DTuple aTranslate;
2938
23
    double fRotate, fShearX;
2939
23
    aMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
2940
23
    basegfx::B2DHomMatrix aMathMatrix;
2941
23
    aMathMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
2942
23
            aScale,
2943
23
            -fShearX,
2944
23
            fRotate,
2945
23
            aTranslate);
2946
2947
    // Calculate scaling factors from size of the transformed unit polygon as ersatz for the not
2948
    // usable current snap rectangle.
2949
23
    basegfx::B2DPolygon aB2DPolygon(basegfx::utils::createUnitPolygon());
2950
23
    aB2DPolygon.transform(aMathMatrix);
2951
23
    basegfx::B2DRange aB2DRange(aB2DPolygon.getB2DRange());
2952
23
    double fPolygonWidth = aB2DRange.getWidth();
2953
23
    if (fPolygonWidth == 0)
2954
0
        fPolygonWidth = 1;
2955
23
    double fPolygonHeight = aB2DRange.getHeight();
2956
23
    if (fPolygonHeight == 0)
2957
0
        fPolygonHeight = 1;
2958
23
    const double aFactorX = static_cast<double>(rMaxRect.GetWidth()) / fPolygonWidth;
2959
23
    const double aFactorY = static_cast<double>(rMaxRect.GetHeight()) / fPolygonHeight;
2960
2961
    // Generate matrix, that would produce the desired rMaxRect when applied to unit square
2962
23
    aMathMatrix.scale(aFactorX, aFactorY);
2963
23
    aB2DPolygon = basegfx::utils::createUnitPolygon();
2964
23
    aB2DPolygon.transform(aMathMatrix);
2965
23
    aB2DRange = aB2DPolygon.getB2DRange();
2966
23
    const double fPolygonLeft = aB2DRange.getMinX();
2967
23
    const double fPolygonTop = aB2DRange.getMinY();
2968
23
    aMathMatrix.translate(rMaxRect.Left() - fPolygonLeft, rMaxRect.Top() - fPolygonTop);
2969
2970
    // Create a Matrix from aMathMatrix, which is usable with TRSetBaseGeometry
2971
23
    aMathMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
2972
23
    aMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
2973
23
            aScale,
2974
23
            -fShearX,
2975
23
            fRotate,
2976
23
            aTranslate);
2977
2978
    // Now use TRSetBaseGeometry to actually perform scale, shear, rotate and translate
2979
    // on the shape. That considers gluepoints, interaction handles and text area, and includes
2980
    // setting rectangles dirty and broadcast.
2981
23
    TRSetBaseGeometry(aMatrix, aPolyPolygon);
2982
23
}
2983
2984
void SdrObjCustomShape::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
2985
21.4k
{
2986
    // The shape might have already flipping in its enhanced geometry. LibreOffice applies
2987
    // such after all transformations. We remove it, but remember it to apply them later.
2988
21.4k
    bool bIsMirroredX = IsMirroredX();
2989
21.4k
    bool bIsMirroredY = IsMirroredY();
2990
21.4k
    if (bIsMirroredX || bIsMirroredY)
2991
0
    {
2992
0
        Point aCurrentCenter = GetSnapRect().Center();
2993
0
        if (bIsMirroredX) // mirror on the y-axis
2994
0
        {
2995
0
            Mirror(aCurrentCenter, Point(aCurrentCenter.X(), aCurrentCenter.Y() + 1000));
2996
0
        }
2997
0
        if (bIsMirroredY) // mirror on the x-axis
2998
0
        {
2999
0
            Mirror(aCurrentCenter, Point(aCurrentCenter.X() + 1000, aCurrentCenter.Y()));
3000
0
        }
3001
0
    }
3002
3003
    // break up matrix
3004
21.4k
    basegfx::B2DTuple aScale;
3005
21.4k
    basegfx::B2DTuple aTranslate;
3006
21.4k
    double fRotate, fShearX;
3007
21.4k
    rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
3008
3009
    // reset object shear and rotations
3010
21.4k
    m_fObjectRotation = 0.0;
3011
21.4k
    maGeo.m_nRotationAngle = 0_deg100;
3012
21.4k
    maGeo.RecalcSinCos();
3013
21.4k
    maGeo.m_nShearAngle = 0_deg100;
3014
21.4k
    maGeo.RecalcTan();
3015
3016
    // if anchor is used, make position relative to it
3017
21.4k
    if(getSdrModelFromSdrObject().IsWriter())
3018
2.49k
    {
3019
2.49k
        if(GetAnchorPos().X() || GetAnchorPos().Y())
3020
0
        {
3021
0
            aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
3022
0
        }
3023
2.49k
    }
3024
3025
    // scale
3026
21.4k
    Size aSize(basegfx::fround<tools::Long>(fabs(aScale.getX())),
3027
21.4k
               basegfx::fround<tools::Long>(fabs(aScale.getY())));
3028
    // fdo#47434 We need a valid rectangle here
3029
21.4k
    if( !aSize.Height() ) aSize.setHeight( 1 );
3030
21.4k
    if( !aSize.Width() ) aSize.setWidth( 1 );
3031
21.4k
    tools::Rectangle aBaseRect(Point(), aSize);
3032
21.4k
    SetLogicRect(aBaseRect);
3033
3034
    // Apply flipping from Matrix, which is a transformation relative to origin
3035
21.4k
    if (aScale.getX() < 0.0)
3036
0
        Mirror(Point(0, 0), Point(0, 1000)); // mirror on the y-axis
3037
21.4k
    if (aScale.getY() < 0.0)
3038
0
        Mirror(Point(0, 0), Point(1000, 0)); // mirror on the x-axis
3039
3040
    // shear?
3041
21.4k
    if(!basegfx::fTools::equalZero(fShearX))
3042
0
    {
3043
0
        GeoStat aGeoStat;
3044
        // #i123181# The fix for #121932# here was wrong, the trunk version does not correct the
3045
        // mirrored shear values, neither at the object level, nor on the API or XML level. Taking
3046
        // back the mirroring of the shear angle
3047
0
        aGeoStat.m_nShearAngle = Degree100(basegfx::fround(basegfx::rad2deg<100>(atan(fShearX))));
3048
0
        aGeoStat.RecalcTan();
3049
0
        Shear(Point(), aGeoStat.m_nShearAngle, aGeoStat.mfTanShearAngle, false);
3050
0
    }
3051
3052
    // rotation?
3053
21.4k
    if(!basegfx::fTools::equalZero(fRotate))
3054
2.30k
    {
3055
2.30k
        GeoStat aGeoStat;
3056
3057
        // #i78696#
3058
        // fRotate is mathematically correct, but aGeoStat.nRotationAngle is
3059
        // mirrored -> mirror value here
3060
2.30k
        aGeoStat.m_nRotationAngle = NormAngle36000(Degree100(basegfx::fround(-basegfx::rad2deg<100>(fRotate))));
3061
2.30k
        aGeoStat.RecalcSinCos();
3062
2.30k
        Rotate(Point(), aGeoStat.m_nRotationAngle, aGeoStat.mfSinRotationAngle, aGeoStat.mfCosRotationAngle);
3063
2.30k
    }
3064
3065
    // translate?
3066
21.4k
    if(!aTranslate.equalZero())
3067
19.7k
    {
3068
19.7k
        Move(Size(basegfx::fround<tools::Long>(aTranslate.getX()),
3069
19.7k
                  basegfx::fround<tools::Long>(aTranslate.getY())));
3070
19.7k
    }
3071
3072
    // Apply flipping from enhanced geometry at center of the shape.
3073
21.4k
    if (!(bIsMirroredX || bIsMirroredY))
3074
21.4k
        return;
3075
3076
    // create mathematically matrix for the applied transformations
3077
    // aScale was in most cases built from a rectangle including edge
3078
    // and is therefore mathematically too large by 1
3079
0
    if (aScale.getX() > 2.0 && aScale.getY() > 2.0)
3080
0
        aScale -= basegfx::B2DTuple(1.0, 1.0);
3081
0
    basegfx::B2DHomMatrix aMathMat = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
3082
0
                    aScale, -fShearX, fRotate,
3083
0
                    aTranslate);
3084
    // Use matrix to get current center
3085
0
    basegfx::B2DPoint aCenter(0.5,0.5);
3086
0
    aCenter = aMathMat * aCenter;
3087
0
    double fCenterX = aCenter.getX();
3088
0
    double fCenterY = aCenter.getY();
3089
0
    if (bIsMirroredX) // vertical axis
3090
0
        Mirror(Point(basegfx::fround<tools::Long>(fCenterX), basegfx::fround<tools::Long>(fCenterY)),
3091
0
            Point(basegfx::fround<tools::Long>(fCenterX), basegfx::fround<tools::Long>(fCenterY + 1000.0)));
3092
0
    if (bIsMirroredY) // horizontal axis
3093
0
        Mirror(Point(basegfx::fround<tools::Long>(fCenterX), basegfx::fround<tools::Long>(fCenterY)),
3094
0
            Point(basegfx::fround<tools::Long>(fCenterX + 1000.0), basegfx::fround<tools::Long>(fCenterY)));
3095
0
}
3096
3097
// taking fObjectRotation instead of aGeo.nAngle
3098
bool SdrObjCustomShape::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
3099
21.4k
{
3100
    // get turn and shear
3101
21.4k
    double fRotate = basegfx::deg2rad(m_fObjectRotation);
3102
21.4k
    double fShearX = toRadians(maGeo.m_nShearAngle);
3103
3104
    // get aRectangle, this is the unrotated snaprect
3105
21.4k
    tools::Rectangle aRectangle(getRectangle());
3106
3107
21.4k
    bool bMirroredX = IsMirroredX();
3108
21.4k
    bool bMirroredY = IsMirroredY();
3109
21.4k
    if ( bMirroredX || bMirroredY )
3110
0
    {   // we have to retrieve the unmirrored rect
3111
3112
0
        GeoStat aNewGeo(maGeo);
3113
3114
0
        if ( bMirroredX )
3115
0
        {
3116
0
            fShearX = -fShearX;
3117
0
            tools::Polygon aPol = Rect2Poly(getRectangle(), aNewGeo);
3118
0
            tools::Rectangle aBoundRect( aPol.GetBoundRect() );
3119
3120
0
            Point aRef1( ( aBoundRect.Left() + aBoundRect.Right() ) >> 1, aBoundRect.Top() );
3121
0
            Point aRef2( aRef1.X(), aRef1.Y() + 1000 );
3122
0
            sal_uInt16 i;
3123
0
            sal_uInt16 nPointCount=aPol.GetSize();
3124
0
            for (i=0; i<nPointCount; i++)
3125
0
            {
3126
0
                MirrorPoint(aPol[i],aRef1,aRef2);
3127
0
            }
3128
            // mirror polygon and move it a bit
3129
0
            tools::Polygon aPol0(aPol);
3130
0
            aPol[0]=aPol0[1];
3131
0
            aPol[1]=aPol0[0];
3132
0
            aPol[2]=aPol0[3];
3133
0
            aPol[3]=aPol0[2];
3134
0
            aPol[4]=aPol0[1];
3135
0
            aRectangle = svx::polygonToRectangle(aPol, aNewGeo);
3136
0
        }
3137
0
        if ( bMirroredY )
3138
0
        {
3139
0
            fShearX = -fShearX;
3140
0
            tools::Polygon aPol( Rect2Poly( aRectangle, aNewGeo ) );
3141
0
            tools::Rectangle aBoundRect( aPol.GetBoundRect() );
3142
3143
0
            Point aRef1( aBoundRect.Left(), ( aBoundRect.Top() + aBoundRect.Bottom() ) >> 1 );
3144
0
            Point aRef2( aRef1.X() + 1000, aRef1.Y() );
3145
0
            sal_uInt16 i;
3146
0
            sal_uInt16 nPointCount=aPol.GetSize();
3147
0
            for (i=0; i<nPointCount; i++)
3148
0
            {
3149
0
                MirrorPoint(aPol[i],aRef1,aRef2);
3150
0
            }
3151
            // mirror polygon and move it a bit
3152
0
            tools::Polygon aPol0(aPol);
3153
0
            aPol[0]=aPol0[1]; // This was WRONG for vertical (!)
3154
0
            aPol[1]=aPol0[0]; // #i121932# Despite my own comment above
3155
0
            aPol[2]=aPol0[3]; // it was *not* wrong even when the reordering
3156
0
            aPol[3]=aPol0[2]; // *seems* to be specific for X-Mirrorings. Oh
3157
0
            aPol[4]=aPol0[1]; // will I be happy when this old stuff is |gone| with aw080 (!)
3158
0
            aRectangle = svx::polygonToRectangle(aPol, aNewGeo);
3159
0
        }
3160
0
    }
3161
3162
    // fill other values
3163
21.4k
    basegfx::B2DTuple aScale(aRectangle.GetWidth(), aRectangle.GetHeight());
3164
21.4k
    basegfx::B2DTuple aTranslate(aRectangle.Left(), aRectangle.Top());
3165
3166
    // position may be relative to anchorpos, convert
3167
21.4k
    if(getSdrModelFromSdrObject().IsWriter())
3168
2.49k
    {
3169
2.49k
        if(GetAnchorPos().X() || GetAnchorPos().Y())
3170
0
        {
3171
0
            aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
3172
0
        }
3173
2.49k
    }
3174
3175
    // build matrix
3176
21.4k
    rMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
3177
21.4k
        aScale,
3178
21.4k
        basegfx::fTools::equalZero(fShearX) ? 0.0 : tan(fShearX),
3179
21.4k
        -fRotate,
3180
21.4k
        aTranslate);
3181
3182
21.4k
    return false;
3183
21.4k
}
3184
3185
std::unique_ptr<sdr::contact::ViewContact> SdrObjCustomShape::CreateObjectSpecificViewContact()
3186
152k
{
3187
152k
    return std::make_unique<sdr::contact::ViewContactOfSdrObjCustomShape>(*this);
3188
152k
}
3189
3190
// #i33136#
3191
bool SdrObjCustomShape::doConstructOrthogonal(std::u16string_view rName)
3192
0
{
3193
0
    bool bRetval(false);
3194
3195
0
    if(o3tl::equalsIgnoreAsciiCase(rName, u"quadrat"))
3196
0
    {
3197
0
        bRetval = true;
3198
0
    }
3199
0
    else if(o3tl::equalsIgnoreAsciiCase(rName, u"round-quadrat"))
3200
0
    {
3201
0
        bRetval = true;
3202
0
    }
3203
0
    else if(o3tl::equalsIgnoreAsciiCase(rName, u"circle"))
3204
0
    {
3205
0
        bRetval = true;
3206
0
    }
3207
0
    else if(o3tl::equalsIgnoreAsciiCase(rName, u"circle-pie"))
3208
0
    {
3209
0
        bRetval = true;
3210
0
    }
3211
0
    else if(o3tl::equalsIgnoreAsciiCase(rName, u"ring"))
3212
0
    {
3213
0
        bRetval = true;
3214
0
    }
3215
3216
0
    return bRetval;
3217
0
}
3218
3219
// #i37011# centralize throw-away of render geometry
3220
void SdrObjCustomShape::InvalidateRenderGeometry()
3221
5.88M
{
3222
5.88M
    mXRenderedCustomShape = nullptr;
3223
5.88M
    mpLastShadowGeometry = nullptr;
3224
5.88M
}
3225
3226
void SdrObjCustomShape::setUnoShape(const uno::Reference<drawing::XShape>& rxUnoShape)
3227
839k
{
3228
839k
    SdrTextObj::setUnoShape(rxUnoShape);
3229
3230
    // The shape engine is created with _current_ shape. This means we
3231
    // _must_ reset it when the shape changes.
3232
839k
    mxCustomShapeEngine.clear();
3233
839k
}
3234
3235
OUString SdrObjCustomShape::GetCustomShapeName() const
3236
0
{
3237
0
    OUString sShapeName;
3238
0
    OUString aEngine( GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE ).GetValue() );
3239
0
    if ( aEngine.isEmpty()
3240
0
         || aEngine == "com.sun.star.drawing.EnhancedCustomShapeEngine" )
3241
0
    {
3242
0
        OUString sShapeType;
3243
0
        const SdrCustomShapeGeometryItem& rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
3244
0
        const uno::Any* pAny = rGeometryItem.GetPropertyValueByName( u"Type"_ustr );
3245
0
        if ( pAny && ( *pAny >>= sShapeType ) )
3246
0
            sShapeName = EnhancedCustomShapeTypeNames::GetAccName( sShapeType );
3247
0
    }
3248
0
    return sShapeName;
3249
0
}
3250
3251
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */