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