1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/uno/Reference.h>
21 #include <com/sun/star/uno/XComponentContext.hpp>
22 #include <com/sun/star/awt/Rectangle.hpp>
23 #include <com/sun/star/beans/PropertyValue.hpp>
24 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
25 #include <com/sun/star/lang/XInitialization.hpp>
26 #include <com/sun/star/lang/XServiceInfo.hpp>
27 #include <com/sun/star/drawing/XCustomShapeEngine.hpp>
28 #include <svx/EnhancedCustomShape2d.hxx>
29 #include "EnhancedCustomShape3d.hxx"
30 #include "EnhancedCustomShapeFontWork.hxx"
31 #include "EnhancedCustomShapeHandle.hxx"
32 #include <svx/unoshape.hxx>
33 #include <svx/unopage.hxx>
34 #include <svx/svdobj.hxx>
35 #include <svx/svdoashp.hxx>
36 #include <svx/svdogrp.hxx>
37 #include <editeng/outlobj.hxx>
38 #include <svl/itemset.hxx>
39 #include <svx/svdopath.hxx>
40 #include <svx/svdpage.hxx>
41 #include <svx/svditer.hxx>
42 #include <svx/xfillit0.hxx>
43 #include <svx/xlineit0.hxx>
44 #include <basegfx/polygon/b2dpolypolygontools.hxx>
45 #include <com/sun/star/document/XActionLockable.hpp>
46 #include <cppuhelper/implbase.hxx>
47 #include <cppuhelper/supportsservice.hxx>
50 using namespace css::uno
;
53 class SdrObjCustomShape
;
57 class EnhancedCustomShapeEngine
: public cppu::WeakImplHelper
59 css::lang::XInitialization
,
60 css::lang::XServiceInfo
,
61 css::drawing::XCustomShapeEngine
64 css::uno::Reference
< css::drawing::XShape
> mxShape
;
65 bool mbForceGroupWithText
;
67 rtl::Reference
<SdrObject
> ImplForceGroupWithText(
68 const SdrObjCustomShape
& rSdrObjCustomShape
,
69 SdrObject
* pRenderedShape
);
72 EnhancedCustomShapeEngine();
75 virtual void SAL_CALL
acquire() noexcept override
;
76 virtual void SAL_CALL
release() noexcept override
;
79 virtual void SAL_CALL
initialize( const css::uno::Sequence
< css::uno::Any
>& aArguments
) override
;
82 virtual OUString SAL_CALL
getImplementationName() override
;
83 virtual sal_Bool SAL_CALL
supportsService( const OUString
& rServiceName
) override
;
84 virtual css::uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
87 virtual css::uno::Reference
< css::drawing::XShape
> SAL_CALL
render() override
;
88 virtual css::awt::Rectangle SAL_CALL
getTextBounds() override
;
89 virtual css::drawing::PolyPolygonBezierCoords SAL_CALL
getLineGeometry() override
;
90 virtual css::uno::Sequence
< css::uno::Reference
< css::drawing::XCustomShapeHandle
> > SAL_CALL
getInteraction() override
;
93 EnhancedCustomShapeEngine::EnhancedCustomShapeEngine() :
94 mbForceGroupWithText ( false )
99 void SAL_CALL
EnhancedCustomShapeEngine::acquire() noexcept
101 OWeakObject::acquire();
103 void SAL_CALL
EnhancedCustomShapeEngine::release() noexcept
105 OWeakObject::release();
109 void SAL_CALL
EnhancedCustomShapeEngine::initialize( const Sequence
< Any
>& aArguments
)
111 Sequence
< beans::PropertyValue
> aParameter
;
112 for ( const auto& rArgument
: aArguments
)
114 if ( rArgument
>>= aParameter
)
117 for (const beans::PropertyValue
& rProp
: aParameter
)
119 if ( rProp
.Name
== "CustomShape" )
120 rProp
.Value
>>= mxShape
;
121 else if ( rProp
.Name
== "ForceGroupWithText" )
122 rProp
.Value
>>= mbForceGroupWithText
;
127 OUString SAL_CALL
EnhancedCustomShapeEngine::getImplementationName()
129 return u
"com.sun.star.drawing.EnhancedCustomShapeEngine"_ustr
;
131 sal_Bool SAL_CALL
EnhancedCustomShapeEngine::supportsService( const OUString
& rServiceName
)
133 return cppu::supportsService(this, rServiceName
);
135 Sequence
< OUString
> SAL_CALL
EnhancedCustomShapeEngine::getSupportedServiceNames()
137 return { u
"com.sun.star.drawing.CustomShapeEngine"_ustr
};
140 // XCustomShapeEngine
141 rtl::Reference
<SdrObject
> EnhancedCustomShapeEngine::ImplForceGroupWithText(
142 const SdrObjCustomShape
& rSdrObjCustomShape
,
143 SdrObject
* pRenderedShape1
)
145 rtl::Reference
<SdrObject
> pRenderedShape
= pRenderedShape1
;
146 const bool bHasText(rSdrObjCustomShape
.HasText());
148 if ( pRenderedShape
|| bHasText
)
151 const SdrObject
* pShadowGeometry(rSdrObjCustomShape
.GetSdrObjectShadowFromCustomShape());
153 if ( pShadowGeometry
)
155 if ( pRenderedShape
)
157 if ( dynamic_cast<const SdrObjGroup
*>( pRenderedShape
.get() ) == nullptr )
159 auto pTmp
= std::move(pRenderedShape
);
160 pRenderedShape
= new SdrObjGroup(rSdrObjCustomShape
.getSdrModelFromSdrObject());
161 static_cast<SdrObjGroup
*>(pRenderedShape
.get())->GetSubList()->NbcInsertObject( pTmp
.get() );
164 static_cast<SdrObjGroup
*>(pRenderedShape
.get())->GetSubList()->NbcInsertObject(
165 pShadowGeometry
->CloneSdrObject(pShadowGeometry
->getSdrModelFromSdrObject()).get(),
170 pRenderedShape
= pShadowGeometry
->CloneSdrObject(pShadowGeometry
->getSdrModelFromSdrObject());
177 // #i37011# also create a text object and add at rPos + 1
178 rtl::Reference
<SdrObject
> pTextObj( SdrObjFactory::MakeNewObject(
179 rSdrObjCustomShape
.getSdrModelFromSdrObject(),
180 rSdrObjCustomShape
.GetObjInventor(),
184 OutlinerParaObject
* pParaObj(rSdrObjCustomShape
.GetOutlinerParaObject());
187 pTextObj
->NbcSetOutlinerParaObject( *pParaObj
);
189 // copy all attributes
190 SfxItemSet
aTargetItemSet(rSdrObjCustomShape
.GetMergedItemSet());
192 // clear fill and line style
193 aTargetItemSet
.Put(XLineStyleItem(drawing::LineStyle_NONE
));
194 aTargetItemSet
.Put(XFillStyleItem(drawing::FillStyle_NONE
));
196 // get the text bounds and set at text object
197 tools::Rectangle
aTextBounds(rSdrObjCustomShape
.GetSnapRect());
198 auto pSdrObjCustomShape
= dynamic_cast< SdrObjCustomShape
* >(SdrObject::getSdrObjectFromXShape(mxShape
));
200 if(pSdrObjCustomShape
)
202 EnhancedCustomShape2d
aCustomShape2d(*pSdrObjCustomShape
);
203 aTextBounds
= aCustomShape2d
.GetTextRect();
206 pTextObj
->SetSnapRect( aTextBounds
);
208 // if rotated, copy GeoStat, too.
209 const GeoStat
& rSourceGeo(rSdrObjCustomShape
.GetGeoStat());
210 if ( rSourceGeo
.m_nRotationAngle
)
213 rSdrObjCustomShape
.GetSnapRect().Center(),
214 rSourceGeo
.m_nRotationAngle
,
215 rSourceGeo
.mfSinRotationAngle
,
216 rSourceGeo
.mfCosRotationAngle
);
219 // set modified ItemSet at text object
220 pTextObj
->SetMergedItemSet(aTargetItemSet
);
222 if ( pRenderedShape
)
224 if ( dynamic_cast<const SdrObjGroup
*>( pRenderedShape
.get() ) == nullptr )
226 auto pTmp
= std::move(pRenderedShape
);
227 pRenderedShape
= new SdrObjGroup(rSdrObjCustomShape
.getSdrModelFromSdrObject());
228 static_cast<SdrObjGroup
*>(pRenderedShape
.get())->GetSubList()->NbcInsertObject( pTmp
.get() );
230 static_cast<SdrObjGroup
*>(pRenderedShape
.get())->GetSubList()->NbcInsertObject( pTextObj
.get() );
233 pRenderedShape
= std::move(pTextObj
);
237 if ( pRenderedShape
)
239 if ( dynamic_cast<const SdrObjGroup
*>( pRenderedShape
.get() ) == nullptr )
241 auto pTmp
= std::move(pRenderedShape
);
242 pRenderedShape
= new SdrObjGroup(rSdrObjCustomShape
.getSdrModelFromSdrObject());
243 static_cast<SdrObjGroup
*>(pRenderedShape
.get())->GetSubList()->NbcInsertObject( pTmp
.get() );
248 return pRenderedShape
;
251 Reference
< drawing::XShape
> SAL_CALL
EnhancedCustomShapeEngine::render()
253 SdrObjCustomShape
* pSdrObjCustomShape
= dynamic_cast< SdrObjCustomShape
* >(SdrObject::getSdrObjectFromXShape(mxShape
));
255 if(!pSdrObjCustomShape
)
257 return Reference
< drawing::XShape
>();
260 // retrieving the TextPath property to check if feature is enabled
261 const SdrCustomShapeGeometryItem
& rGeometryItem(pSdrObjCustomShape
->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
));
262 bool bTextPathOn
= false;
263 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName( u
"TextPath"_ustr
, u
"TextPath"_ustr
);
265 *pAny
>>= bTextPathOn
;
267 EnhancedCustomShape2d
aCustomShape2d(*pSdrObjCustomShape
);
268 Degree100 nRotateAngle
= aCustomShape2d
.GetRotateAngle();
270 bool bFlipV
= aCustomShape2d
.IsFlipVert();
271 bool bFlipH
= aCustomShape2d
.IsFlipHorz();
272 bool bLineGeometryNeededOnly
= bTextPathOn
;
274 rtl::Reference
<SdrObject
> xRenderedShape(aCustomShape2d
.CreateObject(bLineGeometryNeededOnly
));
279 rtl::Reference
<SdrObject
> xRenderedFontWork(
280 EnhancedCustomShapeFontWork::CreateFontWork(
281 xRenderedShape
.get(),
282 *pSdrObjCustomShape
));
284 if (xRenderedFontWork
)
286 xRenderedShape
= std::move(xRenderedFontWork
);
289 rtl::Reference
<SdrObject
> xRenderedShape3d(EnhancedCustomShape3d::Create3DObject(xRenderedShape
.get(), *pSdrObjCustomShape
));
290 if (xRenderedShape3d
)
292 bFlipV
= bFlipH
= false;
293 nRotateAngle
= 0_deg100
;
294 xRenderedShape
= std::move(xRenderedShape3d
);
297 tools::Rectangle
aRect(pSdrObjCustomShape
->GetSnapRect());
298 const GeoStat
& rGeoStat(pSdrObjCustomShape
->GetGeoStat());
300 if ( rGeoStat
.m_nShearAngle
)
302 Degree100 nShearAngle
= rGeoStat
.m_nShearAngle
;
303 double nTan
= rGeoStat
.mfTanShearAngle
;
304 if (bFlipV
!= bFlipH
)
306 nShearAngle
= -nShearAngle
;
310 xRenderedShape
->Shear(pSdrObjCustomShape
->GetSnapRect().Center(), nShearAngle
, nTan
, false);
313 xRenderedShape
->NbcRotate(pSdrObjCustomShape
->GetSnapRect().Center(), nRotateAngle
);
316 Point
aLeft( aRect
.Left(), ( aRect
.Top() + aRect
.Bottom() ) >> 1 );
317 Point
aRight( aLeft
.X() + 1000, aLeft
.Y() );
318 xRenderedShape
->NbcMirror( aLeft
, aRight
);
322 Point
aTop( ( aRect
.Left() + aRect
.Right() ) >> 1, aRect
.Top() );
323 Point
aBottom( aTop
.X(), aTop
.Y() + 1000 );
324 xRenderedShape
->NbcMirror( aTop
, aBottom
);
327 xRenderedShape
->NbcSetStyleSheet(pSdrObjCustomShape
->GetStyleSheet(), true);
328 xRenderedShape
->RecalcSnapRect();
331 if ( mbForceGroupWithText
)
333 xRenderedShape
= ImplForceGroupWithText(
335 xRenderedShape
.get());
338 Reference
< drawing::XShape
> xShape
;
342 aCustomShape2d
.ApplyGluePoints(xRenderedShape
.get());
343 xShape
= SvxDrawPage::CreateShapeByTypeAndInventor( xRenderedShape
->GetObjIdentifier(),
344 xRenderedShape
->GetObjInventor(), xRenderedShape
.get() );
350 awt::Rectangle SAL_CALL
EnhancedCustomShapeEngine::getTextBounds()
352 awt::Rectangle aTextRect
;
353 if (SdrObjCustomShape
* pSdrObjCustomShape
= dynamic_cast< SdrObjCustomShape
* >(SdrObject::getSdrObjectFromXShape(mxShape
)))
355 uno::Reference
< document::XActionLockable
> xLockable( mxShape
, uno::UNO_QUERY
);
357 if(xLockable
.is() && !xLockable
->isActionLocked())
359 EnhancedCustomShape2d
aCustomShape2d(*pSdrObjCustomShape
);
360 tools::Rectangle
aRect( aCustomShape2d
.GetTextRect() );
361 aTextRect
.X
= aRect
.Left();
362 aTextRect
.Y
= aRect
.Top();
363 aTextRect
.Width
= aRect
.GetWidth();
364 aTextRect
.Height
= aRect
.GetHeight();
371 drawing::PolyPolygonBezierCoords SAL_CALL
EnhancedCustomShapeEngine::getLineGeometry()
373 drawing::PolyPolygonBezierCoords aPolyPolygonBezierCoords
;
374 SdrObjCustomShape
* pSdrObjCustomShape
= dynamic_cast< SdrObjCustomShape
* >(SdrObject::getSdrObjectFromXShape(mxShape
));
376 if(pSdrObjCustomShape
)
378 EnhancedCustomShape2d
aCustomShape2d(*pSdrObjCustomShape
);
379 rtl::Reference
<SdrObject
> pObj
= aCustomShape2d
.CreateLineGeometry();
383 tools::Rectangle
aRect(pSdrObjCustomShape
->GetSnapRect());
384 bool bFlipV
= aCustomShape2d
.IsFlipVert();
385 bool bFlipH
= aCustomShape2d
.IsFlipHorz();
386 const GeoStat
& rGeoStat(pSdrObjCustomShape
->GetGeoStat());
388 if ( rGeoStat
.m_nShearAngle
)
390 Degree100 nShearAngle
= rGeoStat
.m_nShearAngle
;
391 double nTan
= rGeoStat
.mfTanShearAngle
;
392 if (bFlipV
!= bFlipH
)
394 nShearAngle
= -nShearAngle
;
397 pObj
->Shear( aRect
.Center(), nShearAngle
, nTan
, false);
399 Degree100 nRotateAngle
= aCustomShape2d
.GetRotateAngle();
401 pObj
->NbcRotate( aRect
.Center(), nRotateAngle
);
404 Point
aTop( ( aRect
.Left() + aRect
.Right() ) >> 1, aRect
.Top() );
405 Point
aBottom( aTop
.X(), aTop
.Y() + 1000 );
406 pObj
->NbcMirror( aTop
, aBottom
);
410 Point
aLeft( aRect
.Left(), ( aRect
.Top() + aRect
.Bottom() ) >> 1 );
411 Point
aRight( aLeft
.X() + 1000, aLeft
.Y() );
412 pObj
->NbcMirror( aLeft
, aRight
);
415 basegfx::B2DPolyPolygon aPolyPolygon
;
416 SdrObjListIter
aIter( *pObj
, SdrIterMode::DeepWithGroups
);
418 while ( aIter
.IsMore() )
420 basegfx::B2DPolyPolygon aPP
;
421 const SdrObject
* pNext
= aIter
.Next();
423 if ( auto pPathObj
= dynamic_cast<const SdrPathObj
*>(pNext
) )
425 aPP
= pPathObj
->GetPathPoly();
429 rtl::Reference
<SdrObject
> pNewObj
= pNext
->ConvertToPolyObj( false, false );
430 SdrPathObj
* pPath
= dynamic_cast<SdrPathObj
*>( pNewObj
.get() );
432 aPP
= pPath
->GetPathPoly();
436 aPolyPolygon
.append(aPP
);
439 basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( aPolyPolygon
,
440 aPolyPolygonBezierCoords
);
444 return aPolyPolygonBezierCoords
;
447 Sequence
< Reference
< drawing::XCustomShapeHandle
> > SAL_CALL
EnhancedCustomShapeEngine::getInteraction()
449 sal_uInt32 i
, nHdlCount
= 0;
450 SdrObjCustomShape
* pSdrObjCustomShape
= dynamic_cast< SdrObjCustomShape
* >(SdrObject::getSdrObjectFromXShape(mxShape
));
452 if(pSdrObjCustomShape
)
454 EnhancedCustomShape2d
aCustomShape2d(*pSdrObjCustomShape
);
455 nHdlCount
= aCustomShape2d
.GetHdlCount();
458 Sequence
< Reference
< drawing::XCustomShapeHandle
> > aSeq( nHdlCount
);
459 auto aSeqRange
= asNonConstRange(aSeq
);
461 for ( i
= 0; i
< nHdlCount
; i
++ )
462 aSeqRange
[ i
] = new EnhancedCustomShapeHandle( mxShape
, i
);
468 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
469 com_sun_star_drawing_EnhancedCustomShapeEngine_get_implementation(
470 css::uno::XComponentContext
*,
471 css::uno::Sequence
<css::uno::Any
> const &)
473 return cppu::acquire(new EnhancedCustomShapeEngine
);
476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */