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/unoapi.hxx>
35 #include <svx/svdobj.hxx>
36 #include <svx/svdoashp.hxx>
37 #include <svx/svdogrp.hxx>
38 #include <editeng/outlobj.hxx>
39 #include <svl/itemset.hxx>
40 #include <svx/svdopath.hxx>
41 #include <svx/svdpage.hxx>
42 #include <svx/svditer.hxx>
43 #include <svx/xfillit0.hxx>
44 #include <svx/xlineit0.hxx>
46 #include <com/sun/star/document/XActionLockable.hpp>
47 #include <cppuhelper/implbase.hxx>
49 
50 using namespace css;
51 using namespace css::uno;
52 
53 class SdrObject;
54 class SdrObjCustomShape;
55 
56 namespace {
57 
58 class EnhancedCustomShapeEngine : public cppu::WeakImplHelper
59 <
60  css::lang::XInitialization,
61  css::lang::XServiceInfo,
62  css::drawing::XCustomShapeEngine
63 >
64 {
65  css::uno::Reference< css::drawing::XShape > mxShape;
66  bool mbForceGroupWithText;
67 
68  std::unique_ptr<SdrObject, SdrObjectFreeOp> ImplForceGroupWithText(
69  const SdrObjCustomShape& rSdrObjCustomShape,
70  std::unique_ptr<SdrObject, SdrObjectFreeOp> pRenderedShape);
71 
72 public:
73  EnhancedCustomShapeEngine();
74 
75  // XInterface
76  virtual void SAL_CALL acquire() noexcept override;
77  virtual void SAL_CALL release() noexcept override;
78 
79  // XInitialization
80  virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
81 
82  // XServiceInfo
83  virtual OUString SAL_CALL getImplementationName() override;
84  virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override;
85  virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
86 
87  // XCustomShapeEngine
88  virtual css::uno::Reference< css::drawing::XShape > SAL_CALL render() override;
89  virtual css::awt::Rectangle SAL_CALL getTextBounds() override;
90  virtual css::drawing::PolyPolygonBezierCoords SAL_CALL getLineGeometry() override;
91  virtual css::uno::Sequence< css::uno::Reference< css::drawing::XCustomShapeHandle > > SAL_CALL getInteraction() override;
92 };
93 
94 EnhancedCustomShapeEngine::EnhancedCustomShapeEngine() :
95  mbForceGroupWithText ( false )
96 {
97 }
98 
99 // XInterface
100 void SAL_CALL EnhancedCustomShapeEngine::acquire() noexcept
101 {
102  OWeakObject::acquire();
103 }
104 void SAL_CALL EnhancedCustomShapeEngine::release() noexcept
105 {
106  OWeakObject::release();
107 }
108 
109 // XInitialization
110 void SAL_CALL EnhancedCustomShapeEngine::initialize( const Sequence< Any >& aArguments )
111 {
113  for ( const auto& rArgument : aArguments )
114  {
115  if ( rArgument >>= aParameter )
116  break;
117  }
118  for ( const beans::PropertyValue& rProp : std::as_const(aParameter) )
119  {
120  if ( rProp.Name == "CustomShape" )
121  rProp.Value >>= mxShape;
122  else if ( rProp.Name == "ForceGroupWithText" )
123  rProp.Value >>= mbForceGroupWithText;
124  }
125 }
126 
127 // XServiceInfo
128 OUString SAL_CALL EnhancedCustomShapeEngine::getImplementationName()
129 {
130  return "com.sun.star.drawing.EnhancedCustomShapeEngine";
131 }
132 sal_Bool SAL_CALL EnhancedCustomShapeEngine::supportsService( const OUString& rServiceName )
133 {
134  return cppu::supportsService(this, rServiceName);
135 }
136 Sequence< OUString > SAL_CALL EnhancedCustomShapeEngine::getSupportedServiceNames()
137 {
138  return { "com.sun.star.drawing.CustomShapeEngine" };
139 }
140 
141 // XCustomShapeEngine
142 std::unique_ptr<SdrObject, SdrObjectFreeOp> EnhancedCustomShapeEngine::ImplForceGroupWithText(
143  const SdrObjCustomShape& rSdrObjCustomShape,
144  std::unique_ptr<SdrObject, SdrObjectFreeOp> pRenderedShape)
145 {
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.reset(new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject()));
161  static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.release() );
162  }
163 
164  static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject(
165  pShadowGeometry->CloneSdrObject(pShadowGeometry->getSdrModelFromSdrObject()),
166  0);
167  }
168  else
169  {
170  pRenderedShape.reset( 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
178  std::unique_ptr<SdrObject, SdrObjectFreeOp> pTextObj( SdrObjFactory::MakeNewObject(
179  rSdrObjCustomShape.getSdrModelFromSdrObject(),
180  rSdrObjCustomShape.GetObjInventor(),
181  OBJ_TEXT) );
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.nRotationAngle )
211  {
212  pTextObj->NbcRotate(
213  rSdrObjCustomShape.GetSnapRect().Center(),
214  rSourceGeo.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.reset(new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject()));
228  static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.release() );
229  }
230  static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTextObj.release() );
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.reset(new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject()));
243  static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.release() );
244  }
245  }
246  }
247 
248  return pRenderedShape;
249 }
250 
251 void SetTemporary( uno::Reference< drawing::XShape > const & xShape )
252 {
253  if ( xShape.is() )
254  {
255  SvxShape* pShape = comphelper::getFromUnoTunnel<SvxShape>( xShape );
256  if ( pShape )
257  pShape->TakeSdrObjectOwnership();
258  }
259 }
260 
261 Reference< drawing::XShape > SAL_CALL EnhancedCustomShapeEngine::render()
262 {
263  SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
264 
265  if(!pSdrObjCustomShape)
266  {
267  return Reference< drawing::XShape >();
268  }
269 
270  // retrieving the TextPath property to check if feature is enabled
271  const SdrCustomShapeGeometryItem& rGeometryItem(pSdrObjCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
272  bool bTextPathOn = false;
273  const uno::Any* pAny = rGeometryItem.GetPropertyValueByName( "TextPath", "TextPath" );
274  if ( pAny )
275  *pAny >>= bTextPathOn;
276 
277  EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
278  Degree100 nRotateAngle = aCustomShape2d.GetRotateAngle();
279 
280  bool bFlipV = aCustomShape2d.IsFlipVert();
281  bool bFlipH = aCustomShape2d.IsFlipHorz();
282  bool bLineGeometryNeededOnly = bTextPathOn;
283 
284  std::unique_ptr<SdrObject, SdrObjectFreeOp> xRenderedShape(aCustomShape2d.CreateObject(bLineGeometryNeededOnly));
285  if (xRenderedShape)
286  {
287  if ( bTextPathOn )
288  {
289  std::unique_ptr<SdrObject, SdrObjectFreeOp> xRenderedFontWork(
291  xRenderedShape.get(),
292  *pSdrObjCustomShape));
293 
294  if (xRenderedFontWork)
295  {
296  xRenderedShape = std::move(xRenderedFontWork);
297  }
298  }
299  std::unique_ptr<SdrObject, SdrObjectFreeOp> xRenderedShape3d(EnhancedCustomShape3d::Create3DObject(xRenderedShape.get(), *pSdrObjCustomShape));
300  if (xRenderedShape3d)
301  {
302  bFlipV = bFlipH = false;
303  nRotateAngle = 0_deg100;
304  xRenderedShape = std::move(xRenderedShape3d);
305  }
306 
307  tools::Rectangle aRect(pSdrObjCustomShape->GetSnapRect());
308  const GeoStat& rGeoStat(pSdrObjCustomShape->GetGeoStat());
309 
310  if ( rGeoStat.nShearAngle )
311  {
312  Degree100 nShearAngle = rGeoStat.nShearAngle;
313  double nTan = rGeoStat.mfTanShearAngle;
314  if (bFlipV != bFlipH)
315  {
316  nShearAngle = -nShearAngle;
317  nTan = -nTan;
318  }
319 
320  xRenderedShape->Shear(pSdrObjCustomShape->GetSnapRect().Center(), nShearAngle, nTan, false);
321  }
322  if(nRotateAngle )
323  xRenderedShape->NbcRotate(pSdrObjCustomShape->GetSnapRect().Center(), nRotateAngle);
324  if ( bFlipV )
325  {
326  Point aLeft( aRect.Left(), ( aRect.Top() + aRect.Bottom() ) >> 1 );
327  Point aRight( aLeft.X() + 1000, aLeft.Y() );
328  xRenderedShape->NbcMirror( aLeft, aRight );
329  }
330  if ( bFlipH )
331  {
332  Point aTop( ( aRect.Left() + aRect.Right() ) >> 1, aRect.Top() );
333  Point aBottom( aTop.X(), aTop.Y() + 1000 );
334  xRenderedShape->NbcMirror( aTop, aBottom );
335  }
336 
337  xRenderedShape->NbcSetStyleSheet(pSdrObjCustomShape->GetStyleSheet(), true);
338  xRenderedShape->RecalcSnapRect();
339  }
340 
341  if ( mbForceGroupWithText )
342  {
343  xRenderedShape = ImplForceGroupWithText(
344  *pSdrObjCustomShape,
345  std::move(xRenderedShape));
346  }
347 
348  Reference< drawing::XShape > xShape;
349 
350  if (xRenderedShape)
351  {
352  aCustomShape2d.ApplyGluePoints(xRenderedShape.get());
353  SdrObject* pRenderedShape = xRenderedShape.release();
355  pRenderedShape->GetObjInventor(), pRenderedShape );
356  }
357 
358  SetTemporary( xShape );
359 
360  return xShape;
361 }
362 
363 awt::Rectangle SAL_CALL EnhancedCustomShapeEngine::getTextBounds()
364 {
365  awt::Rectangle aTextRect;
366  if (SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape)))
367  {
368  uno::Reference< document::XActionLockable > xLockable( mxShape, uno::UNO_QUERY );
369 
370  if(xLockable.is() && !xLockable->isActionLocked())
371  {
372  EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
373  tools::Rectangle aRect( aCustomShape2d.GetTextRect() );
374  aTextRect.X = aRect.Left();
375  aTextRect.Y = aRect.Top();
376  aTextRect.Width = aRect.GetWidth();
377  aTextRect.Height = aRect.GetHeight();
378  }
379  }
380 
381  return aTextRect;
382 }
383 
384 drawing::PolyPolygonBezierCoords SAL_CALL EnhancedCustomShapeEngine::getLineGeometry()
385 {
386  drawing::PolyPolygonBezierCoords aPolyPolygonBezierCoords;
387  SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
388 
389  if(pSdrObjCustomShape)
390  {
391  EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
392  SdrObjectUniquePtr pObj = aCustomShape2d.CreateLineGeometry();
393 
394  if ( pObj )
395  {
396  tools::Rectangle aRect(pSdrObjCustomShape->GetSnapRect());
397  bool bFlipV = aCustomShape2d.IsFlipVert();
398  bool bFlipH = aCustomShape2d.IsFlipHorz();
399  const GeoStat& rGeoStat(pSdrObjCustomShape->GetGeoStat());
400 
401  if ( rGeoStat.nShearAngle )
402  {
403  Degree100 nShearAngle = rGeoStat.nShearAngle;
404  double nTan = rGeoStat.mfTanShearAngle;
405  if (bFlipV != bFlipH)
406  {
407  nShearAngle = -nShearAngle;
408  nTan = -nTan;
409  }
410  pObj->Shear( aRect.Center(), nShearAngle, nTan, false);
411  }
412  Degree100 nRotateAngle = aCustomShape2d.GetRotateAngle();
413  if( nRotateAngle )
414  pObj->NbcRotate( aRect.Center(), nRotateAngle );
415  if ( bFlipH )
416  {
417  Point aTop( ( aRect.Left() + aRect.Right() ) >> 1, aRect.Top() );
418  Point aBottom( aTop.X(), aTop.Y() + 1000 );
419  pObj->NbcMirror( aTop, aBottom );
420  }
421  if ( bFlipV )
422  {
423  Point aLeft( aRect.Left(), ( aRect.Top() + aRect.Bottom() ) >> 1 );
424  Point aRight( aLeft.X() + 1000, aLeft.Y() );
425  pObj->NbcMirror( aLeft, aRight );
426  }
427 
428  basegfx::B2DPolyPolygon aPolyPolygon;
430 
431  while ( aIter.IsMore() )
432  {
434  const SdrObject* pNext = aIter.Next();
435 
436  if ( auto pPathObj = dynamic_cast<const SdrPathObj*>(pNext) )
437  {
438  aPP = pPathObj->GetPathPoly();
439  }
440  else
441  {
442  SdrObjectUniquePtr pNewObj = pNext->ConvertToPolyObj( false, false );
443  SdrPathObj* pPath = dynamic_cast<SdrPathObj*>( pNewObj.get() );
444  if ( pPath )
445  aPP = pPath->GetPathPoly();
446  }
447 
448  if ( aPP.count() )
449  aPolyPolygon.append(aPP);
450  }
451  pObj.reset();
453  aPolyPolygonBezierCoords );
454  }
455  }
456 
457  return aPolyPolygonBezierCoords;
458 }
459 
460 Sequence< Reference< drawing::XCustomShapeHandle > > SAL_CALL EnhancedCustomShapeEngine::getInteraction()
461 {
462  sal_uInt32 i, nHdlCount = 0;
463  SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
464 
465  if(pSdrObjCustomShape)
466  {
467  EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
468  nHdlCount = aCustomShape2d.GetHdlCount();
469  }
470 
471  Sequence< Reference< drawing::XCustomShapeHandle > > aSeq( nHdlCount );
472 
473  for ( i = 0; i < nHdlCount; i++ )
474  aSeq[ i ] = new EnhancedCustomShapeHandle( mxShape, i );
475  return aSeq;
476 }
477 
478 }
479 
480 extern "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 &)
constexpr tools::Long Left() const
static SdrObject * getSdrObjectFromXShape(const css::uno::Reference< css::uno::XInterface > &xInt)
Definition: unoshape.cxx:4009
virtual void NbcInsertObject(SdrObject *pObj, size_t nPos=SAL_MAX_SIZE)
Definition: svdpage.cxx:283
static SdrObject * MakeNewObject(SdrModel &rSdrModel, SdrInventor nInventor, SdrObjKind nObjIdentifier, const tools::Rectangle *pSnapRect=nullptr)
Definition: svdobj.cxx:3160
static rtl::Reference< SvxShape > CreateShapeByTypeAndInventor(sal_uInt16 nType, SdrInventor nInventor, SdrObject *pObj, SvxDrawPage *pPage=nullptr, OUString const &referer=OUString())
Definition: unopage.cxx:607
virtual SdrObjKind GetObjIdentifier() const
Definition: svdobj.cxx:659
virtual const tools::Rectangle & GetSnapRect() const override
Definition: svdoattr.cxx:49
virtual bool HasText() const override
Definition: svdotxat.cxx:417
uno::Reference< drawing::XShape > const mxShape
The transformation of a rectangle into a polygon, by using angle parameters from GeoStat.
Definition: svdtrans.hxx:214
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
SfxStyleSheet * GetStyleSheet() const
Definition: svdobj.cxx:2225
const GeoStat & GetGeoStat() const
Definition: svdotext.hxx:392
constexpr TypedWhichId< SdrCustomShapeGeometryItem > SDRATTR_CUSTOMSHAPE_GEOMETRY(SDRATTR_CUSTOMSHAPE_FIRST+2)
int i
void TakeSdrObjectOwnership()
takes the ownership of the SdrObject.
Definition: unoshape.cxx:246
unsigned char sal_Bool
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:279
const SdrObject * GetSdrObjectShadowFromCustomShape() const
Definition: svdoashp.cxx:420
const SfxPoolItem & GetMergedItem(const sal_uInt16 nWhich) const
Definition: svdobj.cxx:2013
Abstract DrawObject.
Definition: svdobj.hxx:259
virtual SdrInventor GetObjInventor() const
Definition: svdobj.cxx:654
constexpr Point Center() const
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
SdrObjectUniquePtr ConvertToPolyObj(bool bBezier, bool bLineToArea) const
Definition: svdobj.cxx:2595
sal_uInt32 count() const
static SdrObject * Create3DObject(const SdrObject *pShape2d, const SdrObjCustomShape &rSdrObjCustomShape)
virtual OutlinerParaObject * GetOutlinerParaObject() const override
Definition: svdotext.cxx:1329
static SdrObject * CreateFontWork(const SdrObject *pShape2d, const SdrObjCustomShape &rSdrObjCustomShape)
const SfxItemSet & GetMergedItemSet() const
Definition: svdobj.cxx:1978
Sequence< sal_Int8 > aSeq
std::unique_ptr< SdrObject, SdrObjectFreeOp > SdrObjectUniquePtr
Definition: svdobj.hxx:97
const basegfx::B2DPolyPolygon & GetPathPoly() const
Definition: svdopath.hxx:141
void B2DPolyPolygonToUnoPolyPolygonBezierCoords(const B2DPolyPolygon &rPolyPolygon, css::drawing::PolyPolygonBezierCoords &rPolyPolygonBezierCoordsRetval)
periodic cubic Spline (ni)
Definition: svdobjkind.hxx:42