LibreOffice Module svx (master) 1
EnhancedCustomShapeEngine.cxx
Go to the documentation of this file.
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 <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>
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>
45#include <com/sun/star/document/XActionLockable.hpp>
48
49using namespace css;
50using namespace css::uno;
51
52class SdrObject;
54
55namespace {
56
57class EnhancedCustomShapeEngine : public cppu::WeakImplHelper
58<
59 css::lang::XInitialization,
60 css::lang::XServiceInfo,
61 css::drawing::XCustomShapeEngine
62>
63{
64 css::uno::Reference< css::drawing::XShape > mxShape;
65 bool mbForceGroupWithText;
66
67 std::unique_ptr<SdrObject, SdrObjectFreeOp> ImplForceGroupWithText(
68 const SdrObjCustomShape& rSdrObjCustomShape,
69 std::unique_ptr<SdrObject, SdrObjectFreeOp> pRenderedShape);
70
71public:
72 EnhancedCustomShapeEngine();
73
74 // XInterface
75 virtual void SAL_CALL acquire() noexcept override;
76 virtual void SAL_CALL release() noexcept override;
77
78 // XInitialization
79 virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
80
81 // XServiceInfo
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;
85
86 // XCustomShapeEngine
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;
91};
92
93EnhancedCustomShapeEngine::EnhancedCustomShapeEngine() :
94 mbForceGroupWithText ( false )
95{
96}
97
98// XInterface
99void SAL_CALL EnhancedCustomShapeEngine::acquire() noexcept
100{
101 OWeakObject::acquire();
102}
103void SAL_CALL EnhancedCustomShapeEngine::release() noexcept
104{
105 OWeakObject::release();
106}
107
108// XInitialization
109void SAL_CALL EnhancedCustomShapeEngine::initialize( const Sequence< Any >& aArguments )
110{
111 Sequence< beans::PropertyValue > aParameter;
112 for ( const auto& rArgument : aArguments )
113 {
114 if ( rArgument >>= aParameter )
115 break;
116 }
117 for ( const beans::PropertyValue& rProp : std::as_const(aParameter) )
118 {
119 if ( rProp.Name == "CustomShape" )
120 rProp.Value >>= mxShape;
121 else if ( rProp.Name == "ForceGroupWithText" )
122 rProp.Value >>= mbForceGroupWithText;
123 }
124}
125
126// XServiceInfo
127OUString SAL_CALL EnhancedCustomShapeEngine::getImplementationName()
128{
129 return "com.sun.star.drawing.EnhancedCustomShapeEngine";
130}
131sal_Bool SAL_CALL EnhancedCustomShapeEngine::supportsService( const OUString& rServiceName )
132{
133 return cppu::supportsService(this, rServiceName);
134}
135Sequence< OUString > SAL_CALL EnhancedCustomShapeEngine::getSupportedServiceNames()
136{
137 return { "com.sun.star.drawing.CustomShapeEngine" };
138}
139
140// XCustomShapeEngine
141std::unique_ptr<SdrObject, SdrObjectFreeOp> EnhancedCustomShapeEngine::ImplForceGroupWithText(
142 const SdrObjCustomShape& rSdrObjCustomShape,
143 std::unique_ptr<SdrObject, SdrObjectFreeOp> pRenderedShape)
144{
145 const bool bHasText(rSdrObjCustomShape.HasText());
146
147 if ( pRenderedShape || bHasText )
148 {
149 // applying shadow
150 const SdrObject* pShadowGeometry(rSdrObjCustomShape.GetSdrObjectShadowFromCustomShape());
151
152 if ( pShadowGeometry )
153 {
154 if ( pRenderedShape )
155 {
156 if ( dynamic_cast<const SdrObjGroup*>( pRenderedShape.get() ) == nullptr )
157 {
158 auto pTmp = std::move(pRenderedShape);
159 pRenderedShape.reset(new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject()));
160 static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.release() );
161 }
162
163 static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject(
164 pShadowGeometry->CloneSdrObject(pShadowGeometry->getSdrModelFromSdrObject()),
165 0);
166 }
167 else
168 {
169 pRenderedShape.reset( pShadowGeometry->CloneSdrObject(pShadowGeometry->getSdrModelFromSdrObject()) );
170 }
171 }
172
173 // apply text
174 if ( bHasText )
175 {
176 // #i37011# also create a text object and add at rPos + 1
177 std::unique_ptr<SdrObject, SdrObjectFreeOp> pTextObj( SdrObjFactory::MakeNewObject(
178 rSdrObjCustomShape.getSdrModelFromSdrObject(),
179 rSdrObjCustomShape.GetObjInventor(),
181
182 // Copy text content
183 OutlinerParaObject* pParaObj(rSdrObjCustomShape.GetOutlinerParaObject());
184
185 if( pParaObj )
186 pTextObj->NbcSetOutlinerParaObject( *pParaObj );
187
188 // copy all attributes
189 SfxItemSet aTargetItemSet(rSdrObjCustomShape.GetMergedItemSet());
190
191 // clear fill and line style
192 aTargetItemSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
193 aTargetItemSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
194
195 // get the text bounds and set at text object
196 tools::Rectangle aTextBounds(rSdrObjCustomShape.GetSnapRect());
197 auto pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
198
199 if(pSdrObjCustomShape)
200 {
201 EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
202 aTextBounds = aCustomShape2d.GetTextRect();
203 }
204
205 pTextObj->SetSnapRect( aTextBounds );
206
207 // if rotated, copy GeoStat, too.
208 const GeoStat& rSourceGeo(rSdrObjCustomShape.GetGeoStat());
209 if ( rSourceGeo.nRotationAngle )
210 {
211 pTextObj->NbcRotate(
212 rSdrObjCustomShape.GetSnapRect().Center(),
213 rSourceGeo.nRotationAngle,
214 rSourceGeo.mfSinRotationAngle,
215 rSourceGeo.mfCosRotationAngle);
216 }
217
218 // set modified ItemSet at text object
219 pTextObj->SetMergedItemSet(aTargetItemSet);
220
221 if ( pRenderedShape )
222 {
223 if ( dynamic_cast<const SdrObjGroup*>( pRenderedShape.get() ) == nullptr )
224 {
225 auto pTmp = std::move(pRenderedShape);
226 pRenderedShape.reset(new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject()));
227 static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.release() );
228 }
229 static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTextObj.release() );
230 }
231 else
232 pRenderedShape = std::move(pTextObj);
233 }
234
235 // force group
236 if ( pRenderedShape )
237 {
238 if ( dynamic_cast<const SdrObjGroup*>( pRenderedShape.get() ) == nullptr )
239 {
240 auto pTmp = std::move(pRenderedShape);
241 pRenderedShape.reset(new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject()));
242 static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.release() );
243 }
244 }
245 }
246
247 return pRenderedShape;
248}
249
250void SetTemporary( uno::Reference< drawing::XShape > const & xShape )
251{
252 if ( xShape.is() )
253 {
254 SvxShape* pShape = comphelper::getFromUnoTunnel<SvxShape>( xShape );
255 if ( pShape )
256 pShape->TakeSdrObjectOwnership();
257 }
258}
259
260Reference< drawing::XShape > SAL_CALL EnhancedCustomShapeEngine::render()
261{
262 SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
263
264 if(!pSdrObjCustomShape)
265 {
266 return Reference< drawing::XShape >();
267 }
268
269 // retrieving the TextPath property to check if feature is enabled
270 const SdrCustomShapeGeometryItem& rGeometryItem(pSdrObjCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
271 bool bTextPathOn = false;
272 const uno::Any* pAny = rGeometryItem.GetPropertyValueByName( "TextPath", "TextPath" );
273 if ( pAny )
274 *pAny >>= bTextPathOn;
275
276 EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
277 Degree100 nRotateAngle = aCustomShape2d.GetRotateAngle();
278
279 bool bFlipV = aCustomShape2d.IsFlipVert();
280 bool bFlipH = aCustomShape2d.IsFlipHorz();
281 bool bLineGeometryNeededOnly = bTextPathOn;
282
283 std::unique_ptr<SdrObject, SdrObjectFreeOp> xRenderedShape(aCustomShape2d.CreateObject(bLineGeometryNeededOnly));
284 if (xRenderedShape)
285 {
286 if ( bTextPathOn )
287 {
288 std::unique_ptr<SdrObject, SdrObjectFreeOp> xRenderedFontWork(
290 xRenderedShape.get(),
291 *pSdrObjCustomShape));
292
293 if (xRenderedFontWork)
294 {
295 xRenderedShape = std::move(xRenderedFontWork);
296 }
297 }
298 std::unique_ptr<SdrObject, SdrObjectFreeOp> xRenderedShape3d(EnhancedCustomShape3d::Create3DObject(xRenderedShape.get(), *pSdrObjCustomShape));
299 if (xRenderedShape3d)
300 {
301 bFlipV = bFlipH = false;
302 nRotateAngle = 0_deg100;
303 xRenderedShape = std::move(xRenderedShape3d);
304 }
305
306 tools::Rectangle aRect(pSdrObjCustomShape->GetSnapRect());
307 const GeoStat& rGeoStat(pSdrObjCustomShape->GetGeoStat());
308
309 if ( rGeoStat.nShearAngle )
310 {
311 Degree100 nShearAngle = rGeoStat.nShearAngle;
312 double nTan = rGeoStat.mfTanShearAngle;
313 if (bFlipV != bFlipH)
314 {
315 nShearAngle = -nShearAngle;
316 nTan = -nTan;
317 }
318
319 xRenderedShape->Shear(pSdrObjCustomShape->GetSnapRect().Center(), nShearAngle, nTan, false);
320 }
321 if(nRotateAngle )
322 xRenderedShape->NbcRotate(pSdrObjCustomShape->GetSnapRect().Center(), nRotateAngle);
323 if ( bFlipV )
324 {
325 Point aLeft( aRect.Left(), ( aRect.Top() + aRect.Bottom() ) >> 1 );
326 Point aRight( aLeft.X() + 1000, aLeft.Y() );
327 xRenderedShape->NbcMirror( aLeft, aRight );
328 }
329 if ( bFlipH )
330 {
331 Point aTop( ( aRect.Left() + aRect.Right() ) >> 1, aRect.Top() );
332 Point aBottom( aTop.X(), aTop.Y() + 1000 );
333 xRenderedShape->NbcMirror( aTop, aBottom );
334 }
335
336 xRenderedShape->NbcSetStyleSheet(pSdrObjCustomShape->GetStyleSheet(), true);
337 xRenderedShape->RecalcSnapRect();
338 }
339
340 if ( mbForceGroupWithText )
341 {
342 xRenderedShape = ImplForceGroupWithText(
343 *pSdrObjCustomShape,
344 std::move(xRenderedShape));
345 }
346
347 Reference< drawing::XShape > xShape;
348
349 if (xRenderedShape)
350 {
351 aCustomShape2d.ApplyGluePoints(xRenderedShape.get());
352 SdrObject* pRenderedShape = xRenderedShape.release();
354 pRenderedShape->GetObjInventor(), pRenderedShape );
355 }
356
357 SetTemporary( xShape );
358
359 return xShape;
360}
361
362awt::Rectangle SAL_CALL EnhancedCustomShapeEngine::getTextBounds()
363{
364 awt::Rectangle aTextRect;
365 if (SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape)))
366 {
367 uno::Reference< document::XActionLockable > xLockable( mxShape, uno::UNO_QUERY );
368
369 if(xLockable.is() && !xLockable->isActionLocked())
370 {
371 EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
372 tools::Rectangle aRect( aCustomShape2d.GetTextRect() );
373 aTextRect.X = aRect.Left();
374 aTextRect.Y = aRect.Top();
375 aTextRect.Width = aRect.GetWidth();
376 aTextRect.Height = aRect.GetHeight();
377 }
378 }
379
380 return aTextRect;
381}
382
383drawing::PolyPolygonBezierCoords SAL_CALL EnhancedCustomShapeEngine::getLineGeometry()
384{
385 drawing::PolyPolygonBezierCoords aPolyPolygonBezierCoords;
386 SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
387
388 if(pSdrObjCustomShape)
389 {
390 EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
391 SdrObjectUniquePtr pObj = aCustomShape2d.CreateLineGeometry();
392
393 if ( pObj )
394 {
395 tools::Rectangle aRect(pSdrObjCustomShape->GetSnapRect());
396 bool bFlipV = aCustomShape2d.IsFlipVert();
397 bool bFlipH = aCustomShape2d.IsFlipHorz();
398 const GeoStat& rGeoStat(pSdrObjCustomShape->GetGeoStat());
399
400 if ( rGeoStat.nShearAngle )
401 {
402 Degree100 nShearAngle = rGeoStat.nShearAngle;
403 double nTan = rGeoStat.mfTanShearAngle;
404 if (bFlipV != bFlipH)
405 {
406 nShearAngle = -nShearAngle;
407 nTan = -nTan;
408 }
409 pObj->Shear( aRect.Center(), nShearAngle, nTan, false);
410 }
411 Degree100 nRotateAngle = aCustomShape2d.GetRotateAngle();
412 if( nRotateAngle )
413 pObj->NbcRotate( aRect.Center(), nRotateAngle );
414 if ( bFlipH )
415 {
416 Point aTop( ( aRect.Left() + aRect.Right() ) >> 1, aRect.Top() );
417 Point aBottom( aTop.X(), aTop.Y() + 1000 );
418 pObj->NbcMirror( aTop, aBottom );
419 }
420 if ( bFlipV )
421 {
422 Point aLeft( aRect.Left(), ( aRect.Top() + aRect.Bottom() ) >> 1 );
423 Point aRight( aLeft.X() + 1000, aLeft.Y() );
424 pObj->NbcMirror( aLeft, aRight );
425 }
426
427 basegfx::B2DPolyPolygon aPolyPolygon;
429
430 while ( aIter.IsMore() )
431 {
433 const SdrObject* pNext = aIter.Next();
434
435 if ( auto pPathObj = dynamic_cast<const SdrPathObj*>(pNext) )
436 {
437 aPP = pPathObj->GetPathPoly();
438 }
439 else
440 {
441 SdrObjectUniquePtr pNewObj = pNext->ConvertToPolyObj( false, false );
442 SdrPathObj* pPath = dynamic_cast<SdrPathObj*>( pNewObj.get() );
443 if ( pPath )
444 aPP = pPath->GetPathPoly();
445 }
446
447 if ( aPP.count() )
448 aPolyPolygon.append(aPP);
449 }
450 pObj.reset();
452 aPolyPolygonBezierCoords );
453 }
454 }
455
456 return aPolyPolygonBezierCoords;
457}
458
459Sequence< Reference< drawing::XCustomShapeHandle > > SAL_CALL EnhancedCustomShapeEngine::getInteraction()
460{
461 sal_uInt32 i, nHdlCount = 0;
462 SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
463
464 if(pSdrObjCustomShape)
465 {
466 EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
467 nHdlCount = aCustomShape2d.GetHdlCount();
468 }
469
470 Sequence< Reference< drawing::XCustomShapeHandle > > aSeq( nHdlCount );
471 auto aSeqRange = asNonConstRange(aSeq);
472
473 for ( i = 0; i < nHdlCount; i++ )
474 aSeqRange[ i ] = new EnhancedCustomShapeHandle( mxShape, i );
475 return aSeq;
476}
477
478}
479
480extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
482 css::uno::XComponentContext *,
483 css::uno::Sequence<css::uno::Any> const &)
484{
485 return cppu::acquire(new EnhancedCustomShapeEngine);
486}
487
488/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_drawing_EnhancedCustomShapeEngine_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
static SdrObject * Create3DObject(const SdrObject *pShape2d, const SdrObjCustomShape &rSdrObjCustomShape)
static SdrObject * CreateFontWork(const SdrObject *pShape2d, const SdrObjCustomShape &rSdrObjCustomShape)
The transformation of a rectangle into a polygon, by using angle parameters from GeoStat.
Definition: svdtrans.hxx:201
virtual const tools::Rectangle & GetSnapRect() const override
Definition: svdoattr.cxx:49
const SdrObject * GetSdrObjectShadowFromCustomShape() const
Definition: svdoashp.cxx:419
static SdrObject * MakeNewObject(SdrModel &rSdrModel, SdrInventor nInventor, SdrObjKind nObjIdentifier, const tools::Rectangle *pSnapRect=nullptr)
Definition: svdobj.cxx:3262
virtual void NbcInsertObject(SdrObject *pObj, size_t nPos=SAL_MAX_SIZE)
Definition: svdpage.cxx:276
Abstract DrawObject.
Definition: svdobj.hxx:261
static SdrObject * getSdrObjectFromXShape(const css::uno::Reference< css::uno::XInterface > &xInt)
Definition: unoshape.cxx:4024
const SfxPoolItem & GetMergedItem(const sal_uInt16 nWhich) const
Definition: svdobj.cxx:2043
virtual SdrInventor GetObjInventor() const
Definition: svdobj.cxx:649
virtual SdrObjList * GetSubList() const
Definition: svdobj.cxx:743
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:284
SfxStyleSheet * GetStyleSheet() const
Definition: svdobj.cxx:2278
virtual SdrObjKind GetObjIdentifier() const
Definition: svdobj.cxx:654
const SfxItemSet & GetMergedItemSet() const
Definition: svdobj.cxx:2008
SdrObjectUniquePtr ConvertToPolyObj(bool bBezier, bool bLineToArea) const
Definition: svdobj.cxx:2654
const basegfx::B2DPolyPolygon & GetPathPoly() const
Definition: svdopath.hxx:141
virtual OutlinerParaObject * GetOutlinerParaObject() const override
Definition: svdotext.cxx:1330
virtual bool HasText() const override
Definition: svdotxat.cxx:418
const GeoStat & GetGeoStat() const
Definition: svdotext.hxx:392
static rtl::Reference< SvxShape > CreateShapeByTypeAndInventor(SdrObjKind nType, SdrInventor nInventor, SdrObject *pObj, SvxDrawPage *pPage=nullptr, OUString const &referer=OUString())
Definition: unopage.cxx:611
void TakeSdrObjectOwnership()
takes the ownership of the SdrObject.
Definition: unoshape.cxx:248
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
sal_uInt32 count() const
constexpr Point Center() const
Sequence< sal_Int8 > aSeq
void B2DPolyPolygonToUnoPolyPolygonBezierCoords(const B2DPolyPolygon &rPolyPolygon, css::drawing::PolyPolygonBezierCoords &rPolyPolygonBezierCoordsRetval)
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
uno::Reference< drawing::XShape > const mxShape
constexpr TypedWhichId< SdrCustomShapeGeometryItem > SDRATTR_CUSTOMSHAPE_GEOMETRY(SDRATTR_CUSTOMSHAPE_FIRST+2)
std::unique_ptr< SdrObject, SdrObjectFreeOp > SdrObjectUniquePtr
Definition: svdobj.hxx:98
@ Text
periodic cubic Spline (ni)
unsigned char sal_Bool