LibreOffice Module oox (master)  1
customshapeproperties.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
23 #include <oox/token/properties.hxx>
24 #include <oox/token/tokenmap.hxx>
25 #include <com/sun/star/awt/Rectangle.hpp>
26 #include <com/sun/star/awt/Size.hpp>
27 #include <com/sun/star/beans/PropertyValues.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
30 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
31 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
32 #include <com/sun/star/drawing/XShape.hpp>
33 #include <comphelper/sequence.hxx>
34 #include <sal/log.hxx>
35 
36 #include <algorithm>
37 
38 using namespace ::com::sun::star;
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::beans;
41 using namespace ::com::sun::star::drawing;
42 
43 namespace oox::drawingml {
44 
46 : mnShapePresetType ( -1 )
47 , mbShapeTypeOverride(false)
48 , mbMirroredX ( false )
49 , mbMirroredY ( false )
50 , mnTextRotateAngle ( 0 )
51 , mnTextCameraZRotateAngle ( 0 )
52 , mnArcNum ( 0 )
53 {
54 }
55 
56 uno::Sequence< sal_Int8 > const & CustomShapeProperties::getShapePresetTypeName() const
57 {
59 }
60 
61 sal_Int32 CustomShapeProperties::SetCustomShapeGuideValue( std::vector< CustomShapeGuide >& rGuideList, const CustomShapeGuide& rGuide )
62 {
63  std::vector<CustomShapeGuide>::size_type nIndex = 0;
64  for( ; nIndex < rGuideList.size(); nIndex++ )
65  {
66  if ( rGuideList[ nIndex ].maName == rGuide.maName )
67  break;
68  }
69  if ( nIndex == rGuideList.size() )
70  rGuideList.push_back( rGuide );
71  return static_cast< sal_Int32 >( nIndex );
72 }
73 
74 // returns the index into the guidelist for a given formula name,
75 // if the return value is < 0 then the guide value could not be found
76 sal_Int32 CustomShapeProperties::GetCustomShapeGuideValue( const std::vector< CustomShapeGuide >& rGuideList, std::u16string_view rFormulaName )
77 {
78  // traverse the list from the end, because guide names can be reused
79  // and current is the last one
80  // see a1 guide in gear6 custom shape preset as example
81  sal_Int32 nIndex = static_cast< sal_Int32 >( rGuideList.size() ) - 1;
82  for( ; nIndex >= 0; nIndex-- )
83  {
84  if ( rGuideList[ nIndex ].maName == rFormulaName )
85  break;
86  }
87 
88  return nIndex;
89 }
90 
92 
93 static OUString GetConnectorShapeType( sal_Int32 nType )
94 {
95  SAL_INFO(
96  "oox.drawingml", "preset: " << nType << " " << XML_straightConnector1);
97 
98  OUString sType;
99  switch( nType )
100  {
101  case XML_straightConnector1:
102  sType = "mso-spt32";
103  break;
104  default:
105  break;
106  }
107  return sType;
108 }
109 
111  const Reference < XPropertySet >& xPropSet, const Reference < XShape > & xShape, const awt::Size &aSize )
112 {
113  if ( mnShapePresetType >= 0 )
114  {
115  SAL_INFO("oox.drawingml", "preset: " << mnShapePresetType);
116 
117  if (maPresetDataMap.empty())
119 
120  PropertyMap aPropertyMap;
121  PropertySet aPropSet( xPropSet );
122 
123  OUString sConnectorShapeType = GetConnectorShapeType( mnShapePresetType );
124 
125  if (sConnectorShapeType.getLength() > 0)
126  {
127  SAL_INFO(
128  "oox.drawingml",
129  "connector shape: " << sConnectorShapeType << " ("
130  << mnShapePresetType << ")");
131  //const uno::Reference < drawing::XShape > xShape( xPropSet, UNO_QUERY );
132  Reference< drawing::XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY );
133  if( xDefaulter.is() ) {
134  xDefaulter->createCustomShapeDefaults( sConnectorShapeType );
135  aPropertyMap.setProperty( PROP_Type, sConnectorShapeType );
136  }
137  }
138  else if (maPresetDataMap.find(mnShapePresetType) != maPresetDataMap.end())
139  {
140  SAL_INFO(
141  "oox.drawingml",
142  "found property map for preset: " << mnShapePresetType);
143 
144  aPropertyMap = maPresetDataMap[mnShapePresetType];
145 #ifdef DEBUG
146  aPropertyMap.dumpCode( aPropertyMap.makePropertySet() );
147 #endif
148  }
149 
150  aPropertyMap.setProperty( PROP_MirroredX, mbMirroredX );
151  aPropertyMap.setProperty( PROP_MirroredY, mbMirroredY );
152  aPropertyMap.setProperty( PROP_TextPreRotateAngle, mnTextRotateAngle );
153  aPropertyMap.setProperty( PROP_TextCameraZRotateAngle, mnTextCameraZRotateAngle );
155  aPropSet.setProperty( PROP_CustomShapeGeometry, aSeq );
156 
157  if ( !maAdjustmentGuideList.empty() )
158  {
159  static const OUStringLiteral sCustomShapeGeometry(u"CustomShapeGeometry");
160  static const OUStringLiteral sAdjustmentValues(u"AdjustmentValues");
161  uno::Any aGeoPropSet = xPropSet->getPropertyValue( sCustomShapeGeometry );
162  uno::Sequence< beans::PropertyValue > aGeoPropSeq;
163  if ( aGeoPropSet >>= aGeoPropSeq )
164  {
165  for ( auto& rGeoProp : asNonConstRange(aGeoPropSeq) )
166  {
167  if ( rGeoProp.Name == sAdjustmentValues )
168  {
169  uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentSeq;
170  if ( rGeoProp.Value >>= aAdjustmentSeq )
171  {
172  auto aAdjustmentSeqRange = asNonConstRange(aAdjustmentSeq);
173  int nIndex=0;
174  for (auto const& adjustmentGuide : maAdjustmentGuideList)
175  {
176  if ( adjustmentGuide.maName.getLength() > 3 )
177  {
178  sal_Int32 nAdjustmentIndex = adjustmentGuide.maName.copy( 3 ).toInt32() - 1;
179  if ( ( nAdjustmentIndex >= 0 ) && ( nAdjustmentIndex < aAdjustmentSeq.getLength() ) )
180  {
181  EnhancedCustomShapeAdjustmentValue aAdjustmentVal;
182  aAdjustmentVal.Value <<= adjustmentGuide.maFormula.toInt32();
183  aAdjustmentVal.State = PropertyState_DIRECT_VALUE;
184  aAdjustmentVal.Name = adjustmentGuide.maName;
185  aAdjustmentSeqRange[ nAdjustmentIndex ] = aAdjustmentVal;
186  }
187  } else if ( aAdjustmentSeq.hasElements() ) {
188  EnhancedCustomShapeAdjustmentValue aAdjustmentVal;
189  aAdjustmentVal.Value <<= adjustmentGuide.maFormula.toInt32();
190  aAdjustmentVal.State = PropertyState_DIRECT_VALUE;
191  aAdjustmentVal.Name = adjustmentGuide.maName;
192  if (nIndex < aAdjustmentSeq.getLength())
193  {
194  aAdjustmentSeqRange[nIndex] = aAdjustmentVal;
195  ++nIndex;
196  }
197  }
198  }
199  rGeoProp.Value <<= aAdjustmentSeq;
200  xPropSet->setPropertyValue( sCustomShapeGeometry, Any( aGeoPropSeq ) );
201  break;
202  }
203  }
204  }
205  }
206  }
207  }
208  else
209  {
210  PropertyMap aPropertyMap;
211  aPropertyMap.setProperty( PROP_Type, OUString( "ooxml-non-primitive" ));
212  aPropertyMap.setProperty( PROP_MirroredX, mbMirroredX );
213  aPropertyMap.setProperty( PROP_MirroredY, mbMirroredY );
214  if( mnTextRotateAngle )
215  aPropertyMap.setProperty( PROP_TextPreRotateAngle, mnTextRotateAngle );
216  // Note 1: If Equations are defined - they are processed using internal div by 360 coordinates
217  // while if they are not, standard ooxml coordinates are used.
218  // This size specifically affects scaling.
219  // Note 2: Width and Height are set to 0 to force scaling to 1.
220  awt::Rectangle aViewBox( 0, 0, aSize.Width, aSize.Height );
221  if( !maGuideList.empty() )
222  aViewBox = awt::Rectangle( 0, 0, 0, 0 );
223  aPropertyMap.setProperty( PROP_ViewBox, aViewBox);
224 
226  auto aAdjustmentValuesRange = asNonConstRange(aAdjustmentValues);
227  for ( std::vector<CustomShapeGuide>::size_type i = 0; i < maAdjustmentGuideList.size(); i++ )
228  {
229  EnhancedCustomShapeAdjustmentValue aAdjustmentVal;
230  aAdjustmentVal.Value <<= maAdjustmentGuideList[ i ].maFormula.toInt32();
231  aAdjustmentVal.State = PropertyState_DIRECT_VALUE;
232  aAdjustmentVal.Name = maAdjustmentGuideList[ i ].maName;
233  aAdjustmentValuesRange[ i ] = aAdjustmentVal;
234  }
235  aPropertyMap.setProperty( PROP_AdjustmentValues, aAdjustmentValues);
236 
237  PropertyMap aPath;
238 
239  aPath.setProperty( PROP_Segments, comphelper::containerToSequence(maSegments) );
240 
241  if ( maTextRect.has() ) {
243  { /* tl */ { maTextRect.get().l, maTextRect.get().t },
244  /* br */ { maTextRect.get().r, maTextRect.get().b } }
245  };
246  aPath.setProperty( PROP_TextFrames, aTextFrames);
247  }
248 
249  sal_uInt32 nParameterPairs = 0;
250  for ( auto const & i: maPath2DList )
251  nParameterPairs += i.parameter.size();
252 
253  Sequence< EnhancedCustomShapeParameterPair > aParameterPairs( nParameterPairs );
254  auto aParameterPairsRange = asNonConstRange(aParameterPairs);
255  sal_uInt32 k = 0;
256  for ( auto const & i: maPath2DList )
257  for ( auto const & j: i.parameter )
258  aParameterPairsRange[ k++ ] = j;
259  aPath.setProperty( PROP_Coordinates, aParameterPairs);
260 
261  if ( !maPath2DList.empty() )
262  {
263  bool bAllZero = true;
264  for ( auto const & i: maPath2DList )
265  {
266  if ( i.w || i.h ) {
267  bAllZero = false;
268  break;
269  }
270  }
271 
272  if ( !bAllZero ) {
273  Sequence< awt::Size > aSubViewSize( maPath2DList.size() );
274  std::transform(maPath2DList.begin(), maPath2DList.end(), aSubViewSize.getArray(),
275  [](const auto& p2d)
276  {
277  SAL_INFO("oox.cscode",
278  "set subpath; size: " << p2d.w << " x " << p2d.h);
279  return awt::Size(p2d.w, p2d.h);
280  });
281  aPath.setProperty( PROP_SubViewSize, aSubViewSize);
282  }
283  }
284 
286  aPropertyMap.setProperty( PROP_Path, aPathSequence);
287 
288  Sequence< OUString > aEquations( maGuideList.size() );
289  std::transform(maGuideList.begin(), maGuideList.end(), aEquations.getArray(),
290  [](const auto& g) { return g.maFormula; });
291  aPropertyMap.setProperty( PROP_Equations, aEquations);
292 
294  auto aHandlesRange = asNonConstRange(aHandles);
295  for ( std::vector<AdjustHandle>::size_type i = 0; i < maAdjustHandleList.size(); i++ )
296  {
297  PropertyMap aHandle;
298  // maAdjustmentHandle[ i ].gdRef1 ... maAdjustmentHandle[ i ].gdRef2 ... :(
299  // gdRef1 && gdRef2 -> we do not offer such reference, so it is difficult
300  // to determine the correct adjustment handle that should be updated with the adjustment
301  // position. here is the solution: the adjustment value that is used within the position
302  // has to be updated, in case the position is a formula the first usage of a
303  // adjustment value is decisive
304  if ( maAdjustHandleList[ i ].polar )
305  {
306  // Polar handles in DrawingML
307  // 1. don't have reference center, so PROP_Polar isn't needed.
308  // 2. position always use planar coordinates.
309  // 3. use RefAngle and RefR to specify adjustment value to be updated.
310  // 4. The unit of angular adjustment values are 6000th degree.
311 
312  aHandle.setProperty( PROP_Position, maAdjustHandleList[ i ].pos);
313  if ( maAdjustHandleList[ i ].gdRef1.has() )
314  {
316  if ( nIndex >= 0 )
317  aHandle.setProperty( PROP_RefR, nIndex);
318  }
319  if ( maAdjustHandleList[ i ].gdRef2.has() )
320  {
322  if ( nIndex >= 0 )
323  aHandle.setProperty( PROP_RefAngle, nIndex);
324  }
325  if ( maAdjustHandleList[ i ].min1.has() )
326  aHandle.setProperty( PROP_RadiusRangeMinimum, maAdjustHandleList[ i ].min1.get());
327  if ( maAdjustHandleList[ i ].max1.has() )
328  aHandle.setProperty( PROP_RadiusRangeMaximum, maAdjustHandleList[ i ].max1.get());
329 
330  /* TODO: AngleMin & AngleMax
331  if ( maAdjustHandleList[ i ].min2.has() )
332  aHandle.setProperty( PROP_ ] = maAdjustHandleList[ i ].min2.get());
333  if ( maAdjustHandleList[ i ].max2.has() )
334  aHandle.setProperty( PROP_ ] = maAdjustHandleList[ i ].max2.get());
335  */
336  }
337  else
338  {
339  aHandle.setProperty( PROP_Position, maAdjustHandleList[ i ].pos);
340  if ( maAdjustHandleList[ i ].gdRef1.has() )
341  {
342  // TODO: PROP_RefX and PROP_RefY are not yet part of our file format,
343  // so the handles will not work after save/reload
345  if ( nIndex >= 0 )
346  aHandle.setProperty( PROP_RefX, nIndex);
347  }
348  if ( maAdjustHandleList[ i ].gdRef2.has() )
349  {
351  if ( nIndex >= 0 )
352  aHandle.setProperty( PROP_RefY, nIndex);
353  }
354  if ( maAdjustHandleList[ i ].min1.has() )
355  aHandle.setProperty( PROP_RangeXMinimum, maAdjustHandleList[ i ].min1.get());
356  if ( maAdjustHandleList[ i ].max1.has() )
357  aHandle.setProperty( PROP_RangeXMaximum, maAdjustHandleList[ i ].max1.get());
358  if ( maAdjustHandleList[ i ].min2.has() )
359  aHandle.setProperty( PROP_RangeYMinimum, maAdjustHandleList[ i ].min2.get());
360  if ( maAdjustHandleList[ i ].max2.has() )
361  aHandle.setProperty( PROP_RangeYMaximum, maAdjustHandleList[ i ].max2.get());
362  }
363  aHandlesRange[ i ] = aHandle.makePropertyValueSequence();
364  }
365  aPropertyMap.setProperty( PROP_Handles, aHandles);
366 
367 #ifdef DEBUG
368  // Note that the script oox/source/drawingml/customshapes/generatePresetsData.pl looks
369  // for these ==cscode== and ==csdata== markers, so don't "clean up" these SAL_INFOs.
370  SAL_INFO("oox.cscode", "==cscode== begin");
371  aPropertyMap.dumpCode( aPropertyMap.makePropertySet() );
372  SAL_INFO("oox.cscode", "==cscode== end");
373  SAL_INFO("oox.csdata", "==csdata== begin");
374  aPropertyMap.dumpData( aPropertyMap.makePropertySet() );
375  SAL_INFO("oox.csdata", "==csdata== end");
376 #endif
377  // converting the vector to a sequence
379  PropertySet aPropSet( xPropSet );
380  aPropSet.setProperty( PROP_CustomShapeGeometry, aSeq );
381  }
382 }
383 
384 }
385 
386 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
TokenMap & StaticTokenMap()
Definition: tokenmap.cxx:90
static void dumpData(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
sal_Int32 nIndex
A helper that maps property identifiers to property values.
Definition: propertymap.hxx:51
static sal_Int32 GetCustomShapeGuideValue(const std::vector< CustomShapeGuide > &rGuideList, std::u16string_view rFormulaName)
bool setProperty(sal_Int32 nPropId, Type &&rValue)
Sets the specified property to the passed value.
Definition: propertymap.hxx:69
std::unordered_map< sal_Int32, PropertyMap > PresetDataMap
std::vector< CustomShapeGuide > maGuideList
size_t pos
css::uno::Reference< css::beans::XPropertySet > makePropertySet() const
Creates a property set supporting the XPropertySet interface and inserts all properties.
std::vector< AdjustHandle > maAdjustHandleList
void pushToPropSet(const css::uno::Reference< css::beans::XPropertySet > &xPropSet, const css::uno::Reference< css::drawing::XShape > &xShape, const css::awt::Size &aSize)
OptionalString sType
css::uno::Sequence< sal_Int8 > const & getUtf8TokenName(sal_Int32 nToken) const
Returns the UTF8 name of the passed token identifier as byte sequence.
Definition: tokenmap.hxx:49
float u
css::uno::Sequence< css::beans::PropertyValue > makePropertyValueSequence() const
Returns a sequence of property values, filled with all contained properties.
A wrapper for a UNO property set.
Definition: propertyset.hxx:57
std::vector< css::drawing::EnhancedCustomShapeSegment > maSegments
css::uno::Sequence< sal_Int8 > const & getShapePresetTypeName() const
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
#define SAL_INFO(area, stream)
static void dumpCode(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Sequence< sal_Int8 > aSeq
static sal_Int32 SetCustomShapeGuideValue(std::vector< CustomShapeGuide > &rGuideList, const CustomShapeGuide &rGuide)
OUString maName
Definition: dffdumper.cxx:160
std::vector< CustomShapeGuide > maAdjustmentGuideList
static OUString GetConnectorShapeType(sal_Int32 nType)
bool setProperty(sal_Int32 nPropId, const Type &rValue)
Puts the passed value into the property set.