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 <oox/drawingml/shape.hxx>
21 #include <drawingml/customshapeproperties.hxx>
22 #include <oox/drawingml/theme.hxx>
23 #include <drawingml/fillproperties.hxx>
24 #include <drawingml/graphicproperties.hxx>
25 #include <drawingml/lineproperties.hxx>
26 #include <drawingml/presetgeometrynames.hxx>
27 #include <drawingml/shape3dproperties.hxx>
28 #include "effectproperties.hxx"
29 #include <oox/drawingml/shapepropertymap.hxx>
30 #include <drawingml/textbody.hxx>
31 #include <drawingml/textparagraph.hxx>
32 #include <drawingml/ThemeOverrideFragmentHandler.hxx>
33 #include <drawingml/table/tableproperties.hxx>
34 #include <oox/drawingml/chart/chartconverter.hxx>
35 #include <drawingml/chart/chartspacefragment.hxx>
36 #include <drawingml/chart/chartspacemodel.hxx>
37 #include <o3tl/safeint.hxx>
38 #include <o3tl/unit_conversion.hxx>
39 #include <oox/ppt/pptimport.hxx>
40 #include <oox/vml/vmldrawing.hxx>
41 #include <oox/vml/vmlshape.hxx>
42 #include <oox/vml/vmlshapecontainer.hxx>
43 #include <oox/core/xmlfilterbase.hxx>
44 #include <oox/helper/graphichelper.hxx>
45 #include <oox/helper/propertyset.hxx>
46 #include <oox/helper/modelobjecthelper.hxx>
47 #include <oox/mathml/importutils.hxx>
48 #include <oox/mathml/import.hxx>
49 #include <oox/token/properties.hxx>
50 #include "diagram/datamodel.hxx"
51
52 #include <comphelper/classids.hxx>
53 #include <comphelper/propertysequence.hxx>
54 #include <comphelper/propertyvalue.hxx>
55 #include <comphelper/sequence.hxx>
56 #include <tools/diagnose_ex.h>
57 #include <tools/gen.hxx>
58 #include <tools/globname.hxx>
59 #include <tools/mapunit.hxx>
60 #include <tools/UnitConversion.hxx>
61 #include <editeng/unoprnms.hxx>
62 #include <com/sun/star/awt/Size.hpp>
63 #include <com/sun/star/awt/XBitmap.hpp>
64 #include <com/sun/star/awt/FontWeight.hpp>
65 #include <com/sun/star/graphic/XGraphic.hpp>
66 #include <com/sun/star/container/XNamed.hpp>
67 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
68 #include <com/sun/star/xml/dom/XDocument.hpp>
69 #include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
70 #include <com/sun/star/drawing/FillStyle.hpp>
71 #include <com/sun/star/drawing/HomogenMatrix3.hpp>
72 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
73 #include <com/sun/star/drawing/GraphicExportFilter.hpp>
74 #include <com/sun/star/drawing/XShapes.hpp>
75 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
76 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
77 #include <com/sun/star/embed/XEmbeddedObject.hpp>
78 #include <com/sun/star/text/XText.hpp>
79 #include <com/sun/star/table/BorderLine2.hpp>
80 #include <com/sun/star/table/ShadowFormat.hpp>
81 #include <com/sun/star/chart2/XChartDocument.hpp>
82 #include <com/sun/star/style/ParagraphAdjust.hpp>
83 #include <com/sun/star/io/XOutputStream.hpp>
84
85 #include <basegfx/point/b2dpoint.hxx>
86 #include <basegfx/polygon/b2dpolygon.hxx>
87 #include <basegfx/matrix/b2dhommatrix.hxx>
88 #include <basegfx/matrix/b2dhommatrixtools.hxx>
89 #include <com/sun/star/document/XActionLockable.hpp>
90 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
91 #include <com/sun/star/text/GraphicCrop.hpp>
92 #include <svx/svdtrans.hxx>
93 #include <tools/stream.hxx>
94 #include <unotools/streamwrap.hxx>
95 #include <unotools/fltrcfg.hxx>
96 #include <vcl/graph.hxx>
97 #include <vcl/graphicfilter.hxx>
98 #include <vcl/svapp.hxx>
99 #include <vcl/wmfexternal.hxx>
100 #include <sal/log.hxx>
101 #include <svx/unoapi.hxx>
102 #include <svx/unoshape.hxx>
103 #include <svx/sdtaitm.hxx>
104
105 using namespace ::oox::core;
106 using namespace ::com::sun::star;
107 using namespace ::com::sun::star::uno;
108 using namespace ::com::sun::star::beans;
109 using namespace ::com::sun::star::frame;
110 using namespace ::com::sun::star::text;
111 using namespace ::com::sun::star::drawing;
112 using namespace ::com::sun::star::style;
113
114 namespace oox::drawingml {
115
Shape(const char * pServiceName,bool bDefaultHeight)116 Shape::Shape( const char* pServiceName, bool bDefaultHeight )
117 : mpLinePropertiesPtr( std::make_shared<LineProperties>() )
118 , mpShapeRefLinePropPtr( std::make_shared<LineProperties>() )
119 , mpFillPropertiesPtr( std::make_shared<FillProperties>() )
120 , mpShapeRefFillPropPtr( std::make_shared<FillProperties>() )
121 , mpGraphicPropertiesPtr( std::make_shared<GraphicProperties>() )
122 , mpCustomShapePropertiesPtr( std::make_shared<CustomShapeProperties>() )
123 , mp3DPropertiesPtr( std::make_shared<Shape3DProperties>() )
124 , mpEffectPropertiesPtr( std::make_shared<EffectProperties>() )
125 , mpShapeRefEffectPropPtr( std::make_shared<EffectProperties>() )
126 , mpMasterTextListStyle( std::make_shared<TextListStyle>() )
127 , mnSubType( 0 )
128 , meFrameType( FRAMETYPE_GENERIC )
129 , mnRotation( 0 )
130 , mnDiagramRotation( 0 )
131 , mbFlipH( false )
132 , mbFlipV( false )
133 , mbHidden( false )
134 , mbHiddenMasterShape( false )
135 , mbLocked( false )
136 , mbLockedCanvas( false )
137 , mbWps( false )
138 , mbTextBox( false )
139 , mbHasLinkedTxbx( false )
140 , maDiagramDoms( 0 )
141 {
142 if ( pServiceName )
143 msServiceName = OUString::createFromAscii( pServiceName );
144 setDefaults(bDefaultHeight);
145 }
146
Shape(const ShapePtr & pSourceShape)147 Shape::Shape( const ShapePtr& pSourceShape )
148 : maChildren()
149 , mpTextBody(pSourceShape->mpTextBody)
150 , mpLinePropertiesPtr( pSourceShape->mpLinePropertiesPtr )
151 , mpShapeRefLinePropPtr( pSourceShape->mpShapeRefLinePropPtr )
152 , mpFillPropertiesPtr( pSourceShape->mpFillPropertiesPtr )
153 , mpShapeRefFillPropPtr( pSourceShape->mpShapeRefFillPropPtr )
154 , mpGraphicPropertiesPtr( pSourceShape->mpGraphicPropertiesPtr )
155 , mpCustomShapePropertiesPtr( pSourceShape->mpCustomShapePropertiesPtr )
156 , mpTablePropertiesPtr( pSourceShape->mpTablePropertiesPtr )
157 , mp3DPropertiesPtr( pSourceShape->mp3DPropertiesPtr )
158 , mpEffectPropertiesPtr (pSourceShape->mpEffectPropertiesPtr)
159 , mpShapeRefEffectPropPtr(pSourceShape->mpShapeRefEffectPropPtr)
160 , maShapeProperties( pSourceShape->maShapeProperties )
161 , mpMasterTextListStyle( pSourceShape->mpMasterTextListStyle )
162 , mxShape()
163 , msServiceName( pSourceShape->msServiceName )
164 , msName( pSourceShape->msName )
165 , msInternalName( pSourceShape->msInternalName )
166 , msId( pSourceShape->msId )
167 , mnSubType( pSourceShape->mnSubType )
168 , moSubTypeIndex( pSourceShape->moSubTypeIndex )
169 , maShapeStyleRefs( pSourceShape->maShapeStyleRefs )
170 , maSize( pSourceShape->maSize )
171 , maPosition( pSourceShape->maPosition )
172 , meFrameType( pSourceShape->meFrameType )
173 , mnRotation( pSourceShape->mnRotation )
174 , mnDiagramRotation( pSourceShape->mnDiagramRotation )
175 , mbFlipH( pSourceShape->mbFlipH )
176 , mbFlipV( pSourceShape->mbFlipV )
177 , mbHidden( pSourceShape->mbHidden )
178 , mbHiddenMasterShape( pSourceShape->mbHiddenMasterShape )
179 , mbLocked( pSourceShape->mbLocked )
180 , mbLockedCanvas( pSourceShape->mbLockedCanvas )
181 , mbWps( pSourceShape->mbWps )
182 , mbTextBox( pSourceShape->mbTextBox )
183 , maLinkedTxbxAttr()
184 , mbHasLinkedTxbx(false)
185 , maDiagramDoms( pSourceShape->maDiagramDoms )
186 , mnZOrder(pSourceShape->mnZOrder)
187 , mnZOrderOff(pSourceShape->mnZOrderOff)
188 , mnDataNodeType(pSourceShape->mnDataNodeType)
189 , mfAspectRatio(pSourceShape->mfAspectRatio)
190 , mbUseBgFill(pSourceShape->mbUseBgFill)
191 , maDiagramFontHeights(pSourceShape->maDiagramFontHeights)
192 {}
193
~Shape()194 Shape::~Shape()
195 {
196 }
197
getTableProperties()198 table::TablePropertiesPtr const & Shape::getTableProperties()
199 {
200 if ( !mpTablePropertiesPtr )
201 mpTablePropertiesPtr = std::make_shared<table::TableProperties>();
202 return mpTablePropertiesPtr;
203 }
204
setDefaults(bool bHeight)205 void Shape::setDefaults(bool bHeight)
206 {
207 maDefaultShapeProperties.setProperty(PROP_TextAutoGrowHeight, false);
208 maDefaultShapeProperties.setProperty(PROP_TextWordWrap, true);
209 maDefaultShapeProperties.setProperty(PROP_TextLeftDistance, static_cast< sal_Int32 >( 250 ));
210 maDefaultShapeProperties.setProperty(PROP_TextUpperDistance, static_cast< sal_Int32 >( 125 ));
211 maDefaultShapeProperties.setProperty(PROP_TextRightDistance, static_cast< sal_Int32 >( 250 ));
212 maDefaultShapeProperties.setProperty(PROP_TextLowerDistance, static_cast< sal_Int32 >( 125 ));
213 if (bHeight)
214 maDefaultShapeProperties.setProperty(PROP_CharHeight, static_cast< float >( 18.0 ));
215 maDefaultShapeProperties.setProperty(PROP_TextVerticalAdjust, TextVerticalAdjust_TOP);
216 maDefaultShapeProperties.setProperty(PROP_ParaAdjust,
217 static_cast<sal_Int16>(ParagraphAdjust_LEFT));
218 }
219
setOleObjectType()220 ::oox::vml::OleObjectInfo& Shape::setOleObjectType()
221 {
222 OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setOleObjectType - multiple frame types" );
223 meFrameType = FRAMETYPE_OLEOBJECT;
224 mxOleObjectInfo = std::make_shared<::oox::vml::OleObjectInfo>( true );
225 return *mxOleObjectInfo;
226 }
227
setChartType(bool bEmbedShapes)228 ChartShapeInfo& Shape::setChartType( bool bEmbedShapes )
229 {
230 OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setChartType - multiple frame types" );
231 meFrameType = FRAMETYPE_CHART;
232 if (mbWps)
233 msServiceName = "com.sun.star.drawing.temporaryForXMLImportOLE2Shape";
234 else
235 msServiceName = "com.sun.star.drawing.OLE2Shape";
236 mxChartShapeInfo = std::make_shared<ChartShapeInfo>( bEmbedShapes );
237 return *mxChartShapeInfo;
238 }
239
setDiagramType()240 void Shape::setDiagramType()
241 {
242 OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setDiagramType - multiple frame types" );
243 meFrameType = FRAMETYPE_DIAGRAM;
244 msServiceName = "com.sun.star.drawing.GroupShape";
245 mnSubType = 0;
246 }
247
setTableType()248 void Shape::setTableType()
249 {
250 OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setTableType - multiple frame types" );
251 meFrameType = FRAMETYPE_TABLE;
252 msServiceName = "com.sun.star.drawing.TableShape";
253 mnSubType = 0;
254 }
255
setServiceName(const char * pServiceName)256 void Shape::setServiceName( const char* pServiceName )
257 {
258 if ( pServiceName )
259 msServiceName = OUString::createFromAscii( pServiceName );
260 }
261
getShapeStyleRef(sal_Int32 nRefType) const262 const ShapeStyleRef* Shape::getShapeStyleRef( sal_Int32 nRefType ) const
263 {
264 ShapeStyleRefMap::const_iterator aIt = maShapeStyleRefs.find( nRefType );
265 return (aIt == maShapeStyleRefs.end()) ? nullptr : &aIt->second;
266 }
267
addShape(::oox::core::XmlFilterBase & rFilterBase,const Theme * pTheme,const Reference<XShapes> & rxShapes,const basegfx::B2DHomMatrix & aTransformation,FillProperties & rShapeOrParentShapeFillProps,ShapeIdMap * pShapeMap,oox::drawingml::ShapePtr pParentGroupShape)268 void Shape::addShape(
269 ::oox::core::XmlFilterBase& rFilterBase,
270 const Theme* pTheme,
271 const Reference< XShapes >& rxShapes,
272 const basegfx::B2DHomMatrix& aTransformation,
273 FillProperties& rShapeOrParentShapeFillProps,
274 ShapeIdMap* pShapeMap,
275 oox::drawingml::ShapePtr pParentGroupShape)
276 {
277 SAL_INFO("oox.drawingml", "Shape::addShape: id='" << msId << "'");
278
279 try
280 {
281 OUString sServiceName( msServiceName );
282 if( !sServiceName.isEmpty() )
283 {
284 basegfx::B2DHomMatrix aMatrix( aTransformation );
285 Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, pTheme, rxShapes, false, false, aMatrix, rShapeOrParentShapeFillProps, pParentGroupShape) );
286
287 if( pShapeMap && !msId.isEmpty() )
288 {
289 (*pShapeMap)[ msId ] = shared_from_this();
290 }
291
292 // if this is a group shape, we have to add also each child shape
293 Reference< XShapes > xShapes( xShape, UNO_QUERY );
294 if ( xShapes.is() )
295 addChildren( rFilterBase, *this, pTheme, xShapes, pShapeMap, aMatrix );
296
297 if( meFrameType == FRAMETYPE_DIAGRAM )
298 {
299 keepDiagramCompatibilityInfo();
300
301 // Check if this is the PPTX import, so far converting SmartArt to a non-editable
302 // metafile is only imlemented for DOCX.
303 bool bPowerPoint = dynamic_cast<oox::ppt::PowerPointImport*>(&rFilterBase) != nullptr;
304
305 if (!SvtFilterOptions::Get().IsSmartArt2Shape() && !bPowerPoint)
306 convertSmartArtToMetafile( rFilterBase );
307 }
308
309 NamedShapePairs* pNamedShapePairs = rFilterBase.getDiagramFontHeights();
310 if (xShape.is() && pNamedShapePairs)
311 {
312 auto itPairs = pNamedShapePairs->find(getInternalName());
313 if (itPairs != pNamedShapePairs->end())
314 {
315 auto it = itPairs->second.find(shared_from_this());
316 if (it != itPairs->second.end())
317 {
318 // Our drawingml::Shape is in the list of an internal name, remember the now
319 // inserted XShape.
320 it->second = xShape;
321 }
322 }
323 }
324 }
325 }
326 catch( const Exception& )
327 {
328 TOOLS_WARN_EXCEPTION( "oox.drawingml", "Shape::addShape" );
329 }
330 }
331
setLockedCanvas(bool bLockedCanvas)332 void Shape::setLockedCanvas(bool bLockedCanvas)
333 {
334 mbLockedCanvas = bLockedCanvas;
335 }
336
setWps(bool bWps)337 void Shape::setWps(bool bWps)
338 {
339 mbWps = bWps;
340 }
341
setTextBox(bool bTextBox)342 void Shape::setTextBox(bool bTextBox)
343 {
344 mbTextBox = bTextBox;
345 }
346
applyShapeReference(const Shape & rReferencedShape,bool bUseText)347 void Shape::applyShapeReference( const Shape& rReferencedShape, bool bUseText )
348 {
349 SAL_INFO("oox.drawingml", "Shape::applyShapeReference: apply '" << rReferencedShape.msId << "' to '" << msId << "'");
350
351 if ( rReferencedShape.mpTextBody && bUseText )
352 mpTextBody = std::make_shared<TextBody>( *rReferencedShape.mpTextBody );
353 else
354 mpTextBody.reset();
355 maShapeProperties = rReferencedShape.maShapeProperties;
356 mpShapeRefLinePropPtr = std::make_shared<LineProperties>( rReferencedShape.getActualLineProperties(nullptr) );
357 mpShapeRefFillPropPtr = std::make_shared<FillProperties>( rReferencedShape.getActualFillProperties(nullptr, nullptr) );
358 mpCustomShapePropertiesPtr = std::make_shared<CustomShapeProperties>( *rReferencedShape.mpCustomShapePropertiesPtr );
359 mpTablePropertiesPtr = rReferencedShape.mpTablePropertiesPtr ? std::make_shared<table::TableProperties>( *rReferencedShape.mpTablePropertiesPtr ) : nullptr;
360 mpShapeRefEffectPropPtr = std::make_shared<EffectProperties>( rReferencedShape.getActualEffectProperties(nullptr) );
361 mpMasterTextListStyle = std::make_shared<TextListStyle>( *rReferencedShape.mpMasterTextListStyle );
362 maSize = rReferencedShape.maSize;
363 maPosition = rReferencedShape.maPosition;
364 mnRotation = rReferencedShape.mnRotation;
365 mbFlipH = rReferencedShape.mbFlipH;
366 mbFlipV = rReferencedShape.mbFlipV;
367 mbHidden = rReferencedShape.mbHidden;
368 mbLocked = rReferencedShape.mbLocked;
369 }
370
371 namespace {
372
373 struct ActionLockGuard
374 {
ActionLockGuardoox::drawingml::__anonaedc5fb80111::ActionLockGuard375 explicit ActionLockGuard(Reference<drawing::XShape> const& xShape)
376 : m_xLockable(xShape, UNO_QUERY)
377 {
378 if (m_xLockable.is()) {
379 m_xLockable->addActionLock();
380 }
381 }
~ActionLockGuardoox::drawingml::__anonaedc5fb80111::ActionLockGuard382 ~ActionLockGuard()
383 {
384 if (m_xLockable.is()) {
385 m_xLockable->removeActionLock();
386 }
387 }
388 private:
389 Reference<document::XActionLockable> m_xLockable;
390 };
391
392 }
393
394 // for group shapes, the following method is also adding each child
addChildren(XmlFilterBase & rFilterBase,Shape & rMaster,const Theme * pTheme,const Reference<XShapes> & rxShapes,ShapeIdMap * pShapeMap,const basegfx::B2DHomMatrix & aTransformation)395 void Shape::addChildren(
396 XmlFilterBase& rFilterBase,
397 Shape& rMaster,
398 const Theme* pTheme,
399 const Reference< XShapes >& rxShapes,
400 ShapeIdMap* pShapeMap,
401 const basegfx::B2DHomMatrix& aTransformation )
402 {
403 for (auto const& child : rMaster.maChildren)
404 {
405 child->setMasterTextListStyle( mpMasterTextListStyle );
406 child->addShape( rFilterBase, pTheme, rxShapes, aTransformation, getFillProperties(), pShapeMap, rMaster.shared_from_this());
407 }
408 }
409
lcl_resetPropertyValue(std::vector<beans::PropertyValue> & rPropVec,const OUString & rName)410 static void lcl_resetPropertyValue( std::vector<beans::PropertyValue>& rPropVec, const OUString& rName )
411 {
412 auto aIterator = std::find_if( rPropVec.begin(), rPropVec.end(),
413 [rName]( const beans::PropertyValue& rValue ) { return rValue.Name == rName; } );
414
415 if (aIterator != rPropVec.end())
416 rPropVec.erase( aIterator );
417 }
418
lcl_setPropertyValue(std::vector<beans::PropertyValue> & rPropVec,const OUString & rName,const beans::PropertyValue & rPropertyValue)419 static void lcl_setPropertyValue( std::vector<beans::PropertyValue>& rPropVec,
420 const OUString& rName,
421 const beans::PropertyValue& rPropertyValue )
422 {
423 lcl_resetPropertyValue( rPropVec, rName );
424
425 rPropVec.push_back( rPropertyValue );
426 }
427
lcl_convertAdjust(ParagraphAdjust eAdjust)428 static SdrTextHorzAdjust lcl_convertAdjust( ParagraphAdjust eAdjust )
429 {
430 if (eAdjust == ParagraphAdjust_LEFT)
431 return SDRTEXTHORZADJUST_LEFT;
432 else if (eAdjust == ParagraphAdjust_RIGHT)
433 return SDRTEXTHORZADJUST_RIGHT;
434 else if (eAdjust == ParagraphAdjust_CENTER)
435 return SDRTEXTHORZADJUST_CENTER;
436 return SDRTEXTHORZADJUST_LEFT;
437 }
438
lcl_createPresetShape(const uno::Reference<drawing::XShape> & xShape,const OUString & rClass,const OUString & rPresetType,const CustomShapePropertiesPtr & pCustomShapePropertiesPtr,const TextBodyPtr & pTextBody,const GraphicHelper & rGraphicHelper)439 static void lcl_createPresetShape(const uno::Reference<drawing::XShape>& xShape,
440 const OUString& rClass, const OUString& rPresetType,
441 const CustomShapePropertiesPtr& pCustomShapePropertiesPtr,
442 const TextBodyPtr& pTextBody,
443 const GraphicHelper& rGraphicHelper)
444 {
445 if (!xShape.is() || !pCustomShapePropertiesPtr || !pTextBody)
446 return;
447
448 uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter( xShape,
449 uno::UNO_QUERY );
450
451 if (!xDefaulter.is() || rClass.isEmpty())
452 return;
453
454 Reference<XPropertySet> xSet( xShape, UNO_QUERY );
455 if (!xSet.is())
456 return;
457
458 // The DrawingML shapes from the presetTextWarpDefinitions are mapped to the definitions
459 // in svx/../EnhancedCustomShapeGeometry.cxx, which are used for WordArt shapes from
460 // binary MS Office. Therefore all adjustment values need to be adapted.
461 auto aAdjGdList = pCustomShapePropertiesPtr->getAdjustmentGuideList();
462 Sequence<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustment(
463 !aAdjGdList.empty() ? aAdjGdList.size() : 1 );
464
465 int nIndex = 0;
466 for (const auto& aEntry : aAdjGdList)
467 {
468 double fValue = aEntry.maFormula.toDouble();
469 // then: polar-handle, else: XY-handle
470 // There exist only 8 polar-handles at all in presetTextWarp.
471 if ((rClass == "fontwork-arch-down-curve")
472 || (rClass == "fontwork-arch-down-pour" && aEntry.maName == "adj1")
473 || (rClass == "fontwork-arch-up-curve")
474 || (rClass == "fontwork-arch-up-pour" && aEntry.maName == "adj1")
475 || (rClass == "fontwork-open-circle-curve")
476 || (rClass == "fontwork-open-circle-pour" && aEntry.maName == "adj1")
477 || (rClass == "fontwork-circle-curve")
478 || (rClass == "fontwork-circle-pour" && aEntry.maName == "adj1"))
479 {
480 // DrawingML has 1/60000 degree unit, but WordArt simple degree. Range [0..360[
481 // or range ]-180..180] doesn't matter, because only cos(angle) and
482 // sin(angle) are used.
483 fValue = NormAngle360(fValue / 60000.0);
484 }
485 else
486 {
487 // DrawingML writes adjustment guides as relative value with 100% = 100000,
488 // but WordArt definitions use values absolute in viewBox 0 0 21600 21600,
489 // so scale with 21600/100000 = 0.216, with two exceptions:
490 // X-handles of waves describe increase/decrease relative to horizontal center.
491 // The gdRefR of pour-shapes is not relative to viewBox but to radius.
492 if ((rClass == "mso-spt158" && aEntry.maName == "adj2") // textDoubleWave1
493 || (rClass == "fontwork-wave" && aEntry.maName == "adj2") // textWave1
494 || (rClass == "mso-spt157" && aEntry.maName == "adj2") // textWave2
495 || (rClass == "mso-spt159" && aEntry.maName == "adj2")) // textWave4
496 {
497 fValue = (fValue + 50000.0) * 0.216;
498 }
499 else if ( (rClass == "fontwork-arch-down-pour" && aEntry.maName == "adj2")
500 || (rClass == "fontwork-arch-up-pour" && aEntry.maName == "adj2")
501 || (rClass == "fontwork-open-circle-pour" && aEntry.maName == "adj2")
502 || (rClass == "fontwork-circle-pour" && aEntry.maName == "adj2"))
503 {
504 fValue *= 0.108;
505 }
506 else
507 {
508 fValue *= 0.216;
509 }
510 }
511
512 aAdjustment[nIndex].Value <<= fValue;
513 aAdjustment[nIndex++].State = css::beans::PropertyState_DIRECT_VALUE;
514 }
515
516 // Set properties
517 xSet->setPropertyValue( UNO_NAME_TEXT_AUTOGROWHEIGHT, uno::makeAny( false ) );
518 xSet->setPropertyValue( UNO_NAME_TEXT_AUTOGROWWIDTH, uno::makeAny( false ) );
519 xSet->setPropertyValue( UNO_NAME_FILLSTYLE, uno::makeAny( drawing::FillStyle_SOLID ) );
520
521 // ToDo: Old binary WordArt does not allow different styles for different paragraphs, so it
522 // was not necessary to examine all paragraphs. Solution for DrawingML is needed.
523 // Currently different alignment of paragraphs are lost, for example.
524 const TextParagraphVector& rParagraphs = pTextBody->getParagraphs();
525 if (!rParagraphs.empty() && !rParagraphs[0]->getRuns().empty())
526 {
527 std::shared_ptr<TextParagraph> pParagraph = rParagraphs[0];
528 std::shared_ptr<TextRun> pRun = pParagraph->getRuns()[0];
529 TextCharacterProperties& pProperties = pRun->getTextCharacterProperties();
530
531 if (pProperties.moBold.has() && pProperties.moBold.get())
532 {
533 xSet->setPropertyValue( UNO_NAME_CHAR_WEIGHT, uno::makeAny( css::awt::FontWeight::BOLD ) );
534 }
535 if (pProperties.moItalic.has() && pProperties.moItalic.get())
536 {
537 xSet->setPropertyValue( UNO_NAME_CHAR_POSTURE, uno::makeAny( css::awt::FontSlant::FontSlant_ITALIC ) );
538 }
539 if (pProperties.moHeight.has())
540 {
541 sal_Int32 nHeight = pProperties.moHeight.get() / 100;
542 xSet->setPropertyValue( UNO_NAME_CHAR_HEIGHT, uno::makeAny( nHeight ) );
543 }
544 if (pProperties.maFillProperties.maFillColor.isUsed())
545 {
546 const sal_Int32 aFillColor = static_cast<sal_Int32>(
547 pProperties.maFillProperties.maFillColor.getColor( rGraphicHelper ).GetRGBColor() );
548 xSet->setPropertyValue( UNO_NAME_FILLCOLOR, uno::makeAny( aFillColor ) );
549 }
550 else
551 {
552 // Set default color
553 xSet->setPropertyValue( UNO_NAME_FILLCOLOR, uno::makeAny( COL_BLACK ) );
554 }
555 {
556 ParagraphAdjust eAdjust = ParagraphAdjust_LEFT;
557 if (pParagraph->getProperties().getParaAdjust())
558 eAdjust = *pParagraph->getProperties().getParaAdjust();
559 xSet->setPropertyValue( "ParaAdjust", uno::makeAny( eAdjust ) );
560 SdrObject* pShape = SdrObject::getSdrObjectFromXShape( xShape );
561 assert(pShape);
562 SdrTextHorzAdjust eHorzAdjust = lcl_convertAdjust( eAdjust );
563 pShape->SetMergedItem( SdrTextHorzAdjustItem( eHorzAdjust ) );
564 }
565 }
566
567 // Apply vertical adjustment for text on arc
568 // ToDo: The property is currently not evaluated.
569 SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape);
570 assert(pShape);
571 if (rClass == "fontwork-arch-up-curve" || rClass == "fontwork-circle-curve")
572 pShape->SetMergedItem( SdrTextVertAdjustItem( SdrTextVertAdjust::SDRTEXTVERTADJUST_BOTTOM ) );
573 else if (rClass == "fontwork-arch-down-curve")
574 pShape->SetMergedItem( SdrTextVertAdjustItem( SdrTextVertAdjust::SDRTEXTVERTADJUST_TOP ) );
575
576 // Apply preset shape
577 xDefaulter->createCustomShapeDefaults( rClass );
578
579 auto aGeomPropSeq = xSet->getPropertyValue( "CustomShapeGeometry" )
580 .get<uno::Sequence<beans::PropertyValue>>();
581 auto aGeomPropVec
582 = comphelper::sequenceToContainer<std::vector<beans::PropertyValue>>(
583 aGeomPropSeq );
584
585 // Reset old properties
586 static const OUStringLiteral sTextPath( u"TextPath" );
587 static const OUStringLiteral sAdjustmentValues( u"AdjustmentValues" );
588 static const OUStringLiteral sPresetTextWarp( u"PresetTextWarp" );
589
590 lcl_resetPropertyValue( aGeomPropVec, "CoordinateSize" );
591 lcl_resetPropertyValue( aGeomPropVec, "Equations" );
592 lcl_resetPropertyValue( aGeomPropVec, "Path" );
593 lcl_resetPropertyValue( aGeomPropVec, sAdjustmentValues);
594
595 bool bFromWordArt(false);
596 pTextBody->getTextProperties().maPropertyMap.getProperty(PROP_FromWordArt) >>= bFromWordArt;
597
598 bool bScaleX(false);
599 if (!bFromWordArt
600 && (rPresetType == "textArchDown" || rPresetType == "textArchUp"
601 || rPresetType == "textCircle" || rPresetType == "textButton"))
602 {
603 bScaleX = true;
604 }
605
606 // Apply geometry properties
607 uno::Sequence<beans::PropertyValue> aPropertyValues(
608 comphelper::InitPropertySequence(
609 { { sTextPath, uno::makeAny( true ) },
610 { "TextPathMode",
611 uno::Any( drawing::EnhancedCustomShapeTextPathMode_PATH ) },
612 { "ScaleX", uno::Any(bScaleX) } } ) );
613
614 lcl_setPropertyValue( aGeomPropVec, sTextPath,
615 comphelper::makePropertyValue( sTextPath, aPropertyValues ) );
616
617 lcl_setPropertyValue( aGeomPropVec, sPresetTextWarp,
618 comphelper::makePropertyValue( sPresetTextWarp, rPresetType ) );
619
620 if (!aAdjGdList.empty())
621 {
622 lcl_setPropertyValue( aGeomPropVec, sAdjustmentValues,
623 comphelper::makePropertyValue( sAdjustmentValues, aAdjustment ) );
624 }
625
626 xSet->setPropertyValue(
627 "CustomShapeGeometry",
628 uno::makeAny(comphelper::containerToSequence(aGeomPropVec)));
629 }
630
631 // Some helper methods for createAndInsert
632 namespace
633 {
634 // mirrors aTransformation at its center axis
635 // only valid if neither rotation or shear included
lcl_mirrorAtCenter(basegfx::B2DHomMatrix & aTransformation,bool bFlipH,bool bFlipV)636 void lcl_mirrorAtCenter(basegfx::B2DHomMatrix& aTransformation, bool bFlipH, bool bFlipV)
637 {
638 if (!bFlipH && !bFlipV)
639 return;
640 basegfx::B2DPoint aCenter(0.5, 0.5);
641 aCenter *= aTransformation;
642 aTransformation.translate(-aCenter);
643 aTransformation.scale(bFlipH ? -1.0 : 1.0, bFlipV ? -1.0 : 1.0);
644 aTransformation.translate(aCenter);
645 return;
646 }
647
648 // only valid if neither rotation or shear included
lcl_doSpecialMSOWidthHeightToggle(basegfx::B2DHomMatrix & aTransformation)649 void lcl_doSpecialMSOWidthHeightToggle(basegfx::B2DHomMatrix& aTransformation)
650 {
651 // The values are directly set at the matrix without any matrix multiplication.
652 // That way it is valid for lines too. Those have zero width or height.
653 const double fSx(aTransformation.get(0, 0));
654 const double fSy(aTransformation.get(1, 1));
655 const double fTx(aTransformation.get(0, 2));
656 const double fTy(aTransformation.get(1, 2));
657 aTransformation.set(0, 0, fSy);
658 aTransformation.set(1, 1, fSx);
659 aTransformation.set(0, 2, fTx + 0.5 * (fSx - fSy));
660 aTransformation.set(1, 2, fTy + 0.5 * (fSy - fSx));
661 return;
662 }
663
lcl_RotateAtCenter(basegfx::B2DHomMatrix & aTransformation,const sal_Int32 & rMSORotationAngle)664 void lcl_RotateAtCenter(basegfx::B2DHomMatrix& aTransformation, const sal_Int32& rMSORotationAngle)
665 {
666 if (rMSORotationAngle == 0)
667 return;
668 double fRad = basegfx::deg2rad(rMSORotationAngle / 60000.0);
669 basegfx::B2DPoint aCenter(0.5, 0.5);
670 aCenter *= aTransformation;
671 aTransformation.translate(-aCenter);
672 aTransformation.rotate(fRad);
673 aTransformation.translate(aCenter);
674 return;
675 }
676 }
677
createAndInsert(::oox::core::XmlFilterBase & rFilterBase,const OUString & rServiceName,const Theme * pTheme,const css::uno::Reference<css::drawing::XShapes> & rxShapes,bool bClearText,bool bDoNotInsertEmptyTextBody,basegfx::B2DHomMatrix & aParentTransformation,FillProperties & rShapeOrParentShapeFillProps,oox::drawingml::ShapePtr pParentGroupShape)678 Reference< XShape > const & Shape::createAndInsert(
679 ::oox::core::XmlFilterBase& rFilterBase,
680 const OUString& rServiceName,
681 const Theme* pTheme,
682 const css::uno::Reference< css::drawing::XShapes >& rxShapes,
683 bool bClearText,
684 bool bDoNotInsertEmptyTextBody,
685 basegfx::B2DHomMatrix& aParentTransformation,
686 FillProperties& rShapeOrParentShapeFillProps,
687 oox::drawingml::ShapePtr pParentGroupShape)
688 {
689 bool bIsEmbMedia = false;
690 SAL_INFO("oox.drawingml", "Shape::createAndInsert: id='" << msId << "' service='" << rServiceName << "'");
691
692 formulaimport::XmlStreamBuilder * pMathXml(nullptr);
693 if (mpTextBody)
694 {
695 for (auto const& it : mpTextBody->getParagraphs())
696 {
697 if (it->HasMathXml())
698 {
699 if (!mpTextBody->isEmpty() || pMathXml != nullptr)
700 {
701 SAL_WARN("oox.drawingml", "losing a Math object...");
702 }
703 else
704 {
705 pMathXml = &it->GetMathXml();
706 }
707 }
708 }
709 }
710
711 // tdf#90403 PowerPoint ignores a:ext cx and cy values of p:xfrm, and uses real table width and height
712 if ( mpTablePropertiesPtr && rServiceName == "com.sun.star.drawing.TableShape" )
713 {
714 maSize.Width = 0;
715 for (auto const& elem : mpTablePropertiesPtr->getTableGrid())
716 {
717 maSize.Width = o3tl::saturating_add(maSize.Width, static_cast<sal_Int32>(elem));
718 }
719 maSize.Height = 0;
720 for (auto const& elem : mpTablePropertiesPtr->getTableRows())
721 {
722 maSize.Height = o3tl::saturating_add(maSize.Height, elem.getHeight());
723 }
724 }
725
726 awt::Rectangle aShapeRectHmm(
727 o3tl::convert(maPosition.X, o3tl::Length::emu, o3tl::Length::mm100),
728 o3tl::convert(maPosition.Y, o3tl::Length::emu, o3tl::Length::mm100),
729 o3tl::convert(maSize.Width, o3tl::Length::emu, o3tl::Length::mm100),
730 o3tl::convert(maSize.Height, o3tl::Length::emu, o3tl::Length::mm100));
731
732 OUString aServiceName;
733 if (pMathXml)
734 {
735 // convert this shape to OLE
736 aServiceName = "com.sun.star.drawing.OLE2Shape";
737 msServiceName = aServiceName;
738 meFrameType = FRAMETYPE_GENERIC; // not OLEOBJECT, no stream in package
739 mnSubType = 0;
740 }
741 else if (rServiceName == "com.sun.star.drawing.GraphicObjectShape" &&
742 mpGraphicPropertiesPtr && !mpGraphicPropertiesPtr->m_sMediaPackageURL.isEmpty())
743 {
744 aServiceName = finalizeServiceName( rFilterBase, "com.sun.star.presentation.MediaShape", aShapeRectHmm );
745 bIsEmbMedia = true;
746 }
747 else
748 {
749 aServiceName = finalizeServiceName( rFilterBase, rServiceName, aShapeRectHmm );
750 }
751 // Use custom shape instead of GraphicObjectShape if the image is cropped to
752 // shape. Except rectangle, which does not require further cropping
753 bool bIsCroppedGraphic = (aServiceName == "com.sun.star.drawing.GraphicObjectShape" &&
754 (mpCustomShapePropertiesPtr->getShapePresetType() >= 0 || mpCustomShapePropertiesPtr->getPath2DList().size() > 0) &&
755 mpCustomShapePropertiesPtr->getShapePresetType() != XML_Rect &&
756 mpCustomShapePropertiesPtr->getShapePresetType() != XML_rect);
757 // ToDo: Why is ConnectorShape here treated as custom shape, but below with start and end point?
758 bool bIsCustomShape = ( aServiceName == "com.sun.star.drawing.CustomShape" ||
759 aServiceName == "com.sun.star.drawing.ConnectorShape" ||
760 bIsCroppedGraphic);
761 if(bIsCroppedGraphic)
762 {
763 aServiceName = "com.sun.star.drawing.CustomShape";
764 mpGraphicPropertiesPtr->mbIsCustomShape = true;
765 }
766 bool bUseRotationTransform = ( !mbWps ||
767 aServiceName == "com.sun.star.drawing.LineShape" ||
768 aServiceName == "com.sun.star.drawing.GroupShape" ||
769 mbFlipH ||
770 mbFlipV );
771
772 basegfx::B2DHomMatrix aTransformation; // will be cumulative transformation of this object
773
774 // Special for SmartArt import. Rotate diagram's shape around object's center before sizing.
775 if (bUseRotationTransform && mnDiagramRotation != 0)
776 {
777 aTransformation.translate(-0.5, -0.5);
778 aTransformation.rotate(basegfx::deg2rad(mnDiagramRotation / 60000.0));
779 aTransformation.translate(0.5, 0.5);
780 }
781
782 // Build object matrix from shape size and position; corresponds to MSO ext and off
783 // Only LineShape and ConnectorShape may have zero width or height.
784 if (aServiceName == "com.sun.star.drawing.LineShape"
785 || aServiceName == "com.sun.star.drawing.ConnectorShape")
786 aTransformation.scale(maSize.Width, maSize.Height);
787 else
788 {
789 aTransformation.scale(maSize.Width ? maSize.Width : 1.0,
790 maSize.Height ? maSize.Height : 1.0);
791 }
792
793 // Evaluate object flip. Other shapes than custom shapes have no attribute for flip but use
794 // negative scale. Flip in MSO is at object center.
795 if (!bIsCustomShape && (mbFlipH || mbFlipV))
796 lcl_mirrorAtCenter(aTransformation, mbFlipH, mbFlipV);
797
798 // Evaluate parent flip.
799 // A CustomShape has mirror not as negative scale, but as attributes.
800 basegfx::B2DVector aParentScale(1.0, 1.0);
801 basegfx::B2DVector aParentTranslate(0.0, 0.0);
802 double fParentRotate(0.0);
803 double fParentShearX(0.0);
804 if (pParentGroupShape)
805 {
806 aParentTransformation.decompose(aParentScale, aParentTranslate, fParentRotate, fParentShearX);
807 if (bIsCustomShape)
808 {
809 lcl_mirrorAtCenter(aTransformation, aParentScale.getX() < 0, aParentScale.getY() < 0);
810 if(aParentScale.getX() < 0)
811 mbFlipH = !mbFlipH;
812 if(aParentScale.getY() < 0)
813 mbFlipV = !mbFlipV;
814 }
815 }
816
817 if (maPosition.X != 0 || maPosition.Y != 0)
818 {
819 // if global position is used, add it to transformation
820 if (mbWps && pParentGroupShape == nullptr)
821 aTransformation.translate(
822 o3tl::convert(maPosition.X, o3tl::Length::mm100, o3tl::Length::emu),
823 o3tl::convert(maPosition.Y, o3tl::Length::mm100, o3tl::Length::emu));
824 else
825 aTransformation.translate(maPosition.X, maPosition.Y);
826 }
827
828 // Apply further parent transformations. First scale object then rotate. Other way round would
829 // introduce shearing.
830
831 // The attributes chExt and chOff of the group in oox file contain the values on which the size
832 // and position of the child is based on. If they differ from the actual size of the group as
833 // given in its ext and off attributes, the child has to be transformed according the new values.
834 if (pParentGroupShape)
835 {
836 // ToDo: A diagram in a group might need special handling because it cannot flip and only
837 // resize uniformly. But currently it is imported with zero size, see tdf#139575. That needs
838 // to be fixed beforehand.
839
840 // Scaling is done from left/top edges of the group. So these need to become coordinate axes.
841 aTransformation.translate(-pParentGroupShape->maChPosition.X,
842 -pParentGroupShape->maChPosition.Y);
843
844 // oox allows zero or missing attribute chExt. In that case the scaling factor is 1.
845 // Transform2DContext::onCreateContext has set maChSize to maSize for groups in oox file in
846 // such cases. For own made groups (e.g. diagrams) that is missing.
847 // The factors cumulate on the way through the parent groups, so we do not use maSize of the
848 // direct parent group but the cumulated value from aParentScale.
849 double fFactorX = 1.0;
850 double fFactorY = 1.0;
851 if (pParentGroupShape->maChSize.Width != 0)
852 fFactorX = aParentScale.getX() / pParentGroupShape->maChSize.Width;
853 if (pParentGroupShape->maChSize.Height != 0)
854 fFactorY = aParentScale.getY() / pParentGroupShape->maChSize.Height;
855 if (fFactorX != 1 || fFactorY != 1)
856 {
857 // It depends on the object rotation angle whether scaling is applied to switched
858 // width and height. MSO acts strange in that case (as of May 2021).
859 const sal_Int32 nDeg(mnRotation / 60000);
860 const bool bNeedsMSOWidhtHeightToggle
861 = (nDeg >= 45 && nDeg < 135) || (nDeg >= 225 && nDeg < 315);
862 if (bNeedsMSOWidhtHeightToggle)
863 lcl_doSpecialMSOWidthHeightToggle(aTransformation);
864
865 aTransformation.scale(fFactorX, fFactorY);
866
867 if (bNeedsMSOWidhtHeightToggle)
868 {
869 lcl_doSpecialMSOWidthHeightToggle(aTransformation);
870 // In case of flip the special case needs an additional 180deg rotation.
871 if ((aParentScale.getX() < 0) != (aParentScale.getY() < 0))
872 lcl_RotateAtCenter(aTransformation, 10800000);
873 }
874 }
875 }
876
877 // Apply object rotation at current object center
878 // The flip contained in aParentScale will affect orientation of object rotation angle.
879 sal_Int16 nOrientation = ((aParentScale.getX() < 0) != (aParentScale.getY() < 0)) ? -1 : 1;
880 // ToDo: Not sure about the restrictions given by bUseRotationTransform.
881 if (bUseRotationTransform && mnRotation != 0)
882 lcl_RotateAtCenter(aTransformation, nOrientation * mnRotation);
883
884 if (fParentRotate != 0.0)
885 aTransformation.rotate(fParentRotate);
886 if (!aParentTranslate.equalZero())
887 aTransformation.translate(aParentTranslate);
888
889 aParentTransformation = aTransformation;
890
891 constexpr double fEmuToMm100 = o3tl::convert(1.0, o3tl::Length::emu, o3tl::Length::mm100);
892 aTransformation.scale(fEmuToMm100, fEmuToMm100);
893
894 // OOXML flips shapes before rotating them, so the rotation needs to be inverted
895 if( bIsCustomShape && mbFlipH != mbFlipV )
896 {
897 basegfx::B2DVector aScale, aTranslate;
898 double fRotate, fShearX;
899 aTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
900
901 if(fRotate != 0)
902 {
903 basegfx::B2DPoint aCenter(0.5, 0.5);
904 aCenter *= aTransformation;
905 aTransformation.translate( -aCenter.getX(), -aCenter.getY() );
906 aTransformation.rotate( fRotate * -2.0 );
907 aTransformation.translate( aCenter.getX(), aCenter.getY() );
908 }
909 }
910
911 // special for lineshape
912 if ( aServiceName == "com.sun.star.drawing.LineShape" )
913 {
914 ::basegfx::B2DPolygon aPoly;
915 aPoly.insert( 0, ::basegfx::B2DPoint( 0, 0 ) );
916 aPoly.insert( 1, ::basegfx::B2DPoint( maSize.Width ? 1 : 0, maSize.Height ? 1 : 0 ) );
917 aPoly.transform( aTransformation );
918
919 // now creating the corresponding PolyPolygon
920 sal_Int32 i, nNumPoints = aPoly.count();
921 uno::Sequence< awt::Point > aPointSequence( nNumPoints );
922 awt::Point* pPoints = aPointSequence.getArray();
923 uno::Reference<lang::XServiceInfo> xModelInfo(rFilterBase.getModel(), uno::UNO_QUERY);
924 for( i = 0; i < nNumPoints; ++i )
925 {
926 basegfx::B2DPoint aPoint( aPoly.getB2DPoint( i ) );
927
928 // Guard against zero width or height.
929 if (i)
930 {
931 const basegfx::B2DPoint& rPreviousPoint = aPoly.getB2DPoint(i - 1);
932 if (aPoint.getX() - rPreviousPoint.getX() == 0)
933 aPoint.setX(aPoint.getX() + 1);
934 if (aPoint.getY() - rPreviousPoint.getY() == 0)
935 aPoint.setY(aPoint.getY() + 1);
936 }
937
938 pPoints[i] = awt::Point(static_cast<sal_Int32>(aPoint.getX()), static_cast<sal_Int32>(aPoint.getY()));
939 }
940 uno::Sequence< uno::Sequence< awt::Point > > aPolyPolySequence( 1 );
941 aPolyPolySequence.getArray()[ 0 ] = aPointSequence;
942
943 maShapeProperties.setProperty(PROP_PolyPolygon, aPolyPolySequence);
944 }
945 else if ( aServiceName == "com.sun.star.drawing.ConnectorShape" )
946 {
947 ::basegfx::B2DPolygon aPoly;
948 aPoly.insert( 0, ::basegfx::B2DPoint( 0, 0 ) );
949 aPoly.insert( 1, ::basegfx::B2DPoint( maSize.Width ? 1 : 0, maSize.Height ? 1 : 0 ) );
950 aPoly.transform( aTransformation );
951
952 basegfx::B2DPoint aStartPosition( aPoly.getB2DPoint( 0 ) );
953 basegfx::B2DPoint aEndPosition( aPoly.getB2DPoint( 1 ) );
954 awt::Point aAWTStartPosition( static_cast< sal_Int32 >( aStartPosition.getX() ), static_cast< sal_Int32 >( aStartPosition.getY() ) );
955 awt::Point aAWTEndPosition( static_cast< sal_Int32 >( aEndPosition.getX() ), static_cast< sal_Int32 >( aEndPosition.getY() ) );
956
957 maShapeProperties.setProperty(PROP_StartPosition, aAWTStartPosition);
958 maShapeProperties.setProperty(PROP_EndPosition, aAWTEndPosition);
959 }
960 else
961 {
962 // now set transformation for this object
963 HomogenMatrix3 aMatrix;
964
965 aMatrix.Line1.Column1 = aTransformation.get(0,0);
966 aMatrix.Line1.Column2 = aTransformation.get(0,1);
967 aMatrix.Line1.Column3 = aTransformation.get(0,2);
968
969 aMatrix.Line2.Column1 = aTransformation.get(1,0);
970 aMatrix.Line2.Column2 = aTransformation.get(1,1);
971 aMatrix.Line2.Column3 = aTransformation.get(1,2);
972
973 aMatrix.Line3.Column1 = aTransformation.get(2,0);
974 aMatrix.Line3.Column2 = aTransformation.get(2,1);
975 aMatrix.Line3.Column3 = aTransformation.get(2,2);
976
977 maShapeProperties.setProperty(PROP_Transformation, aMatrix);
978 }
979
980 Reference< lang::XMultiServiceFactory > xServiceFact( rFilterBase.getModel(), UNO_QUERY_THROW );
981 if ( !mxShape.is() )
982 {
983 mxShape.set( xServiceFact->createInstance( aServiceName ), UNO_QUERY_THROW );
984 if (aServiceName == "com.sun.star.drawing.GroupShape")
985 {
986 // TODO why is this necessary? A newly created group shape should have an empty
987 // grab-bag.
988 uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
989 beans::PropertyValues aVals;
990 xPropertySet->setPropertyValue("InteropGrabBag", uno::makeAny(aVals));
991 }
992 }
993
994 Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
995 if (xSet.is())
996 {
997 if( !msName.isEmpty() )
998 {
999 Reference< container::XNamed > xNamed( mxShape, UNO_QUERY );
1000 if( xNamed.is() )
1001 xNamed->setName( msName );
1002 }
1003 if( !msDescription.isEmpty() )
1004 {
1005 xSet->setPropertyValue( "Description", Any( msDescription ) );
1006 }
1007 if (aServiceName != "com.sun.star.text.TextFrame")
1008 rxShapes->add( mxShape );
1009
1010 if ( mbHidden || mbHiddenMasterShape )
1011 {
1012 SAL_INFO("oox.drawingml", "Shape::createAndInsert: invisible shape with id='" << msId << "'");
1013 xSet->setPropertyValue( "Visible", Any( false ) );
1014 // In Excel hidden means not printed, let's use visibility for now until that's handled separately
1015 xSet->setPropertyValue( "Printable", Any( false ) );
1016 }
1017
1018 if (mbLocked)
1019 {
1020 xSet->setPropertyValue("MoveProtect", Any(true));
1021 xSet->setPropertyValue("SizeProtect", Any(true));
1022 }
1023
1024 ActionLockGuard const alg(mxShape);
1025
1026 // sj: removing default text of placeholder objects such as SlideNumberShape or HeaderShape
1027 if ( bClearText )
1028 {
1029 uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY );
1030 if ( xText.is() )
1031 {
1032 xText->setString( "" );
1033 }
1034 }
1035
1036 if (pMathXml)
1037 {
1038 // the "EmbeddedObject" property is read-only, so we have to create
1039 // the shape first, and it can be read only after the shape is
1040 // inserted into the document, so delay the actual import until here
1041 SvGlobalName name(SO3_SM_CLASSID);
1042 xSet->setPropertyValue("CLSID", uno::makeAny(name.GetHexName()));
1043 uno::Reference<embed::XEmbeddedObject> const xObj(
1044 xSet->getPropertyValue("EmbeddedObject"), uno::UNO_QUERY);
1045 if (xObj.is())
1046 {
1047 uno::Reference<uno::XInterface> const xMathModel(xObj->getComponent());
1048 oox::FormulaImportBase *const pMagic(
1049 dynamic_cast<oox::FormulaImportBase*>(xMathModel.get()));
1050 assert(pMagic);
1051 pMagic->readFormulaOoxml(*pMathXml);
1052 }
1053 }
1054
1055 const GraphicHelper& rGraphicHelper = rFilterBase.getGraphicHelper();
1056
1057 ::Color nLinePhClr(ColorTransparency, 0xffffffff);
1058 ::Color nFillPhClr(ColorTransparency, 0xffffffff);
1059 // TODO: use ph color when applying effect properties
1060 //sal_Int32 nEffectPhClr = -1;
1061
1062 // dmapper needs the original rotation angle for calculating square wrap. This angle is not
1063 // available as property there, so store it in InteropGrabBag.
1064 putPropertyToGrabBag("mso-rotation-angle", Any(mnRotation));
1065
1066 if( pTheme )
1067 {
1068 if( const ShapeStyleRef* pLineRef = getShapeStyleRef( XML_lnRef ) )
1069 {
1070 LineProperties aLineProperties;
1071 aLineProperties.maLineFill.moFillType = XML_noFill;
1072 if( const LineProperties* pLineProps = pTheme->getLineStyle( pLineRef->mnThemedIdx ) )
1073 aLineProperties.assignUsed( *pLineProps );
1074 nLinePhClr = pLineRef->maPhClr.getColor( rGraphicHelper );
1075
1076 // Store style-related properties to InteropGrabBag to be able to export them back
1077 uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
1078 {
1079 {"SchemeClr", uno::makeAny(pLineRef->maPhClr.getSchemeName())},
1080 {"Idx", uno::makeAny(pLineRef->mnThemedIdx)},
1081 {"Color", uno::makeAny(nLinePhClr)},
1082 {"LineStyle", uno::makeAny(aLineProperties.getLineStyle())},
1083 {"LineCap", uno::makeAny(aLineProperties.getLineCap())},
1084 {"LineJoint", uno::makeAny(aLineProperties.getLineJoint())},
1085 {"LineWidth", uno::makeAny(aLineProperties.getLineWidth())},
1086 {"Transformations", uno::makeAny(pLineRef->maPhClr.getTransformations())}
1087 });
1088 putPropertyToGrabBag( "StyleLnRef", Any( aProperties ) );
1089 }
1090 if( const ShapeStyleRef* pFillRef = getShapeStyleRef( XML_fillRef ) )
1091 {
1092 if (!mbUseBgFill)
1093 {
1094 nFillPhClr = pFillRef->maPhClr.getColor(rGraphicHelper);
1095 }
1096
1097 OUString sColorScheme = pFillRef->maPhClr.getSchemeName();
1098 if( !sColorScheme.isEmpty() )
1099 {
1100 uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
1101 {
1102 {"SchemeClr", uno::makeAny(sColorScheme)},
1103 {"Idx", uno::makeAny(pFillRef->mnThemedIdx)},
1104 {"Color", uno::makeAny(nFillPhClr)},
1105 {"Transformations", uno::makeAny(pFillRef->maPhClr.getTransformations())}
1106 });
1107
1108 putPropertyToGrabBag( "StyleFillRef", Any( aProperties ) );
1109 }
1110 }
1111 if( const ShapeStyleRef* pEffectRef = getShapeStyleRef( XML_effectRef ) )
1112 {
1113 // TODO: use ph color when applying effect properties
1114 // nEffectPhClr = pEffectRef->maPhClr.getColor( rGraphicHelper );
1115
1116 // Store style-related properties to InteropGrabBag to be able to export them back
1117 uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
1118 {
1119 {"SchemeClr", uno::makeAny(pEffectRef->maPhClr.getSchemeName())},
1120 {"Idx", uno::makeAny(pEffectRef->mnThemedIdx)},
1121 {"Transformations", uno::makeAny(pEffectRef->maPhClr.getTransformations())}
1122 });
1123 putPropertyToGrabBag( "StyleEffectRef", Any( aProperties ) );
1124 }
1125 }
1126 ShapePropertyMap aShapeProps( rFilterBase.getModelObjectHelper() );
1127
1128 // add properties from textbody to shape properties
1129 if( mpTextBody )
1130 {
1131 mpTextBody->getTextProperties().pushRotationAdjustments();
1132 aShapeProps.assignUsed( mpTextBody->getTextProperties().maPropertyMap );
1133 // Push char properties as well - specifically useful when this is a placeholder
1134 if( mpMasterTextListStyle && mpMasterTextListStyle->getListStyle()[0].getTextCharacterProperties().moHeight.has() )
1135 aShapeProps.setProperty(PROP_CharHeight, GetFontHeight( mpMasterTextListStyle->getListStyle()[0].getTextCharacterProperties().moHeight.get() ));
1136 }
1137
1138 // applying properties
1139 aShapeProps.assignUsed( getShapeProperties() );
1140 aShapeProps.assignUsed( maDefaultShapeProperties );
1141 if(mnRotation != 0 && bIsCustomShape)
1142 aShapeProps.setProperty( PROP_RotateAngle, sal_Int32( NormAngle36000( Degree100(mnRotation / -600) ) ));
1143 if( bIsEmbMedia ||
1144 bIsCustomShape ||
1145 aServiceName == "com.sun.star.drawing.GraphicObjectShape" ||
1146 aServiceName == "com.sun.star.drawing.OLE2Shape")
1147 {
1148 mpGraphicPropertiesPtr->pushToPropMap( aShapeProps, rGraphicHelper, mbFlipH, mbFlipV );
1149 }
1150 if ( mpTablePropertiesPtr && aServiceName == "com.sun.star.drawing.TableShape" )
1151 mpTablePropertiesPtr->pushToPropSet( rFilterBase, xSet, mpMasterTextListStyle );
1152
1153 FillProperties aFillProperties = getActualFillProperties(pTheme, &rShapeOrParentShapeFillProps);
1154 if (getFillProperties().moFillType.has() && getFillProperties().moFillType.get() == XML_grpFill)
1155 getFillProperties().assignUsed(aFillProperties);
1156 if(!bIsCroppedGraphic)
1157 aFillProperties.pushToPropMap( aShapeProps, rGraphicHelper, mnRotation, nFillPhClr, mbFlipH, mbFlipV, bIsCustomShape );
1158 LineProperties aLineProperties = getActualLineProperties(pTheme);
1159 aLineProperties.pushToPropMap( aShapeProps, rGraphicHelper, nLinePhClr );
1160 EffectProperties aEffectProperties = getActualEffectProperties(pTheme);
1161 // TODO: use ph color when applying effect properties
1162 aEffectProperties.pushToPropMap( aShapeProps, rGraphicHelper );
1163
1164 // applying autogrowheight property before setting shape size, because
1165 // the shape size might be changed if currently autogrowheight is true
1166 // we must also check that the PropertySet supports the property.
1167 Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
1168 const OUString& rPropName = PropertyMap::getPropertyName( PROP_TextAutoGrowHeight );
1169 if( xSetInfo.is() && xSetInfo->hasPropertyByName( rPropName ) )
1170 if( aShapeProps.hasProperty( PROP_TextAutoGrowHeight ) )
1171 xSet->setPropertyValue( rPropName, Any( false ) );
1172
1173 // do not set properties at a group shape (this causes
1174 // assertions from svx) ...
1175 if( aServiceName != "com.sun.star.drawing.GroupShape" )
1176 {
1177 if (aServiceName == "com.sun.star.text.TextFrame")
1178 {
1179 if (mpCustomShapePropertiesPtr && mpCustomShapePropertiesPtr->getShapeTypeOverride())
1180 {
1181 uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1182 uno::Sequence<beans::PropertyValue> aGrabBag;
1183 propertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
1184 sal_Int32 length = aGrabBag.getLength();
1185 aGrabBag.realloc( length+1);
1186 aGrabBag[length].Name = "mso-orig-shape-type";
1187 uno::Sequence< sal_Int8 > const & aNameSeq =
1188 mpCustomShapePropertiesPtr->getShapePresetTypeName();
1189 OUString sShapePresetTypeName(reinterpret_cast< const char* >(
1190 aNameSeq.getConstArray()), aNameSeq.getLength(), RTL_TEXTENCODING_UTF8);
1191 aGrabBag[length].Value <<= sShapePresetTypeName;
1192 propertySet->setPropertyValue("FrameInteropGrabBag",uno::makeAny(aGrabBag));
1193 }
1194 //If the text box has links then save the link information so that
1195 //it can be accessed in DomainMapper_Impl.cxx while chaining the text frames.
1196 if (isLinkedTxbx())
1197 {
1198 uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1199 uno::Sequence<beans::PropertyValue> aGrabBag;
1200 propertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
1201 sal_Int32 length = aGrabBag.getLength();
1202 aGrabBag.realloc( length + 3 );
1203 aGrabBag[length].Name = "TxbxHasLink";
1204 aGrabBag[length].Value <<= isLinkedTxbx();
1205 aGrabBag[length + 1 ].Name = "Txbx-Id";
1206 aGrabBag[length + 1 ].Value <<= getLinkedTxbxAttributes().id;
1207 aGrabBag[length + 2 ].Name = "Txbx-Seq";
1208 aGrabBag[length + 2 ].Value <<= getLinkedTxbxAttributes().seq;
1209 propertySet->setPropertyValue("FrameInteropGrabBag",uno::makeAny(aGrabBag));
1210 }
1211
1212 // TextFrames have BackColor, not FillColor
1213 if (aShapeProps.hasProperty(PROP_FillColor))
1214 {
1215 aShapeProps.setAnyProperty(PROP_BackColor, aShapeProps.getProperty(PROP_FillColor));
1216 aShapeProps.erase(PROP_FillColor);
1217 }
1218 // TextFrames have BackColorTransparency, not FillTransparence
1219 if (aShapeProps.hasProperty(PROP_FillTransparence))
1220 {
1221 aShapeProps.setAnyProperty(PROP_BackColorTransparency, aShapeProps.getProperty(PROP_FillTransparence));
1222 aShapeProps.erase(PROP_FillTransparence);
1223 }
1224 // TextFrames have BackGraphic, not FillBitmap
1225 if (aShapeProps.hasProperty(PROP_FillBitmap))
1226 {
1227 aShapeProps.setAnyProperty(PROP_BackGraphic, aShapeProps.getProperty(PROP_FillBitmap));
1228 aShapeProps.erase(PROP_FillBitmap);
1229 }
1230 if (aShapeProps.hasProperty(PROP_FillBitmapName))
1231 {
1232 uno::Any aAny = aShapeProps.getProperty(PROP_FillBitmapName);
1233 OUString aFillBitmapName = aAny.get<OUString>();
1234 uno::Reference<awt::XBitmap> xBitmap = rFilterBase.getModelObjectHelper().getFillBitmap(aFillBitmapName);
1235 uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY);
1236 aShapeProps.setProperty(PROP_BackGraphic, xGraphic);
1237 // aShapeProps.erase(PROP_FillBitmapName); // Maybe, leave the name as well
1238 }
1239 // And no LineColor property; individual borders can have colors
1240 if (aShapeProps.hasProperty(PROP_LineColor))
1241 {
1242 uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
1243 static const sal_Int32 aBorders[] =
1244 {
1245 PROP_TopBorder, PROP_LeftBorder, PROP_BottomBorder, PROP_RightBorder
1246 };
1247 for (sal_Int32 nBorder : aBorders)
1248 {
1249 css::table::BorderLine2 aBorderLine = xPropertySet->getPropertyValue(PropertyMap::getPropertyName(nBorder)).get<css::table::BorderLine2>();
1250 aBorderLine.Color = aShapeProps.getProperty(PROP_LineColor).get<sal_Int32>();
1251 if (aLineProperties.moLineWidth.has())
1252 aBorderLine.LineWidth = convertEmuToHmm(aLineProperties.moLineWidth.get());
1253 aShapeProps.setProperty(nBorder, aBorderLine);
1254 }
1255 aShapeProps.erase(PROP_LineColor);
1256 }
1257 if(mnRotation)
1258 {
1259 uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
1260 static const OUStringLiteral aGrabBagPropName = u"FrameInteropGrabBag";
1261 uno::Sequence<beans::PropertyValue> aGrabBag;
1262 xPropertySet->getPropertyValue(aGrabBagPropName) >>= aGrabBag;
1263 beans::PropertyValue aPair;
1264 aPair.Name = "mso-rotation-angle";
1265 aPair.Value <<= mnRotation;
1266 if (aGrabBag.hasElements())
1267 {
1268 sal_Int32 nLength = aGrabBag.getLength();
1269 aGrabBag.realloc(nLength + 1);
1270 aGrabBag[nLength] = aPair;
1271 }
1272 else
1273 {
1274 aGrabBag.realloc(1);
1275 aGrabBag[0] = aPair;
1276 }
1277 xPropertySet->setPropertyValue(aGrabBagPropName, uno::makeAny(aGrabBag));
1278 }
1279 // TextFrames have ShadowFormat, not individual shadow properties.
1280 std::optional<sal_Int32> oShadowDistance;
1281 if (aShapeProps.hasProperty(PROP_ShadowXDistance))
1282 {
1283 oShadowDistance = aShapeProps.getProperty(PROP_ShadowXDistance).get<sal_Int32>();
1284 aShapeProps.erase(PROP_ShadowXDistance);
1285 }
1286 if (aShapeProps.hasProperty(PROP_ShadowYDistance))
1287 {
1288 // There is a single 'dist' attribute, so no need to count the avg of x and y.
1289 aShapeProps.erase(PROP_ShadowYDistance);
1290 }
1291 std::optional<sal_Int32> oShadowColor;
1292 if (aShapeProps.hasProperty(PROP_ShadowColor))
1293 {
1294 oShadowColor = aShapeProps.getProperty(PROP_ShadowColor).get<sal_Int32>();
1295 aShapeProps.erase(PROP_ShadowColor);
1296 }
1297 if (aShapeProps.hasProperty(PROP_Shadow))
1298 aShapeProps.erase(PROP_Shadow);
1299
1300 if (oShadowDistance || oShadowColor || aEffectProperties.maShadow.moShadowDir.has())
1301 {
1302 css::table::ShadowFormat aFormat;
1303 if (oShadowColor)
1304 aFormat.Color = *oShadowColor;
1305 if (aEffectProperties.maShadow.moShadowDir.has())
1306 {
1307 css::table::ShadowLocation nLocation = css::table::ShadowLocation_NONE;
1308 switch (aEffectProperties.maShadow.moShadowDir.get())
1309 {
1310 case 13500000:
1311 nLocation = css::table::ShadowLocation_TOP_LEFT;
1312 break;
1313 case 18900000:
1314 nLocation = css::table::ShadowLocation_TOP_RIGHT;
1315 break;
1316 case 8100000:
1317 nLocation = css::table::ShadowLocation_BOTTOM_LEFT;
1318 break;
1319 case 2700000:
1320 nLocation = css::table::ShadowLocation_BOTTOM_RIGHT;
1321 break;
1322 }
1323 aFormat.Location = nLocation;
1324 }
1325 aFormat.ShadowWidth = *oShadowDistance;
1326 aShapeProps.setProperty(PROP_ShadowFormat, aFormat);
1327 }
1328
1329 }
1330 else if (mbTextBox)
1331 {
1332 aShapeProps.setProperty(PROP_TextBox, true);
1333 }
1334
1335 if (aServiceName != "com.sun.star.text.TextFrame" && isLinkedTxbx())
1336 {
1337 uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1338 uno::Sequence<beans::PropertyValue> aGrabBag;
1339 propertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
1340 sal_Int32 length = aGrabBag.getLength();
1341 aGrabBag.realloc( length + 3 );
1342 aGrabBag[length].Name = "TxbxHasLink";
1343 aGrabBag[length].Value <<= isLinkedTxbx();
1344 aGrabBag[length + 1 ].Name = "Txbx-Id";
1345 aGrabBag[length + 1 ].Value <<= getLinkedTxbxAttributes().id;
1346 aGrabBag[length + 2 ].Name = "Txbx-Seq";
1347 aGrabBag[length + 2 ].Value <<= getLinkedTxbxAttributes().seq;
1348 propertySet->setPropertyValue("InteropGrabBag",uno::makeAny(aGrabBag));
1349 }
1350
1351 // If the shape is a picture placeholder.
1352 if (aServiceName == "com.sun.star.presentation.GraphicObjectShape" && !bClearText)
1353 {
1354 // Placeholder text should be in center of the shape.
1355 aShapeProps.setProperty(PROP_TextContourFrame, false);
1356
1357 /* Placeholder icon should be at the center of the parent shape.
1358 * We use negative graphic crop property because of that we don't
1359 * have padding support.
1360 */
1361 uno::Reference<beans::XPropertySet> xGraphic(xSet->getPropertyValue("Graphic"), uno::UNO_QUERY);
1362 if (xGraphic.is())
1363 {
1364 awt::Size aBitmapSize;
1365 xGraphic->getPropertyValue("Size100thMM") >>= aBitmapSize;
1366 sal_Int32 nXMargin = (aShapeRectHmm.Width - aBitmapSize.Width) / 2;
1367 sal_Int32 nYMargin = (aShapeRectHmm.Height - aBitmapSize.Height) / 2;
1368 if (nXMargin > 0 && nYMargin > 0)
1369 {
1370 text::GraphicCrop aGraphicCrop;
1371 aGraphicCrop.Top = nYMargin * -1;
1372 aGraphicCrop.Bottom = nYMargin * -1;
1373 aGraphicCrop.Left = nXMargin * -1;
1374 aGraphicCrop.Right = nXMargin * -1;
1375 aShapeProps.setProperty(PROP_GraphicCrop, aGraphicCrop);
1376 }
1377 }
1378 }
1379
1380 PropertySet( xSet ).setProperties( aShapeProps );
1381 if (mbLockedCanvas)
1382 {
1383 putPropertyToGrabBag( "LockedCanvas", Any( true ) );
1384 if (aServiceName == "com.sun.star.drawing.LineShape")
1385 {
1386 // It seems the position and size for lines inside a locked canvas is absolute.
1387 mxShape->setPosition(awt::Point(aShapeRectHmm.X, aShapeRectHmm.Y));
1388 mxShape->setSize(awt::Size(aShapeRectHmm.Width, aShapeRectHmm.Height));
1389 }
1390 }
1391
1392 // Store original fill and line colors of the shape and the theme color name to InteropGrabBag
1393 std::vector<beans::PropertyValue> aProperties;
1394 aProperties.push_back(comphelper::makePropertyValue("EmuLineWidth", aLineProperties.moLineWidth.get(0)));
1395 aProperties.push_back(comphelper::makePropertyValue("OriginalSolidFillClr", aShapeProps.getProperty(PROP_FillColor)));
1396 aProperties.push_back(comphelper::makePropertyValue("OriginalLnSolidFillClr", aShapeProps.getProperty(PROP_LineColor)));
1397 OUString sColorFillScheme = aFillProperties.maFillColor.getSchemeName();
1398 if( !aFillProperties.maFillColor.isPlaceHolder() && !sColorFillScheme.isEmpty() )
1399 {
1400 aProperties.push_back(comphelper::makePropertyValue("SpPrSolidFillSchemeClr", sColorFillScheme));
1401 aProperties.push_back(comphelper::makePropertyValue("SpPrSolidFillSchemeClrTransformations", aFillProperties.maFillColor.getTransformations()));
1402 }
1403 OUString sLnColorFillScheme = aLineProperties.maLineFill.maFillColor.getSchemeName();
1404 if( !aLineProperties.maLineFill.maFillColor.isPlaceHolder() && !sLnColorFillScheme.isEmpty() )
1405 {
1406 aProperties.push_back(comphelper::makePropertyValue("SpPrLnSolidFillSchemeClr", sLnColorFillScheme));
1407 auto aResolvedSchemeClr = aLineProperties.maLineFill.maFillColor;
1408 aResolvedSchemeClr.clearTransformations();
1409 aProperties.push_back(comphelper::makePropertyValue("SpPrLnSolidFillResolvedSchemeClr", aResolvedSchemeClr.getColor(rGraphicHelper, nFillPhClr)));
1410 aProperties.push_back(comphelper::makePropertyValue("SpPrLnSolidFillSchemeClrTransformations", aLineProperties.maLineFill.maFillColor.getTransformations()));
1411 }
1412 putPropertiesToGrabBag(comphelper::containerToSequence(aProperties));
1413
1414 // Store original gradient fill of the shape to InteropGrabBag
1415 // LibreOffice doesn't support all the kinds of gradient so we save its complete definition
1416 if( aShapeProps.hasProperty( PROP_FillGradient ) )
1417 {
1418 std::vector<beans::PropertyValue> aGradientStops;
1419 size_t i = 0;
1420 for( const auto& [rPos, rColor] : aFillProperties.maGradientProps.maGradientStops )
1421 { // for each stop in the gradient definition:
1422
1423 // save position
1424 std::vector<beans::PropertyValue> aGradientStop;
1425 aGradientStop.push_back(comphelper::makePropertyValue("Pos", rPos));
1426
1427 OUString sStopColorScheme = rColor.getSchemeName();
1428 if( sStopColorScheme.isEmpty() )
1429 {
1430 // save RGB color
1431 aGradientStop.push_back(comphelper::makePropertyValue("RgbClr", rColor.getColor(rGraphicHelper, nFillPhClr)));
1432 // in the case of a RGB color, transformations are already applied to
1433 // the color with the exception of alpha transformations. We only need
1434 // to keep the transparency value to calculate the alpha value later.
1435 if( rColor.hasTransparency() )
1436 aGradientStop.push_back(comphelper::makePropertyValue("Transparency", rColor.getTransparency()));
1437 }
1438 else
1439 {
1440 // save color with scheme name
1441 aGradientStop.push_back(comphelper::makePropertyValue("SchemeClr", sStopColorScheme));
1442 // save all color transformations
1443 aGradientStop.push_back(comphelper::makePropertyValue("Transformations", rColor.getTransformations()));
1444 }
1445
1446 aGradientStops.push_back(comphelper::makePropertyValue(OUString::number(i), comphelper::containerToSequence(aGradientStop)));
1447 ++i;
1448 }
1449 // If getFillProperties.moFillType is unused that means gradient is defined by a theme
1450 // which is already saved into StyleFillRef property, so no need to save the explicit values too
1451 if( getFillProperties().moFillType.has() )
1452 putPropertyToGrabBag( "GradFillDefinition", uno::Any(comphelper::containerToSequence(aGradientStops)));
1453 putPropertyToGrabBag( "OriginalGradFill", aShapeProps.getProperty(PROP_FillGradient) );
1454 }
1455
1456 // store unsupported effect attributes in the grab bag
1457 if (!aEffectProperties.m_Effects.empty())
1458 {
1459 std::vector<beans::PropertyValue> aEffects;
1460 sal_uInt32 i = 0;
1461 for (auto const& it : aEffectProperties.m_Effects)
1462 {
1463 PropertyValue aEffect = it->getEffect();
1464 if( !aEffect.Name.isEmpty() )
1465 {
1466 std::vector<beans::PropertyValue> aEffectsGrabBag;
1467 aEffectsGrabBag.push_back(comphelper::makePropertyValue("Attribs", aEffect.Value));
1468
1469 Color& aColor( it->moColor );
1470 OUString sColorScheme = aColor.getSchemeName();
1471 if( sColorScheme.isEmpty() )
1472 {
1473 // RGB color and transparency value
1474 aEffectsGrabBag.push_back(comphelper::makePropertyValue("RgbClr", aColor.getColor(rGraphicHelper, nFillPhClr)));
1475 aEffectsGrabBag.push_back(comphelper::makePropertyValue("RgbClrTransparency", aColor.getTransparency()));
1476 }
1477 else
1478 {
1479 // scheme color with name and transformations
1480 aEffectsGrabBag.push_back(comphelper::makePropertyValue("SchemeClr", sColorScheme));
1481 aEffectsGrabBag.push_back(comphelper::makePropertyValue("SchemeClrTransformations", aColor.getTransformations()));
1482 }
1483 aEffects.push_back(comphelper::makePropertyValue(aEffect.Name, comphelper::containerToSequence(aEffectsGrabBag)));
1484 ++i;
1485 }
1486 }
1487 putPropertyToGrabBag("EffectProperties", uno::Any(comphelper::containerToSequence(aEffects)));
1488 }
1489
1490 // add 3D effects if any
1491 Sequence< PropertyValue > aCamera3DEffects = get3DProperties().getCameraAttributes();
1492 Sequence< PropertyValue > aLightRig3DEffects = get3DProperties().getLightRigAttributes();
1493 Sequence< PropertyValue > aShape3DEffects = get3DProperties().getShape3DAttributes( rGraphicHelper, nFillPhClr );
1494 if( aCamera3DEffects.hasElements() || aLightRig3DEffects.hasElements() || aShape3DEffects.hasElements() )
1495 {
1496 uno::Sequence<beans::PropertyValue> a3DEffectsGrabBag = comphelper::InitPropertySequence(
1497 {
1498 {"Camera", uno::makeAny(aCamera3DEffects)},
1499 {"LightRig", uno::makeAny(aLightRig3DEffects)},
1500 {"Shape3D", uno::makeAny(aShape3DEffects)}
1501 });
1502 putPropertyToGrabBag( "3DEffectProperties", Any( a3DEffectsGrabBag ) );
1503 }
1504
1505 if( bIsCustomShape && getTextBody())
1506 {
1507
1508 Sequence< PropertyValue > aTextCamera3DEffects = getTextBody()->get3DProperties().getCameraAttributes();
1509 Sequence< PropertyValue > aTextLightRig3DEffects = getTextBody()->get3DProperties().getLightRigAttributes();
1510 Sequence< PropertyValue > aTextShape3DEffects = getTextBody()->get3DProperties().getShape3DAttributes( rGraphicHelper, nFillPhClr );
1511 if( aTextCamera3DEffects.hasElements() || aTextLightRig3DEffects.hasElements() || aTextShape3DEffects.hasElements() )
1512 {
1513 uno::Sequence<beans::PropertyValue> aText3DEffectsGrabBag = comphelper::InitPropertySequence(
1514 {
1515 {"Camera", uno::makeAny(aTextCamera3DEffects)},
1516 {"LightRig", uno::makeAny(aTextLightRig3DEffects)},
1517 {"Shape3D", uno::makeAny(aTextShape3DEffects)}
1518 });
1519 putPropertyToGrabBag( "Text3DEffectProperties", Any( aText3DEffectsGrabBag ) );
1520 }
1521 }
1522
1523 // store bitmap artistic effects in the grab bag
1524 if( !mpGraphicPropertiesPtr->maBlipProps.maEffect.isEmpty() )
1525 putPropertyToGrabBag( "ArtisticEffectProperties",
1526 Any( mpGraphicPropertiesPtr->maBlipProps.maEffect.getEffect() ) );
1527 }
1528
1529 else if( mbLockedCanvas )
1530 {
1531 //If we have aServiceName as "com.sun.star.drawing.GroupShape" and lockedCanvas
1532 putPropertyToGrabBag( "LockedCanvas", Any( true ) );
1533 }
1534
1535 // These can have a custom geometry, so position should be set here,
1536 // after creation but before custom shape handling, using the position
1537 // we got from the caller.
1538 if (mbWps && aServiceName == "com.sun.star.drawing.LineShape")
1539 mxShape->setPosition(maPosition);
1540
1541 if( bIsCustomShape )
1542 {
1543 if ( mbFlipH )
1544 mpCustomShapePropertiesPtr->setMirroredX( true );
1545 if ( mbFlipV )
1546 mpCustomShapePropertiesPtr->setMirroredY( true );
1547 if( getTextBody() )
1548 {
1549 sal_Int32 nTextCameraZRotation = static_cast< sal_Int32 >( getTextBody()->get3DProperties().maCameraRotation.mnRevolution.get() );
1550 mpCustomShapePropertiesPtr->setTextCameraZRotateAngle( nTextCameraZRotation / 60000 );
1551
1552 sal_Int32 nTextRotateAngle = static_cast< sal_Int32 >( getTextBody()->getTextProperties().moRotation.get( 0 ) );
1553
1554 nTextRotateAngle -= mnDiagramRotation;
1555 /* OOX measures text rotation clockwise in 1/60000th degrees,
1556 relative to the containing shape. setTextRotateAngle wants degrees anticlockwise. */
1557 nTextRotateAngle = -1 * nTextRotateAngle / 60000;
1558
1559 if (getTextBody()->getTextProperties().moUpright)
1560 {
1561 // When upright is set, we want the text without any rotation.
1562 // But if we set 0 here, the text is still rotated if the
1563 // shape containing it is rotated.
1564 // Hence, we rotate the text into the opposite direction of
1565 // the rotation of the shape, by as much as the shape was rotated.
1566 mpCustomShapePropertiesPtr->setTextRotateAngle((mnRotation / 60000) + nTextRotateAngle);
1567 // Also put the initial angles away in a GrabBag.
1568 putPropertyToGrabBag("Upright", Any(true));
1569 putPropertyToGrabBag("nShapeRotationAtImport", Any(mnRotation / 60000));
1570 putPropertyToGrabBag("nTextRotationAtImport", Any(nTextRotateAngle));
1571 }
1572 else
1573 {
1574 mpCustomShapePropertiesPtr->setTextRotateAngle(nTextRotateAngle);
1575 }
1576
1577 auto sHorzOverflow = getTextBody()->getTextProperties().msHorzOverflow;
1578 if (!sHorzOverflow.isEmpty())
1579 putPropertyToGrabBag("horzOverflow", uno::makeAny(getTextBody()->getTextProperties().msHorzOverflow));
1580 auto nVertOverflow = getTextBody()->getTextProperties().msVertOverflow;
1581 if (!nVertOverflow.isEmpty())
1582 putPropertyToGrabBag("vertOverflow", uno::makeAny(getTextBody()->getTextProperties().msVertOverflow));
1583 }
1584
1585 // Note that the script oox/source/drawingml/customshapes/generatePresetsData.pl looks
1586 // for these ==cscode== and ==csdata== markers, so don't "clean up" these SAL_INFOs
1587 SAL_INFO("oox.cscode", "==cscode== shape name: '" << msName << "'");
1588 SAL_INFO("oox.csdata", "==csdata== shape name: '" << msName << "'");
1589 mpCustomShapePropertiesPtr->pushToPropSet( xSet, mxShape, maSize );
1590
1591 if (mpTextBody)
1592 {
1593 bool bIsPresetShape = !mpTextBody->getTextProperties().msPrst.isEmpty();
1594 if (bIsPresetShape)
1595 {
1596 OUString sClass;
1597 const OUString sPresetType = mpTextBody->getTextProperties().msPrst;
1598 sClass = PresetGeometryTypeNames::GetFontworkType( sPresetType );
1599
1600 lcl_createPresetShape( mxShape, sClass, sPresetType, mpCustomShapePropertiesPtr, mpTextBody, rGraphicHelper );
1601 }
1602 }
1603 }
1604 else if( getTextBody() )
1605 getTextBody()->getTextProperties().pushVertSimulation();
1606
1607 // tdf#133037: a bit hackish: force Shape to rotate in the opposite direction the camera would rotate
1608 const sal_Int32 nCameraRotation = get3DProperties().maCameraRotation.mnRevolution.get(0);
1609
1610 PropertySet aPropertySet(mxShape);
1611 if ( !bUseRotationTransform && (mnRotation != 0 || nCameraRotation != 0) )
1612 {
1613 // use the same logic for rotation from VML exporter (SimpleShape::implConvertAndInsert at vmlshape.cxx)
1614 Degree100 nAngle = NormAngle36000( Degree100((mnRotation - nCameraRotation) / -600) );
1615 aPropertySet.setAnyProperty( PROP_RotateAngle, makeAny( sal_Int32( nAngle.get() ) ) );
1616 aPropertySet.setAnyProperty( PROP_HoriOrientPosition, makeAny( maPosition.X ) );
1617 aPropertySet.setAnyProperty( PROP_VertOrientPosition, makeAny( maPosition.Y ) );
1618 }
1619
1620 // in some cases, we don't have any text body.
1621 if( getTextBody() && ( !bDoNotInsertEmptyTextBody || !mpTextBody->isEmpty() ) )
1622 {
1623 Reference < XText > xText( mxShape, UNO_QUERY );
1624 if ( xText.is() ) // not every shape is supporting an XText interface (e.g. GroupShape)
1625 {
1626 TextCharacterProperties aCharStyleProperties;
1627 if( const ShapeStyleRef* pFontRef = getShapeStyleRef( XML_fontRef ) )
1628 {
1629 if( pFontRef->mnThemedIdx != 0 )
1630 {
1631 if( pTheme )
1632 if( const TextCharacterProperties* pCharProps = pTheme->getFontStyle( pFontRef->mnThemedIdx ) )
1633 aCharStyleProperties.assignUsed( *pCharProps );
1634 SAL_INFO("oox.drawingml", "Shape::createAndInsert: use font color");
1635 if ( pFontRef->maPhClr.isUsed() )
1636 {
1637 aCharStyleProperties.maFillProperties.maFillColor = pFontRef->maPhClr;
1638 aCharStyleProperties.maFillProperties.moFillType.set(XML_solidFill);
1639 }
1640 }
1641 }
1642 xText->setString("");
1643 Reference < XTextCursor > xAt = xText->createTextCursor();
1644 getTextBody()->insertAt( rFilterBase, xText, xAt, aCharStyleProperties, mpMasterTextListStyle );
1645
1646 const TextParagraphVector& rParagraphs = getTextBody()->getParagraphs();
1647 if (!rParagraphs.empty())
1648 {
1649 const std::shared_ptr<TextParagraph>& pParagraph = rParagraphs[0];
1650 if (pParagraph->getProperties().getParaAdjust())
1651 {
1652 style::ParagraphAdjust eAdjust = *pParagraph->getProperties().getParaAdjust();
1653 if (eAdjust == style::ParagraphAdjust_CENTER)
1654 {
1655 // If the first paragraph is centered, then set the para adjustment of
1656 // the shape itself to centered as well.
1657 aPropertySet.setAnyProperty(PROP_ParaAdjust, uno::makeAny(eAdjust));
1658 }
1659 }
1660 }
1661 }
1662 }
1663 else if (mbTextBox)
1664 {
1665 // No drawingML text, but WPS text is expected: save the theme
1666 // character color on the shape, then.
1667 if(const ShapeStyleRef* pFontRef = getShapeStyleRef(XML_fontRef))
1668 {
1669 ::Color nCharColor = pFontRef->maPhClr.getColor(rGraphicHelper);
1670 aPropertySet.setAnyProperty(PROP_CharColor, uno::makeAny(nCharColor));
1671 }
1672 }
1673
1674 // Set glow effect properties
1675 if ( aEffectProperties.maGlow.moGlowRad.has() )
1676 {
1677 uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1678 propertySet->setPropertyValue("GlowEffectRadius", makeAny(convertEmuToHmm(aEffectProperties.maGlow.moGlowRad.get())));
1679 propertySet->setPropertyValue("GlowEffectColor", makeAny(aEffectProperties.maGlow.moGlowColor.getColor(rGraphicHelper)));
1680 propertySet->setPropertyValue("GlowEffectTransparency", makeAny(aEffectProperties.maGlow.moGlowColor.getTransparency()));
1681 }
1682
1683 // Set soft edge effect properties
1684 if (aEffectProperties.maSoftEdge.moRad.has())
1685 {
1686 uno::Reference<beans::XPropertySet> propertySet(mxShape, uno::UNO_QUERY);
1687 propertySet->setPropertyValue(
1688 "SoftEdgeRadius", makeAny(convertEmuToHmm(aEffectProperties.maSoftEdge.moRad.get())));
1689 }
1690 }
1691
1692 if( mxShape.is() )
1693 finalizeXShape( rFilterBase, rxShapes );
1694
1695 return mxShape;
1696 }
1697
keepDiagramDrawing(XmlFilterBase & rFilterBase,const OUString & rFragmentPath)1698 void Shape::keepDiagramDrawing(XmlFilterBase& rFilterBase, const OUString& rFragmentPath)
1699 {
1700 uno::Sequence<uno::Any> diagramDrawing(2);
1701 // drawingValue[0] => dom, drawingValue[1] => Sequence of associated relationships
1702
1703 sal_Int32 length = maDiagramDoms.getLength();
1704 maDiagramDoms.realloc(length + 1);
1705
1706 diagramDrawing[0] <<= rFilterBase.importFragment(rFragmentPath);
1707 diagramDrawing[1] <<= resolveRelationshipsOfTypeFromOfficeDoc(rFilterBase, rFragmentPath, u"image");
1708
1709 beans::PropertyValue* pValue = maDiagramDoms.getArray();
1710 pValue[length].Name = "OOXDrawing";
1711 pValue[length].Value <<= diagramDrawing;
1712 }
1713
keepDiagramCompatibilityInfo()1714 void Shape::keepDiagramCompatibilityInfo()
1715 {
1716 try
1717 {
1718 if( !maDiagramDoms.hasElements() )
1719 return;
1720
1721 Reference < XPropertySet > xSet( mxShape, UNO_QUERY_THROW );
1722 Reference < XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
1723 if ( !xSetInfo.is() )
1724 return;
1725
1726 if (mpDiagramData)
1727 {
1728 if (SdrObject* pObj = GetSdrObjectFromXShape(mxShape))
1729 pObj->SetDiagramData(mpDiagramData);
1730 }
1731
1732 const OUString aGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1733 if( !xSetInfo->hasPropertyByName( aGrabBagPropName ) )
1734 return;
1735
1736 Sequence < PropertyValue > aGrabBag;
1737 xSet->getPropertyValue( aGrabBagPropName ) >>= aGrabBag;
1738
1739 // We keep the previous items, if present
1740 if ( aGrabBag.hasElements() )
1741 xSet->setPropertyValue( aGrabBagPropName, Any( comphelper::concatSequences(aGrabBag, maDiagramDoms) ) );
1742 else
1743 xSet->setPropertyValue( aGrabBagPropName, Any( maDiagramDoms ) );
1744 }
1745 catch( const Exception& )
1746 {
1747 TOOLS_WARN_EXCEPTION( "oox.drawingml", "Shape::keepDiagramCompatibilityInfo" );
1748 }
1749 }
1750
syncDiagramFontHeights()1751 void Shape::syncDiagramFontHeights()
1752 {
1753 // Each name represents a group of shapes, for which the font height should have the same
1754 // scaling.
1755 for (const auto& rNameAndPairs : maDiagramFontHeights)
1756 {
1757 // Find out the minimum scale within this group.
1758 const ShapePairs& rShapePairs = rNameAndPairs.second;
1759 sal_Int16 nMinScale = 100;
1760 for (const auto& rShapePair : rShapePairs)
1761 {
1762 uno::Reference<beans::XPropertySet> xPropertySet(rShapePair.second, uno::UNO_QUERY);
1763 if (xPropertySet.is())
1764 {
1765 sal_Int16 nTextFitToSizeScale = 0;
1766 xPropertySet->getPropertyValue("TextFitToSizeScale") >>= nTextFitToSizeScale;
1767 if (nTextFitToSizeScale > 0 && nTextFitToSizeScale < nMinScale)
1768 {
1769 nMinScale = nTextFitToSizeScale;
1770 }
1771 }
1772 }
1773
1774 // Set that minimum scale for all members of the group.
1775 if (nMinScale < 100)
1776 {
1777 for (const auto& rShapePair : rShapePairs)
1778 {
1779 uno::Reference<beans::XPropertySet> xPropertySet(rShapePair.second, uno::UNO_QUERY);
1780 if (xPropertySet.is())
1781 {
1782 xPropertySet->setPropertyValue("TextFitToSizeScale", uno::makeAny(nMinScale));
1783 }
1784 }
1785 }
1786 }
1787 }
1788
convertSmartArtToMetafile(XmlFilterBase const & rFilterBase)1789 void Shape::convertSmartArtToMetafile(XmlFilterBase const & rFilterBase)
1790 {
1791 try
1792 {
1793 Reference<XPropertySet> xSet(mxShape, UNO_QUERY_THROW);
1794
1795 xSet->setPropertyValue("MoveProtect", Any(true));
1796 xSet->setPropertyValue("SizeProtect", Any(true));
1797
1798 // Replace existing shapes with a new Graphic Object rendered
1799 // from them
1800 Reference<XShape> xShape(renderDiagramToGraphic(rFilterBase));
1801 Reference<XShapes> xShapes(mxShape, UNO_QUERY_THROW);
1802 while (xShapes->hasElements())
1803 xShapes->remove(Reference<XShape>(xShapes->getByIndex(0), UNO_QUERY_THROW));
1804 xShapes->add(xShape);
1805 }
1806 catch (const Exception&)
1807 {
1808 TOOLS_WARN_EXCEPTION("oox.drawingml", "Shape::convertSmartArtToMetafile");
1809 }
1810 }
1811
renderDiagramToGraphic(XmlFilterBase const & rFilterBase)1812 Reference < XShape > Shape::renderDiagramToGraphic( XmlFilterBase const & rFilterBase )
1813 {
1814 Reference< XShape > xShape;
1815
1816 try
1817 {
1818 if( !maDiagramDoms.hasElements() )
1819 return xShape;
1820
1821 // Stream in which to place the rendered shape
1822 SvMemoryStream aTempStream;
1823 Reference < io::XStream > xStream( new utl::OStreamWrapper( aTempStream ) );
1824 Reference < io::XOutputStream > xOutputStream( xStream->getOutputStream() );
1825
1826 // Size of the rendering
1827 awt::Size aActualSize = mxShape->getSize();
1828 Size aResolution(Application::GetDefaultDevice()->LogicToPixel(Size(100, 100), MapMode(MapUnit::MapCM)));
1829 double fPixelsPer100thmm = static_cast < double > ( aResolution.Width() ) / 100000.0;
1830 awt::Size aSize( static_cast < sal_Int32 > ( ( fPixelsPer100thmm * aActualSize.Width ) + 0.5 ),
1831 static_cast < sal_Int32 > ( ( fPixelsPer100thmm * aActualSize.Height ) + 0.5 ) );
1832
1833 Sequence< PropertyValue > aFilterData( 4 );
1834 aFilterData[ 0 ].Name = "PixelWidth";
1835 aFilterData[ 0 ].Value <<= aSize.Width;
1836 aFilterData[ 1 ].Name = "PixelHeight";
1837 aFilterData[ 1 ].Value <<= aSize.Height;
1838 aFilterData[ 2 ].Name = "LogicalWidth";
1839 aFilterData[ 2 ].Value <<= aActualSize.Width;
1840 aFilterData[ 3 ].Name = "LogicalHeight";
1841 aFilterData[ 3 ].Value <<= aActualSize.Height;
1842
1843 Sequence < PropertyValue > aDescriptor( 3 );
1844 aDescriptor[ 0 ].Name = "OutputStream";
1845 aDescriptor[ 0 ].Value <<= xOutputStream;
1846 aDescriptor[ 1 ].Name = "FilterName";
1847 aDescriptor[ 1 ].Value <<= OUString("SVM"); // Rendering format
1848 aDescriptor[ 2 ].Name = "FilterData";
1849 aDescriptor[ 2 ].Value <<= aFilterData;
1850
1851 Reference < lang::XComponent > xSourceDoc( mxShape, UNO_QUERY_THROW );
1852 Reference < XGraphicExportFilter > xGraphicExporter = GraphicExportFilter::create( rFilterBase.getComponentContext() );
1853 xGraphicExporter->setSourceDocument( xSourceDoc );
1854 xGraphicExporter->filter( aDescriptor );
1855
1856 aTempStream.Seek( STREAM_SEEK_TO_BEGIN );
1857
1858 Graphic aGraphic;
1859 GraphicFilter aFilter( false );
1860 if ( aFilter.ImportGraphic( aGraphic, "", aTempStream, GRFILTER_FORMAT_NOTFOUND, nullptr, GraphicFilterImportFlags::NONE, static_cast < Sequence < PropertyValue >* > ( nullptr ) ) != ERRCODE_NONE )
1861 {
1862 SAL_WARN( "oox.drawingml", "Shape::renderDiagramToGraphic: Unable to import rendered stream into graphic object" );
1863 return xShape;
1864 }
1865
1866 Reference < graphic::XGraphic > xGraphic( aGraphic.GetXGraphic() );
1867 Reference < lang::XMultiServiceFactory > xServiceFact( rFilterBase.getModel(), UNO_QUERY_THROW );
1868 xShape.set( xServiceFact->createInstance( "com.sun.star.drawing.GraphicObjectShape" ), UNO_QUERY_THROW );
1869 Reference < XPropertySet > xPropSet( xShape, UNO_QUERY_THROW );
1870 xPropSet->setPropertyValue( "Graphic", Any( xGraphic ) );
1871 xPropSet->setPropertyValue( "MoveProtect", Any( true ) );
1872 xPropSet->setPropertyValue( "SizeProtect", Any( true ) );
1873 xPropSet->setPropertyValue( "Name", Any( OUString( "RenderedShapes" ) ) );
1874 }
1875 catch( const Exception& )
1876 {
1877 TOOLS_WARN_EXCEPTION( "oox.drawingml", "Shape::renderDiagramToGraphic" );
1878 }
1879
1880 return xShape;
1881 }
1882
setTextBody(const TextBodyPtr & pTextBody)1883 void Shape::setTextBody(const TextBodyPtr & pTextBody)
1884 {
1885 mpTextBody = pTextBody;
1886 }
1887
setMasterTextListStyle(const TextListStylePtr & pMasterTextListStyle)1888 void Shape::setMasterTextListStyle( const TextListStylePtr& pMasterTextListStyle )
1889 {
1890 SAL_INFO("oox.drawingml", "Shape::setMasterTextListStyle: Set master text list style to shape id='" << msId << "'");
1891
1892 mpMasterTextListStyle = pMasterTextListStyle;
1893 }
1894
finalizeServiceName(XmlFilterBase & rFilter,const OUString & rServiceName,const awt::Rectangle & rShapeRect)1895 OUString Shape::finalizeServiceName( XmlFilterBase& rFilter, const OUString& rServiceName, const awt::Rectangle& rShapeRect )
1896 {
1897 OUString aServiceName = rServiceName;
1898 switch( meFrameType )
1899 {
1900 case FRAMETYPE_OLEOBJECT:
1901 {
1902 awt::Size aOleSize( rShapeRect.Width, rShapeRect.Height );
1903 if( rFilter.getOleObjectHelper().importOleObject( maShapeProperties, *mxOleObjectInfo, aOleSize ) )
1904 aServiceName = "com.sun.star.drawing.OLE2Shape";
1905
1906 // get the path to the representation graphic
1907 OUString aGraphicPath;
1908 if( !mxOleObjectInfo->maShapeId.isEmpty() )
1909 if( ::oox::vml::Drawing* pVmlDrawing = rFilter.getVmlDrawing() )
1910 if( const ::oox::vml::ShapeBase* pVmlShape = pVmlDrawing->getShapes().getShapeById( mxOleObjectInfo->maShapeId ) )
1911 aGraphicPath = pVmlShape->getGraphicPath();
1912
1913 // import and store the graphic
1914 if( !aGraphicPath.isEmpty() )
1915 {
1916 // Transfer shape's width and height to graphicsfilter (can be used by WMF/EMF)
1917 WmfExternal aExtHeader;
1918 aExtHeader.mapMode = 8; // MM_ANISOTROPIC
1919 aExtHeader.xExt = rShapeRect.Width;
1920 aExtHeader.yExt = rShapeRect.Height;
1921
1922 Reference< graphic::XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic( aGraphicPath, &aExtHeader );
1923 if( xGraphic.is() )
1924 maShapeProperties.setProperty(PROP_Graphic, xGraphic);
1925 }
1926 }
1927 break;
1928
1929 default:;
1930 }
1931 return aServiceName;
1932 }
1933
finalizeXShape(XmlFilterBase & rFilter,const Reference<XShapes> & rxShapes)1934 void Shape::finalizeXShape( XmlFilterBase& rFilter, const Reference< XShapes >& rxShapes )
1935 {
1936 switch( meFrameType )
1937 {
1938 case FRAMETYPE_CHART:
1939 {
1940 OSL_ENSURE( !mxChartShapeInfo->maFragmentPath.isEmpty(), "Shape::finalizeXShape - missing chart fragment" );
1941 if( mxShape.is() && !mxChartShapeInfo->maFragmentPath.isEmpty() ) try
1942 {
1943 // set the chart2 OLE class ID at the OLE shape
1944 PropertySet aShapeProp( mxShape );
1945 aShapeProp.setProperty( PROP_CLSID, OUString( "12dcae26-281f-416f-a234-c3086127382e" ) );
1946
1947 // get the XModel interface of the embedded object from the OLE shape
1948 Reference< frame::XModel > xDocModel;
1949 aShapeProp.getProperty( xDocModel, PROP_Model );
1950 Reference< chart2::XChartDocument > xChartDoc( xDocModel, UNO_QUERY_THROW );
1951
1952 // load the chart data from the XML fragment
1953 bool bMSO2007Doc = rFilter.isMSO2007Document();
1954 chart::ChartSpaceModel aModel(bMSO2007Doc);
1955 rtl::Reference<chart::ChartSpaceFragment> pChartSpaceFragment = new chart::ChartSpaceFragment(
1956 rFilter, mxChartShapeInfo->maFragmentPath, aModel );
1957 const OUString aThemeOverrideFragmentPath( pChartSpaceFragment->
1958 getFragmentPathFromFirstTypeFromOfficeDoc(u"themeOverride") );
1959 rFilter.importFragment( pChartSpaceFragment );
1960 ::oox::ppt::PowerPointImport *pPowerPointImport =
1961 dynamic_cast< ::oox::ppt::PowerPointImport* >(&rFilter);
1962
1963 // The original theme.
1964 ThemePtr pTheme;
1965
1966 if (!aThemeOverrideFragmentPath.isEmpty() && pPowerPointImport)
1967 {
1968 // Handle theme override.
1969 uno::Reference< xml::sax::XFastSAXSerializable > xDoc(
1970 rFilter.importFragment(aThemeOverrideFragmentPath), uno::UNO_QUERY_THROW);
1971 pTheme = pPowerPointImport->getActualSlidePersist()->getTheme();
1972 auto pThemeOverride = std::make_shared<Theme>(*pTheme);
1973 rFilter.importFragment(
1974 new ThemeOverrideFragmentHandler(rFilter, aThemeOverrideFragmentPath,
1975 *pThemeOverride),
1976 xDoc);
1977 pPowerPointImport->getActualSlidePersist()->setTheme(pThemeOverride);
1978 }
1979
1980 // convert imported chart model to chart document
1981 Reference< drawing::XShapes > xExternalPage;
1982 if( !mxChartShapeInfo->mbEmbedShapes )
1983 xExternalPage = rxShapes;
1984 if( rFilter.getChartConverter() )
1985 {
1986 rFilter.getChartConverter()->convertFromModel( rFilter, aModel, xChartDoc, xExternalPage, mxShape->getPosition(), mxShape->getSize() );
1987 if( !xChartDoc->hasInternalDataProvider() )
1988 {
1989 Reference< chart2::data::XDataReceiver > xDataRec( xChartDoc, UNO_QUERY );
1990 Reference< chart2::data::XDataSource > xData = xDataRec->getUsedData();
1991 if( !xData->getDataSequences().hasElements() || !xData->getDataSequences()[0]->getValues().is() ||
1992 !xData->getDataSequences()[0]->getValues()->getData().hasElements() )
1993 {
1994 rFilter.useInternalChartDataTable( true );
1995 rFilter.getChartConverter()->convertFromModel( rFilter, aModel, xChartDoc, xExternalPage, mxShape->getPosition(), mxShape->getSize() );
1996 rFilter.useInternalChartDataTable( false );
1997 }
1998 }
1999
2000 }
2001
2002 if (!aThemeOverrideFragmentPath.isEmpty() && pPowerPointImport)
2003 {
2004 // Restore the original theme.
2005 pPowerPointImport->getActualSlidePersist()->setTheme(pTheme);
2006 }
2007 }
2008 catch( Exception& )
2009 {
2010 }
2011 }
2012 break;
2013
2014 default:;
2015 }
2016 }
2017
putPropertyToGrabBag(const OUString & sPropertyName,const Any & aPropertyValue)2018 void Shape::putPropertyToGrabBag( const OUString& sPropertyName, const Any& aPropertyValue )
2019 {
2020 PropertyValue aNewProperty;
2021 aNewProperty.Name = sPropertyName;
2022 aNewProperty.Value = aPropertyValue;
2023 putPropertyToGrabBag( aNewProperty );
2024 }
2025
putPropertyToGrabBag(const PropertyValue & pProperty)2026 void Shape::putPropertyToGrabBag( const PropertyValue& pProperty )
2027 {
2028 Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
2029 Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
2030 const OUString aGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
2031 if( mxShape.is() && xSet.is() && xSetInfo.is() && xSetInfo->hasPropertyByName( aGrabBagPropName ) )
2032 {
2033 Sequence< PropertyValue > aGrabBag;
2034 xSet->getPropertyValue( aGrabBagPropName ) >>= aGrabBag;
2035
2036 sal_Int32 length = aGrabBag.getLength();
2037 aGrabBag.realloc( length + 1 );
2038 aGrabBag[length] = pProperty;
2039
2040 xSet->setPropertyValue( aGrabBagPropName, Any( aGrabBag ) );
2041 }
2042 }
2043
putPropertiesToGrabBag(const Sequence<PropertyValue> & aProperties)2044 void Shape::putPropertiesToGrabBag( const Sequence< PropertyValue >& aProperties )
2045 {
2046 Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
2047 Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
2048 const OUString aGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
2049 if( !(mxShape.is() && xSet.is() && xSetInfo.is() && xSetInfo->hasPropertyByName( aGrabBagPropName )) )
2050 return;
2051
2052 // get existing grab bag
2053 Sequence< PropertyValue > aGrabBag;
2054 xSet->getPropertyValue( aGrabBagPropName ) >>= aGrabBag;
2055
2056 std::vector<PropertyValue> aVec;
2057 aVec.reserve(aProperties.getLength());
2058
2059 // put the new items
2060 std::transform(aProperties.begin(), aProperties.end(), std::back_inserter(aVec),
2061 [](const PropertyValue& rProp) {
2062 PropertyValue aProp;
2063 aProp.Name = rProp.Name;
2064 aProp.Value = rProp.Value;
2065 return aProp;
2066 });
2067
2068 // put it back to the shape
2069 xSet->setPropertyValue( aGrabBagPropName, Any( comphelper::concatSequences(aGrabBag, aVec) ) );
2070 }
2071
getActualFillProperties(const Theme * pTheme,const FillProperties * pParentShapeFillProps) const2072 FillProperties Shape::getActualFillProperties(const Theme* pTheme, const FillProperties* pParentShapeFillProps) const
2073 {
2074 FillProperties aFillProperties;
2075 aFillProperties.moFillType = XML_noFill;
2076
2077 // Reference shape properties
2078 aFillProperties.assignUsed( *mpShapeRefFillPropPtr );
2079
2080 // Theme
2081 if( pTheme != nullptr )
2082 {
2083 if( const ShapeStyleRef* pFillRef = getShapeStyleRef( XML_fillRef ) )
2084 {
2085 if( const FillProperties* pFillProps = pTheme->getFillStyle( pFillRef->mnThemedIdx ) )
2086 aFillProperties.assignUsed( *pFillProps );
2087 }
2088 }
2089
2090 // Properties specified directly for this shape
2091 aFillProperties.assignUsed(getFillProperties());
2092
2093 // Parent shape's properties
2094 if ( pParentShapeFillProps != nullptr)
2095 if( getFillProperties().moFillType.has() && getFillProperties().moFillType.get() == XML_grpFill )
2096 aFillProperties.assignUsed( *pParentShapeFillProps );
2097
2098 return aFillProperties;
2099 }
2100
getActualLineProperties(const Theme * pTheme) const2101 LineProperties Shape::getActualLineProperties(const Theme* pTheme) const
2102 {
2103 LineProperties aLineProperties;
2104 aLineProperties.maLineFill.moFillType = XML_noFill;
2105
2106 // Reference shape properties
2107 aLineProperties.assignUsed( *mpShapeRefLinePropPtr );
2108
2109 // Theme
2110 if( pTheme != nullptr )
2111 {
2112 if( const ShapeStyleRef* pLineRef = getShapeStyleRef( XML_lnRef ) )
2113 {
2114 if( const LineProperties* pLineProps = pTheme->getLineStyle( pLineRef->mnThemedIdx ) )
2115 aLineProperties.assignUsed( *pLineProps );
2116 }
2117 }
2118
2119 // Properties specified directly for this shape
2120 aLineProperties.assignUsed( getLineProperties() );
2121
2122 return aLineProperties;
2123 }
2124
getActualEffectProperties(const Theme * pTheme) const2125 EffectProperties Shape::getActualEffectProperties(const Theme* pTheme) const
2126 {
2127 EffectProperties aEffectProperties;
2128
2129 // Reference shape properties
2130 aEffectProperties.assignUsed( *mpShapeRefEffectPropPtr );
2131
2132 // Theme
2133 if( pTheme != nullptr )
2134 {
2135 if( const ShapeStyleRef* pEffectRef = getShapeStyleRef( XML_effectRef ) )
2136 {
2137 if( const EffectProperties* pEffectProps = pTheme->getEffectStyle( pEffectRef->mnThemedIdx ) )
2138 aEffectProperties.assignUsed( *pEffectProps );
2139 }
2140 }
2141
2142 // Properties specified directly for this shape
2143 aEffectProperties.assignUsed ( getEffectProperties() );
2144
2145 return aEffectProperties;
2146 }
2147
resolveRelationshipsOfTypeFromOfficeDoc(core::XmlFilterBase & rFilter,const OUString & sFragment,std::u16string_view sType)2148 uno::Sequence< uno::Sequence< uno::Any > > Shape::resolveRelationshipsOfTypeFromOfficeDoc(core::XmlFilterBase& rFilter, const OUString& sFragment, std::u16string_view sType )
2149 {
2150 uno::Sequence< uno::Sequence< uno::Any > > xRelListTemp;
2151 sal_Int32 counter = 0;
2152
2153 core::RelationsRef xRels = rFilter.importRelations( sFragment );
2154 if ( xRels )
2155 {
2156 core::RelationsRef xImageRels = xRels->getRelationsFromTypeFromOfficeDoc( sType );
2157 if ( xImageRels )
2158 {
2159 xRelListTemp.realloc( xImageRels->size() );
2160 for (auto const& imageRel : *xImageRels)
2161 {
2162 uno::Sequence< uno::Any > diagramRelTuple (3);
2163 // [0] => RID, [1] => InputStream [2] => extension
2164 OUString sRelId = imageRel.second.maId;
2165
2166 diagramRelTuple[0] <<= sRelId;
2167 OUString sTarget = xImageRels->getFragmentPathFromRelId( sRelId );
2168
2169 uno::Reference< io::XInputStream > xImageInputStrm( rFilter.openInputStream( sTarget ), uno::UNO_SET_THROW );
2170 StreamDataSequence dataSeq;
2171 if ( rFilter.importBinaryData( dataSeq, sTarget ) )
2172 {
2173 diagramRelTuple[1] <<= dataSeq;
2174 }
2175
2176 diagramRelTuple[2] <<= sTarget.copy( sTarget.lastIndexOf(".") );
2177
2178 xRelListTemp[counter] = diagramRelTuple;
2179 ++counter;
2180 }
2181 xRelListTemp.realloc(counter);
2182
2183 }
2184 }
2185 return xRelListTemp;
2186 }
2187
cloneFillProperties()2188 void Shape::cloneFillProperties()
2189 {
2190 auto pFillProperties = std::make_shared<FillProperties>();
2191 pFillProperties->assignUsed(*mpFillPropertiesPtr);
2192 mpFillPropertiesPtr = pFillProperties;
2193 }
2194 }
2195
2196 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2197