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 rtl::Reference<SdrObject> ImplForceGroupWithText(
68 const SdrObjCustomShape& rSdrObjCustomShape,
69 SdrObject* 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
141rtl::Reference<SdrObject> EnhancedCustomShapeEngine::ImplForceGroupWithText(
142 const SdrObjCustomShape& rSdrObjCustomShape,
143 SdrObject* pRenderedShape1)
144{
145 rtl::Reference<SdrObject> pRenderedShape = pRenderedShape1;
146 const bool bHasText(rSdrObjCustomShape.HasText());
147
148 if ( pRenderedShape || bHasText )
149 {
150 // applying shadow
151 const SdrObject* pShadowGeometry(rSdrObjCustomShape.GetSdrObjectShadowFromCustomShape());
152
153 if ( pShadowGeometry )
154 {
155 if ( pRenderedShape )
156 {
157 if ( dynamic_cast<const SdrObjGroup*>( pRenderedShape.get() ) == nullptr )
158 {
159 auto pTmp = std::move(pRenderedShape);
160 pRenderedShape = new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject());
161 static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.get() );
162 }
163
164 static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject(
165 pShadowGeometry->CloneSdrObject(pShadowGeometry->getSdrModelFromSdrObject()).get(),
166 0);
167 }
168 else
169 {
170 pRenderedShape = pShadowGeometry->CloneSdrObject(pShadowGeometry->getSdrModelFromSdrObject());
171 }
172 }
173
174 // apply text
175 if ( bHasText )
176 {
177 // #i37011# also create a text object and add at rPos + 1
179 rSdrObjCustomShape.getSdrModelFromSdrObject(),
180 rSdrObjCustomShape.GetObjInventor(),
182
183 // Copy text content
184 OutlinerParaObject* pParaObj(rSdrObjCustomShape.GetOutlinerParaObject());
185
186 if( pParaObj )
187 pTextObj->NbcSetOutlinerParaObject( *pParaObj );
188
189 // copy all attributes
190 SfxItemSet aTargetItemSet(rSdrObjCustomShape.GetMergedItemSet());
191
192 // clear fill and line style
193 aTargetItemSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
194 aTargetItemSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
195
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));
199
200 if(pSdrObjCustomShape)
201 {
202 EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
203 aTextBounds = aCustomShape2d.GetTextRect();
204 }
205
206 pTextObj->SetSnapRect( aTextBounds );
207
208 // if rotated, copy GeoStat, too.
209 const GeoStat& rSourceGeo(rSdrObjCustomShape.GetGeoStat());
210 if ( rSourceGeo.m_nRotationAngle )
211 {
212 pTextObj->NbcRotate(
213 rSdrObjCustomShape.GetSnapRect().Center(),
214 rSourceGeo.m_nRotationAngle,
215 rSourceGeo.mfSinRotationAngle,
216 rSourceGeo.mfCosRotationAngle);
217 }
218
219 // set modified ItemSet at text object
220 pTextObj->SetMergedItemSet(aTargetItemSet);
221
222 if ( pRenderedShape )
223 {
224 if ( dynamic_cast<const SdrObjGroup*>( pRenderedShape.get() ) == nullptr )
225 {
226 auto pTmp = std::move(pRenderedShape);
227 pRenderedShape = new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject());
228 static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.get() );
229 }
230 static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTextObj.get() );
231 }
232 else
233 pRenderedShape = std::move(pTextObj);
234 }
235
236 // force group
237 if ( pRenderedShape )
238 {
239 if ( dynamic_cast<const SdrObjGroup*>( pRenderedShape.get() ) == nullptr )
240 {
241 auto pTmp = std::move(pRenderedShape);
242 pRenderedShape = new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject());
243 static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.get() );
244 }
245 }
246 }
247
248 return pRenderedShape;
249}
250
251Reference< drawing::XShape > SAL_CALL EnhancedCustomShapeEngine::render()
252{
253 SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
254
255 if(!pSdrObjCustomShape)
256 {
257 return Reference< drawing::XShape >();
258 }
259
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( "TextPath", "TextPath" );
264 if ( pAny )
265 *pAny >>= bTextPathOn;
266
267 EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
268 Degree100 nRotateAngle = aCustomShape2d.GetRotateAngle();
269
270 bool bFlipV = aCustomShape2d.IsFlipVert();
271 bool bFlipH = aCustomShape2d.IsFlipHorz();
272 bool bLineGeometryNeededOnly = bTextPathOn;
273
274 rtl::Reference<SdrObject> xRenderedShape(aCustomShape2d.CreateObject(bLineGeometryNeededOnly));
275 if (xRenderedShape)
276 {
277 if ( bTextPathOn )
278 {
279 rtl::Reference<SdrObject> xRenderedFontWork(
281 xRenderedShape.get(),
282 *pSdrObjCustomShape));
283
284 if (xRenderedFontWork)
285 {
286 xRenderedShape = std::move(xRenderedFontWork);
287 }
288 }
289 rtl::Reference<SdrObject> xRenderedShape3d(EnhancedCustomShape3d::Create3DObject(xRenderedShape.get(), *pSdrObjCustomShape));
290 if (xRenderedShape3d)
291 {
292 bFlipV = bFlipH = false;
293 nRotateAngle = 0_deg100;
294 xRenderedShape = std::move(xRenderedShape3d);
295 }
296
297 tools::Rectangle aRect(pSdrObjCustomShape->GetSnapRect());
298 const GeoStat& rGeoStat(pSdrObjCustomShape->GetGeoStat());
299
300 if ( rGeoStat.m_nShearAngle )
301 {
302 Degree100 nShearAngle = rGeoStat.m_nShearAngle;
303 double nTan = rGeoStat.mfTanShearAngle;
304 if (bFlipV != bFlipH)
305 {
306 nShearAngle = -nShearAngle;
307 nTan = -nTan;
308 }
309
310 xRenderedShape->Shear(pSdrObjCustomShape->GetSnapRect().Center(), nShearAngle, nTan, false);
311 }
312 if(nRotateAngle )
313 xRenderedShape->NbcRotate(pSdrObjCustomShape->GetSnapRect().Center(), nRotateAngle);
314 if ( bFlipV )
315 {
316 Point aLeft( aRect.Left(), ( aRect.Top() + aRect.Bottom() ) >> 1 );
317 Point aRight( aLeft.X() + 1000, aLeft.Y() );
318 xRenderedShape->NbcMirror( aLeft, aRight );
319 }
320 if ( bFlipH )
321 {
322 Point aTop( ( aRect.Left() + aRect.Right() ) >> 1, aRect.Top() );
323 Point aBottom( aTop.X(), aTop.Y() + 1000 );
324 xRenderedShape->NbcMirror( aTop, aBottom );
325 }
326
327 xRenderedShape->NbcSetStyleSheet(pSdrObjCustomShape->GetStyleSheet(), true);
328 xRenderedShape->RecalcSnapRect();
329 }
330
331 if ( mbForceGroupWithText )
332 {
333 xRenderedShape = ImplForceGroupWithText(
334 *pSdrObjCustomShape,
335 xRenderedShape.get());
336 }
337
338 Reference< drawing::XShape > xShape;
339
340 if (xRenderedShape)
341 {
342 aCustomShape2d.ApplyGluePoints(xRenderedShape.get());
343 xShape = SvxDrawPage::CreateShapeByTypeAndInventor( xRenderedShape->GetObjIdentifier(),
344 xRenderedShape->GetObjInventor(), xRenderedShape.get() );
345 }
346
347 return xShape;
348}
349
350awt::Rectangle SAL_CALL EnhancedCustomShapeEngine::getTextBounds()
351{
352 awt::Rectangle aTextRect;
353 if (SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape)))
354 {
355 uno::Reference< document::XActionLockable > xLockable( mxShape, uno::UNO_QUERY );
356
357 if(xLockable.is() && !xLockable->isActionLocked())
358 {
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();
365 }
366 }
367
368 return aTextRect;
369}
370
371drawing::PolyPolygonBezierCoords SAL_CALL EnhancedCustomShapeEngine::getLineGeometry()
372{
373 drawing::PolyPolygonBezierCoords aPolyPolygonBezierCoords;
374 SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
375
376 if(pSdrObjCustomShape)
377 {
378 EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
379 rtl::Reference<SdrObject> pObj = aCustomShape2d.CreateLineGeometry();
380
381 if ( pObj )
382 {
383 tools::Rectangle aRect(pSdrObjCustomShape->GetSnapRect());
384 bool bFlipV = aCustomShape2d.IsFlipVert();
385 bool bFlipH = aCustomShape2d.IsFlipHorz();
386 const GeoStat& rGeoStat(pSdrObjCustomShape->GetGeoStat());
387
388 if ( rGeoStat.m_nShearAngle )
389 {
390 Degree100 nShearAngle = rGeoStat.m_nShearAngle;
391 double nTan = rGeoStat.mfTanShearAngle;
392 if (bFlipV != bFlipH)
393 {
394 nShearAngle = -nShearAngle;
395 nTan = -nTan;
396 }
397 pObj->Shear( aRect.Center(), nShearAngle, nTan, false);
398 }
399 Degree100 nRotateAngle = aCustomShape2d.GetRotateAngle();
400 if( nRotateAngle )
401 pObj->NbcRotate( aRect.Center(), nRotateAngle );
402 if ( bFlipH )
403 {
404 Point aTop( ( aRect.Left() + aRect.Right() ) >> 1, aRect.Top() );
405 Point aBottom( aTop.X(), aTop.Y() + 1000 );
406 pObj->NbcMirror( aTop, aBottom );
407 }
408 if ( bFlipV )
409 {
410 Point aLeft( aRect.Left(), ( aRect.Top() + aRect.Bottom() ) >> 1 );
411 Point aRight( aLeft.X() + 1000, aLeft.Y() );
412 pObj->NbcMirror( aLeft, aRight );
413 }
414
415 basegfx::B2DPolyPolygon aPolyPolygon;
417
418 while ( aIter.IsMore() )
419 {
421 const SdrObject* pNext = aIter.Next();
422
423 if ( auto pPathObj = dynamic_cast<const SdrPathObj*>(pNext) )
424 {
425 aPP = pPathObj->GetPathPoly();
426 }
427 else
428 {
429 rtl::Reference<SdrObject> pNewObj = pNext->ConvertToPolyObj( false, false );
430 SdrPathObj* pPath = dynamic_cast<SdrPathObj*>( pNewObj.get() );
431 if ( pPath )
432 aPP = pPath->GetPathPoly();
433 }
434
435 if ( aPP.count() )
436 aPolyPolygon.append(aPP);
437 }
438 pObj.clear();
440 aPolyPolygonBezierCoords );
441 }
442 }
443
444 return aPolyPolygonBezierCoords;
445}
446
447Sequence< Reference< drawing::XCustomShapeHandle > > SAL_CALL EnhancedCustomShapeEngine::getInteraction()
448{
449 sal_uInt32 i, nHdlCount = 0;
450 SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
451
452 if(pSdrObjCustomShape)
453 {
454 EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
455 nHdlCount = aCustomShape2d.GetHdlCount();
456 }
457
458 Sequence< Reference< drawing::XCustomShapeHandle > > aSeq( nHdlCount );
459 auto aSeqRange = asNonConstRange(aSeq);
460
461 for ( i = 0; i < nHdlCount; i++ )
462 aSeqRange[ i ] = new EnhancedCustomShapeHandle( mxShape, i );
463 return aSeq;
464}
465
466}
467
468extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
470 css::uno::XComponentContext *,
471 css::uno::Sequence<css::uno::Any> const &)
472{
473 return cppu::acquire(new EnhancedCustomShapeEngine);
474}
475
476/* 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 rtl::Reference< SdrObject > Create3DObject(const SdrObject *pShape2d, const SdrObjCustomShape &rSdrObjCustomShape)
static rtl::Reference< 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:422
static rtl::Reference< SdrObject > MakeNewObject(SdrModel &rSdrModel, SdrInventor nInventor, SdrObjKind nObjIdentifier, const tools::Rectangle *pSnapRect=nullptr)
Definition: svdobj.cxx:3279
virtual void NbcInsertObject(SdrObject *pObj, size_t nPos=SAL_MAX_SIZE)
Definition: svdpage.cxx:244
Abstract DrawObject.
Definition: svdobj.hxx:260
static SdrObject * getSdrObjectFromXShape(const css::uno::Reference< css::uno::XInterface > &xInt)
Definition: unoshape.cxx:4020
const SfxPoolItem & GetMergedItem(const sal_uInt16 nWhich) const
Definition: svdobj.cxx:2009
virtual void SAL_CALL acquire() noexcept override final
Definition: svdobj.cxx:487
virtual void SAL_CALL release() noexcept override final
Definition: svdobj.cxx:495
virtual SdrInventor GetObjInventor() const
Definition: svdobj.cxx:621
virtual SdrObjList * GetSubList() const
Definition: svdobj.cxx:717
rtl::Reference< SdrObject > ConvertToPolyObj(bool bBezier, bool bLineToArea) const
Definition: svdobj.cxx:2620
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:289
SfxStyleSheet * GetStyleSheet() const
Definition: svdobj.cxx:2244
const SfxItemSet & GetMergedItemSet() const
Definition: svdobj.cxx:1974
const basegfx::B2DPolyPolygon & GetPathPoly() const
Definition: svdopath.hxx:141
virtual OutlinerParaObject * GetOutlinerParaObject() const override
Definition: svdotext.cxx:1412
virtual bool HasText() const override
Definition: svdotxat.cxx:420
const GeoStat & GetGeoStat() const
Definition: svdotext.hxx:419
static rtl::Reference< SvxShape > CreateShapeByTypeAndInventor(SdrObjKind nType, SdrInventor nInventor, SdrObject *pObj, SvxDrawPage *pPage=nullptr, OUString const &referer=OUString())
Definition: unopage.cxx:613
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
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
uno::Reference< drawing::XShape > const mxShape
constexpr TypedWhichId< SdrCustomShapeGeometryItem > SDRATTR_CUSTOMSHAPE_GEOMETRY(SDRATTR_CUSTOMSHAPE_FIRST+2)
@ Text
closed free-hand line
unsigned char sal_Bool