bump product version to 5.0.4.1
[LibreOffice.git] / svx / source / customshapes / EnhancedCustomShape2d.cxx
bloba463eb8b53764ea41e33f82a3c7b8e470cf7fce4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "svx/EnhancedCustomShape2d.hxx"
21 #include "svx/EnhancedCustomShapeGeometry.hxx"
22 #include "svx/EnhancedCustomShapeTypeNames.hxx"
23 #include <svx/svdoashp.hxx>
24 #include <svx/svdtrans.hxx>
25 #include <svx/svdocirc.hxx>
26 #include <svx/svdogrp.hxx>
27 #include <svx/svdopath.hxx>
28 #include <svx/svdocapt.hxx>
29 #include <svx/svdpage.hxx>
30 #include <svx/xflclit.hxx>
31 #include <svx/sdasaitm.hxx>
32 #include <svx/svdmodel.hxx>
33 #include <rtl/crc.h>
34 #include <rtl/math.hxx>
35 #include <svx/xfillit0.hxx>
36 #include <svx/xlnstit.hxx>
37 #include <svx/xlnedit.hxx>
38 #include <svx/xlnstwit.hxx>
39 #include <svx/xlnedwit.hxx>
40 #include <svx/xlnstcit.hxx>
41 #include <svx/xlnedcit.hxx>
42 #include <svx/xflgrit.hxx>
43 #include <svx/xflhtit.hxx>
44 #include <svx/xbtmpit.hxx>
45 #include <svx/xgrad.hxx>
46 #include <svx/xhatch.hxx>
47 #include <com/sun/star/awt/Size.hpp>
48 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
49 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
50 #include <boost/shared_ptr.hpp>
51 #include <basegfx/numeric/ftools.hxx>
52 #include <basegfx/color/bcolortools.hxx>
53 #include <basegfx/polygon/b2dpolygon.hxx>
54 #include <basegfx/polygon/b2dpolygontools.hxx>
55 #include <basegfx/matrix/b2dhommatrixtools.hxx>
56 #include <rtl/strbuf.hxx>
57 #include <math.h>
59 using namespace ::com::sun::star;
60 using namespace ::com::sun::star::uno;
61 using namespace ::com::sun::star::drawing;
62 using namespace ::com::sun::star::drawing::EnhancedCustomShapeSegmentCommand;
64 void EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( EnhancedCustomShapeParameter& rParameter, const sal_Int32 nValue )
66 sal_uInt32 nDat = (sal_uInt32)nValue;
67 sal_Int32 nNewValue = nValue;
69 // check if this is a special point
70 if ( ( nDat >> 16 ) == 0x8000 )
72 nNewValue = (sal_uInt16)nDat;
73 rParameter.Type = EnhancedCustomShapeParameterType::EQUATION;
75 else
76 rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
77 rParameter.Value <<= nNewValue;
80 OUString EnhancedCustomShape2d::GetEquation( const sal_uInt16 nFlags, sal_Int32 nP1, sal_Int32 nP2, sal_Int32 nP3 )
82 OUString aEquation;
83 bool b1Special = ( nFlags & 0x2000 ) != 0;
84 bool b2Special = ( nFlags & 0x4000 ) != 0;
85 bool b3Special = ( nFlags & 0x8000 ) != 0;
86 switch( nFlags & 0xff )
88 case 0 :
89 case 14 :
91 sal_Int32 nOptimize = 0;
92 if ( nP1 )
93 nOptimize |= 1;
94 if ( nP2 )
95 nOptimize |= 2;
96 if ( b1Special )
97 nOptimize |= 4;
98 if ( b2Special )
99 nOptimize |= 8;
100 switch( nOptimize )
102 case 0 :
103 break;
104 case 1 :
105 case 4 :
106 case 5 :
107 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
108 break;
109 case 2 :
110 case 8 :
111 case 10:
112 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
113 break;
114 default :
116 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
117 aEquation += OUString( (sal_Unicode)'+' );
118 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
120 break;
122 if ( b3Special || nP3 )
124 aEquation += OUString( (sal_Unicode)'-' );
125 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
128 break;
129 case 1 :
131 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
132 if ( b2Special || ( nP2 != 1 ) )
134 aEquation += OUString( (sal_Unicode)'*' );
135 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
137 if ( b3Special || ( ( nP3 != 1 ) && ( nP3 != 0 ) ) )
139 aEquation += OUString( (sal_Unicode)'/' );
140 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
143 break;
144 case 2 :
146 aEquation += "(";
147 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
148 aEquation += "+";
149 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
150 aEquation += ")/2";
152 break;
153 case 3 :
155 aEquation += "abs(";
156 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
157 aEquation += ")";
159 break;
160 case 4 :
162 aEquation += "min(";
163 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
164 aEquation += ",";
165 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
166 aEquation += ")";
168 break;
169 case 5 :
171 aEquation += "max(";
172 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
173 aEquation += ",";
174 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
175 aEquation += ")";
177 break;
178 case 6 :
180 aEquation += "if(";
181 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
182 aEquation += OUString( (sal_Unicode)',' );
183 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
184 aEquation += OUString( (sal_Unicode)',' );
185 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
186 aEquation += OUString( (sal_Unicode)')' );
188 break;
189 case 7 :
191 aEquation += "sqrt(";
192 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
193 aEquation += "*";
194 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
195 aEquation += "+";
196 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
197 aEquation += "*";
198 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
199 aEquation += "+";
200 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
201 aEquation += "*";
202 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
203 aEquation += OUString( (sal_Unicode)')' );
205 break;
206 case 8 :
208 aEquation += "atan2(";
209 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
210 aEquation += ",";
211 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
212 aEquation += ")/(pi/180)";
214 break;
215 case 9 :
217 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
218 aEquation += "*sin(";
219 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
220 aEquation += "*(pi/180))";
222 break;
223 case 10 :
225 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
226 aEquation += "*cos(";
227 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
228 aEquation += "*(pi/180))";
230 break;
231 case 11 :
233 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
234 aEquation += "*cos(atan2(";
235 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
236 aEquation += ",";
237 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
238 aEquation += "))";
240 break;
241 case 12 :
243 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
244 aEquation += "*sin(atan2(";
245 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
246 aEquation += ",";
247 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
248 aEquation += "))";
250 break;
251 case 13 :
253 aEquation += "sqrt(";
254 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
255 aEquation += ")";
257 break;
258 case 15 :
260 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
261 aEquation += "*sqrt(1-(";
262 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
263 aEquation += "/";
264 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
265 aEquation += ")";
266 aEquation += "*(";
267 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
268 aEquation += "/";
269 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
270 aEquation += "))";
272 break;
273 case 16 :
275 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
276 aEquation += "*tan(";
277 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
278 aEquation += ")";
280 break;
281 case 0x80 :
283 aEquation += "sqrt(";
284 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
285 aEquation += "*";
286 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
287 aEquation += "-";
288 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
289 aEquation += "*";
290 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
291 aEquation += OUString( (sal_Unicode)')' );
293 break;
294 case 0x81 :
296 aEquation += "(cos(";
297 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
298 aEquation += "*(pi/180))*(";
299 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
300 aEquation += "-10800)+sin(";
301 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
302 aEquation += "*(pi/180))*(";
303 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
304 aEquation += "-10800))+10800";
306 break;
307 case 0x82 :
309 aEquation += "-(sin(";
310 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
311 aEquation += "*(pi/180))*(";
312 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
313 aEquation += "-10800)-cos(";
314 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
315 aEquation += "*(pi/180))*(";
316 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
317 aEquation += "-10800))+10800";
319 break;
321 return aEquation;
324 void EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( OUString& rParameter, const sal_Int32 nPara, const bool bIsSpecialValue )
326 if ( bIsSpecialValue )
328 if ( nPara & 0x400 )
330 rParameter += "?";
331 rParameter += OUString::number( ( nPara & 0xff ) );
332 rParameter += " ";
334 else
336 switch( nPara )
338 case DFF_Prop_adjustValue :
339 case DFF_Prop_adjust2Value :
340 case DFF_Prop_adjust3Value :
341 case DFF_Prop_adjust4Value :
342 case DFF_Prop_adjust5Value :
343 case DFF_Prop_adjust6Value :
344 case DFF_Prop_adjust7Value :
345 case DFF_Prop_adjust8Value :
346 case DFF_Prop_adjust9Value :
347 case DFF_Prop_adjust10Value :
349 rParameter += "$";
350 rParameter += OUString::number( ( nPara - DFF_Prop_adjustValue ) );
351 rParameter += " ";
353 break;
354 case DFF_Prop_geoLeft :
356 rParameter += "left";
358 break;
359 case DFF_Prop_geoTop :
361 rParameter += "top";
363 break;
364 case DFF_Prop_geoRight :
366 rParameter += "right";
368 break;
369 case DFF_Prop_geoBottom :
371 rParameter += "bottom";
373 break;
377 else
379 rParameter += OUString::number( ( nPara ) );
383 void EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( EnhancedCustomShapeParameter& rParameter, const sal_Int32 nPara, const bool bIsSpecialValue, bool bHorz )
385 sal_Int32 nValue = 0;
386 if ( bIsSpecialValue )
388 if ( ( nPara >= 0x100 ) && ( nPara <= 0x107 ) )
390 nValue = nPara & 0xff;
391 rParameter.Type = EnhancedCustomShapeParameterType::ADJUSTMENT;
393 else if ( ( nPara >= 3 ) && ( nPara <= 0x82 ) )
395 nValue = nPara - 3;
396 rParameter.Type = EnhancedCustomShapeParameterType::EQUATION;
398 else if ( nPara == 0 )
400 nValue = 0;
401 if ( bHorz )
402 rParameter.Type = EnhancedCustomShapeParameterType::LEFT;
403 else
404 rParameter.Type = EnhancedCustomShapeParameterType::TOP;
406 else if ( nPara == 1 )
408 nValue = 0;
409 if ( bHorz )
410 rParameter.Type = EnhancedCustomShapeParameterType::RIGHT;
411 else
412 rParameter.Type = EnhancedCustomShapeParameterType::BOTTOM;
414 else if ( nPara == 2 ) // means to be centered, but should not be
415 { // used in our implementation
416 nValue = 5600;
417 rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
419 else
421 nValue = nPara;
422 rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
425 else
427 nValue = nPara;
428 rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
430 rParameter.Value <<= nValue;
433 bool EnhancedCustomShape2d::ConvertSequenceToEnhancedCustomShape2dHandle(
434 const com::sun::star::beans::PropertyValues& rHandleProperties,
435 EnhancedCustomShape2d::Handle& rDestinationHandle )
437 bool bRetValue = false;
438 sal_uInt32 i, nProperties = rHandleProperties.getLength();
439 if ( nProperties )
441 rDestinationHandle.nFlags = HandleFlags::NONE;
442 for ( i = 0; i < nProperties; i++ )
444 const com::sun::star::beans::PropertyValue& rPropVal = rHandleProperties[ i ];
446 if ( rPropVal.Name == "Position" )
448 if ( rPropVal.Value >>= rDestinationHandle.aPosition )
449 bRetValue = true;
451 else if ( rPropVal.Name == "MirroredX" )
453 bool bMirroredX;
454 if ( rPropVal.Value >>= bMirroredX )
456 if ( bMirroredX )
457 rDestinationHandle.nFlags |= HandleFlags::MIRRORED_X;
460 else if ( rPropVal.Name == "MirroredY" )
462 bool bMirroredY;
463 if ( rPropVal.Value >>= bMirroredY )
465 if ( bMirroredY )
466 rDestinationHandle.nFlags |= HandleFlags::MIRRORED_Y;
469 else if ( rPropVal.Name == "Switched" )
471 bool bSwitched;
472 if ( rPropVal.Value >>= bSwitched )
474 if ( bSwitched )
475 rDestinationHandle.nFlags |= HandleFlags::SWITCHED;
478 else if ( rPropVal.Name == "Polar" )
480 if ( rPropVal.Value >>= rDestinationHandle.aPolar )
481 rDestinationHandle.nFlags |= HandleFlags::POLAR;
483 else if ( rPropVal.Name == "RefX" )
485 if ( rPropVal.Value >>= rDestinationHandle.nRefX )
486 rDestinationHandle.nFlags |= HandleFlags::REFX;
488 else if ( rPropVal.Name == "RefY" )
490 if ( rPropVal.Value >>= rDestinationHandle.nRefY )
491 rDestinationHandle.nFlags |= HandleFlags::REFY;
493 else if ( rPropVal.Name == "RefAngle" )
495 if ( rPropVal.Value >>= rDestinationHandle.nRefAngle )
496 rDestinationHandle.nFlags |= HandleFlags::REFANGLE;
498 else if ( rPropVal.Name == "RefR" )
500 if ( rPropVal.Value >>= rDestinationHandle.nRefR )
501 rDestinationHandle.nFlags |= HandleFlags::REFR;
503 else if ( rPropVal.Name == "RadiusRangeMinimum" )
505 if ( rPropVal.Value >>= rDestinationHandle.aRadiusRangeMinimum )
506 rDestinationHandle.nFlags |= HandleFlags::RADIUS_RANGE_MINIMUM;
508 else if ( rPropVal.Name == "RadiusRangeMaximum" )
510 if ( rPropVal.Value >>= rDestinationHandle.aRadiusRangeMaximum )
511 rDestinationHandle.nFlags |= HandleFlags::RADIUS_RANGE_MAXIMUM;
513 else if ( rPropVal.Name == "RangeXMinimum" )
515 if ( rPropVal.Value >>= rDestinationHandle.aXRangeMinimum )
516 rDestinationHandle.nFlags |= HandleFlags::RANGE_X_MINIMUM;
518 else if ( rPropVal.Name == "RangeXMaximum" )
520 if ( rPropVal.Value >>= rDestinationHandle.aXRangeMaximum )
521 rDestinationHandle.nFlags |= HandleFlags::RANGE_X_MAXIMUM;
523 else if ( rPropVal.Name == "RangeYMinimum" )
525 if ( rPropVal.Value >>= rDestinationHandle.aYRangeMinimum )
526 rDestinationHandle.nFlags |= HandleFlags::RANGE_Y_MINIMUM;
528 else if ( rPropVal.Name == "RangeYMaximum" )
530 if ( rPropVal.Value >>= rDestinationHandle.aYRangeMaximum )
531 rDestinationHandle.nFlags |= HandleFlags::RANGE_Y_MAXIMUM;
535 return bRetValue;
538 const sal_Int32* EnhancedCustomShape2d::ApplyShapeAttributes( const SdrCustomShapeGeometryItem& rGeometryItem )
540 const sal_Int32* pDefData = NULL;
541 const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( eSpType );
542 if ( pDefCustomShape )
543 pDefData = pDefCustomShape->pDefData;
546 // AdjustmentValues
547 const Any* pAny = ((SdrCustomShapeGeometryItem&)rGeometryItem).GetPropertyValueByName( "AdjustmentValues" );
548 if ( pAny )
549 *pAny >>= seqAdjustmentValues;
552 // Coordsize
553 const Any* pViewBox = ((SdrCustomShapeGeometryItem&)rGeometryItem).GetPropertyValueByName( "ViewBox" );
554 com::sun::star::awt::Rectangle aViewBox;
555 if ( pViewBox && (*pViewBox >>= aViewBox ) )
557 nCoordLeft = aViewBox.X;
558 nCoordTop = aViewBox.Y;
559 nCoordWidthG = labs( aViewBox.Width );
560 nCoordHeightG = labs( aViewBox.Height);
562 const OUString sPath( "Path" );
565 // Path/Coordinates
566 pAny = ((SdrCustomShapeGeometryItem&)rGeometryItem).GetPropertyValueByName( sPath, "Coordinates" );
567 if ( pAny )
568 *pAny >>= seqCoordinates;
571 // Path/GluePoints
572 pAny = ((SdrCustomShapeGeometryItem&)rGeometryItem).GetPropertyValueByName( sPath, "GluePoints" );
573 if ( pAny )
574 *pAny >>= seqGluePoints;
577 // Path/Segments
578 pAny = ((SdrCustomShapeGeometryItem&)rGeometryItem).GetPropertyValueByName( sPath, "Segments" );
579 if ( pAny )
580 *pAny >>= seqSegments;
583 // Path/SubViewSize
584 pAny = ((SdrCustomShapeGeometryItem&)rGeometryItem).GetPropertyValueByName( sPath, "SubViewSize" );
585 if ( pAny )
586 *pAny >>= seqSubViewSize;
589 // Path/StretchX
590 pAny = ((SdrCustomShapeGeometryItem&)rGeometryItem).GetPropertyValueByName( sPath, "StretchX" );
591 if ( pAny )
593 sal_Int32 nStretchX = 0;
594 if ( *pAny >>= nStretchX )
595 nXRef = nStretchX;
599 // Path/StretchY
600 pAny = ((SdrCustomShapeGeometryItem&)rGeometryItem).GetPropertyValueByName( sPath, "StretchY" );
601 if ( pAny )
603 sal_Int32 nStretchY = 0;
604 if ( *pAny >>= nStretchY )
605 nYRef = nStretchY;
609 // Path/TextFrames
610 pAny = ((SdrCustomShapeGeometryItem&)rGeometryItem).GetPropertyValueByName( sPath, "TextFrames" );
611 if ( pAny )
612 *pAny >>= seqTextFrames;
615 // Equations
616 pAny = ((SdrCustomShapeGeometryItem&)rGeometryItem).GetPropertyValueByName( "Equations" );
617 if ( pAny )
618 *pAny >>= seqEquations;
621 // Handles
622 pAny = ((SdrCustomShapeGeometryItem&)rGeometryItem).GetPropertyValueByName( "Handles" );
623 if ( pAny )
624 *pAny >>= seqHandles;
626 return pDefData;
629 EnhancedCustomShape2d::~EnhancedCustomShape2d()
633 void EnhancedCustomShape2d::SetPathSize( sal_Int32 nIndex )
635 sal_Int32 nWidth = 0;
636 sal_Int32 nHeight = 0;
638 if ( seqSubViewSize.getLength() && nIndex < seqSubViewSize.getLength() ) {
639 nWidth = seqSubViewSize[ nIndex ].Width;
640 nHeight = seqSubViewSize[ nIndex ].Height;
641 SAL_INFO(
642 "svx",
643 "set subpath " << nIndex << " size: " << nWidth << " x "
644 << nHeight);
647 if ( nWidth && nHeight ) {
648 nCoordWidth = nWidth;
649 nCoordHeight = nHeight;
650 } else {
651 nCoordWidth = nCoordWidthG;
652 nCoordHeight = nCoordHeightG;
655 fXScale = nCoordWidth == 0 ? 0.0 : (double)aLogicRect.GetWidth() / (double)nCoordWidth;
656 fYScale = nCoordHeight == 0 ? 0.0 : (double)aLogicRect.GetHeight() / (double)nCoordHeight;
657 if ( bOOXMLShape )
659 SAL_INFO(
660 "svx",
661 "ooxml shape, path width: " << nCoordWidth << " height: "
662 << nCoordHeight);
663 if ( nCoordWidth == 0 )
664 fXScale = 1.0;
665 if ( nCoordHeight == 0 )
666 fYScale = 1.0;
668 if ( (sal_uInt32)nXRef != 0x80000000 && aLogicRect.GetHeight() )
670 fXRatio = (double)aLogicRect.GetWidth() / (double)aLogicRect.GetHeight();
671 if ( fXRatio > 1 )
672 fXScale /= fXRatio;
673 else
674 fXRatio = 1.0;
676 else
677 fXRatio = 1.0;
678 if ( (sal_uInt32)nYRef != 0x80000000 && aLogicRect.GetWidth() )
680 fYRatio = (double)aLogicRect.GetHeight() / (double)aLogicRect.GetWidth();
681 if ( fYRatio > 1 )
682 fYScale /= fYRatio;
683 else
684 fYRatio = 1.0;
686 else
687 fYRatio = 1.0;
690 EnhancedCustomShape2d::EnhancedCustomShape2d( SdrObject* pAObj ) :
691 SfxItemSet ( pAObj->GetMergedItemSet() ),
692 pCustomShapeObj ( pAObj ),
693 eSpType ( mso_sptNil ),
694 nCoordLeft ( 0 ),
695 nCoordTop ( 0 ),
696 nCoordWidthG ( 21600 ),
697 nCoordHeightG ( 21600 ),
698 bOOXMLShape ( false ),
699 nXRef ( 0x80000000 ),
700 nYRef ( 0x80000000 ),
701 nColorData ( 0 ),
702 bTextFlow ( false ),
703 bFilled ( static_cast<const XFillStyleItem&>(pAObj->GetMergedItem( XATTR_FILLSTYLE )).GetValue() != drawing::FillStyle_NONE ),
704 bStroked ( static_cast<const XLineStyleItem&>(pAObj->GetMergedItem( XATTR_LINESTYLE )).GetValue() != drawing::LineStyle_NONE ),
705 bFlipH ( false ),
706 bFlipV ( false )
708 // bTextFlow needs to be set before clearing the TextDirection Item
710 ClearItem( SDRATTR_TEXTDIRECTION ); //SJ: vertical writing is not required, by removing this item no outliner is created
712 // #i105323# For 2D AtoShapes, the shadow attirbute does not need to be applied to any
713 // of the constucted helper SdrObjects. This would lead to problems since the shadow
714 // of one helper object would fall on one helper object behind it (e.g. with the
715 // eyes of the smiley shape). This is not wanted; instead a single shadow 'behind'
716 // the AutoShape visualisation is wanted. This is done with primitive functionailty
717 // now in SdrCustomShapePrimitive2D::create2DDecomposition, but only for 2D objects
718 // (see there and in EnhancedCustomShape3d::Create3DObject to read more).
719 // This exception may be removed later when AutoShapes will create primitives directly.
720 // So, currently remove the ShadowAttribute from the ItemSet to not apply it to any
721 // 2D helper shape.
722 ClearItem(SDRATTR_SHADOW);
724 Point aP( pCustomShapeObj->GetSnapRect().Center() );
725 Size aS( pCustomShapeObj->GetLogicRect().GetSize() );
726 aP.X() -= aS.Width() / 2;
727 aP.Y() -= aS.Height() / 2;
728 aLogicRect = Rectangle( aP, aS );
730 OUString sShapeType;
731 const SdrCustomShapeGeometryItem& rGeometryItem = static_cast<const SdrCustomShapeGeometryItem&>(pCustomShapeObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
732 const Any* pAny = rGeometryItem.GetPropertyValueByName( "Type" );
733 if ( pAny ) {
734 *pAny >>= sShapeType;
735 bOOXMLShape = ( sShapeType.startsWith("ooxml-") );
736 OSL_TRACE("shape type: %s %d", OUStringToOString( sShapeType, RTL_TEXTENCODING_ASCII_US ).getStr(), bOOXMLShape);
738 eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );
740 pAny = rGeometryItem.GetPropertyValueByName( "MirroredX" );
741 if ( pAny )
742 *pAny >>= bFlipH;
743 pAny = rGeometryItem.GetPropertyValueByName( "MirroredY" );
744 if ( pAny )
745 *pAny >>= bFlipV;
747 if ( pCustomShapeObj->ISA( SdrObjCustomShape ) ) // should always be a SdrObjCustomShape, but you don't know
748 nRotateAngle = (sal_Int32)(static_cast<SdrObjCustomShape*>(pCustomShapeObj)->GetObjectRotation() * 100.0);
749 else
750 nRotateAngle = pCustomShapeObj->GetRotateAngle();
752 /*const sal_Int32* pDefData =*/ ApplyShapeAttributes( rGeometryItem );
753 SetPathSize();
755 switch( eSpType )
757 case mso_sptCan : nColorData = 0x20400000; break;
758 case mso_sptCube : nColorData = 0x302e0000; break;
759 case mso_sptActionButtonBlank : nColorData = 0x502ce400; break;
760 case mso_sptActionButtonHome : nColorData = 0x702ce4ce; break;
761 case mso_sptActionButtonHelp : nColorData = 0x602ce4c0; break;
762 case mso_sptActionButtonInformation : nColorData = 0x702ce4c5; break;
763 case mso_sptActionButtonBackPrevious : nColorData = 0x602ce4c0; break;
764 case mso_sptActionButtonForwardNext : nColorData = 0x602ce4c0; break;
765 case mso_sptActionButtonBeginning : nColorData = 0x602ce4c0; break;
766 case mso_sptActionButtonEnd : nColorData = 0x602ce4c0; break;
767 case mso_sptActionButtonReturn : nColorData = 0x602ce4c0; break;
768 case mso_sptActionButtonDocument : nColorData = 0x702ce4ec; break;
769 case mso_sptActionButtonSound : nColorData = 0x602ce4c0; break;
770 case mso_sptActionButtonMovie : nColorData = 0x602ce4c0; break;
771 case mso_sptBevel : nColorData = 0x502ce400; break;
772 case mso_sptFoldedCorner : nColorData = 0x20e00000; break;
773 case mso_sptSmileyFace : nColorData = 0x20e00000; break;
774 case mso_sptNil :
776 if( sShapeType.getLength() > 4 &&
777 sShapeType.match( "col-" ))
779 nColorData = sShapeType.copy( 4 ).toUInt32( 16 );
782 break;
783 case mso_sptCurvedLeftArrow :
784 case mso_sptCurvedRightArrow :
785 case mso_sptCurvedUpArrow :
786 case mso_sptCurvedDownArrow : nColorData = 0x20d00000; break;
787 case mso_sptRibbon2 : nColorData = 0x30ee0000; break;
788 case mso_sptRibbon : nColorData = 0x30ee0000; break;
790 case mso_sptEllipseRibbon2 : nColorData = 0x30ee0000; break;
791 case mso_sptEllipseRibbon : nColorData = 0x30ee0000; break;
793 case mso_sptVerticalScroll : nColorData = 0x30ee0000; break;
794 case mso_sptHorizontalScroll : nColorData = 0x30ee0000; break;
795 default:
796 break;
799 sal_Int32 i, nLength = seqEquations.getLength();
801 if ( nLength )
803 vNodesSharedPtr.resize( nLength );
804 vEquationResults.resize( nLength );
805 for ( i = 0; i < seqEquations.getLength(); i++ )
807 vEquationResults[ i ].bReady = false;
810 vNodesSharedPtr[ i ] = EnhancedCustomShape::FunctionParser::parseFunction( seqEquations[ i ], *this );
812 catch ( EnhancedCustomShape::ParseError& )
814 SAL_INFO(
815 "svx",
816 "error: equation number: " << i << ", parser failed ("
817 << seqEquations[i] << ")");
822 double EnhancedCustomShape2d::GetEnumFunc( const EnumFunc eFunc ) const
824 double fRet = 0.0;
825 switch( eFunc )
827 case ENUM_FUNC_PI : fRet = F_PI; break;
828 case ENUM_FUNC_LEFT : fRet = 0.0; break;
829 case ENUM_FUNC_TOP : fRet = 0.0; break;
830 case ENUM_FUNC_RIGHT : fRet = (double)nCoordWidth * fXRatio; break;
831 case ENUM_FUNC_BOTTOM : fRet = (double)nCoordHeight * fYRatio; break;
832 case ENUM_FUNC_XSTRETCH : fRet = nXRef; break;
833 case ENUM_FUNC_YSTRETCH : fRet = nYRef; break;
834 case ENUM_FUNC_HASSTROKE : fRet = bStroked ? 1.0 : 0.0; break;
835 case ENUM_FUNC_HASFILL : fRet = bFilled ? 1.0 : 0.0; break;
836 case ENUM_FUNC_WIDTH : fRet = nCoordWidth; break;
837 case ENUM_FUNC_HEIGHT : fRet = nCoordHeight; break;
838 case ENUM_FUNC_LOGWIDTH : fRet = aLogicRect.GetWidth(); break;
839 case ENUM_FUNC_LOGHEIGHT : fRet = aLogicRect.GetHeight(); break;
841 return fRet;
843 double EnhancedCustomShape2d::GetAdjustValueAsDouble( const sal_Int32 nIndex ) const
845 double fNumber = 0.0;
846 if ( nIndex < seqAdjustmentValues.getLength() )
848 if ( seqAdjustmentValues[ nIndex ].Value.getValueTypeClass() == TypeClass_DOUBLE )
849 seqAdjustmentValues[ nIndex ].Value >>= fNumber;
850 else
852 sal_Int32 nNumber = 0;
853 seqAdjustmentValues[ nIndex ].Value >>= nNumber;
854 fNumber = (double)nNumber;
857 return fNumber;
859 double EnhancedCustomShape2d::GetEquationValueAsDouble( const sal_Int32 nIndex ) const
861 double fNumber = 0.0;
862 #if OSL_DEBUG_LEVEL > 1
863 static sal_uInt32 nLevel = 0;
864 #endif
865 if ( nIndex < (sal_Int32)vNodesSharedPtr.size() )
867 if ( vNodesSharedPtr[ nIndex ].get() ) {
868 #if OSL_DEBUG_LEVEL > 1
869 nLevel ++;
870 #endif
873 if ( vEquationResults[ nIndex ].bReady )
874 fNumber = vEquationResults[ nIndex ].fValue;
875 else {
876 // cast to non const, so that we can optimize by caching
877 // equation results, without changing all the const in the stack
878 struct EquationResult &aResult = const_cast<EnhancedCustomShape2d*>(this)->vEquationResults[ nIndex ];
880 fNumber = aResult.fValue = (*vNodesSharedPtr[ nIndex ])();
881 aResult.bReady = true;
883 if ( !rtl::math::isFinite( fNumber ) )
884 fNumber = 0.0;
885 #if OSL_DEBUG_LEVEL > 1
886 OSL_TRACE("equation %d (level: %d): %s --> %f (angle: %f)", nIndex,
887 nLevel, OUStringToOString( seqEquations[ nIndex ],
888 RTL_TEXTENCODING_ASCII_US ).getStr(), fNumber, 180.0*fNumber/10800000.0);
889 #endif
892 catch ( ... )
894 OSL_TRACE("error: EnhancedCustomShape2d::GetEquationValueAsDouble failed");
896 #if OSL_DEBUG_LEVEL > 1
897 nLevel --;
898 #endif
900 SAL_INFO(
901 "svx",
902 "?" << nIndex << " --> " << fNumber << " (angle: "
903 << 180.0*fNumber/10800000.0 << ")");
906 return fNumber;
908 sal_Int32 EnhancedCustomShape2d::GetAdjustValueAsInteger( const sal_Int32 nIndex, const sal_Int32 nDefault ) const
910 sal_Int32 nNumber = nDefault;
911 if ( nIndex < seqAdjustmentValues.getLength() )
913 if ( seqAdjustmentValues[ nIndex ].Value.getValueTypeClass() == TypeClass_DOUBLE )
915 double fNumber = 0;
916 seqAdjustmentValues[ nIndex ].Value >>= fNumber;
917 nNumber = (sal_Int32)fNumber;
919 else
920 seqAdjustmentValues[ nIndex ].Value >>= nNumber;
922 return nNumber;
924 bool EnhancedCustomShape2d::SetAdjustValueAsDouble( const double& rValue, const sal_Int32 nIndex )
926 bool bRetValue = false;
927 if ( nIndex < seqAdjustmentValues.getLength() )
929 // updating our local adjustment sequence
930 seqAdjustmentValues[ nIndex ].Value <<= rValue;
931 seqAdjustmentValues[ nIndex ].State = com::sun::star::beans::PropertyState_DIRECT_VALUE;
932 bRetValue = true;
934 return bRetValue;
937 Point EnhancedCustomShape2d::GetPoint( const com::sun::star::drawing::EnhancedCustomShapeParameterPair& rPair,
938 const bool bScale, const bool bReplaceGeoSize ) const
940 Point aRetValue;
941 sal_uInt32 nPass = 0;
944 sal_uInt32 nIndex = nPass;
946 double fVal;
947 const EnhancedCustomShapeParameter& rParameter = nIndex ? rPair.Second : rPair.First;
948 if ( nPass ) // height
950 GetParameter( fVal, rParameter, false, bReplaceGeoSize );
951 fVal -= nCoordTop;
952 if ( bScale )
954 fVal *= fYScale;
956 aRetValue.Y() = (sal_Int32)fVal;
958 else // width
960 GetParameter( fVal, rParameter, bReplaceGeoSize, false );
961 fVal -= nCoordLeft;
962 if ( bScale )
964 fVal *= fXScale;
966 aRetValue.X() = static_cast<long>(fVal);
969 while ( ++nPass < 2 );
970 return aRetValue;
973 bool EnhancedCustomShape2d::GetParameter( double& rRetValue, const EnhancedCustomShapeParameter& rParameter,
974 const bool bReplaceGeoWidth, const bool bReplaceGeoHeight ) const
976 rRetValue = 0.0;
977 bool bRetValue = false;
978 switch ( rParameter.Type )
980 case EnhancedCustomShapeParameterType::ADJUSTMENT :
982 sal_Int32 nAdjustmentIndex = 0;
983 if ( rParameter.Value >>= nAdjustmentIndex )
985 rRetValue = GetAdjustValueAsDouble( nAdjustmentIndex );
986 bRetValue = true;
989 break;
990 case EnhancedCustomShapeParameterType::EQUATION :
992 sal_Int32 nEquationIndex = 0;
993 if ( rParameter.Value >>= nEquationIndex )
995 rRetValue = GetEquationValueAsDouble( nEquationIndex );
996 bRetValue = true;
999 break;
1000 case EnhancedCustomShapeParameterType::NORMAL :
1002 if ( rParameter.Value.getValueTypeClass() == TypeClass_DOUBLE )
1004 double fValue(0.0);
1005 if ( rParameter.Value >>= fValue )
1007 rRetValue = fValue;
1008 bRetValue = true;
1011 else
1013 sal_Int32 nValue = 0;
1014 if ( rParameter.Value >>= nValue )
1016 rRetValue = nValue;
1017 bRetValue = true;
1018 if ( bReplaceGeoWidth && ( nValue == nCoordWidth ) )
1019 rRetValue *= fXRatio;
1020 else if ( bReplaceGeoHeight && ( nValue == nCoordHeight ) )
1021 rRetValue *= fYRatio;
1025 break;
1026 case EnhancedCustomShapeParameterType::LEFT :
1028 rRetValue = 0.0;
1029 bRetValue = true;
1031 break;
1032 case EnhancedCustomShapeParameterType::TOP :
1034 rRetValue = 0.0;
1035 bRetValue = true;
1037 break;
1038 case EnhancedCustomShapeParameterType::RIGHT :
1040 rRetValue = nCoordWidth;
1041 bRetValue = true;
1043 break;
1044 case EnhancedCustomShapeParameterType::BOTTOM :
1046 rRetValue = nCoordHeight;
1047 bRetValue = true;
1049 break;
1051 return bRetValue;
1054 // nLumDat 28-31 = number of luminance entries in nLumDat
1055 // nLumDat 27-24 = nLumDatEntry 0
1056 // nLumDat 23-20 = nLumDatEntry 1 ...
1057 // each 4bit entry is to be interpreted as a 10 percent signed luminance changing
1058 sal_Int32 EnhancedCustomShape2d::GetLuminanceChange( sal_uInt32 nIndex ) const
1060 const sal_uInt32 nCount = nColorData >> 28;
1061 if ( !nCount )
1062 return 0;
1064 if ( nIndex >= nCount )
1065 nIndex = nCount - 1;
1067 const sal_Int32 nLumDat = nColorData << ( ( 1 + nIndex ) << 2 );
1068 return ( nLumDat >> 28 ) * 10;
1071 Color EnhancedCustomShape2d::GetColorData( const Color& rFillColor, sal_uInt32 nIndex, double dBrightness ) const
1073 const sal_Int32 nLuminance = GetLuminanceChange(nIndex);
1074 if( !nLuminance && dBrightness == 1.0 )
1075 return rFillColor;
1077 basegfx::BColor aHSVColor=
1078 basegfx::tools::rgb2hsv(
1079 basegfx::BColor(rFillColor.GetRed()/255.0,
1080 rFillColor.GetGreen()/255.0,
1081 rFillColor.GetBlue()/255.0));
1082 if (nLuminance ) {
1083 if( nLuminance > 0 )
1085 aHSVColor.setGreen(
1086 aHSVColor.getGreen() * (1.0-nLuminance/100.0));
1087 aHSVColor.setBlue(
1088 nLuminance/100.0 +
1089 (1.0-nLuminance/100.0)*aHSVColor.getBlue());
1091 else if( nLuminance < 0 )
1093 aHSVColor.setBlue(
1094 (1.0+nLuminance/100.0)*aHSVColor.getBlue());
1098 aHSVColor = basegfx::tools::hsv2rgb(aHSVColor);
1099 return Color( (sal_uInt8)static_cast< sal_Int32 >( basegfx::clamp(dBrightness*aHSVColor.getRed(),0.0,1.0) * 255.0 + 0.5 ),
1100 (sal_uInt8)static_cast< sal_Int32 >( basegfx::clamp(dBrightness*aHSVColor.getGreen(),0.0,1.0) * 255.0 + 0.5 ),
1101 (sal_uInt8)static_cast< sal_Int32 >( basegfx::clamp(dBrightness*aHSVColor.getBlue(),0.0,1.0) * 255.0 + 0.5 ) );
1104 Rectangle EnhancedCustomShape2d::GetTextRect() const
1106 sal_Int32 nIndex, nSize = seqTextFrames.getLength();
1107 if ( !nSize )
1108 return aLogicRect;
1109 nIndex = 0;
1110 if ( bTextFlow && ( nSize > 1 ) )
1111 nIndex++;
1112 Point aTopLeft( GetPoint( seqTextFrames[ nIndex ].TopLeft, !bOOXMLShape, true ) );
1113 Point aBottomRight( GetPoint( seqTextFrames[ nIndex ].BottomRight, !bOOXMLShape, true ) );
1114 if ( bFlipH )
1116 aTopLeft.X() = aLogicRect.GetWidth() - aTopLeft.X();
1117 aBottomRight.X() = aLogicRect.GetWidth() - aBottomRight.X();
1119 if ( bFlipV )
1121 aTopLeft.Y() = aLogicRect.GetHeight() - aTopLeft.Y();
1122 aBottomRight.Y() = aLogicRect.GetHeight() - aBottomRight.Y();
1124 Rectangle aRect( aTopLeft, aBottomRight );
1125 SAL_INFO("svx", aRect.GetWidth() << " x " << aRect.GetHeight());
1126 if( aRect.GetWidth() <= 1 || aRect.GetHeight() <= 1 )
1127 return aLogicRect;
1128 aRect.Move( aLogicRect.Left(), aLogicRect.Top() );
1129 aRect.Justify();
1130 return aRect;
1133 sal_uInt32 EnhancedCustomShape2d::GetHdlCount() const
1135 return seqHandles.getLength();
1138 bool EnhancedCustomShape2d::GetHandlePosition( const sal_uInt32 nIndex, Point& rReturnPosition ) const
1140 bool bRetValue = false;
1141 if ( nIndex < GetHdlCount() )
1143 Handle aHandle;
1144 if ( ConvertSequenceToEnhancedCustomShape2dHandle( seqHandles[ nIndex ], aHandle ) )
1146 if ( aHandle.nFlags & HandleFlags::POLAR )
1148 Point aReferencePoint( GetPoint( aHandle.aPolar, true, false ) );
1150 double fAngle;
1151 double fRadius;
1152 GetParameter( fRadius, aHandle.aPosition.First, false, false );
1153 GetParameter( fAngle, aHandle.aPosition.Second, false, false );
1155 double a = ( 360.0 - fAngle ) * F_PI180;
1156 double dx = fRadius * fXScale;
1157 double fX = dx * cos( a );
1158 double fY =-dx * sin( a );
1159 rReturnPosition =
1160 Point(
1161 Round( fX + aReferencePoint.X() ),
1162 basegfx::fTools::equalZero(fXScale) ? aReferencePoint.Y() :
1163 Round( ( fY * fYScale ) / fXScale + aReferencePoint.Y() ) );
1165 else
1167 if ( aHandle.nFlags & HandleFlags::SWITCHED )
1169 if ( aLogicRect.GetHeight() > aLogicRect.GetWidth() )
1171 com::sun::star::drawing::EnhancedCustomShapeParameter aFirst = aHandle.aPosition.First;
1172 com::sun::star::drawing::EnhancedCustomShapeParameter aSecond = aHandle.aPosition.Second;
1173 aHandle.aPosition.First = aSecond;
1174 aHandle.aPosition.Second = aFirst;
1177 rReturnPosition = GetPoint( aHandle.aPosition, true, false );
1179 const GeoStat aGeoStat( static_cast<SdrObjCustomShape*>(pCustomShapeObj)->GetGeoStat() );
1180 if ( aGeoStat.nShearAngle )
1182 double nTan = aGeoStat.nTan;
1183 if ((bFlipV&&!bFlipH )||(bFlipH&&!bFlipV))
1184 nTan = -nTan;
1185 ShearPoint( rReturnPosition, Point( aLogicRect.GetWidth() / 2, aLogicRect.GetHeight() / 2 ), nTan );
1187 if ( nRotateAngle )
1189 double a = nRotateAngle * F_PI18000;
1190 RotatePoint( rReturnPosition, Point( aLogicRect.GetWidth() / 2, aLogicRect.GetHeight() / 2 ), sin( a ), cos( a ) );
1192 if ( bFlipH )
1193 rReturnPosition.X() = aLogicRect.GetWidth() - rReturnPosition.X();
1194 if ( bFlipV )
1195 rReturnPosition.Y() = aLogicRect.GetHeight() - rReturnPosition.Y();
1196 rReturnPosition.Move( aLogicRect.Left(), aLogicRect.Top() );
1197 bRetValue = true;
1200 return bRetValue;
1203 bool EnhancedCustomShape2d::SetHandleControllerPosition( const sal_uInt32 nIndex, const com::sun::star::awt::Point& rPosition )
1205 bool bRetValue = false;
1206 if ( nIndex < GetHdlCount() )
1208 Handle aHandle;
1209 if ( ConvertSequenceToEnhancedCustomShape2dHandle( seqHandles[ nIndex ], aHandle ) )
1211 Point aP( rPosition.X, rPosition.Y );
1212 // apply the negative object rotation to the controller position
1214 aP.Move( -aLogicRect.Left(), -aLogicRect.Top() );
1215 if ( bFlipH )
1216 aP.X() = aLogicRect.GetWidth() - aP.X();
1217 if ( bFlipV )
1218 aP.Y() = aLogicRect.GetHeight() - aP.Y();
1219 if ( nRotateAngle )
1221 double a = -nRotateAngle * F_PI18000;
1222 RotatePoint( aP, Point( aLogicRect.GetWidth() / 2, aLogicRect.GetHeight() / 2 ), sin( a ), cos( a ) );
1224 const GeoStat aGeoStat( static_cast<SdrObjCustomShape*>(pCustomShapeObj)->GetGeoStat() );
1225 if ( aGeoStat.nShearAngle )
1227 double nTan = -aGeoStat.nTan;
1228 if ((bFlipV&&!bFlipH )||(bFlipH&&!bFlipV))
1229 nTan = -nTan;
1230 ShearPoint( aP, Point( aLogicRect.GetWidth() / 2, aLogicRect.GetHeight() / 2 ), nTan );
1233 double fPos1 = aP.X(); //( bFlipH ) ? aLogicRect.GetWidth() - aP.X() : aP.X();
1234 double fPos2 = aP.Y(); //( bFlipV ) ? aLogicRect.GetHeight() -aP.Y() : aP.Y();
1235 fPos1 /= fXScale;
1236 fPos2 /= fYScale;
1238 if ( aHandle.nFlags & HandleFlags::SWITCHED )
1240 if ( aLogicRect.GetHeight() > aLogicRect.GetWidth() )
1242 double fX = fPos1;
1243 double fY = fPos2;
1244 fPos1 = fY;
1245 fPos2 = fX;
1249 sal_Int32 nFirstAdjustmentValue = -1, nSecondAdjustmentValue = -1;
1251 if ( aHandle.aPosition.First.Type == EnhancedCustomShapeParameterType::ADJUSTMENT )
1252 aHandle.aPosition.First.Value >>= nFirstAdjustmentValue;
1253 if ( aHandle.aPosition.Second.Type == EnhancedCustomShapeParameterType::ADJUSTMENT )
1254 aHandle.aPosition.Second.Value>>= nSecondAdjustmentValue;
1256 if ( aHandle.nFlags & HandleFlags::POLAR )
1258 double fXRef, fYRef, fAngle;
1259 GetParameter( fXRef, aHandle.aPolar.First, false, false );
1260 GetParameter( fYRef, aHandle.aPolar.Second, false, false );
1261 const double fDX = fPos1 - fXRef;
1262 fAngle = -( atan2( -fPos2 + fYRef, ( ( fDX == 0.0L ) ? 0.000000001 : fDX ) ) / F_PI180 );
1263 double fX = ( fPos1 - fXRef );
1264 double fY = ( fPos2 - fYRef );
1265 double fRadius = sqrt( fX * fX + fY * fY );
1266 if ( aHandle.nFlags & HandleFlags::RADIUS_RANGE_MINIMUM )
1268 double fMin;
1269 GetParameter( fMin, aHandle.aRadiusRangeMinimum, false, false );
1270 if ( fRadius < fMin )
1271 fRadius = fMin;
1273 if ( aHandle.nFlags & HandleFlags::RADIUS_RANGE_MAXIMUM )
1275 double fMax;
1276 GetParameter( fMax, aHandle.aRadiusRangeMaximum, false, false );
1277 if ( fRadius > fMax )
1278 fRadius = fMax;
1280 if ( nFirstAdjustmentValue >= 0 )
1281 SetAdjustValueAsDouble( fRadius, nFirstAdjustmentValue );
1282 if ( nSecondAdjustmentValue >= 0 )
1283 SetAdjustValueAsDouble( fAngle, nSecondAdjustmentValue );
1285 else
1287 if ( aHandle.nFlags & HandleFlags::REFX )
1289 nFirstAdjustmentValue = aHandle.nRefX;
1290 fPos1 *= 100000.0;
1291 fPos1 /= nCoordWidth;
1293 if ( aHandle.nFlags & HandleFlags::REFY )
1295 nSecondAdjustmentValue = aHandle.nRefY;
1296 fPos2 *= 100000.0;
1297 fPos2 /= nCoordHeight;
1299 if ( nFirstAdjustmentValue >= 0 )
1301 if ( aHandle.nFlags & HandleFlags::RANGE_X_MINIMUM ) // check if horizontal handle needs to be within a range
1303 double fXMin;
1304 GetParameter( fXMin, aHandle.aXRangeMinimum, false, false );
1305 if ( fPos1 < fXMin )
1306 fPos1 = fXMin;
1308 if ( aHandle.nFlags & HandleFlags::RANGE_X_MAXIMUM ) // check if horizontal handle needs to be within a range
1310 double fXMax;
1311 GetParameter( fXMax, aHandle.aXRangeMaximum, false, false );
1312 if ( fPos1 > fXMax )
1313 fPos1 = fXMax;
1315 SetAdjustValueAsDouble( fPos1, nFirstAdjustmentValue );
1317 if ( nSecondAdjustmentValue >= 0 )
1319 if ( aHandle.nFlags & HandleFlags::RANGE_Y_MINIMUM ) // check if vertical handle needs to be within a range
1321 double fYMin;
1322 GetParameter( fYMin, aHandle.aYRangeMinimum, false, false );
1323 if ( fPos2 < fYMin )
1324 fPos2 = fYMin;
1326 if ( aHandle.nFlags & HandleFlags::RANGE_Y_MAXIMUM ) // check if vertical handle needs to be within a range
1328 double fYMax;
1329 GetParameter( fYMax, aHandle.aYRangeMaximum, false, false );
1330 if ( fPos2 > fYMax )
1331 fPos2 = fYMax;
1333 SetAdjustValueAsDouble( fPos2, nSecondAdjustmentValue );
1336 // and writing them back into the GeometryItem
1337 SdrCustomShapeGeometryItem aGeometryItem(
1338 static_cast<const SdrCustomShapeGeometryItem&>(pCustomShapeObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )));
1339 com::sun::star::beans::PropertyValue aPropVal;
1340 aPropVal.Name = "AdjustmentValues";
1341 aPropVal.Value <<= seqAdjustmentValues;
1342 aGeometryItem.SetPropertyValue( aPropVal );
1343 pCustomShapeObj->SetMergedItem( aGeometryItem );
1344 bRetValue = true;
1347 return bRetValue;
1350 void EnhancedCustomShape2d::SwapStartAndEndArrow( SdrObject* pObj ) //#108274
1352 XLineStartItem aLineStart;
1353 aLineStart.SetLineStartValue(static_cast<const XLineStartItem&>(pObj->GetMergedItem( XATTR_LINEEND )).GetLineStartValue());
1354 XLineStartWidthItem aLineStartWidth(static_cast<const XLineStartWidthItem&>(pObj->GetMergedItem( XATTR_LINEENDWIDTH )).GetValue());
1355 XLineStartCenterItem aLineStartCenter(static_cast<const XLineStartCenterItem&>(pObj->GetMergedItem( XATTR_LINEENDCENTER )).GetValue());
1357 XLineEndItem aLineEnd;
1358 aLineEnd.SetLineEndValue(static_cast<const XLineEndItem&>(pObj->GetMergedItem( XATTR_LINESTART )).GetLineEndValue());
1359 XLineEndWidthItem aLineEndWidth(static_cast<const XLineEndWidthItem&>(pObj->GetMergedItem( XATTR_LINESTARTWIDTH )).GetValue());
1360 XLineEndCenterItem aLineEndCenter(static_cast<const XLineEndCenterItem&>(pObj->GetMergedItem( XATTR_LINESTARTCENTER )).GetValue());
1362 pObj->SetMergedItem( aLineStart );
1363 pObj->SetMergedItem( aLineStartWidth );
1364 pObj->SetMergedItem( aLineStartCenter );
1365 pObj->SetMergedItem( aLineEnd );
1366 pObj->SetMergedItem( aLineEndWidth );
1367 pObj->SetMergedItem( aLineEndCenter );
1370 static basegfx::B2DPolygon CreateArc( const Rectangle& rRect, const Point& rStart, const Point& rEnd, const bool bClockwise, bool bFullCircle = false )
1372 Rectangle aRect( rRect );
1373 Point aStart( rStart );
1374 Point aEnd( rEnd );
1376 sal_Int32 bSwapStartEndAngle = 0;
1378 if ( aRect.Left() > aRect.Right() )
1379 bSwapStartEndAngle ^= 0x01;
1380 if ( aRect.Top() > aRect.Bottom() )
1381 bSwapStartEndAngle ^= 0x11;
1382 if ( bSwapStartEndAngle )
1384 aRect.Justify();
1385 if ( bSwapStartEndAngle & 1 )
1387 Point aTmp( aStart );
1388 aStart = aEnd;
1389 aEnd = aTmp;
1393 Polygon aTempPoly( aRect, aStart, aEnd, POLY_ARC, bFullCircle );
1394 basegfx::B2DPolygon aRetval;
1396 if ( bClockwise )
1398 for ( sal_uInt16 j = aTempPoly.GetSize(); j--; )
1400 aRetval.append(basegfx::B2DPoint(aTempPoly[ j ].X(), aTempPoly[ j ].Y()));
1403 else
1405 for ( sal_uInt16 j = 0; j < aTempPoly.GetSize(); j++ )
1407 aRetval.append(basegfx::B2DPoint(aTempPoly[ j ].X(), aTempPoly[ j ].Y()));
1411 return aRetval;
1414 void EnhancedCustomShape2d::CreateSubPath( sal_uInt16& rSrcPt, sal_uInt16& rSegmentInd, std::vector< SdrPathObj* >& rObjectList,
1415 const bool bLineGeometryNeededOnly,
1416 const bool bSortFilledObjectsToBack,
1417 sal_Int32 nIndex )
1419 bool bNoFill = false;
1420 bool bNoStroke = false;
1421 double dBrightness = 1.0;
1423 basegfx::B2DPolyPolygon aNewB2DPolyPolygon;
1424 basegfx::B2DPolygon aNewB2DPolygon;
1426 SetPathSize( nIndex );
1428 sal_Int32 nCoordSize = seqCoordinates.getLength();
1429 sal_Int32 nSegInfoSize = seqSegments.getLength();
1430 if ( !nSegInfoSize )
1432 const EnhancedCustomShapeParameterPair* pTmp = seqCoordinates.getArray();
1434 for ( sal_Int32 nPtNum(0L); nPtNum < nCoordSize; nPtNum++ )
1436 const Point aTempPoint(GetPoint( *pTmp++, true, true ));
1437 aNewB2DPolygon.append(basegfx::B2DPoint(aTempPoint.X(), aTempPoint.Y()));
1440 aNewB2DPolygon.setClosed(true);
1442 else
1444 for ( ;rSegmentInd < nSegInfoSize; )
1446 sal_Int16 nCommand = seqSegments[ rSegmentInd ].Command;
1447 sal_Int16 nPntCount= seqSegments[ rSegmentInd++ ].Count;
1449 switch ( nCommand )
1451 case NOFILL :
1452 bNoFill = true;
1453 break;
1454 case NOSTROKE :
1455 bNoStroke = true;
1456 break;
1457 case DARKEN :
1458 dBrightness = 0.66666666;
1459 break;
1460 case DARKENLESS :
1461 dBrightness = 0.83333333;
1462 break;
1463 case LIGHTEN :
1464 dBrightness = 1.16666666;
1465 break;
1466 case LIGHTENLESS :
1467 dBrightness = 1.33333333;
1468 break;
1469 case MOVETO :
1471 if(aNewB2DPolygon.count() > 1L)
1473 // #i76201# Add conversion to closed polygon when first and last points are equal
1474 basegfx::tools::checkClosed(aNewB2DPolygon);
1475 aNewB2DPolyPolygon.append(aNewB2DPolygon);
1478 aNewB2DPolygon.clear();
1480 if ( rSrcPt < nCoordSize )
1482 const Point aTempPoint(GetPoint( seqCoordinates[ rSrcPt++ ], true, true ));
1483 SAL_INFO(
1484 "svx",
1485 "moveTo: " << aTempPoint.X() << ","
1486 << aTempPoint.Y());
1487 aNewB2DPolygon.append(basegfx::B2DPoint(aTempPoint.X(), aTempPoint.Y()));
1490 break;
1491 case ENDSUBPATH :
1492 break;
1493 case CLOSESUBPATH :
1495 if(aNewB2DPolygon.count())
1497 if(aNewB2DPolygon.count() > 1L)
1499 aNewB2DPolygon.setClosed(true);
1500 aNewB2DPolyPolygon.append(aNewB2DPolygon);
1503 aNewB2DPolygon.clear();
1506 break;
1507 case CURVETO :
1509 for ( sal_uInt16 i = 0; ( i < nPntCount ) && ( ( rSrcPt + 2 ) < nCoordSize ); i++ )
1511 const Point aControlA(GetPoint( seqCoordinates[ rSrcPt++ ], true, true ));
1512 const Point aControlB(GetPoint( seqCoordinates[ rSrcPt++ ], true, true ));
1513 const Point aEnd(GetPoint( seqCoordinates[ rSrcPt++ ], true, true ));
1515 DBG_ASSERT(aNewB2DPolygon.count(), "EnhancedCustomShape2d::CreateSubPath: Error in adding control point (!)");
1516 aNewB2DPolygon.appendBezierSegment(
1517 basegfx::B2DPoint(aControlA.X(), aControlA.Y()),
1518 basegfx::B2DPoint(aControlB.X(), aControlB.Y()),
1519 basegfx::B2DPoint(aEnd.X(), aEnd.Y()));
1522 break;
1524 case ANGLEELLIPSE :
1526 if ( nPntCount )
1528 if(aNewB2DPolygon.count() > 1L)
1530 // #i76201# Add conversion to closed polygon when first and last points are equal
1531 basegfx::tools::checkClosed(aNewB2DPolygon);
1532 aNewB2DPolyPolygon.append(aNewB2DPolygon);
1534 aNewB2DPolygon.clear();
1537 case ANGLEELLIPSETO :
1539 for ( sal_uInt16 i = 0; ( i < nPntCount ) && ( ( rSrcPt + 2 ) < nCoordSize ); i++ )
1541 // create a circle
1542 Point _aCenter;
1543 double fWidth, fHeight;
1544 const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( mso_sptEllipse );
1545 bool bIsDefaultViewBox = false;
1546 bool bIsDefaultPath = false;
1547 bool bIsMSEllipse = false;
1549 if( ( nCoordWidth == pDefCustomShape->nCoordWidth )
1550 && ( nCoordHeight == pDefCustomShape->nCoordHeight ) )
1551 bIsDefaultViewBox = true;
1552 sal_Int32 j, nCount = pDefCustomShape->nVertices;//==3
1553 com::sun::star::uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeParameterPair> seqCoordinates1, seqCoordinates2;
1555 seqCoordinates1.realloc( nCount );
1556 for ( j = 0; j < nCount; j++ )
1558 seqCoordinates1[j] = seqCoordinates[ rSrcPt + j];
1561 seqCoordinates2.realloc( nCount );
1562 for ( j = 0; j < nCount; j++ )
1564 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqCoordinates2[ j ].First, pDefCustomShape->pVertices[ j ].nValA );
1565 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqCoordinates2[ j ].Second, pDefCustomShape->pVertices[ j ].nValB );
1567 if(seqCoordinates1 == seqCoordinates2)
1568 bIsDefaultPath = true;
1570 OUString sShpType;
1571 SdrCustomShapeGeometryItem& rGeometryItem = const_cast<SdrCustomShapeGeometryItem&>(static_cast<const SdrCustomShapeGeometryItem&>(pCustomShapeObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )));
1572 Any* pAny = rGeometryItem.GetPropertyValueByName( "Type" );
1573 if ( pAny )
1574 *pAny >>= sShpType;
1575 if( sShpType.getLength() > 3 &&
1576 sShpType.startsWith( "mso" )){
1577 bIsMSEllipse = true;
1579 if( (! bIsDefaultPath && ! bIsDefaultViewBox) || (bIsDefaultViewBox && bIsMSEllipse) /*&& (nGeneratorVersion == SfxObjectShell::Sym_L2)*/ )
1581 _aCenter = GetPoint( seqCoordinates[ rSrcPt ], true, true );
1582 GetParameter( fWidth, seqCoordinates[ rSrcPt + 1 ].First, true, false );
1583 GetParameter( fHeight, seqCoordinates[ rSrcPt + 1 ].Second, false, true );
1584 fWidth /= 2;
1585 fHeight /= 2;
1586 }else if( bIsDefaultPath && !bIsDefaultViewBox /*&& (nGeneratorVersion == SfxObjectShell::Sym_L2)*/ )
1588 _aCenter.X() = nCoordWidth/2 * fXScale;
1589 _aCenter.Y() = nCoordHeight/2 * fYScale;
1590 fWidth = nCoordWidth/2;
1591 fHeight = nCoordHeight/2;
1592 const Any* pViewBox = ((SdrCustomShapeGeometryItem&)rGeometryItem).GetPropertyValueByName( "ViewBox" );
1593 com::sun::star::awt::Rectangle aViewBox;
1594 if ( pViewBox && (*pViewBox >>= aViewBox ) )
1596 aViewBox.Width = pDefCustomShape->nCoordWidth;
1597 aViewBox.Height = pDefCustomShape->nCoordHeight;
1599 com::sun::star::beans::PropertyValue aPropVal;
1600 aPropVal.Name = "ViewBox";
1601 aPropVal.Value <<= aViewBox;
1602 rGeometryItem.SetPropertyValue( aPropVal );
1603 pCustomShapeObj->SetMergedItem( rGeometryItem );
1604 }else{
1605 _aCenter = GetPoint( seqCoordinates[ rSrcPt ], true, true );
1606 GetParameter( fWidth, seqCoordinates[ rSrcPt + 1 ].First, true, false);
1607 GetParameter( fHeight, seqCoordinates[ rSrcPt + 1 ].Second, false, true );
1610 fWidth *= fXScale;
1611 fHeight*= fYScale;
1612 Point aP( (sal_Int32)( _aCenter.X() - fWidth ), (sal_Int32)( _aCenter.Y() - fHeight ) );
1613 Size aS( (sal_Int32)( fWidth * 2.0 ), (sal_Int32)( fHeight * 2.0 ) );
1614 Rectangle aRect( aP, aS );
1615 if ( aRect.GetWidth() && aRect.GetHeight() )
1617 double fStartAngle, fEndAngle;
1618 GetParameter( fStartAngle, seqCoordinates[ rSrcPt + 2 ].First, false, false );
1619 GetParameter( fEndAngle , seqCoordinates[ rSrcPt + 2 ].Second, false, false );
1621 if ( ((sal_Int32)fStartAngle % 360) != ((sal_Int32)fEndAngle % 360) )
1623 if ( (sal_Int32)fStartAngle & 0x7fff0000 ) // SJ: if the angle was imported from our escher import, then the
1624 fStartAngle /= 65536.0; // value is shifted by 16. TODO: already change the fixed float to a
1625 if ( (sal_Int32)fEndAngle & 0x7fff0000 ) // double in the import filter
1627 fEndAngle /= 65536.0;
1628 fEndAngle = fEndAngle + fStartAngle;
1629 if ( fEndAngle < 0 )
1630 { // in the binary filter the endangle is the amount
1631 double fTemp = fStartAngle;
1632 fStartAngle = fEndAngle;
1633 fEndAngle = fTemp;
1636 double fCenterX = aRect.Center().X();
1637 double fCenterY = aRect.Center().Y();
1638 double fx1 = ( cos( fStartAngle * F_PI180 ) * 65536.0 * fXScale ) + fCenterX;
1639 double fy1 = ( -sin( fStartAngle * F_PI180 ) * 65536.0 * fYScale ) + fCenterY;
1640 double fx2 = ( cos( fEndAngle * F_PI180 ) * 65536.0 * fXScale ) + fCenterX;
1641 double fy2 = ( -sin( fEndAngle * F_PI180 ) * 65536.0 * fYScale ) + fCenterY;
1642 aNewB2DPolygon.append(CreateArc( aRect, Point( (sal_Int32)fx1, (sal_Int32)fy1 ), Point( (sal_Int32)fx2, (sal_Int32)fy2 ), false));
1644 else
1645 { /* SJ: TODO: this block should be replaced sometimes, because the current point
1646 is not set correct, it also does not use the correct moveto
1647 point if ANGLEELLIPSETO was used, but the method CreateArc
1648 is at the moment not able to draw full circles (if startangle is 0
1649 and endangle 360 nothing is painted :-( */
1650 sal_Int32 nXControl = (sal_Int32)((double)aRect.GetWidth() * 0.2835 );
1651 sal_Int32 nYControl = (sal_Int32)((double)aRect.GetHeight() * 0.2835 );
1652 Point aCenter( aRect.Center() );
1654 // append start point
1655 aNewB2DPolygon.append(basegfx::B2DPoint(aCenter.X(), aRect.Top()));
1657 // append four bezier segments
1658 aNewB2DPolygon.appendBezierSegment(
1659 basegfx::B2DPoint(aCenter.X() + nXControl, aRect.Top()),
1660 basegfx::B2DPoint(aRect.Right(), aCenter.Y() - nYControl),
1661 basegfx::B2DPoint(aRect.Right(), aCenter.Y()));
1663 aNewB2DPolygon.appendBezierSegment(
1664 basegfx::B2DPoint(aRect.Right(), aCenter.Y() + nYControl),
1665 basegfx::B2DPoint(aCenter.X() + nXControl, aRect.Bottom()),
1666 basegfx::B2DPoint(aCenter.X(), aRect.Bottom()));
1668 aNewB2DPolygon.appendBezierSegment(
1669 basegfx::B2DPoint(aCenter.X() - nXControl, aRect.Bottom()),
1670 basegfx::B2DPoint(aRect.Left(), aCenter.Y() + nYControl),
1671 basegfx::B2DPoint(aRect.Left(), aCenter.Y()));
1673 aNewB2DPolygon.appendBezierSegment(
1674 basegfx::B2DPoint(aRect.Left(), aCenter.Y() - nYControl),
1675 basegfx::B2DPoint(aCenter.X() - nXControl, aRect.Top()),
1676 basegfx::B2DPoint(aCenter.X(), aRect.Top()));
1678 // close, rescue last controlpoint, remove double last point
1679 basegfx::tools::closeWithGeometryChange(aNewB2DPolygon);
1682 rSrcPt += 3;
1685 break;
1687 case QUADRATICCURVETO :
1689 for ( sal_Int32 i(0L); ( i < nPntCount ) && ( rSrcPt + 1 < nCoordSize ); i++ )
1691 if ( rSrcPt )
1693 const Point aPreviousEndPoint(GetPoint( seqCoordinates[ rSrcPt - 1 ], true, true));
1694 const Point aControlQ(GetPoint( seqCoordinates[ rSrcPt++ ], true, true ));
1695 const Point aEnd(GetPoint( seqCoordinates[ rSrcPt++ ], true, true ));
1696 const Point aControlA((aPreviousEndPoint + (aControlQ * 2)) / 3);
1697 const Point aControlB(((aControlQ * 2) + aEnd) / 3);
1699 DBG_ASSERT(aNewB2DPolygon.count(), "EnhancedCustomShape2d::CreateSubPath: Error in adding Q control point (!)");
1700 aNewB2DPolygon.appendBezierSegment(
1701 basegfx::B2DPoint(aControlA.X(), aControlA.Y()),
1702 basegfx::B2DPoint(aControlB.X(), aControlB.Y()),
1703 basegfx::B2DPoint(aEnd.X(), aEnd.Y()));
1705 else // no previous point , do a moveto
1707 rSrcPt++; // skip control point
1708 const Point aEnd(GetPoint( seqCoordinates[ rSrcPt++ ], true, true ));
1710 DBG_ASSERT(aNewB2DPolygon.count(), "EnhancedCustomShape2d::CreateSubPath: Error in adding Q control point (!)");
1711 aNewB2DPolygon.append(basegfx::B2DPoint(aEnd.X(), aEnd.Y()));
1715 break;
1717 case LINETO :
1719 for ( sal_Int32 i(0L); ( i < nPntCount ) && ( rSrcPt < nCoordSize ); i++ )
1721 const Point aTempPoint(GetPoint( seqCoordinates[ rSrcPt++ ], true, true ));
1722 SAL_INFO(
1723 "svx",
1724 "lineTo: " << aTempPoint.X() << ","
1725 << aTempPoint.Y());
1726 aNewB2DPolygon.append(basegfx::B2DPoint(aTempPoint.X(), aTempPoint.Y()));
1729 break;
1731 case ARC :
1732 case CLOCKWISEARC :
1734 if(aNewB2DPolygon.count() > 1L)
1736 // #i76201# Add conversion to closed polygon when first and last points are equal
1737 basegfx::tools::checkClosed(aNewB2DPolygon);
1738 aNewB2DPolyPolygon.append(aNewB2DPolygon);
1741 aNewB2DPolygon.clear();
1743 case ARCTO :
1744 case CLOCKWISEARCTO :
1746 bool bClockwise = ( nCommand == CLOCKWISEARC ) || ( nCommand == CLOCKWISEARCTO );
1747 sal_uInt32 nXor = bClockwise ? 3 : 2;
1748 for ( sal_uInt16 i = 0; ( i < nPntCount ) && ( ( rSrcPt + 3 ) < nCoordSize ); i++ )
1750 Rectangle aRect( GetPoint( seqCoordinates[ rSrcPt ], true, true ), GetPoint( seqCoordinates[ rSrcPt + 1 ], true, true ) );
1751 if ( aRect.GetWidth() && aRect.GetHeight() )
1753 Point aCenter( aRect.Center() );
1754 Point aStart( GetPoint( seqCoordinates[ (sal_uInt16)( rSrcPt + nXor ) ], true, true ) );
1755 Point aEnd( GetPoint( seqCoordinates[ (sal_uInt16)( rSrcPt + ( nXor ^ 1 ) ) ], true, true ) );
1756 aStart.X() = (sal_Int32)( ( (double)( aStart.X() - aCenter.X() ) ) ) + aCenter.X();
1757 aStart.Y() = (sal_Int32)( ( (double)( aStart.Y() - aCenter.Y() ) ) ) + aCenter.Y();
1758 aEnd.X() = (sal_Int32)( ( (double)( aEnd.X() - aCenter.X() ) ) ) + aCenter.X();
1759 aEnd.Y() = (sal_Int32)( ( (double)( aEnd.Y() - aCenter.Y() ) ) ) + aCenter.Y();
1760 aNewB2DPolygon.append(CreateArc( aRect, aStart, aEnd, bClockwise));
1762 rSrcPt += 4;
1765 break;
1767 case ARCANGLETO :
1769 double fWR, fHR, fStartAngle, fSwingAngle;
1771 for ( sal_uInt16 i = 0; ( i < nPntCount ) && ( rSrcPt + 1 < nCoordSize ); i++ )
1773 GetParameter ( fWR, seqCoordinates[ (sal_uInt16)( rSrcPt ) ].First, true, false );
1774 GetParameter ( fHR, seqCoordinates[ (sal_uInt16)( rSrcPt ) ].Second, false, true );
1776 GetParameter ( fStartAngle, seqCoordinates[ (sal_uInt16)( rSrcPt + 1) ].First, false, false );
1777 GetParameter ( fSwingAngle, seqCoordinates[ (sal_uInt16)( rSrcPt + 1 ) ].Second, false, false );
1779 // Convert angles to radians, but don't do any scaling / translation yet.
1781 fStartAngle *= F_PI180;
1782 fSwingAngle *= F_PI180;
1784 OSL_TRACE("ARCANGLETO scale: %f x %f angles: %f, %f", fWR, fHR, fStartAngle, fSwingAngle);
1786 bool bClockwise = fSwingAngle >= 0.0;
1788 if (aNewB2DPolygon.count() > 0)
1790 basegfx::B2DPoint aStartPointB2D( aNewB2DPolygon.getB2DPoint(aNewB2DPolygon.count() - 1 ) );
1791 Point aStartPoint( 0, 0 );
1793 double fT = atan2((fWR*sin(fStartAngle)), (fHR*cos(fStartAngle)));
1794 double fTE = atan2((fWR*sin(fStartAngle + fSwingAngle)), fHR*cos(fStartAngle + fSwingAngle));
1796 OSL_TRACE("ARCANGLETO angles: %f, %f --> parameters: %f, %f", fStartAngle, fSwingAngle, fT, fTE );
1798 fWR *= fXScale;
1799 fHR *= fYScale;
1801 Rectangle aRect ( Point ( aStartPoint.getX() - fWR*cos(fT) - fWR, aStartPoint.getY() - fHR*sin(fT) - fHR ),
1802 Point ( aStartPoint.getX() - fWR*cos(fT) + fWR, aStartPoint.getY() - fHR*sin(fT) + fHR) );
1804 Point aEndPoint ( aStartPoint.getX() - fWR*(cos(fT) - cos(fTE)), aStartPoint.getY() - fHR*(sin(fT) - sin(fTE)) );
1806 SAL_INFO(
1807 "svx",
1808 "ARCANGLETO rect: " << aRect.Left() << ", "
1809 << aRect.Top() << " x " << aRect.Right()
1810 << ", " << aRect.Bottom() << " start: "
1811 << aStartPoint.X() << ", "
1812 << aStartPoint.Y() << " end: "
1813 << aEndPoint.X() << ", " << aEndPoint.Y()
1814 << " clockwise: " << int(bClockwise));
1815 basegfx::B2DPolygon aArc = CreateArc( aRect, bClockwise ? aEndPoint : aStartPoint, bClockwise ? aStartPoint : aEndPoint, bClockwise, aStartPoint == aEndPoint && fSwingAngle > F_PI);
1816 // Now that we have the arc, move it to aStartPointB2D.
1817 basegfx::B2DHomMatrix aMatrix = basegfx::tools::createTranslateB2DHomMatrix(aStartPointB2D.getX(), aStartPointB2D.getY());
1818 aArc.transform(aMatrix);
1819 aNewB2DPolygon.append(aArc);
1822 rSrcPt += 2;
1825 break;
1827 case ELLIPTICALQUADRANTX :
1828 case ELLIPTICALQUADRANTY :
1830 bool bFirstDirection(true);
1831 basegfx::B2DPoint aControlPointA;
1832 basegfx::B2DPoint aControlPointB;
1834 for ( sal_uInt16 i = 0; ( i < nPntCount ) && ( rSrcPt < nCoordSize ); i++ )
1836 sal_uInt32 nModT = ( nCommand == ELLIPTICALQUADRANTX ) ? 1 : 0;
1837 Point aCurrent( GetPoint( seqCoordinates[ rSrcPt ], true, true ) );
1839 if ( rSrcPt ) // we need a previous point
1841 Point aPrev( GetPoint( seqCoordinates[ rSrcPt - 1 ], true, true ) );
1842 sal_Int32 nX, nY;
1843 nX = aCurrent.X() - aPrev.X();
1844 nY = aCurrent.Y() - aPrev.Y();
1845 if ( ( nY ^ nX ) & 0x80000000 )
1847 if ( !i )
1848 bFirstDirection = true;
1849 else if ( !bFirstDirection )
1850 nModT ^= 1;
1852 else
1854 if ( !i )
1855 bFirstDirection = false;
1856 else if ( bFirstDirection )
1857 nModT ^= 1;
1859 if ( nModT ) // get the right corner
1861 nX = aCurrent.X();
1862 nY = aPrev.Y();
1864 else
1866 nX = aPrev.X();
1867 nY = aCurrent.Y();
1869 sal_Int32 nXVec = ( nX - aPrev.X() ) >> 1;
1870 sal_Int32 nYVec = ( nY - aPrev.Y() ) >> 1;
1871 Point aControl1( aPrev.X() + nXVec, aPrev.Y() + nYVec );
1873 aControlPointA = basegfx::B2DPoint(aControl1.X(), aControl1.Y());
1875 nXVec = ( nX - aCurrent.X() ) >> 1;
1876 nYVec = ( nY - aCurrent.Y() ) >> 1;
1877 Point aControl2( aCurrent.X() + nXVec, aCurrent.Y() + nYVec );
1879 aControlPointB = basegfx::B2DPoint(aControl2.X(), aControl2.Y());
1881 aNewB2DPolygon.appendBezierSegment(
1882 aControlPointA,
1883 aControlPointB,
1884 basegfx::B2DPoint(aCurrent.X(), aCurrent.Y()));
1886 else
1888 aNewB2DPolygon.append(basegfx::B2DPoint(aCurrent.X(), aCurrent.Y()));
1891 rSrcPt++;
1894 break;
1896 #ifdef DBG_CUSTOMSHAPE
1897 case UNKNOWN :
1898 default :
1900 OStringBuffer aString("CustomShapes::unknown PolyFlagValue :");
1901 aString.append(static_cast<sal_Int32>(nCommand));
1902 OSL_FAIL(aString.getStr());
1904 break;
1905 #endif
1907 if ( nCommand == ENDSUBPATH )
1908 break;
1911 if ( rSegmentInd == nSegInfoSize )
1912 rSegmentInd++;
1914 if(aNewB2DPolygon.count() > 1L)
1916 // #i76201# Add conversion to closed polygon when first and last points are equal
1917 basegfx::tools::checkClosed(aNewB2DPolygon);
1918 aNewB2DPolyPolygon.append(aNewB2DPolygon);
1921 if(aNewB2DPolyPolygon.count())
1923 if( !bLineGeometryNeededOnly )
1925 // hack aNewB2DPolyPolygon to fill logic rect - this is
1926 // needed to produce gradient fills that look like mso
1927 aNewB2DPolygon.clear();
1928 aNewB2DPolygon.append(basegfx::B2DPoint(0,0));
1929 aNewB2DPolygon.setClosed(true);
1930 aNewB2DPolyPolygon.append(aNewB2DPolygon);
1932 aNewB2DPolygon.clear();
1933 aNewB2DPolygon.append(basegfx::B2DPoint(aLogicRect.GetWidth(),
1934 aLogicRect.GetHeight()));
1935 aNewB2DPolygon.setClosed(true);
1936 aNewB2DPolyPolygon.append(aNewB2DPolygon);
1939 // #i37011#
1940 bool bForceCreateTwoObjects(false);
1942 if(!bSortFilledObjectsToBack && !aNewB2DPolyPolygon.isClosed() && !bNoStroke)
1944 bForceCreateTwoObjects = true;
1947 if(bLineGeometryNeededOnly)
1949 bForceCreateTwoObjects = true;
1950 bNoFill = true;
1951 bNoStroke = false;
1954 if(bForceCreateTwoObjects || bSortFilledObjectsToBack)
1956 if(bFilled && !bNoFill)
1958 basegfx::B2DPolyPolygon aClosedPolyPolygon(aNewB2DPolyPolygon);
1959 aClosedPolyPolygon.setClosed(true);
1960 SdrPathObj* pFill = new SdrPathObj(OBJ_POLY, aClosedPolyPolygon, dBrightness);
1961 SfxItemSet aTempSet(*this);
1962 aTempSet.Put(makeSdrShadowItem(false));
1963 aTempSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
1964 pFill->SetMergedItemSet(aTempSet);
1965 rObjectList.push_back(pFill);
1968 if(!bNoStroke)
1970 // there is no reason to use OBJ_PLIN here when the polygon is actually closed,
1971 // the non-fill is defined by XFILL_NONE. Since SdrPathObj::ImpForceKind() needs
1972 // to correct the polygon (here: open it) using the type, the last edge may get lost.
1973 // Thus, use a type that fits the polygon
1974 SdrPathObj* pStroke = new SdrPathObj(
1975 aNewB2DPolyPolygon.isClosed() ? OBJ_POLY : OBJ_PLIN,
1976 aNewB2DPolyPolygon, dBrightness);
1977 SfxItemSet aTempSet(*this);
1978 aTempSet.Put(makeSdrShadowItem(false));
1979 aTempSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
1980 pStroke->SetMergedItemSet(aTempSet);
1981 rObjectList.push_back(pStroke);
1984 else
1986 SdrPathObj* pObj = 0;
1987 SfxItemSet aTempSet(*this);
1988 aTempSet.Put(makeSdrShadowItem(false));
1990 if(bNoFill)
1992 // see comment above about OBJ_PLIN
1993 pObj = new SdrPathObj(
1994 aNewB2DPolyPolygon.isClosed() ? OBJ_POLY : OBJ_PLIN,
1995 aNewB2DPolyPolygon, dBrightness);
1996 aTempSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
1998 else
2000 aNewB2DPolyPolygon.setClosed(true);
2001 pObj = new SdrPathObj(OBJ_POLY, aNewB2DPolyPolygon, dBrightness);
2004 if(bNoStroke)
2006 aTempSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
2009 if(pObj)
2011 pObj->SetMergedItemSet(aTempSet);
2012 rObjectList.push_back(pObj);
2018 void CorrectCalloutArrows( MSO_SPT eSpType, sal_uInt32 nLineObjectCount, std::vector< SdrPathObj* >& vObjectList )
2020 bool bAccent = false;
2021 switch( eSpType )
2023 case mso_sptCallout1 :
2024 case mso_sptBorderCallout1 :
2025 case mso_sptCallout90 :
2026 case mso_sptBorderCallout90 :
2027 default:
2028 break;
2030 case mso_sptAccentCallout1 :
2031 case mso_sptAccentBorderCallout1 :
2032 case mso_sptAccentCallout90 :
2033 case mso_sptAccentBorderCallout90 :
2035 sal_uInt32 i, nLine = 0;
2036 for ( i = 0; i < vObjectList.size(); i++ )
2038 SdrPathObj* pObj( vObjectList[ i ] );
2039 if(pObj->IsLine())
2041 nLine++;
2042 if ( nLine == nLineObjectCount )
2044 pObj->ClearMergedItem( XATTR_LINESTART );
2045 pObj->ClearMergedItem( XATTR_LINEEND );
2050 break;
2052 // switch start & end
2053 case mso_sptAccentCallout2 :
2054 case mso_sptAccentBorderCallout2 :
2055 bAccent = true;
2056 //fall-through
2057 case mso_sptCallout2 :
2058 case mso_sptBorderCallout2 :
2060 sal_uInt32 i, nLine = 0;
2061 for ( i = 0; i < vObjectList.size(); i++ )
2063 SdrPathObj* pObj( vObjectList[ i ] );
2064 if(pObj->IsLine())
2066 nLine++;
2067 if ( nLine == 1 )
2068 pObj->ClearMergedItem( XATTR_LINEEND );
2069 else if ( ( bAccent && ( nLine == nLineObjectCount - 1 ) ) || ( !bAccent && ( nLine == nLineObjectCount ) ) )
2070 pObj->ClearMergedItem( XATTR_LINESTART );
2071 else
2073 pObj->ClearMergedItem( XATTR_LINESTART );
2074 pObj->ClearMergedItem( XATTR_LINEEND );
2079 break;
2081 case mso_sptAccentCallout3 :
2082 case mso_sptAccentBorderCallout3 :
2083 bAccent = false;
2084 //fall-through
2085 case mso_sptCallout3 :
2086 case mso_sptBorderCallout3 :
2088 sal_uInt32 i, nLine = 0;
2089 for ( i = 0; i < vObjectList.size(); i++ )
2091 SdrPathObj* pObj( vObjectList[ i ] );
2092 if(pObj->IsLine())
2094 if ( nLine )
2096 pObj->ClearMergedItem( XATTR_LINESTART );
2097 pObj->ClearMergedItem( XATTR_LINEEND );
2099 else
2100 EnhancedCustomShape2d::SwapStartAndEndArrow( pObj );
2102 nLine++;
2106 break;
2110 void EnhancedCustomShape2d::AdaptObjColor(SdrPathObj& rObj, const SfxItemSet& rCustomShapeSet,
2111 sal_uInt32& nColorIndex, sal_uInt32 nColorCount)
2113 if ( !rObj.IsLine() )
2115 const drawing::FillStyle eFillStyle = static_cast<const XFillStyleItem&>(rObj.GetMergedItem(XATTR_FILLSTYLE)).GetValue();
2116 switch( eFillStyle )
2118 default:
2119 case drawing::FillStyle_SOLID:
2121 Color aFillColor;
2122 if ( nColorCount || rObj.GetBrightness() != 1.0 )
2124 aFillColor = GetColorData(
2125 static_cast<const XFillColorItem&>(rCustomShapeSet.Get( XATTR_FILLCOLOR )).GetColorValue(),
2126 std::min(nColorIndex, nColorCount-1), rObj.GetBrightness() );
2127 rObj.SetMergedItem( XFillColorItem( "", aFillColor ) );
2129 break;
2131 case drawing::FillStyle_GRADIENT:
2133 XGradient aXGradient(static_cast<const XFillGradientItem&>(rObj.GetMergedItem(XATTR_FILLGRADIENT)).GetGradientValue());
2134 if ( nColorCount || rObj.GetBrightness() != 1.0 )
2136 aXGradient.SetStartColor(
2137 GetColorData(
2138 aXGradient.GetStartColor(),
2139 std::min(nColorIndex, nColorCount-1), rObj.GetBrightness() ));
2140 aXGradient.SetEndColor(
2141 GetColorData(
2142 aXGradient.GetEndColor(),
2143 std::min(nColorIndex, nColorCount-1), rObj.GetBrightness() ));
2146 rObj.SetMergedItem( XFillGradientItem( "", aXGradient ) );
2147 break;
2149 case drawing::FillStyle_HATCH:
2151 XHatch aXHatch(static_cast<const XFillHatchItem&>(rObj.GetMergedItem(XATTR_FILLHATCH)).GetHatchValue());
2152 if ( nColorCount || rObj.GetBrightness() != 1.0 )
2154 aXHatch.SetColor(
2155 GetColorData(
2156 aXHatch.GetColor(),
2157 std::min(nColorIndex, nColorCount-1), rObj.GetBrightness() ));
2160 rObj.SetMergedItem( XFillHatchItem( "", aXHatch ) );
2161 break;
2163 case drawing::FillStyle_BITMAP:
2165 if ( nColorCount || rObj.GetBrightness() != 1.0 )
2167 Bitmap aBitmap(static_cast<const XFillBitmapItem&>(rObj.GetMergedItem(XATTR_FILLBITMAP)).GetGraphicObject().GetGraphic().GetBitmapEx().GetBitmap());
2169 aBitmap.Adjust(
2170 static_cast< short > ( GetLuminanceChange(
2171 std::min(nColorIndex, nColorCount-1))));
2173 rObj.SetMergedItem(XFillBitmapItem(OUString(), Graphic(aBitmap)));
2176 break;
2180 if ( nColorIndex < nColorCount )
2181 nColorIndex++;
2185 SdrObject* EnhancedCustomShape2d::CreatePathObj( bool bLineGeometryNeededOnly )
2187 sal_Int32 nCoordSize = seqCoordinates.getLength();
2188 if ( !nCoordSize )
2189 return NULL;
2191 sal_uInt16 nSrcPt = 0;
2192 sal_uInt16 nSegmentInd = 0;
2194 std::vector< SdrPathObj* > vObjectList;
2195 bool bSortFilledObjectsToBack = SortFilledObjectsToBackByDefault( eSpType );
2197 sal_Int32 nSubPathIndex = 0;
2199 while( nSegmentInd <= seqSegments.getLength() )
2201 CreateSubPath( nSrcPt, nSegmentInd, vObjectList, bLineGeometryNeededOnly, bSortFilledObjectsToBack, nSubPathIndex );
2202 nSubPathIndex ++;
2205 SdrObject* pRet = NULL;
2207 if ( !vObjectList.empty() )
2209 const SfxItemSet& rCustomShapeSet = pCustomShapeObj->GetMergedItemSet();
2210 sal_uInt32 nColorCount = nColorData >> 28;
2211 sal_uInt32 nColorIndex = 0;
2213 // #i37011# remove invisible objects
2214 if(!vObjectList.empty())
2216 std::vector< SdrPathObj* > vTempList;
2218 for(size_t i = 0; i < vObjectList.size(); ++i)
2220 SdrPathObj* pObj(vObjectList[i]);
2221 const drawing::LineStyle eLineStyle =static_cast<const XLineStyleItem&>(pObj->GetMergedItem(XATTR_LINESTYLE)).GetValue();
2222 const drawing::FillStyle eFillStyle = static_cast<const XFillStyleItem&>(pObj->GetMergedItem(XATTR_FILLSTYLE)).GetValue();
2224 //SJ: #i40600# if bLineGeometryNeededOnly is set linystyle does not matter
2225 if( !bLineGeometryNeededOnly && ( drawing::LineStyle_NONE == eLineStyle ) && ( drawing::FillStyle_NONE == eFillStyle ) )
2226 delete pObj;
2227 else
2228 vTempList.push_back(pObj);
2231 vObjectList = vTempList;
2234 if(1L == vObjectList.size())
2236 // a single object, correct some values
2237 AdaptObjColor(*vObjectList[0L],rCustomShapeSet,nColorIndex,nColorCount);
2239 else
2241 sal_Int32 nLineObjectCount = 0;
2242 sal_Int32 nAreaObjectCount = 0;
2244 // correct some values and collect content data
2245 for ( size_t i = 0; i < vObjectList.size(); ++i )
2247 SdrPathObj* pObj( vObjectList[ i ] );
2249 if(pObj->IsLine())
2251 nLineObjectCount++;
2253 else
2255 nAreaObjectCount++;
2256 AdaptObjColor(*pObj,rCustomShapeSet,nColorIndex,nColorCount);
2260 // #i88870# correct line arrows for callouts
2261 if ( nLineObjectCount )
2262 CorrectCalloutArrows( eSpType, nLineObjectCount, vObjectList );
2264 // sort objects so that filled ones are in front. Necessary
2265 // for some strange objects
2266 if ( bSortFilledObjectsToBack )
2268 std::vector< SdrPathObj* > vTempList;
2269 vTempList.reserve(vObjectList.size());
2271 for ( size_t i = 0; i < vObjectList.size(); ++i )
2273 SdrPathObj* pObj( vObjectList[ i ] );
2275 if ( !pObj->IsLine() )
2277 vTempList.push_back(pObj);
2281 for ( size_t i = 0; i < vObjectList.size(); ++i )
2283 SdrPathObj* pObj( vObjectList[ i ] );
2285 if ( pObj->IsLine() )
2287 vTempList.push_back(pObj);
2291 vObjectList = vTempList;
2296 // #i37011#
2297 if(!vObjectList.empty())
2299 // copy remaining objects to pRet
2300 if(vObjectList.size() > 1)
2302 pRet = new SdrObjGroup;
2304 for (size_t i = 0; i < vObjectList.size(); ++i)
2306 SdrObject* pObj(vObjectList[i]);
2307 pRet->GetSubList()->NbcInsertObject(pObj);
2310 else if(1 == vObjectList.size())
2312 pRet = vObjectList[0L];
2315 if(pRet)
2317 // move to target position
2318 Rectangle aCurRect(pRet->GetSnapRect());
2319 aCurRect.Move(aLogicRect.Left(), aLogicRect.Top());
2320 pRet->NbcSetSnapRect(aCurRect);
2324 return pRet;
2327 SdrObject* EnhancedCustomShape2d::CreateObject( bool bLineGeometryNeededOnly )
2329 SdrObject* pRet = NULL;
2331 if ( eSpType == mso_sptRectangle )
2333 pRet = new SdrRectObj( aLogicRect );
2334 pRet->SetMergedItemSet( *this );
2336 if ( !pRet )
2337 pRet = CreatePathObj( bLineGeometryNeededOnly );
2339 return pRet;
2342 void EnhancedCustomShape2d::ApplyGluePoints( SdrObject* pObj )
2344 if ( pObj && seqGluePoints.getLength() )
2346 sal_uInt32 i, nCount = seqGluePoints.getLength();
2347 for ( i = 0; i < nCount; i++ )
2349 SdrGluePoint aGluePoint;
2351 aGluePoint.SetPos( GetPoint( seqGluePoints[ i ], true, true ) );
2352 aGluePoint.SetPercent( false );
2353 aGluePoint.SetAlign( SdrAlign::VERT_TOP | SdrAlign::HORZ_LEFT );
2354 aGluePoint.SetEscDir( SdrEscapeDirection::SMART );
2355 SdrGluePointList* pList = pObj->ForceGluePointList();
2356 if( pList )
2357 /* sal_uInt16 nId = */ pList->Insert( aGluePoint );
2362 bool EnhancedCustomShape2d::IsPostRotate() const
2364 return pCustomShapeObj->ISA( SdrObjCustomShape ) && static_cast<SdrObjCustomShape*>(pCustomShapeObj)->IsPostRotate();
2367 SdrObject* EnhancedCustomShape2d::CreateLineGeometry()
2369 return CreateObject( true );
2373 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */