Line data Source code
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 <config_folders.h>
21 : #include "rtl/bootstrap.hxx"
22 : #include <oox/export/vmlexport.hxx>
23 :
24 : #include <oox/token/tokens.hxx>
25 :
26 : #include <rtl/strbuf.hxx>
27 : #include <rtl/ustring.hxx>
28 :
29 : #include <tools/stream.hxx>
30 : #include <comphelper/sequenceashashmap.hxx>
31 : #include <svx/svdotext.hxx>
32 : #include <vcl/cvtgrf.hxx>
33 : #include <filter/msfilter/msdffimp.hxx>
34 : #include <filter/msfilter/util.hxx>
35 : #include <filter/msfilter/escherex.hxx>
36 :
37 : #include <com/sun/star/drawing/XShape.hpp>
38 : #include <com/sun/star/text/HoriOrientation.hpp>
39 : #include <com/sun/star/text/VertOrientation.hpp>
40 : #include <com/sun/star/text/RelOrientation.hpp>
41 :
42 : #include <cstdio>
43 :
44 : using namespace sax_fastparser;
45 : using namespace oox::vml;
46 : using namespace com::sun::star;
47 :
48 860 : VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr pSerializer, VMLTextExport* pTextExport )
49 860 : : EscherEx( EscherExGlobalRef(new EscherExGlobal(0)), 0, /*bOOXML=*/true )
50 : , m_pSerializer( pSerializer )
51 : , m_pTextExport( pTextExport )
52 : , m_eHOri( 0 )
53 : , m_eVOri( 0 )
54 : , m_eHRel( 0 )
55 : , m_eVRel( 0 )
56 : , m_pNdTopLeft( 0 )
57 : , m_pSdrObject( 0 )
58 : , m_pShapeAttrList( NULL )
59 : , m_nShapeType( ESCHER_ShpInst_Nil )
60 : , m_nShapeFlags(0)
61 860 : , m_pShapeStyle( new OStringBuffer( 200 ) )
62 2580 : , m_pShapeTypeWritten( new bool[ ESCHER_ShpInst_COUNT ] )
63 : {
64 860 : mnGroupLevel = 1;
65 860 : memset( m_pShapeTypeWritten, 0, ESCHER_ShpInst_COUNT * sizeof( bool ) );
66 860 : }
67 :
68 1056 : void VMLExport::SetFS( ::sax_fastparser::FSHelperPtr pSerializer )
69 : {
70 1056 : m_pSerializer = pSerializer;
71 1056 : }
72 :
73 2580 : VMLExport::~VMLExport()
74 : {
75 860 : delete mpOutStrm, mpOutStrm = NULL;
76 860 : delete m_pShapeStyle, m_pShapeStyle = NULL;
77 860 : delete[] m_pShapeTypeWritten, m_pShapeTypeWritten = NULL;
78 1720 : }
79 :
80 1378 : void VMLExport::OpenContainer( sal_uInt16 nEscherContainer, int nRecInstance )
81 : {
82 1378 : EscherEx::OpenContainer( nEscherContainer, nRecInstance );
83 :
84 1378 : if ( nEscherContainer == ESCHER_SpContainer )
85 : {
86 : // opening a shape container
87 : #if OSL_DEBUG_LEVEL > 0
88 : if ( m_nShapeType != ESCHER_ShpInst_Nil )
89 : fprintf( stderr, "Warning! VMLExport::OpenContainer(): opening shape inside a shape.\n" );
90 : #endif
91 1378 : m_nShapeType = ESCHER_ShpInst_Nil;
92 1378 : m_pShapeAttrList = m_pSerializer->createAttrList();
93 :
94 1378 : if ( !m_pShapeStyle->isEmpty() )
95 2 : m_pShapeStyle->makeStringAndClear();
96 :
97 1378 : m_pShapeStyle->ensureCapacity( 200 );
98 :
99 : // postpone the output so that we are able to write even the elements
100 : // that we learn inside Commit()
101 1378 : m_pSerializer->mark();
102 : }
103 1378 : }
104 :
105 1378 : void VMLExport::CloseContainer()
106 : {
107 1378 : if ( mRecTypes.back() == ESCHER_SpContainer )
108 : {
109 : // write the shape now when we have all the info
110 1378 : sal_Int32 nShapeElement = StartShape();
111 :
112 1378 : m_pSerializer->mergeTopMarks();
113 :
114 1378 : EndShape( nShapeElement );
115 :
116 : // cleanup
117 1378 : m_nShapeType = ESCHER_ShpInst_Nil;
118 1378 : m_pShapeAttrList = NULL;
119 : }
120 :
121 1378 : EscherEx::CloseContainer();
122 1378 : }
123 :
124 60 : sal_uInt32 VMLExport::EnterGroup( const OUString& rShapeName, const Rectangle* pRect )
125 : {
126 60 : sal_uInt32 nShapeId = GenerateShapeId();
127 :
128 60 : OStringBuffer aStyle( 200 );
129 60 : FastAttributeList *pAttrList = m_pSerializer->createAttrList();
130 :
131 60 : pAttrList->add( XML_id, ShapeIdString( nShapeId ) );
132 :
133 60 : if ( rShapeName.getLength() )
134 34 : pAttrList->add( XML_alt, OUStringToOString( rShapeName, RTL_TEXTENCODING_UTF8 ) );
135 :
136 60 : bool rbAbsolutePos = true;
137 : //editAs
138 120 : OUString rEditAs = EscherEx::GetEditAs();
139 60 : if (!rEditAs.isEmpty())
140 : {
141 8 : pAttrList->add(XML_editas, OUStringToOString( rEditAs, RTL_TEXTENCODING_UTF8 ));
142 8 : rbAbsolutePos = false;
143 : }
144 :
145 : // style
146 60 : if ( pRect )
147 60 : AddRectangleDimensions( aStyle, *pRect, rbAbsolutePos );
148 :
149 60 : if ( !aStyle.isEmpty() )
150 60 : pAttrList->add( XML_style, aStyle.makeStringAndClear() );
151 :
152 : // coordorigin/coordsize
153 60 : if ( pRect && ( mnGroupLevel == 1 ) )
154 : {
155 : pAttrList->add( XML_coordorigin,
156 100 : OStringBuffer( 20 ).append( sal_Int32( pRect->Left() ) )
157 100 : .append( "," ).append( sal_Int32( pRect->Top() ) )
158 50 : .makeStringAndClear() );
159 :
160 : pAttrList->add( XML_coordsize,
161 100 : OStringBuffer( 20 ).append( sal_Int32( pRect->Right() ) - sal_Int32( pRect->Left() ) )
162 100 : .append( "," ).append( sal_Int32( pRect->Bottom() ) - sal_Int32( pRect->Top() ) )
163 50 : .makeStringAndClear() );
164 : }
165 :
166 60 : m_pSerializer->startElementNS( XML_v, XML_group, XFastAttributeListRef( pAttrList ) );
167 :
168 60 : mnGroupLevel++;
169 120 : return nShapeId;
170 : }
171 :
172 60 : void VMLExport::LeaveGroup()
173 : {
174 60 : --mnGroupLevel;
175 60 : m_pSerializer->endElementNS( XML_v, XML_group );
176 60 : }
177 :
178 1378 : void VMLExport::AddShape( sal_uInt32 nShapeType, sal_uInt32 nShapeFlags, sal_uInt32 nShapeId )
179 : {
180 1378 : m_nShapeType = nShapeType;
181 1378 : m_nShapeFlags = nShapeFlags;
182 : // If shape is a watermark object - should keep the original shape's name
183 : // because Microsoft detects if it is a watermark by the actual name
184 1378 : if (!IsWaterMarkShape(m_pSdrObject->GetName()))
185 : {
186 : // Not a watermark object
187 1368 : m_pShapeAttrList->add( XML_id, ShapeIdString( nShapeId ) );
188 : }
189 : else
190 : {
191 : // A watermark object - store the optional shape ID also ('o:spid')
192 10 : m_pShapeAttrList->add( XML_id, OUStringToOString(m_pSdrObject->GetName(), RTL_TEXTENCODING_UTF8) );
193 : }
194 1378 : }
195 :
196 4448 : bool VMLExport::IsWaterMarkShape(const OUString& rStr)
197 : {
198 4448 : if (rStr.isEmpty() ) return false;
199 :
200 2960 : if (rStr.match(OUString("PowerPlusWaterMarkObject")) || rStr.match(OUString("WordPictureWatermark")))
201 42 : return true;
202 : else
203 2918 : return false;
204 : }
205 :
206 54 : static void impl_AddArrowHead( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
207 : {
208 54 : if ( !pAttrList )
209 54 : return;
210 :
211 54 : const char *pArrowHead = NULL;
212 54 : switch ( nValue )
213 : {
214 0 : case ESCHER_LineNoEnd: pArrowHead = "none"; break;
215 42 : case ESCHER_LineArrowEnd: pArrowHead = "block"; break;
216 2 : case ESCHER_LineArrowStealthEnd: pArrowHead = "classic"; break;
217 4 : case ESCHER_LineArrowDiamondEnd: pArrowHead = "diamond"; break;
218 0 : case ESCHER_LineArrowOvalEnd: pArrowHead = "oval"; break;
219 6 : case ESCHER_LineArrowOpenEnd: pArrowHead = "open"; break;
220 : }
221 :
222 54 : if ( pArrowHead )
223 54 : pAttrList->add( nElement, pArrowHead );
224 : }
225 :
226 54 : static void impl_AddArrowLength( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
227 : {
228 54 : if ( !pAttrList )
229 54 : return;
230 :
231 54 : const char *pArrowLength = NULL;
232 54 : switch ( nValue )
233 : {
234 2 : case ESCHER_LineShortArrow: pArrowLength = "short"; break;
235 52 : case ESCHER_LineMediumLenArrow: pArrowLength = "medium"; break;
236 0 : case ESCHER_LineLongArrow: pArrowLength = "long"; break;
237 : }
238 :
239 54 : if ( pArrowLength )
240 54 : pAttrList->add( nElement, pArrowLength );
241 : }
242 :
243 54 : static void impl_AddArrowWidth( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
244 : {
245 54 : if ( !pAttrList )
246 54 : return;
247 :
248 54 : const char *pArrowWidth = NULL;
249 54 : switch ( nValue )
250 : {
251 2 : case ESCHER_LineNarrowArrow: pArrowWidth = "narrow"; break;
252 52 : case ESCHER_LineMediumWidthArrow: pArrowWidth = "medium"; break;
253 0 : case ESCHER_LineWideArrow: pArrowWidth = "wide"; break;
254 : }
255 :
256 54 : if ( pArrowWidth )
257 54 : pAttrList->add( nElement, pArrowWidth );
258 : }
259 :
260 2328 : static void impl_AddBool( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, bool bValue )
261 : {
262 2328 : if ( !pAttrList )
263 2328 : return;
264 :
265 2328 : pAttrList->add( nElement, bValue? "t": "f" );
266 : }
267 :
268 2620 : static void impl_AddColor( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nColor )
269 : {
270 : #if OSL_DEBUG_LEVEL > 0
271 : if ( nColor & 0xFF000000 )
272 : fprintf( stderr, "TODO: this is not a RGB value!\n" );
273 : #endif
274 :
275 2620 : if ( !pAttrList || ( nColor & 0xFF000000 ) )
276 2620 : return;
277 :
278 2620 : nColor = ( ( nColor & 0xFF ) << 16 ) + ( nColor & 0xFF00 ) + ( ( nColor & 0xFF0000 ) >> 16 );
279 :
280 2620 : const char *pColor = NULL;
281 : char pRgbColor[10];
282 2620 : switch ( nColor )
283 : {
284 414 : case 0x000000: pColor = "black"; break;
285 6 : case 0xC0C0C0: pColor = "silver"; break;
286 6 : case 0x808080: pColor = "gray"; break;
287 188 : case 0xFFFFFF: pColor = "white"; break;
288 0 : case 0x800000: pColor = "maroon"; break;
289 68 : case 0xFF0000: pColor = "red"; break;
290 0 : case 0x800080: pColor = "purple"; break;
291 0 : case 0xFF00FF: pColor = "fuchsia"; break;
292 34 : case 0x008000: pColor = "green"; break;
293 4 : case 0x00FF00: pColor = "lime"; break;
294 0 : case 0x808000: pColor = "olive"; break;
295 10 : case 0xFFFF00: pColor = "yellow"; break;
296 0 : case 0x000080: pColor = "navy"; break;
297 32 : case 0x0000FF: pColor = "blue"; break;
298 0 : case 0x008080: pColor = "teal"; break;
299 44 : case 0x00FFFF: pColor = "aqua"; break;
300 : default:
301 : {
302 1814 : snprintf( pRgbColor, sizeof( pRgbColor ), "#%06x", static_cast< unsigned int >( nColor ) ); // not too handy to use OString::valueOf() here :-(
303 1814 : pColor = pRgbColor;
304 : }
305 1814 : break;
306 : }
307 :
308 2620 : pAttrList->add( nElement, pColor );
309 : }
310 :
311 372 : static void impl_AddInt( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
312 : {
313 372 : if ( !pAttrList )
314 372 : return;
315 :
316 372 : pAttrList->add( nElement, OString::number( nValue ).getStr() );
317 : }
318 :
319 29400 : inline sal_uInt16 impl_GetUInt16( const sal_uInt8* &pVal )
320 : {
321 29400 : sal_uInt16 nRet = *pVal++;
322 29400 : nRet += ( *pVal++ ) << 8;
323 29400 : return nRet;
324 : }
325 :
326 30836 : inline sal_Int32 impl_GetPointComponent( const sal_uInt8* &pVal, sal_uInt16 nPointSize )
327 : {
328 30836 : sal_Int32 nRet = 0;
329 30836 : if ( ( nPointSize == 0xfff0 ) || ( nPointSize == 4 ) )
330 : {
331 28444 : sal_uInt16 nUnsigned = *pVal++;
332 28444 : nUnsigned += ( *pVal++ ) << 8;
333 :
334 28444 : nRet = sal_Int16( nUnsigned );
335 : }
336 2392 : else if ( nPointSize == 8 )
337 : {
338 2392 : sal_uInt32 nUnsigned = *pVal++;
339 2392 : nUnsigned += ( *pVal++ ) << 8;
340 2392 : nUnsigned += ( *pVal++ ) << 16;
341 2392 : nUnsigned += ( *pVal++ ) << 24;
342 :
343 2392 : nRet = nUnsigned;
344 : }
345 :
346 30836 : return nRet;
347 : }
348 :
349 1378 : void VMLExport::AddSdrObjectVMLObject( const SdrObject& rObj)
350 : {
351 1378 : m_pSdrObject = &rObj;
352 1378 : }
353 1378 : void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect )
354 : {
355 1378 : if ( m_nShapeType == ESCHER_ShpInst_Nil )
356 1600 : return;
357 :
358 : // postpone the output of the embedded elements so that they are written
359 : // inside the shapes
360 1156 : m_pSerializer->mark();
361 :
362 : // dimensions
363 1156 : if ( m_nShapeType == ESCHER_ShpInst_Line )
364 22 : AddLineDimensions( rRect );
365 : else
366 1134 : AddRectangleDimensions( *m_pShapeStyle, rRect );
367 :
368 : // properties
369 : bool bAlreadyWritten[ 0xFFF ];
370 1156 : memset( bAlreadyWritten, 0, sizeof( bAlreadyWritten ) );
371 1156 : const EscherProperties &rOpts = rProps.GetOpts();
372 23156 : for ( EscherProperties::const_iterator it = rOpts.begin(); it != rOpts.end(); ++it )
373 : {
374 22000 : sal_uInt16 nId = ( it->nPropId & 0x0FFF );
375 :
376 22000 : if ( bAlreadyWritten[ nId ] )
377 6948 : continue;
378 :
379 15052 : switch ( nId )
380 : {
381 : case ESCHER_Prop_WrapText: // 133
382 : {
383 1128 : const char *pWrapType = NULL;
384 1128 : switch ( it->nPropValue )
385 : {
386 : case ESCHER_WrapSquare:
387 296 : case ESCHER_WrapByPoints: pWrapType = "square"; break; // these two are equivalent according to the docu
388 832 : case ESCHER_WrapNone: pWrapType = "none"; break;
389 0 : case ESCHER_WrapTopBottom: pWrapType = "topAndBottom"; break;
390 0 : case ESCHER_WrapThrough: pWrapType = "through"; break;
391 : }
392 1128 : if ( pWrapType )
393 : m_pSerializer->singleElementNS( XML_w10, XML_wrap,
394 : XML_type, pWrapType,
395 1128 : FSEND );
396 : }
397 1128 : bAlreadyWritten[ ESCHER_Prop_WrapText ] = true;
398 1128 : break;
399 :
400 : // coordorigin
401 : case ESCHER_Prop_geoLeft: // 320
402 : case ESCHER_Prop_geoTop: // 321
403 : {
404 326 : sal_uInt32 nLeft = 0, nTop = 0;
405 :
406 326 : if ( nId == ESCHER_Prop_geoLeft )
407 : {
408 326 : nLeft = it->nPropValue;
409 326 : rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
410 : }
411 : else
412 : {
413 0 : nTop = it->nPropValue;
414 0 : rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
415 : }
416 326 : if(nTop!=0 && nLeft!=0)
417 : m_pShapeAttrList->add( XML_coordorigin,
418 0 : OStringBuffer( 20 ).append( sal_Int32( nLeft ) )
419 0 : .append( "," ).append( sal_Int32( nTop ) )
420 0 : .makeStringAndClear() );
421 : }
422 326 : bAlreadyWritten[ ESCHER_Prop_geoLeft ] = true;
423 326 : bAlreadyWritten[ ESCHER_Prop_geoTop ] = true;
424 326 : break;
425 :
426 : // coordsize
427 : case ESCHER_Prop_geoRight: // 322
428 : case ESCHER_Prop_geoBottom: // 323
429 : {
430 670 : sal_uInt32 nLeft = 0, nRight = 0, nTop = 0, nBottom = 0;
431 670 : rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
432 670 : rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
433 :
434 670 : if ( nId == ESCHER_Prop_geoRight )
435 : {
436 670 : nRight = it->nPropValue;
437 670 : rProps.GetOpt( ESCHER_Prop_geoBottom, nBottom );
438 : }
439 : else
440 : {
441 0 : nBottom = it->nPropValue;
442 0 : rProps.GetOpt( ESCHER_Prop_geoRight, nRight );
443 : }
444 :
445 670 : if(nTop!=0 && nLeft!=0 && nBottom!=0 && nRight!=0 )
446 : m_pShapeAttrList->add( XML_coordsize,
447 0 : OStringBuffer( 20 ).append( sal_Int32( nRight ) - sal_Int32( nLeft ) )
448 0 : .append( "," ).append( sal_Int32( nBottom ) - sal_Int32( nTop ) )
449 0 : .makeStringAndClear() );
450 : }
451 670 : bAlreadyWritten[ ESCHER_Prop_geoRight ] = true;
452 670 : bAlreadyWritten[ ESCHER_Prop_geoBottom ] = true;
453 670 : break;
454 :
455 : case ESCHER_Prop_pVertices: // 325
456 : case ESCHER_Prop_pSegmentInfo: // 326
457 : {
458 : EscherPropSortStruct aVertices;
459 : EscherPropSortStruct aSegments;
460 :
461 1340 : if ( rProps.GetOpt( ESCHER_Prop_pVertices, aVertices ) &&
462 670 : rProps.GetOpt( ESCHER_Prop_pSegmentInfo, aSegments ) )
463 : {
464 670 : const sal_uInt8 *pVerticesIt = aVertices.pBuf + 6;
465 670 : const sal_uInt8 *pSegmentIt = aSegments.pBuf;
466 670 : OStringBuffer aPath( 512 );
467 :
468 670 : sal_uInt16 nPointSize = aVertices.pBuf[4] + ( aVertices.pBuf[5] << 8 );
469 :
470 : // number of segments
471 670 : sal_uInt16 nSegments = impl_GetUInt16( pSegmentIt );
472 670 : pSegmentIt += 4;
473 :
474 29400 : for ( ; nSegments; --nSegments )
475 : {
476 28730 : sal_uInt16 nSeg = impl_GetUInt16( pSegmentIt );
477 28730 : switch ( nSeg )
478 : {
479 : case 0x4000: // moveto
480 : {
481 758 : sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
482 758 : sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
483 758 : if (nX >= 0 && nY >= 0 )
484 686 : aPath.append( "m" ).append( nX ).append( "," ).append( nY );
485 : }
486 758 : break;
487 : case 0xb300:
488 : case 0xac00:
489 13430 : break;
490 : case 0x0001: // lineto
491 : {
492 12622 : sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
493 12622 : sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
494 12622 : aPath.append( "l" ).append( nX ).append( "," ).append( nY );
495 : }
496 12622 : break;
497 : case 0x2001: // curveto
498 : {
499 414 : sal_Int32 nX1 = impl_GetPointComponent( pVerticesIt, nPointSize );
500 414 : sal_Int32 nY1 = impl_GetPointComponent( pVerticesIt, nPointSize );
501 414 : sal_Int32 nX2 = impl_GetPointComponent( pVerticesIt, nPointSize );
502 414 : sal_Int32 nY2 = impl_GetPointComponent( pVerticesIt, nPointSize );
503 414 : sal_Int32 nX3 = impl_GetPointComponent( pVerticesIt, nPointSize );
504 414 : sal_Int32 nY3 = impl_GetPointComponent( pVerticesIt, nPointSize );
505 414 : aPath.append( "c" ).append( nX1 ).append( "," ).append( nY1 ).append( "," )
506 414 : .append( nX2 ).append( "," ).append( nY2 ).append( "," )
507 414 : .append( nX3 ).append( "," ).append( nY3 );
508 : }
509 414 : break;
510 : case 0xaa00: // nofill
511 4 : aPath.append( "nf" );
512 4 : break;
513 : case 0xab00: // nostroke
514 4 : aPath.append( "ns" );
515 4 : break;
516 : case 0x6001: // close
517 486 : aPath.append( "x" );
518 486 : break;
519 : case 0x8000: // end
520 674 : aPath.append( "e" );
521 674 : break;
522 : default:
523 : // See EscherPropertyContainer::CreateCustomShapeProperties, by default nSeg is simply the number of points.
524 : // FIXME: we miss out a significant amount of complexity from
525 : // the above method here, and do some rather odd things to match.
526 338 : int nElems = aVertices.nPropSize / ( nPointSize * 2);
527 338 : if (nSeg > nElems)
528 : {
529 : SAL_WARN("oox", "Busted escher export " << nSeg << "vs . " << nElems << " truncating point stream");
530 292 : nSeg = nElems;
531 : }
532 1134 : for (int i = 0; i < nSeg; ++i)
533 : {
534 796 : sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nPointSize);
535 796 : sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nPointSize);
536 796 : if (nX >= 0 && nY >= 0 )
537 52 : aPath.append("l").append(nX).append(",").append(nY);
538 : }
539 338 : break;
540 : }
541 : }
542 670 : OString pathString = aPath.makeStringAndClear();
543 670 : if ( !aPath.isEmpty() && pathString != "xe" )
544 0 : m_pShapeAttrList->add( XML_path, pathString );
545 : }
546 : #if OSL_DEBUG_LEVEL > 0
547 : else
548 : fprintf( stderr, "TODO: unhandled shape path, missing either pVertices or pSegmentInfo.\n" );
549 : #endif
550 : }
551 670 : bAlreadyWritten[ ESCHER_Prop_pVertices ] = true;
552 670 : bAlreadyWritten[ ESCHER_Prop_pSegmentInfo ] = true;
553 670 : break;
554 :
555 : case ESCHER_Prop_fillType: // 384
556 : case ESCHER_Prop_fillColor: // 385
557 : case ESCHER_Prop_fillBackColor: // 387
558 : case ESCHER_Prop_fillBlip: // 390
559 : case ESCHER_Prop_fNoFillHitTest: // 447
560 : case ESCHER_Prop_fillOpacity: // 386
561 : {
562 : sal_uInt32 nValue;
563 1156 : sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
564 :
565 1156 : if ( rProps.GetOpt( ESCHER_Prop_fillType, nValue ) )
566 : {
567 814 : const char *pFillType = NULL;
568 814 : switch ( nValue )
569 : {
570 674 : case ESCHER_FillSolid: pFillType = "solid"; break;
571 : // TODO case ESCHER_FillPattern: pFillType = ""; break;
572 28 : case ESCHER_FillTexture: pFillType = "tile"; break;
573 : // TODO case ESCHER_FillPicture: pFillType = ""; break;
574 : // TODO case ESCHER_FillShade: pFillType = ""; break;
575 : // TODO case ESCHER_FillShadeCenter: pFillType = ""; break;
576 : // TODO case ESCHER_FillShadeShape: pFillType = ""; break;
577 : // TODO case ESCHER_FillShadeScale: pFillType = ""; break;
578 : // TODO case ESCHER_FillShadeTitle: pFillType = ""; break;
579 : // TODO case ESCHER_FillBackground: pFillType = ""; break;
580 : default:
581 : #if OSL_DEBUG_LEVEL > 0
582 : fprintf( stderr, "TODO: unhandled fill type\n" );
583 : #endif
584 112 : break;
585 : }
586 814 : if ( pFillType )
587 702 : pAttrList->add( XML_type, pFillType );
588 : }
589 342 : else if (!rProps.GetOpt(ESCHER_Prop_fillColor, nValue))
590 334 : pAttrList->add( XML_on, "false" );
591 :
592 1156 : if ( rProps.GetOpt( ESCHER_Prop_fillColor, nValue ) )
593 718 : impl_AddColor( m_pShapeAttrList, XML_fillcolor, nValue );
594 :
595 1156 : if ( rProps.GetOpt( ESCHER_Prop_fillBackColor, nValue ) )
596 724 : impl_AddColor( pAttrList, XML_color2, nValue );
597 :
598 1156 : bool imageData = false;
599 : EscherPropSortStruct aStruct;
600 1156 : if ( rProps.GetOpt( ESCHER_Prop_fillBlip, aStruct ) && m_pTextExport)
601 : {
602 106 : SvMemoryStream aStream;
603 106 : int nHeaderSize = 25; // The first bytes are WW8-specific, we're only interested in the PNG
604 106 : aStream.Write(aStruct.pBuf + nHeaderSize, aStruct.nPropSize - nHeaderSize);
605 106 : aStream.Seek(0);
606 212 : Graphic aGraphic;
607 106 : GraphicConverter::Import(aStream, aGraphic);
608 212 : OUString aImageId = m_pTextExport->GetDrawingML().WriteImage( aGraphic );
609 106 : pAttrList->add(FSNS(XML_r, XML_id), OUStringToOString(aImageId, RTL_TEXTENCODING_UTF8));
610 212 : imageData = true;
611 : }
612 :
613 1156 : if ( rProps.GetOpt( ESCHER_Prop_fNoFillHitTest, nValue ) )
614 1128 : impl_AddBool( pAttrList, FSNS(XML_o, XML_detectmouseclick), nValue != 0 );
615 :
616 1156 : if (rProps.GetOpt(ESCHER_Prop_fillOpacity, nValue))
617 : // Partly undo the transformation at the end of EscherPropertyContainer::CreateFillProperties(): VML opacity is 0..1.
618 18 : pAttrList->add(XML_opacity, OString::number(double((nValue * 100) >> 16) / 100));
619 :
620 1156 : if (imageData)
621 106 : m_pSerializer->singleElementNS( XML_v, XML_imagedata, XFastAttributeListRef( pAttrList ) );
622 : else
623 1050 : m_pSerializer->singleElementNS( XML_v, XML_fill, XFastAttributeListRef( pAttrList ) );
624 : }
625 1156 : bAlreadyWritten[ ESCHER_Prop_fillType ] = true;
626 1156 : bAlreadyWritten[ ESCHER_Prop_fillColor ] = true;
627 1156 : bAlreadyWritten[ ESCHER_Prop_fillBackColor ] = true;
628 1156 : bAlreadyWritten[ ESCHER_Prop_fillBlip ] = true;
629 1156 : bAlreadyWritten[ ESCHER_Prop_fNoFillHitTest ] = true;
630 1156 : bAlreadyWritten[ ESCHER_Prop_fillOpacity ] = true;
631 1156 : break;
632 :
633 : case ESCHER_Prop_lineColor: // 448
634 : case ESCHER_Prop_lineWidth: // 459
635 : case ESCHER_Prop_lineDashing: // 462
636 : case ESCHER_Prop_lineStartArrowhead: // 464
637 : case ESCHER_Prop_lineEndArrowhead: // 465
638 : case ESCHER_Prop_lineStartArrowWidth: // 466
639 : case ESCHER_Prop_lineStartArrowLength: // 467
640 : case ESCHER_Prop_lineEndArrowWidth: // 468
641 : case ESCHER_Prop_lineEndArrowLength: // 469
642 : case ESCHER_Prop_lineJoinStyle: // 470
643 : case ESCHER_Prop_lineEndCapStyle: // 471
644 : {
645 : sal_uInt32 nValue;
646 1156 : sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
647 :
648 1156 : if ( rProps.GetOpt( ESCHER_Prop_lineColor, nValue ) )
649 1156 : impl_AddColor( pAttrList, XML_color, nValue );
650 :
651 1156 : if ( rProps.GetOpt( ESCHER_Prop_lineWidth, nValue ) )
652 372 : impl_AddInt( pAttrList, XML_weight, nValue );
653 :
654 1156 : if ( rProps.GetOpt( ESCHER_Prop_lineDashing, nValue ) )
655 : {
656 28 : const char *pDashStyle = NULL;
657 28 : switch ( nValue )
658 : {
659 0 : case ESCHER_LineSolid: pDashStyle = "solid"; break;
660 0 : case ESCHER_LineDashSys: pDashStyle = "shortdash"; break;
661 0 : case ESCHER_LineDotSys: pDashStyle = "shortdot"; break;
662 0 : case ESCHER_LineDashDotSys: pDashStyle = "shortdashdot"; break;
663 0 : case ESCHER_LineDashDotDotSys: pDashStyle = "shortdashdotdot"; break;
664 0 : case ESCHER_LineDotGEL: pDashStyle = "dot"; break;
665 14 : case ESCHER_LineDashGEL: pDashStyle = "dash"; break;
666 8 : case ESCHER_LineLongDashGEL: pDashStyle = "longdash"; break;
667 0 : case ESCHER_LineDashDotGEL: pDashStyle = "dashdot"; break;
668 0 : case ESCHER_LineLongDashDotGEL: pDashStyle = "longdashdot"; break;
669 6 : case ESCHER_LineLongDashDotDotGEL: pDashStyle = "longdashdotdot"; break;
670 : }
671 28 : if ( pDashStyle )
672 28 : pAttrList->add( XML_dashstyle, pDashStyle );
673 : }
674 :
675 1156 : if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowhead, nValue ) )
676 12 : impl_AddArrowHead( pAttrList, XML_startarrow, nValue );
677 :
678 1156 : if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowhead, nValue ) )
679 42 : impl_AddArrowHead( pAttrList, XML_endarrow, nValue );
680 :
681 1156 : if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowWidth, nValue ) )
682 12 : impl_AddArrowWidth( pAttrList, XML_startarrowwidth, nValue );
683 :
684 1156 : if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowLength, nValue ) )
685 12 : impl_AddArrowLength( pAttrList, XML_startarrowlength, nValue );
686 :
687 1156 : if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowWidth, nValue ) )
688 42 : impl_AddArrowWidth( pAttrList, XML_endarrowwidth, nValue );
689 :
690 1156 : if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowLength, nValue ) )
691 42 : impl_AddArrowLength( pAttrList, XML_endarrowlength, nValue );
692 :
693 1156 : if ( rProps.GetOpt( ESCHER_Prop_lineJoinStyle, nValue ) )
694 : {
695 1156 : const char *pJoinStyle = NULL;
696 1156 : switch ( nValue )
697 : {
698 84 : case ESCHER_LineJoinBevel: pJoinStyle = "bevel"; break;
699 106 : case ESCHER_LineJoinMiter: pJoinStyle = "miter"; break;
700 966 : case ESCHER_LineJoinRound: pJoinStyle = "round"; break;
701 : }
702 1156 : if ( pJoinStyle )
703 1156 : pAttrList->add( XML_joinstyle, pJoinStyle );
704 : }
705 :
706 1156 : if ( rProps.GetOpt( ESCHER_Prop_lineEndCapStyle, nValue ) )
707 : {
708 1156 : const char *pEndCap = NULL;
709 1156 : switch ( nValue )
710 : {
711 8 : case ESCHER_LineEndCapRound: pEndCap = "round"; break;
712 10 : case ESCHER_LineEndCapSquare: pEndCap = "square"; break;
713 1138 : case ESCHER_LineEndCapFlat: pEndCap = "flat"; break;
714 : }
715 1156 : if ( pEndCap )
716 1156 : pAttrList->add( XML_endcap, pEndCap );
717 : }
718 :
719 1156 : m_pSerializer->singleElementNS( XML_v, XML_stroke, XFastAttributeListRef( pAttrList ) );
720 : }
721 1156 : bAlreadyWritten[ ESCHER_Prop_lineColor ] = true;
722 1156 : bAlreadyWritten[ ESCHER_Prop_lineWidth ] = true;
723 1156 : bAlreadyWritten[ ESCHER_Prop_lineDashing ] = true;
724 1156 : bAlreadyWritten[ ESCHER_Prop_lineStartArrowhead ] = true;
725 1156 : bAlreadyWritten[ ESCHER_Prop_lineEndArrowhead ] = true;
726 1156 : bAlreadyWritten[ ESCHER_Prop_lineStartArrowWidth ] = true;
727 1156 : bAlreadyWritten[ ESCHER_Prop_lineStartArrowLength ] = true;
728 1156 : bAlreadyWritten[ ESCHER_Prop_lineEndArrowWidth ] = true;
729 1156 : bAlreadyWritten[ ESCHER_Prop_lineEndArrowLength ] = true;
730 1156 : bAlreadyWritten[ ESCHER_Prop_lineJoinStyle ] = true;
731 1156 : bAlreadyWritten[ ESCHER_Prop_lineEndCapStyle ] = true;
732 1156 : break;
733 :
734 : case ESCHER_Prop_fHidden:
735 0 : if ( !it->nPropValue )
736 0 : m_pShapeStyle->append( ";visibility:hidden" );
737 0 : break;
738 : case ESCHER_Prop_shadowColor:
739 : case ESCHER_Prop_fshadowObscured:
740 : {
741 1156 : sal_uInt32 nValue = 0;
742 1156 : bool bShadow = false;
743 1156 : bool bObscured = false;
744 1156 : if ( rProps.GetOpt( ESCHER_Prop_fshadowObscured, nValue ) )
745 : {
746 1156 : bShadow = (( nValue & 0x20002 ) == 0x20002 );
747 1156 : bObscured = (( nValue & 0x10001 ) == 0x10001 );
748 : }
749 1156 : if ( bShadow )
750 : {
751 22 : sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
752 22 : impl_AddBool( pAttrList, XML_on, bShadow );
753 22 : impl_AddBool( pAttrList, XML_obscured, bObscured );
754 :
755 22 : if ( rProps.GetOpt( ESCHER_Prop_shadowColor, nValue ) )
756 22 : impl_AddColor( pAttrList, XML_color, nValue );
757 :
758 22 : m_pSerializer->singleElementNS( XML_v, XML_shadow, XFastAttributeListRef( pAttrList ) );
759 22 : bAlreadyWritten[ ESCHER_Prop_fshadowObscured ] = true;
760 22 : bAlreadyWritten[ ESCHER_Prop_shadowColor ] = true;
761 : }
762 : }
763 1156 : break;
764 : case ESCHER_Prop_gtextUNICODE:
765 : case ESCHER_Prop_gtextFont:
766 : {
767 : EscherPropSortStruct aUnicode;
768 34 : if (rProps.GetOpt(ESCHER_Prop_gtextUNICODE, aUnicode))
769 : {
770 34 : SvMemoryStream aStream;
771 34 : aStream.Write(it->pBuf, it->nPropSize);
772 34 : aStream.Seek(0);
773 68 : OUString aTextPathString = SvxMSDffManager::MSDFFReadZString(aStream, it->nPropSize, true);
774 34 : aStream.Seek(0);
775 :
776 : m_pSerializer->singleElementNS( XML_v, XML_path,
777 : XML_textpathok, "t",
778 34 : FSEND );
779 :
780 34 : sax_fastparser::FastAttributeList* pAttrList = m_pSerializer->createAttrList();
781 34 : pAttrList->add(XML_on, "t");
782 34 : pAttrList->add(XML_fitshape, "t");
783 34 : pAttrList->add(XML_string, OUStringToOString(aTextPathString, RTL_TEXTENCODING_UTF8));
784 : EscherPropSortStruct aFont;
785 68 : OUString aStyle;
786 34 : if (rProps.GetOpt(ESCHER_Prop_gtextFont, aFont))
787 : {
788 34 : aStream.Write(aFont.pBuf, aFont.nPropSize);
789 34 : aStream.Seek(0);
790 34 : OUString aTextPathFont = SvxMSDffManager::MSDFFReadZString(aStream, aFont.nPropSize, true);
791 34 : aStyle += "font-family:\"" + aTextPathFont + "\"";
792 : }
793 34 : if (!aStyle.isEmpty())
794 34 : pAttrList->add(XML_style, OUStringToOString(aStyle, RTL_TEXTENCODING_UTF8));
795 68 : m_pSerializer->singleElementNS(XML_v, XML_textpath, XFastAttributeListRef(pAttrList));
796 : }
797 :
798 34 : bAlreadyWritten[ESCHER_Prop_gtextUNICODE] = true;
799 34 : bAlreadyWritten[ESCHER_Prop_gtextFont] = true;
800 : }
801 34 : break;
802 : case ESCHER_Prop_Rotation:
803 : {
804 : // The higher half of the variable contains the angle.
805 46 : m_pShapeStyle->append(";rotation:").append(double(it->nPropValue >> 16));
806 46 : bAlreadyWritten[ESCHER_Prop_Rotation] = true;
807 : }
808 46 : break;
809 : case ESCHER_Prop_fNoLineDrawDash:
810 : {
811 : // See DffPropertyReader::ApplyLineAttributes().
812 1156 : impl_AddBool( m_pShapeAttrList, XML_stroked, (it->nPropValue & 8) != 0 );
813 1156 : bAlreadyWritten[ESCHER_Prop_fNoLineDrawDash] = true;
814 : }
815 1156 : break;
816 : case ESCHER_Prop_wzName:
817 : {
818 738 : SvMemoryStream aStream;
819 738 : aStream.Write(it->pBuf, it->nPropSize);
820 738 : aStream.Seek(0);
821 1476 : OUString idStr = SvxMSDffManager::MSDFFReadZString(aStream, it->nPropSize, true);
822 738 : aStream.Seek(0);
823 738 : if (!IsWaterMarkShape(m_pSdrObject->GetName()))
824 728 : m_pShapeAttrList->add(XML_ID, OUStringToOString(idStr, RTL_TEXTENCODING_UTF8).getStr());
825 :
826 1476 : bAlreadyWritten[ESCHER_Prop_wzName] = true;
827 : }
828 738 : break;
829 : default:
830 : #if OSL_DEBUG_LEVEL > 0
831 : fprintf( stderr, "TODO VMLExport::Commit(), unimplemented id: %d, value: %" SAL_PRIuUINT32 ", data: [%" SAL_PRIuUINT32 ", %p]\n",
832 : nId, it->nPropValue, it->nPropSize, it->pBuf );
833 : if ( it->nPropSize )
834 : {
835 : const sal_uInt8 *pIt = it->pBuf;
836 : fprintf( stderr, " ( " );
837 : for ( int nCount = it->nPropSize; nCount; --nCount )
838 : {
839 : fprintf( stderr, "%02x ", *pIt );
840 : ++pIt;
841 : }
842 : fprintf( stderr, ")\n" );
843 : }
844 : #endif
845 6816 : break;
846 : }
847 : }
848 :
849 1156 : m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_POSTPONE );
850 : }
851 :
852 1428 : OString VMLExport::ShapeIdString( sal_uInt32 nId )
853 : {
854 1428 : return OStringBuffer( 20 ).append( "shape_" ).append( sal_Int64( nId ) ).makeStringAndClear();
855 : }
856 :
857 1216 : void VMLExport::AddFlipXY( )
858 : {
859 1216 : const sal_uInt32 nFlipHandV = SHAPEFLAG_FLIPH + SHAPEFLAG_FLIPV;
860 1216 : switch ( m_nShapeFlags & nFlipHandV )
861 : {
862 4 : case SHAPEFLAG_FLIPH: m_pShapeStyle->append( ";flip:x" ); break;
863 66 : case SHAPEFLAG_FLIPV: m_pShapeStyle->append( ";flip:y" ); break;
864 4 : case (nFlipHandV): m_pShapeStyle->append( ";flip:xy" ); break;
865 : }
866 1216 : }
867 :
868 22 : void VMLExport::AddLineDimensions( const Rectangle& rRectangle )
869 : {
870 : // style
871 22 : if ( !m_pShapeStyle->isEmpty() )
872 0 : m_pShapeStyle->append( ";" );
873 :
874 22 : m_pShapeStyle->append( "position:absolute" );
875 :
876 22 : AddFlipXY();
877 :
878 : // the actual dimensions
879 44 : OString aLeft, aTop, aRight, aBottom;
880 :
881 22 : if ( mnGroupLevel == 1 )
882 : {
883 16 : const OString aPt( "pt" );
884 16 : aLeft = OString::number( double( rRectangle.Left() ) / 20 ) + aPt;
885 16 : aTop = OString::number( double( rRectangle.Top() ) / 20 ) + aPt;
886 16 : aRight = OString::number( double( rRectangle.Right() ) / 20 ) + aPt;
887 16 : aBottom = OString::number( double( rRectangle.Bottom() ) / 20 ) + aPt;
888 : }
889 : else
890 : {
891 6 : aLeft = OString::number( rRectangle.Left() );
892 6 : aTop = OString::number( rRectangle.Top() );
893 6 : aRight = OString::number( rRectangle.Right() );
894 6 : aBottom = OString::number( rRectangle.Bottom() );
895 : }
896 :
897 : m_pShapeAttrList->add( XML_from,
898 44 : OStringBuffer( 20 ).append( aLeft )
899 22 : .append( "," ).append( aTop )
900 22 : .makeStringAndClear() );
901 :
902 : m_pShapeAttrList->add( XML_to,
903 44 : OStringBuffer( 20 ).append( aRight )
904 22 : .append( "," ).append( aBottom )
905 44 : .makeStringAndClear() );
906 22 : }
907 :
908 1194 : void VMLExport::AddRectangleDimensions( OStringBuffer& rBuffer, const Rectangle& rRectangle, bool rbAbsolutePos)
909 : {
910 1194 : if ( !rBuffer.isEmpty() )
911 0 : rBuffer.append( ";" );
912 :
913 1194 : if (rbAbsolutePos)
914 : {
915 1186 : rBuffer.append( "position:absolute;" );
916 : }
917 :
918 1194 : if ( mnGroupLevel == 1 )
919 : {
920 560 : rBuffer.append( "margin-left:" ).append( double( rRectangle.Left() ) / 20 )
921 1120 : .append( "pt;margin-top:" ).append( double( rRectangle.Top() ) / 20 )
922 1120 : .append( "pt;width:" ).append( double( rRectangle.Right() - rRectangle.Left() ) / 20 )
923 1120 : .append( "pt;height:" ).append( double( rRectangle.Bottom() - rRectangle.Top() ) / 20 )
924 560 : .append( "pt" );
925 : }
926 : else
927 : {
928 634 : rBuffer.append( "left:" ).append( rRectangle.Left() )
929 1268 : .append( ";top:" ).append( rRectangle.Top() )
930 1268 : .append( ";width:" ).append( rRectangle.Right() - rRectangle.Left() )
931 1268 : .append( ";height:" ).append( rRectangle.Bottom() - rRectangle.Top() );
932 : }
933 :
934 1194 : AddFlipXY();
935 1194 : }
936 :
937 0 : void VMLExport::AddShapeAttribute( sal_Int32 nAttribute, const OString& rValue )
938 : {
939 0 : m_pShapeAttrList->add( nAttribute, rValue );
940 0 : }
941 :
942 14 : std::vector<OString> lcl_getShapeTypes()
943 : {
944 14 : std::vector<OString> aRet;
945 :
946 28 : OUString aPath("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/filter/vml-shape-types");
947 14 : rtl::Bootstrap::expandMacros(aPath);
948 28 : SvFileStream aStream(aPath, STREAM_READ);
949 14 : if (aStream.GetError() != ERRCODE_NONE)
950 : SAL_WARN("oox", "failed to open vml-shape-types");
951 28 : OString aLine;
952 14 : bool bNotDone = aStream.ReadLine(aLine);
953 5712 : while (bNotDone)
954 : {
955 : // Filter out comments.
956 5684 : if (!aLine.startsWith("/"))
957 2842 : aRet.push_back(aLine);
958 5684 : bNotDone = aStream.ReadLine(aLine);
959 : }
960 28 : return aRet;
961 : }
962 :
963 2286 : bool lcl_isTextBox(const SdrObject* pSdrObject)
964 : {
965 2286 : uno::Reference<beans::XPropertySet> xPropertySet(const_cast<SdrObject*>(pSdrObject)->getUnoShape(), uno::UNO_QUERY);
966 2286 : if (xPropertySet.is())
967 : {
968 2286 : uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
969 2286 : return xPropertySetInfo->hasPropertyByName("TextBox") && xPropertySet->getPropertyValue("TextBox").get<bool>();
970 : }
971 0 : return false;
972 : }
973 :
974 1156 : OUString lcl_getAnchorIdFromGrabBag(const SdrObject* pSdrObject)
975 : {
976 1156 : OUString aResult;
977 :
978 2312 : uno::Reference<beans::XPropertySet> xShape(const_cast<SdrObject*>(pSdrObject)->getUnoShape(), uno::UNO_QUERY);
979 1156 : if (xShape->getPropertySetInfo()->hasPropertyByName("InteropGrabBag"))
980 : {
981 996 : comphelper::SequenceAsHashMap aInteropGrabBag(xShape->getPropertyValue("InteropGrabBag"));
982 996 : if (aInteropGrabBag.find("AnchorId") != aInteropGrabBag.end())
983 316 : aInteropGrabBag["AnchorId"] >>= aResult;
984 : }
985 :
986 2312 : return aResult;
987 : }
988 :
989 1378 : sal_Int32 VMLExport::StartShape()
990 : {
991 1378 : if ( m_nShapeType == ESCHER_ShpInst_Nil )
992 222 : return -1;
993 :
994 : // some of the shapes have their own name ;-)
995 1156 : sal_Int32 nShapeElement = -1;
996 1156 : bool bReferToShapeType = false;
997 1156 : switch ( m_nShapeType )
998 : {
999 344 : case ESCHER_ShpInst_NotPrimitive: nShapeElement = XML_shape; break;
1000 310 : case ESCHER_ShpInst_Rectangle: nShapeElement = XML_rect; break;
1001 0 : case ESCHER_ShpInst_RoundRectangle: nShapeElement = XML_roundrect; break;
1002 32 : case ESCHER_ShpInst_Ellipse: nShapeElement = XML_oval; break;
1003 0 : case ESCHER_ShpInst_Arc: nShapeElement = XML_arc; break;
1004 22 : case ESCHER_ShpInst_Line: nShapeElement = XML_line; break;
1005 : default:
1006 448 : if ( m_nShapeType < ESCHER_ShpInst_COUNT )
1007 : {
1008 448 : nShapeElement = XML_shape;
1009 :
1010 : // a predefined shape?
1011 448 : static std::vector<OString> aShapeTypes = lcl_getShapeTypes();
1012 448 : OString aShapeType = aShapeTypes[ m_nShapeType ];
1013 448 : if ( aShapeType != "NULL" )
1014 : {
1015 358 : bReferToShapeType = true;
1016 358 : if ( !m_pShapeTypeWritten[ m_nShapeType ] )
1017 : {
1018 72 : m_pSerializer->write( aShapeType.getStr() );
1019 72 : m_pShapeTypeWritten[ m_nShapeType ] = true;
1020 : }
1021 : }
1022 : else
1023 : {
1024 : // rectangle is probably the best fallback...
1025 90 : nShapeElement = XML_rect;
1026 448 : }
1027 : }
1028 448 : break;
1029 : }
1030 :
1031 : // anchoring
1032 1156 : switch (m_eHOri)
1033 : {
1034 : case text::HoriOrientation::LEFT:
1035 2 : m_pShapeStyle->append(";mso-position-horizontal:left");
1036 2 : break;
1037 : case text::HoriOrientation::CENTER:
1038 22 : m_pShapeStyle->append(";mso-position-horizontal:center");
1039 22 : break;
1040 : case text::HoriOrientation::RIGHT:
1041 2 : m_pShapeStyle->append(";mso-position-horizontal:right");
1042 2 : break;
1043 : case text::HoriOrientation::INSIDE:
1044 0 : m_pShapeStyle->append(";mso-position-horizontal:inside");
1045 0 : break;
1046 : case text::HoriOrientation::OUTSIDE:
1047 0 : m_pShapeStyle->append(";mso-position-horizontal:outside");
1048 0 : break;
1049 : default:
1050 : case text::HoriOrientation::NONE:
1051 1130 : break;
1052 : }
1053 1156 : switch (m_eHRel)
1054 : {
1055 : case text::RelOrientation::PAGE_PRINT_AREA:
1056 10 : m_pShapeStyle->append(";mso-position-horizontal-relative:margin");
1057 10 : break;
1058 : case text::RelOrientation::PAGE_FRAME:
1059 : case text::RelOrientation::PAGE_LEFT:
1060 : case text::RelOrientation::PAGE_RIGHT:
1061 66 : m_pShapeStyle->append(";mso-position-horizontal-relative:page");
1062 66 : break;
1063 : case text::RelOrientation::CHAR:
1064 0 : m_pShapeStyle->append(";mso-position-horizontal-relative:char");
1065 0 : break;
1066 : default:
1067 1080 : break;
1068 : }
1069 :
1070 1156 : switch (m_eVOri)
1071 : {
1072 : case text::VertOrientation::TOP:
1073 : case text::VertOrientation::LINE_TOP:
1074 : case text::VertOrientation::CHAR_TOP:
1075 14 : m_pShapeStyle->append(";mso-position-vertical:top");
1076 14 : break;
1077 : case text::VertOrientation::CENTER:
1078 : case text::VertOrientation::LINE_CENTER:
1079 16 : m_pShapeStyle->append(";mso-position-vertical:center");
1080 16 : break;
1081 : case text::VertOrientation::BOTTOM:
1082 : case text::VertOrientation::LINE_BOTTOM:
1083 : case text::VertOrientation::CHAR_BOTTOM:
1084 0 : m_pShapeStyle->append(";mso-position-vertical:bottom");
1085 0 : break;
1086 : default:
1087 : case text::VertOrientation::NONE:
1088 1126 : break;
1089 : }
1090 1156 : switch (m_eVRel)
1091 : {
1092 : case text::RelOrientation::PAGE_PRINT_AREA:
1093 18 : m_pShapeStyle->append(";mso-position-vertical-relative:margin");
1094 18 : break;
1095 : case text::RelOrientation::PAGE_FRAME:
1096 68 : m_pShapeStyle->append(";mso-position-vertical-relative:page");
1097 68 : break;
1098 : default:
1099 1070 : break;
1100 : }
1101 :
1102 : // add style
1103 1156 : m_pShapeAttrList->add( XML_style, m_pShapeStyle->makeStringAndClear() );
1104 :
1105 1156 : OUString sAnchorId = lcl_getAnchorIdFromGrabBag(m_pSdrObject);
1106 1156 : if (!sAnchorId.isEmpty())
1107 316 : m_pShapeAttrList->addNS(XML_wp14, XML_anchorId, OUStringToOString(sAnchorId, RTL_TEXTENCODING_UTF8));
1108 :
1109 1156 : if ( nShapeElement >= 0 && !m_pShapeAttrList->hasAttribute( XML_type ) )
1110 : {
1111 1156 : if ( bReferToShapeType )
1112 : {
1113 : m_pShapeAttrList->add( XML_type, OStringBuffer( 20 )
1114 716 : .append( "shapetype_" ).append( sal_Int32( m_nShapeType ) )
1115 358 : .makeStringAndClear() );
1116 : }
1117 :
1118 : // start of the shape
1119 1156 : m_pSerializer->startElementNS( XML_v, nShapeElement, XFastAttributeListRef( m_pShapeAttrList ) );
1120 : }
1121 : else
1122 : {
1123 : // start of the shape
1124 0 : m_pSerializer->startElementNS( XML_v, nShapeElement, XFastAttributeListRef( m_pShapeAttrList ) );
1125 : }
1126 :
1127 : // now check if we have some editeng text (not associated textbox) and we have a text exporter registered
1128 1156 : const SdrTextObj* pTxtObj = PTR_CAST(SdrTextObj, m_pSdrObject);
1129 1156 : if (pTxtObj && m_pTextExport && msfilter::util::HasTextBoxContent(m_nShapeType) && !IsWaterMarkShape(m_pSdrObject->GetName()) && !lcl_isTextBox(m_pSdrObject))
1130 : {
1131 1000 : const OutlinerParaObject* pParaObj = 0;
1132 1000 : bool bOwnParaObj = false;
1133 :
1134 : /*
1135 : #i13885#
1136 : When the object is actively being edited, that text is not set into
1137 : the objects normal text object, but lives in a separate object.
1138 : */
1139 1000 : if (pTxtObj->IsTextEditActive())
1140 : {
1141 0 : pParaObj = pTxtObj->GetEditOutlinerParaObject();
1142 0 : bOwnParaObj = true;
1143 : }
1144 : else
1145 : {
1146 1000 : pParaObj = pTxtObj->GetOutlinerParaObject();
1147 : }
1148 :
1149 1000 : if( pParaObj )
1150 : {
1151 : // this is reached only in case some text is attached to the shape
1152 242 : m_pSerializer->startElementNS(XML_v, XML_textbox, FSEND);
1153 242 : m_pTextExport->WriteOutliner(*pParaObj);
1154 242 : m_pSerializer->endElementNS(XML_v, XML_textbox);
1155 242 : if( bOwnParaObj )
1156 0 : delete pParaObj;
1157 : }
1158 : }
1159 :
1160 1156 : return nShapeElement;
1161 : }
1162 :
1163 1378 : void VMLExport::EndShape( sal_Int32 nShapeElement )
1164 : {
1165 1378 : if ( nShapeElement >= 0 )
1166 : {
1167 1156 : if (m_pTextExport && lcl_isTextBox(m_pSdrObject))
1168 : {
1169 130 : uno::Reference<beans::XPropertySet> xPropertySet(const_cast<SdrObject*>(m_pSdrObject)->getUnoShape(), uno::UNO_QUERY);
1170 260 : comphelper::SequenceAsHashMap aCustomShapeProperties(xPropertySet->getPropertyValue("CustomShapeGeometry"));
1171 130 : sax_fastparser::FastAttributeList* pTextboxAttrList = m_pSerializer->createAttrList();
1172 130 : if (aCustomShapeProperties.find("TextPreRotateAngle") != aCustomShapeProperties.end())
1173 : {
1174 130 : sal_Int32 nTextRotateAngle = aCustomShapeProperties["TextPreRotateAngle"].get<sal_Int32>();
1175 130 : if (nTextRotateAngle == -270)
1176 4 : pTextboxAttrList->add(XML_style, "mso-layout-flow-alt:bottom-to-top");
1177 : }
1178 260 : sax_fastparser::XFastAttributeListRef xTextboxAttrList(pTextboxAttrList);
1179 130 : pTextboxAttrList = 0;
1180 130 : m_pSerializer->startElementNS(XML_v, XML_textbox, xTextboxAttrList);
1181 :
1182 130 : m_pTextExport->WriteVMLTextBox(uno::Reference<drawing::XShape>(xPropertySet, uno::UNO_QUERY_THROW));
1183 :
1184 260 : m_pSerializer->endElementNS(XML_v, XML_textbox);
1185 : }
1186 :
1187 : // end of the shape
1188 1156 : m_pSerializer->endElementNS( XML_v, nShapeElement );
1189 : }
1190 1378 : }
1191 :
1192 672 : sal_uInt32 VMLExport::AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri, sal_Int16 eVOri, sal_Int16 eHRel, sal_Int16 eVRel, const Point* pNdTopLeft, const bool bOOxmlExport )
1193 : {
1194 672 : m_pSdrObject = &rObj;
1195 672 : m_eHOri = eHOri;
1196 672 : m_eVOri = eVOri;
1197 672 : m_eHRel = eHRel;
1198 672 : m_eVRel = eVRel;
1199 672 : m_pNdTopLeft = pNdTopLeft;
1200 672 : return EscherEx::AddSdrObject(rObj, bOOxmlExport);
1201 408 : }
1202 :
1203 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|