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/RuntimeException.hpp>
22 #include <com/sun/star/uno/XComponentContext.hpp>
23 #include <com/sun/star/awt/Rectangle.hpp>
24 #include <com/sun/star/beans/PropertyValue.hpp>
25 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
26 #include <com/sun/star/lang/XInitialization.hpp>
27 #include <com/sun/star/lang/XServiceInfo.hpp>
28 #include <com/sun/star/drawing/XCustomShapeEngine.hpp>
29 #include <rtl/ref.hxx>
30 #include <svx/EnhancedCustomShape2d.hxx>
31 #include "EnhancedCustomShape3d.hxx"
32 #include "EnhancedCustomShapeFontWork.hxx"
33 #include "EnhancedCustomShapeHandle.hxx"
34 #include <svx/EnhancedCustomShapeGeometry.hxx>
35 #include <svx/unoshape.hxx>
36 #include <svx/unopage.hxx>
37 #include <svx/unoapi.hxx>
38 #include <svx/svdobj.hxx>
39 #include <svx/svdoashp.hxx>
40 #include <svx/svdogrp.hxx>
41 #include <svx/svdorect.hxx>
42 #include <editeng/outlobj.hxx>
43 #include <editeng/outliner.hxx>
44 #include <svx/svdoutl.hxx>
45 #include <svl/itemset.hxx>
46 #include <svx/svdopath.hxx>
47 #include <svx/svdpage.hxx>
48 #include <svx/svdmodel.hxx>
49 #include <svx/svditer.hxx>
50 #include <svx/xfillit0.hxx>
51 #include <svx/xlineit0.hxx>
52 #include <uno/mapping.hxx>
53 #include <basegfx/polygon/b2dpolypolygontools.hxx>
54 #include <com/sun/star/document/XActionLockable.hpp>
55 #include <cppuhelper/implbase.hxx>
56 #include <cppuhelper/supportsservice.hxx>
59 using namespace css::uno
;
62 class SdrObjCustomShape
;
66 class EnhancedCustomShapeEngine
: public cppu::WeakImplHelper
68 css::lang::XInitialization
,
69 css::lang::XServiceInfo
,
70 css::drawing::XCustomShapeEngine
73 css::uno::Reference
< css::drawing::XShape
> mxShape
;
74 bool mbForceGroupWithText
;
76 std::unique_ptr
<SdrObject
, SdrObjectFreeOp
> ImplForceGroupWithText(
77 const SdrObjCustomShape
& rSdrObjCustomShape
,
78 std::unique_ptr
<SdrObject
, SdrObjectFreeOp
> pRenderedShape
);
81 EnhancedCustomShapeEngine();
84 virtual void SAL_CALL
acquire() throw() override
;
85 virtual void SAL_CALL
release() throw() override
;
88 virtual void SAL_CALL
initialize( const css::uno::Sequence
< css::uno::Any
>& aArguments
) override
;
91 virtual OUString SAL_CALL
getImplementationName() override
;
92 virtual sal_Bool SAL_CALL
supportsService( const OUString
& rServiceName
) override
;
93 virtual css::uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
96 virtual css::uno::Reference
< css::drawing::XShape
> SAL_CALL
render() override
;
97 virtual css::awt::Rectangle SAL_CALL
getTextBounds() override
;
98 virtual css::drawing::PolyPolygonBezierCoords SAL_CALL
getLineGeometry() override
;
99 virtual css::uno::Sequence
< css::uno::Reference
< css::drawing::XCustomShapeHandle
> > SAL_CALL
getInteraction() override
;
102 EnhancedCustomShapeEngine::EnhancedCustomShapeEngine() :
103 mbForceGroupWithText ( false )
108 void SAL_CALL
EnhancedCustomShapeEngine::acquire() throw()
110 OWeakObject::acquire();
112 void SAL_CALL
EnhancedCustomShapeEngine::release() throw()
114 OWeakObject::release();
118 void SAL_CALL
EnhancedCustomShapeEngine::initialize( const Sequence
< Any
>& aArguments
)
120 Sequence
< beans::PropertyValue
> aParameter
;
121 for ( const auto& rArgument
: aArguments
)
123 if ( rArgument
>>= aParameter
)
126 for ( const beans::PropertyValue
& rProp
: std::as_const(aParameter
) )
128 if ( rProp
.Name
== "CustomShape" )
129 rProp
.Value
>>= mxShape
;
130 else if ( rProp
.Name
== "ForceGroupWithText" )
131 rProp
.Value
>>= mbForceGroupWithText
;
136 OUString SAL_CALL
EnhancedCustomShapeEngine::getImplementationName()
138 return "com.sun.star.drawing.EnhancedCustomShapeEngine";
140 sal_Bool SAL_CALL
EnhancedCustomShapeEngine::supportsService( const OUString
& rServiceName
)
142 return cppu::supportsService(this, rServiceName
);
144 Sequence
< OUString
> SAL_CALL
EnhancedCustomShapeEngine::getSupportedServiceNames()
146 Sequence
<OUString
> aRet
{ "com.sun.star.drawing.CustomShapeEngine" };
150 // XCustomShapeEngine
151 std::unique_ptr
<SdrObject
, SdrObjectFreeOp
> EnhancedCustomShapeEngine::ImplForceGroupWithText(
152 const SdrObjCustomShape
& rSdrObjCustomShape
,
153 std::unique_ptr
<SdrObject
, SdrObjectFreeOp
> pRenderedShape
)
155 const bool bHasText(rSdrObjCustomShape
.HasText());
157 if ( pRenderedShape
|| bHasText
)
160 const SdrObject
* pShadowGeometry(rSdrObjCustomShape
.GetSdrObjectShadowFromCustomShape());
162 if ( pShadowGeometry
)
164 if ( pRenderedShape
)
166 if ( dynamic_cast<const SdrObjGroup
*>( pRenderedShape
.get() ) == nullptr )
168 auto pTmp
= std::move(pRenderedShape
);
169 pRenderedShape
.reset(new SdrObjGroup(rSdrObjCustomShape
.getSdrModelFromSdrObject()));
170 static_cast<SdrObjGroup
*>(pRenderedShape
.get())->GetSubList()->NbcInsertObject( pTmp
.release() );
173 static_cast<SdrObjGroup
*>(pRenderedShape
.get())->GetSubList()->NbcInsertObject(
174 pShadowGeometry
->CloneSdrObject(pShadowGeometry
->getSdrModelFromSdrObject()),
179 pRenderedShape
.reset( pShadowGeometry
->CloneSdrObject(pShadowGeometry
->getSdrModelFromSdrObject()) );
186 // #i37011# also create a text object and add at rPos + 1
187 std::unique_ptr
<SdrObject
, SdrObjectFreeOp
> pTextObj( SdrObjFactory::MakeNewObject(
188 rSdrObjCustomShape
.getSdrModelFromSdrObject(),
189 rSdrObjCustomShape
.GetObjInventor(),
193 OutlinerParaObject
* pParaObj(rSdrObjCustomShape
.GetOutlinerParaObject());
196 pTextObj
->NbcSetOutlinerParaObject( std::make_unique
<OutlinerParaObject
>(*pParaObj
) );
198 // copy all attributes
199 SfxItemSet
aTargetItemSet(rSdrObjCustomShape
.GetMergedItemSet());
201 // clear fill and line style
202 aTargetItemSet
.Put(XLineStyleItem(drawing::LineStyle_NONE
));
203 aTargetItemSet
.Put(XFillStyleItem(drawing::FillStyle_NONE
));
205 // get the text bounds and set at text object
206 tools::Rectangle
aTextBounds(rSdrObjCustomShape
.GetSnapRect());
207 const bool bIsSdrObjCustomShape(nullptr != dynamic_cast< SdrObjCustomShape
* >(GetSdrObjectFromXShape(mxShape
)));
209 if(bIsSdrObjCustomShape
)
211 SdrObjCustomShape
& rSdrObjCustomShape2(
212 static_cast< SdrObjCustomShape
& >(
213 *GetSdrObjectFromXShape(mxShape
)));
214 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape2
);
215 aTextBounds
= aCustomShape2d
.GetTextRect();
218 pTextObj
->SetSnapRect( aTextBounds
);
220 // if rotated, copy GeoStat, too.
221 const GeoStat
& rSourceGeo(rSdrObjCustomShape
.GetGeoStat());
222 if ( rSourceGeo
.nRotationAngle
)
225 rSdrObjCustomShape
.GetSnapRect().Center(),
226 rSourceGeo
.nRotationAngle
,
231 // set modified ItemSet at text object
232 pTextObj
->SetMergedItemSet(aTargetItemSet
);
234 if ( pRenderedShape
)
236 if ( dynamic_cast<const SdrObjGroup
*>( pRenderedShape
.get() ) == nullptr )
238 auto pTmp
= std::move(pRenderedShape
);
239 pRenderedShape
.reset(new SdrObjGroup(rSdrObjCustomShape
.getSdrModelFromSdrObject()));
240 static_cast<SdrObjGroup
*>(pRenderedShape
.get())->GetSubList()->NbcInsertObject( pTmp
.release() );
242 static_cast<SdrObjGroup
*>(pRenderedShape
.get())->GetSubList()->NbcInsertObject( pTextObj
.release() );
245 pRenderedShape
= std::move(pTextObj
);
249 if ( pRenderedShape
)
251 if ( dynamic_cast<const SdrObjGroup
*>( pRenderedShape
.get() ) == nullptr )
253 auto pTmp
= std::move(pRenderedShape
);
254 pRenderedShape
.reset(new SdrObjGroup(rSdrObjCustomShape
.getSdrModelFromSdrObject()));
255 static_cast<SdrObjGroup
*>(pRenderedShape
.get())->GetSubList()->NbcInsertObject( pTmp
.release() );
260 return pRenderedShape
;
263 void SetTemporary( uno::Reference
< drawing::XShape
> const & xShape
)
267 SvxShape
* pShape
= comphelper::getUnoTunnelImplementation
<SvxShape
>( xShape
);
269 pShape
->TakeSdrObjectOwnership();
273 Reference
< drawing::XShape
> SAL_CALL
EnhancedCustomShapeEngine::render()
275 const bool bIsSdrObjCustomShape(nullptr != dynamic_cast< SdrObjCustomShape
* >(GetSdrObjectFromXShape(mxShape
)));
277 if(!bIsSdrObjCustomShape
)
279 return Reference
< drawing::XShape
>();
282 SdrObjCustomShape
& rSdrObjCustomShape(
283 static_cast< SdrObjCustomShape
& >(
284 *GetSdrObjectFromXShape(mxShape
)));
286 // retrieving the TextPath property to check if feature is enabled
287 const SdrCustomShapeGeometryItem
& rGeometryItem(rSdrObjCustomShape
.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
));
288 bool bTextPathOn
= false;
289 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName( "TextPath", "TextPath" );
291 *pAny
>>= bTextPathOn
;
293 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
294 sal_Int32 nRotateAngle
= aCustomShape2d
.GetRotateAngle();
296 bool bFlipV
= aCustomShape2d
.IsFlipVert();
297 bool bFlipH
= aCustomShape2d
.IsFlipHorz();
298 bool bLineGeometryNeededOnly
= bTextPathOn
;
300 std::unique_ptr
<SdrObject
, SdrObjectFreeOp
> xRenderedShape(aCustomShape2d
.CreateObject(bLineGeometryNeededOnly
));
305 std::unique_ptr
<SdrObject
, SdrObjectFreeOp
> xRenderedFontWork(
306 EnhancedCustomShapeFontWork::CreateFontWork(
307 xRenderedShape
.get(),
308 rSdrObjCustomShape
));
310 if (xRenderedFontWork
)
312 xRenderedShape
= std::move(xRenderedFontWork
);
315 std::unique_ptr
<SdrObject
, SdrObjectFreeOp
> xRenderedShape3d(EnhancedCustomShape3d::Create3DObject(xRenderedShape
.get(), rSdrObjCustomShape
));
316 if (xRenderedShape3d
)
318 bFlipV
= bFlipH
= false;
320 xRenderedShape
= std::move(xRenderedShape3d
);
323 tools::Rectangle
aRect(rSdrObjCustomShape
.GetSnapRect());
324 const GeoStat
& rGeoStat(rSdrObjCustomShape
.GetGeoStat());
326 if ( rGeoStat
.nShearAngle
)
328 long nShearAngle
= rGeoStat
.nShearAngle
;
329 double nTan
= rGeoStat
.nTan
;
330 if (bFlipV
!= bFlipH
)
332 nShearAngle
= -nShearAngle
;
336 xRenderedShape
->Shear(rSdrObjCustomShape
.GetSnapRect().Center(), nShearAngle
, nTan
, false);
340 double a
= nRotateAngle
* F_PI18000
;
342 xRenderedShape
->NbcRotate(rSdrObjCustomShape
.GetSnapRect().Center(), nRotateAngle
, sin( a
), cos( a
));
346 Point
aLeft( aRect
.Left(), ( aRect
.Top() + aRect
.Bottom() ) >> 1 );
347 Point
aRight( aLeft
.X() + 1000, aLeft
.Y() );
348 xRenderedShape
->NbcMirror( aLeft
, aRight
);
352 Point
aTop( ( aRect
.Left() + aRect
.Right() ) >> 1, aRect
.Top() );
353 Point
aBottom( aTop
.X(), aTop
.Y() + 1000 );
354 xRenderedShape
->NbcMirror( aTop
, aBottom
);
357 xRenderedShape
->NbcSetStyleSheet(rSdrObjCustomShape
.GetStyleSheet(), true);
358 xRenderedShape
->RecalcSnapRect();
361 if ( mbForceGroupWithText
)
363 xRenderedShape
= ImplForceGroupWithText(
365 std::move(xRenderedShape
));
368 Reference
< drawing::XShape
> xShape
;
372 aCustomShape2d
.ApplyGluePoints(xRenderedShape
.get());
373 SdrObject
* pRenderedShape
= xRenderedShape
.release();
374 xShape
= SvxDrawPage::CreateShapeByTypeAndInventor( pRenderedShape
->GetObjIdentifier(),
375 pRenderedShape
->GetObjInventor(), pRenderedShape
);
378 SetTemporary( xShape
);
383 awt::Rectangle SAL_CALL
EnhancedCustomShapeEngine::getTextBounds()
385 awt::Rectangle aTextRect
;
386 const bool bIsSdrObjCustomShape(nullptr != dynamic_cast< SdrObjCustomShape
* >(GetSdrObjectFromXShape(mxShape
)));
388 if(bIsSdrObjCustomShape
)
390 SdrObjCustomShape
& rSdrObjCustomShape(static_cast< SdrObjCustomShape
& >(*GetSdrObjectFromXShape(mxShape
)));
391 uno::Reference
< document::XActionLockable
> xLockable( mxShape
, uno::UNO_QUERY
);
393 if(xLockable
.is() && !xLockable
->isActionLocked())
395 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
396 tools::Rectangle
aRect( aCustomShape2d
.GetTextRect() );
397 aTextRect
.X
= aRect
.Left();
398 aTextRect
.Y
= aRect
.Top();
399 aTextRect
.Width
= aRect
.GetWidth();
400 aTextRect
.Height
= aRect
.GetHeight();
407 drawing::PolyPolygonBezierCoords SAL_CALL
EnhancedCustomShapeEngine::getLineGeometry()
409 drawing::PolyPolygonBezierCoords aPolyPolygonBezierCoords
;
410 const bool bIsSdrObjCustomShape(nullptr != dynamic_cast< SdrObjCustomShape
* >(GetSdrObjectFromXShape(mxShape
)));
412 if(bIsSdrObjCustomShape
)
414 SdrObjCustomShape
& rSdrObjCustomShape(
415 static_cast< SdrObjCustomShape
& >(
416 *GetSdrObjectFromXShape(mxShape
)));
417 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
418 SdrObject
* pObj
= aCustomShape2d
.CreateLineGeometry();
422 tools::Rectangle
aRect(rSdrObjCustomShape
.GetSnapRect());
423 bool bFlipV
= aCustomShape2d
.IsFlipVert();
424 bool bFlipH
= aCustomShape2d
.IsFlipHorz();
425 const GeoStat
& rGeoStat(rSdrObjCustomShape
.GetGeoStat());
427 if ( rGeoStat
.nShearAngle
)
429 long nShearAngle
= rGeoStat
.nShearAngle
;
430 double nTan
= rGeoStat
.nTan
;
431 if (bFlipV
!= bFlipH
)
433 nShearAngle
= -nShearAngle
;
436 pObj
->Shear( aRect
.Center(), nShearAngle
, nTan
, false);
438 sal_Int32 nRotateAngle
= aCustomShape2d
.GetRotateAngle();
441 double a
= nRotateAngle
* F_PI18000
;
442 pObj
->NbcRotate( aRect
.Center(), nRotateAngle
, sin( a
), cos( a
) );
446 Point
aTop( ( aRect
.Left() + aRect
.Right() ) >> 1, aRect
.Top() );
447 Point
aBottom( aTop
.X(), aTop
.Y() + 1000 );
448 pObj
->NbcMirror( aTop
, aBottom
);
452 Point
aLeft( aRect
.Left(), ( aRect
.Top() + aRect
.Bottom() ) >> 1 );
453 Point
aRight( aLeft
.X() + 1000, aLeft
.Y() );
454 pObj
->NbcMirror( aLeft
, aRight
);
457 basegfx::B2DPolyPolygon aPolyPolygon
;
458 SdrObjListIter
aIter( *pObj
, SdrIterMode::DeepWithGroups
);
460 while ( aIter
.IsMore() )
462 basegfx::B2DPolyPolygon aPP
;
463 const SdrObject
* pNext
= aIter
.Next();
465 if ( auto pPathObj
= dynamic_cast<const SdrPathObj
*>(pNext
) )
467 aPP
= pPathObj
->GetPathPoly();
471 SdrObjectUniquePtr pNewObj
= pNext
->ConvertToPolyObj( false, false );
472 SdrPathObj
* pPath
= dynamic_cast<SdrPathObj
*>( pNewObj
.get() );
474 aPP
= pPath
->GetPathPoly();
478 aPolyPolygon
.append(aPP
);
480 SdrObject::Free( pObj
);
481 basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( aPolyPolygon
,
482 aPolyPolygonBezierCoords
);
486 return aPolyPolygonBezierCoords
;
489 Sequence
< Reference
< drawing::XCustomShapeHandle
> > SAL_CALL
EnhancedCustomShapeEngine::getInteraction()
491 sal_uInt32 i
, nHdlCount
= 0;
492 const bool bIsSdrObjCustomShape(nullptr != dynamic_cast< SdrObjCustomShape
* >(GetSdrObjectFromXShape(mxShape
)));
494 if(bIsSdrObjCustomShape
)
496 SdrObjCustomShape
& rSdrObjCustomShape(
497 static_cast< SdrObjCustomShape
& >(
498 *GetSdrObjectFromXShape(mxShape
)));
499 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
500 nHdlCount
= aCustomShape2d
.GetHdlCount();
503 Sequence
< Reference
< drawing::XCustomShapeHandle
> > aSeq( nHdlCount
);
505 for ( i
= 0; i
< nHdlCount
; i
++ )
506 aSeq
[ i
] = new EnhancedCustomShapeHandle( mxShape
, i
);
512 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
513 com_sun_star_drawing_EnhancedCustomShapeEngine_get_implementation(
514 css::uno::XComponentContext
*,
515 css::uno::Sequence
<css::uno::Any
> const &)
517 return cppu::acquire(new EnhancedCustomShapeEngine
);
520 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */