bump product version to 4.1.6.2
[LibreOffice.git] / oox / source / export / vmlexport.cxx
blobd6623c069f0a8ca57fc3e2b23e9e8a087a9cbb69
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 <oox/export/vmlexport.hxx>
22 #include <oox/token/tokens.hxx>
24 #include <rtl/strbuf.hxx>
25 #include <rtl/ustring.hxx>
27 #include <tools/stream.hxx>
28 #include <svx/svdotext.hxx>
29 #include <vcl/cvtgrf.hxx>
31 #include <cstdio>
34 using namespace sax_fastparser;
35 using namespace oox::vml;
37 VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr pSerializer, VMLTextExport* pTextExport )
38 : EscherEx( EscherExGlobalRef(new EscherExGlobal(0)), 0 )
39 , m_pSerializer( pSerializer )
40 , m_pTextExport( pTextExport )
41 , m_pSdrObject( 0 )
42 , m_pShapeAttrList( NULL )
43 , m_nShapeType( ESCHER_ShpInst_Nil )
44 , m_nShapeFlags(0)
45 , m_pShapeStyle( new OStringBuffer( 200 ) )
46 , m_pShapeTypeWritten( new bool[ ESCHER_ShpInst_COUNT ] )
48 mnGroupLevel = 1;
49 memset( m_pShapeTypeWritten, 0, ESCHER_ShpInst_COUNT * sizeof( bool ) );
52 VMLExport::~VMLExport()
54 delete mpOutStrm, mpOutStrm = NULL;
55 delete m_pShapeStyle, m_pShapeStyle = NULL;
56 delete[] m_pShapeTypeWritten, m_pShapeTypeWritten = NULL;
59 void VMLExport::OpenContainer( sal_uInt16 nEscherContainer, int nRecInstance )
61 EscherEx::OpenContainer( nEscherContainer, nRecInstance );
63 if ( nEscherContainer == ESCHER_SpContainer )
65 // opening a shape container
66 #if OSL_DEBUG_LEVEL > 0
67 if ( m_nShapeType != ESCHER_ShpInst_Nil )
68 fprintf( stderr, "Warning! VMLExport::OpenContainer(): opening shape inside a shape.\n" );
69 #endif
70 m_nShapeType = ESCHER_ShpInst_Nil;
71 m_pShapeAttrList = m_pSerializer->createAttrList();
73 if ( m_pShapeStyle->getLength() )
74 m_pShapeStyle->makeStringAndClear();
76 m_pShapeStyle->ensureCapacity( 200 );
78 // postpone the output so that we are able to write even the elements
79 // that we learn inside Commit()
80 m_pSerializer->mark();
84 void VMLExport::CloseContainer()
86 if ( mRecTypes.back() == ESCHER_SpContainer )
88 // write the shape now when we have all the info
89 sal_Int32 nShapeElement = StartShape();
91 m_pSerializer->mergeTopMarks();
93 EndShape( nShapeElement );
95 // cleanup
96 m_nShapeType = ESCHER_ShpInst_Nil;
97 m_pShapeAttrList = NULL;
100 EscherEx::CloseContainer();
103 sal_uInt32 VMLExport::EnterGroup( const OUString& rShapeName, const Rectangle* pRect )
105 sal_uInt32 nShapeId = GenerateShapeId();
107 OStringBuffer aStyle( 200 );
108 FastAttributeList *pAttrList = m_pSerializer->createAttrList();
110 pAttrList->add( XML_id, ShapeIdString( nShapeId ) );
112 if ( rShapeName.getLength() )
113 pAttrList->add( XML_alt, OUStringToOString( rShapeName, RTL_TEXTENCODING_UTF8 ) );
115 // style
116 if ( pRect )
117 AddRectangleDimensions( aStyle, *pRect );
119 if ( aStyle.getLength() )
120 pAttrList->add( XML_style, aStyle.makeStringAndClear() );
122 // coordorigin/coordsize
123 if ( pRect && ( mnGroupLevel == 1 ) )
125 pAttrList->add( XML_coordorigin,
126 OStringBuffer( 20 ).append( sal_Int32( pRect->Left() ) )
127 .append( "," ).append( sal_Int32( pRect->Top() ) )
128 .makeStringAndClear() );
130 pAttrList->add( XML_coordsize,
131 OStringBuffer( 20 ).append( sal_Int32( pRect->Right() ) - sal_Int32( pRect->Left() ) )
132 .append( "," ).append( sal_Int32( pRect->Bottom() ) - sal_Int32( pRect->Top() ) )
133 .makeStringAndClear() );
136 m_pSerializer->startElementNS( XML_v, XML_group, XFastAttributeListRef( pAttrList ) );
138 mnGroupLevel++;
139 return nShapeId;
142 void VMLExport::LeaveGroup()
144 --mnGroupLevel;
145 m_pSerializer->endElementNS( XML_v, XML_group );
148 void VMLExport::AddShape( sal_uInt32 nShapeType, sal_uInt32 nShapeFlags, sal_uInt32 nShapeId )
150 m_nShapeType = nShapeType;
151 m_nShapeFlags = nShapeFlags;
153 m_pShapeAttrList->add( XML_id, ShapeIdString( nShapeId ) );
156 static void impl_AddArrowHead( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
158 if ( !pAttrList )
159 return;
161 const char *pArrowHead = NULL;
162 switch ( nValue )
164 case ESCHER_LineNoEnd: pArrowHead = "none"; break;
165 case ESCHER_LineArrowEnd: pArrowHead = "block"; break;
166 case ESCHER_LineArrowStealthEnd: pArrowHead = "classic"; break;
167 case ESCHER_LineArrowDiamondEnd: pArrowHead = "diamond"; break;
168 case ESCHER_LineArrowOvalEnd: pArrowHead = "oval"; break;
169 case ESCHER_LineArrowOpenEnd: pArrowHead = "open"; break;
172 if ( pArrowHead )
173 pAttrList->add( nElement, pArrowHead );
176 static void impl_AddArrowLength( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
178 if ( !pAttrList )
179 return;
181 const char *pArrowLength = NULL;
182 switch ( nValue )
184 case ESCHER_LineShortArrow: pArrowLength = "short"; break;
185 case ESCHER_LineMediumLenArrow: pArrowLength = "medium"; break;
186 case ESCHER_LineLongArrow: pArrowLength = "long"; break;
189 if ( pArrowLength )
190 pAttrList->add( nElement, pArrowLength );
193 static void impl_AddArrowWidth( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
195 if ( !pAttrList )
196 return;
198 const char *pArrowWidth = NULL;
199 switch ( nValue )
201 case ESCHER_LineNarrowArrow: pArrowWidth = "narrow"; break;
202 case ESCHER_LineMediumWidthArrow: pArrowWidth = "medium"; break;
203 case ESCHER_LineWideArrow: pArrowWidth = "wide"; break;
206 if ( pArrowWidth )
207 pAttrList->add( nElement, pArrowWidth );
210 static void impl_AddBool( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, bool bValue )
212 if ( !pAttrList )
213 return;
215 pAttrList->add( nElement, bValue? "t": "f" );
218 static void impl_AddColor( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nColor )
220 #if OSL_DEBUG_LEVEL > 0
221 if ( nColor & 0xFF000000 )
222 fprintf( stderr, "TODO: this is not a RGB value!\n" );
223 #endif
225 if ( !pAttrList || ( nColor & 0xFF000000 ) )
226 return;
228 nColor = ( ( nColor & 0xFF ) << 16 ) + ( nColor & 0xFF00 ) + ( ( nColor & 0xFF0000 ) >> 16 );
230 const char *pColor = NULL;
231 char pRgbColor[10];
232 switch ( nColor )
234 case 0x000000: pColor = "black"; break;
235 case 0xC0C0C0: pColor = "silver"; break;
236 case 0x808080: pColor = "gray"; break;
237 case 0xFFFFFF: pColor = "white"; break;
238 case 0x800000: pColor = "maroon"; break;
239 case 0xFF0000: pColor = "red"; break;
240 case 0x800080: pColor = "purple"; break;
241 case 0xFF00FF: pColor = "fuchsia"; break;
242 case 0x008000: pColor = "green"; break;
243 case 0x00FF00: pColor = "lime"; break;
244 case 0x808000: pColor = "olive"; break;
245 case 0xFFFF00: pColor = "yellow"; break;
246 case 0x000080: pColor = "navy"; break;
247 case 0x0000FF: pColor = "blue"; break;
248 case 0x008080: pColor = "teal"; break;
249 case 0x00FFFF: pColor = "aqua"; break;
250 default:
252 snprintf( pRgbColor, sizeof( pRgbColor ), "#%06x", static_cast< unsigned int >( nColor ) ); // not too handy to use OString::valueOf() here :-(
253 pColor = pRgbColor;
255 break;
258 pAttrList->add( nElement, pColor );
261 static void impl_AddInt( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
263 if ( !pAttrList )
264 return;
266 pAttrList->add( nElement, OString::number( nValue ).getStr() );
269 inline sal_uInt16 impl_GetUInt16( const sal_uInt8* &pVal )
271 sal_uInt16 nRet = *pVal++;
272 nRet += ( *pVal++ ) << 8;
273 return nRet;
276 inline sal_Int32 impl_GetPointComponent( const sal_uInt8* &pVal, sal_uInt16 nPointSize )
278 sal_Int32 nRet = 0;
279 if ( ( nPointSize == 0xfff0 ) || ( nPointSize == 4 ) )
281 sal_uInt16 nUnsigned = *pVal++;
282 nUnsigned += ( *pVal++ ) << 8;
284 nRet = sal_Int16( nUnsigned );
286 else if ( nPointSize == 8 )
288 sal_uInt32 nUnsigned = *pVal++;
289 nUnsigned += ( *pVal++ ) << 8;
290 nUnsigned += ( *pVal++ ) << 16;
291 nUnsigned += ( *pVal++ ) << 24;
293 nRet = nUnsigned;
296 return nRet;
299 void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect )
301 if ( m_nShapeType == ESCHER_ShpInst_Nil )
302 return;
304 // postpone the output of the embedded elements so that they are written
305 // inside the shapes
306 m_pSerializer->mark();
308 // dimensions
309 if ( m_nShapeType == ESCHER_ShpInst_Line )
310 AddLineDimensions( rRect );
311 else
312 AddRectangleDimensions( *m_pShapeStyle, rRect );
314 // properties
315 bool bAlreadyWritten[ 0xFFF ];
316 memset( bAlreadyWritten, 0, sizeof( bAlreadyWritten ) );
317 const EscherProperties &rOpts = rProps.GetOpts();
318 for ( EscherProperties::const_iterator it = rOpts.begin(); it != rOpts.end(); ++it )
320 sal_uInt16 nId = ( it->nPropId & 0x0FFF );
322 if ( bAlreadyWritten[ nId ] )
323 continue;
325 switch ( nId )
327 case ESCHER_Prop_WrapText: // 133
329 const char *pWrapType = NULL;
330 switch ( it->nPropValue )
332 case ESCHER_WrapSquare:
333 case ESCHER_WrapByPoints: pWrapType = "square"; break; // these two are equivalent according to the docu
334 case ESCHER_WrapNone: pWrapType = "none"; break;
335 case ESCHER_WrapTopBottom: pWrapType = "topAndBottom"; break;
336 case ESCHER_WrapThrough: pWrapType = "through"; break;
338 if ( pWrapType )
339 m_pSerializer->singleElementNS( XML_v, XML_wrap,
340 FSNS( XML_v, XML_type ), pWrapType,
341 FSEND );
343 bAlreadyWritten[ ESCHER_Prop_WrapText ] = true;
344 break;
346 // coordorigin
347 case ESCHER_Prop_geoLeft: // 320
348 case ESCHER_Prop_geoTop: // 321
350 sal_uInt32 nLeft = 0, nTop = 0;
352 if ( nId == ESCHER_Prop_geoLeft )
354 nLeft = it->nPropValue;
355 rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
357 else
359 nTop = it->nPropValue;
360 rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
363 m_pShapeAttrList->add( XML_coordorigin,
364 OStringBuffer( 20 ).append( sal_Int32( nLeft ) )
365 .append( "," ).append( sal_Int32( nTop ) )
366 .makeStringAndClear() );
368 bAlreadyWritten[ ESCHER_Prop_geoLeft ] = true;
369 bAlreadyWritten[ ESCHER_Prop_geoTop ] = true;
370 break;
372 // coordsize
373 case ESCHER_Prop_geoRight: // 322
374 case ESCHER_Prop_geoBottom: // 323
376 sal_uInt32 nLeft = 0, nRight = 0, nTop = 0, nBottom = 0;
377 rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
378 rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
380 if ( nId == ESCHER_Prop_geoRight )
382 nRight = it->nPropValue;
383 rProps.GetOpt( ESCHER_Prop_geoBottom, nBottom );
385 else
387 nBottom = it->nPropValue;
388 rProps.GetOpt( ESCHER_Prop_geoRight, nRight );
391 m_pShapeAttrList->add( XML_coordsize,
392 OStringBuffer( 20 ).append( sal_Int32( nRight ) - sal_Int32( nLeft ) )
393 .append( "," ).append( sal_Int32( nBottom ) - sal_Int32( nTop ) )
394 .makeStringAndClear() );
396 bAlreadyWritten[ ESCHER_Prop_geoRight ] = true;
397 bAlreadyWritten[ ESCHER_Prop_geoBottom ] = true;
398 break;
400 case ESCHER_Prop_pVertices: // 325
401 case ESCHER_Prop_pSegmentInfo: // 326
403 EscherPropSortStruct aVertices;
404 EscherPropSortStruct aSegments;
406 if ( rProps.GetOpt( ESCHER_Prop_pVertices, aVertices ) &&
407 rProps.GetOpt( ESCHER_Prop_pSegmentInfo, aSegments ) )
409 const sal_uInt8 *pVerticesIt = aVertices.pBuf + 6;
410 const sal_uInt8 *pSegmentIt = aSegments.pBuf;
411 OStringBuffer aPath( 512 );
413 sal_uInt16 nPointSize = aVertices.pBuf[4] + ( aVertices.pBuf[5] << 8 );
415 // number of segments
416 sal_uInt16 nSegments = impl_GetUInt16( pSegmentIt );
417 pSegmentIt += 4;
419 for ( ; nSegments; --nSegments )
421 sal_uInt16 nSeg = impl_GetUInt16( pSegmentIt );
422 switch ( nSeg )
424 case 0x4000: // moveto
426 sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
427 sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
428 aPath.append( "m" ).append( nX ).append( "," ).append( nY );
430 break;
431 case 0xb300:
432 case 0xac00:
433 break;
434 case 0x0001: // lineto
436 sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
437 sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
438 aPath.append( "l" ).append( nX ).append( "," ).append( nY );
440 break;
441 case 0x2001: // curveto
443 sal_Int32 nX1 = impl_GetPointComponent( pVerticesIt, nPointSize );
444 sal_Int32 nY1 = impl_GetPointComponent( pVerticesIt, nPointSize );
445 sal_Int32 nX2 = impl_GetPointComponent( pVerticesIt, nPointSize );
446 sal_Int32 nY2 = impl_GetPointComponent( pVerticesIt, nPointSize );
447 sal_Int32 nX3 = impl_GetPointComponent( pVerticesIt, nPointSize );
448 sal_Int32 nY3 = impl_GetPointComponent( pVerticesIt, nPointSize );
449 aPath.append( "c" ).append( nX1 ).append( "," ).append( nY1 ).append( "," )
450 .append( nX2 ).append( "," ).append( nY2 ).append( "," )
451 .append( nX3 ).append( "," ).append( nY3 );
453 break;
454 case 0xaa00: // nofill
455 aPath.append( "nf" );
456 break;
457 case 0xab00: // nostroke
458 aPath.append( "ns" );
459 break;
460 case 0x6001: // close
461 aPath.append( "x" );
462 break;
463 case 0x8000: // end
464 aPath.append( "e" );
465 break;
466 default:
467 // See EscherPropertyContainer::CreateCustomShapeProperties, by default nSeg is simply the number of points.
468 for (int i = 0; i < nSeg; ++i)
470 sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nPointSize);
471 sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nPointSize);
472 aPath.append("l").append(nX).append(",").append(nY);
474 break;
478 if ( aPath.getLength() )
479 m_pShapeAttrList->add( XML_path, aPath.getStr() );
481 #if OSL_DEBUG_LEVEL > 0
482 else
483 fprintf( stderr, "TODO: unhandled shape path, missing either pVertices or pSegmentInfo.\n" );
484 #endif
486 bAlreadyWritten[ ESCHER_Prop_pVertices ] = true;
487 bAlreadyWritten[ ESCHER_Prop_pSegmentInfo ] = true;
488 break;
490 case ESCHER_Prop_fillType: // 384
491 case ESCHER_Prop_fillColor: // 385
492 case ESCHER_Prop_fillBackColor: // 387
493 case ESCHER_Prop_fillBlip: // 390
494 case ESCHER_Prop_fNoFillHitTest: // 447
496 sal_uInt32 nValue;
497 sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
499 if ( rProps.GetOpt( ESCHER_Prop_fillType, nValue ) )
501 const char *pFillType = NULL;
502 switch ( nValue )
504 case ESCHER_FillSolid: pFillType = "solid"; break;
505 // TODO case ESCHER_FillPattern: pFillType = ""; break;
506 case ESCHER_FillTexture: pFillType = "tile"; break;
507 // TODO case ESCHER_FillPicture: pFillType = ""; break;
508 // TODO case ESCHER_FillShade: pFillType = ""; break;
509 // TODO case ESCHER_FillShadeCenter: pFillType = ""; break;
510 // TODO case ESCHER_FillShadeShape: pFillType = ""; break;
511 // TODO case ESCHER_FillShadeScale: pFillType = ""; break;
512 // TODO case ESCHER_FillShadeTitle: pFillType = ""; break;
513 // TODO case ESCHER_FillBackground: pFillType = ""; break;
514 default:
515 #if OSL_DEBUG_LEVEL > 0
516 fprintf( stderr, "TODO: unhandled fill type\n" );
517 #endif
518 break;
520 if ( pFillType )
521 pAttrList->add( XML_type, pFillType );
524 if ( rProps.GetOpt( ESCHER_Prop_fillColor, nValue ) )
525 impl_AddColor( m_pShapeAttrList, XML_fillcolor, nValue );
527 if ( rProps.GetOpt( ESCHER_Prop_fillBackColor, nValue ) )
528 impl_AddColor( pAttrList, XML_color2, nValue );
530 EscherPropSortStruct aStruct;
531 if ( rProps.GetOpt( ESCHER_Prop_fillBlip, aStruct ) && m_pTextExport)
533 SvMemoryStream aStream;
534 int nHeaderSize = 25; // The first bytes are WW8-specific, we're only interested in the PNG
535 aStream.Write(aStruct.pBuf + nHeaderSize, aStruct.nPropSize - nHeaderSize);
536 aStream.Seek(0);
537 Graphic aGraphic;
538 GraphicConverter::Import(aStream, aGraphic, CVT_PNG);
539 OUString aImageId = m_pTextExport->GetDrawingML().WriteImage( aGraphic );
540 pAttrList->add(FSNS(XML_r, XML_id), OUStringToOString(aImageId, RTL_TEXTENCODING_UTF8));
543 if ( rProps.GetOpt( ESCHER_Prop_fNoFillHitTest, nValue ) )
544 impl_AddBool( pAttrList, XML_detectmouseclick, nValue );
546 m_pSerializer->singleElementNS( XML_v, XML_fill, XFastAttributeListRef( pAttrList ) );
548 bAlreadyWritten[ ESCHER_Prop_fillType ] = true;
549 bAlreadyWritten[ ESCHER_Prop_fillColor ] = true;
550 bAlreadyWritten[ ESCHER_Prop_fillBackColor ] = true;
551 bAlreadyWritten[ ESCHER_Prop_fillBlip ] = true;
552 bAlreadyWritten[ ESCHER_Prop_fNoFillHitTest ] = true;
553 break;
555 case ESCHER_Prop_lineColor: // 448
556 case ESCHER_Prop_lineWidth: // 459
557 case ESCHER_Prop_lineDashing: // 462
558 case ESCHER_Prop_lineStartArrowhead: // 464
559 case ESCHER_Prop_lineEndArrowhead: // 465
560 case ESCHER_Prop_lineStartArrowWidth: // 466
561 case ESCHER_Prop_lineStartArrowLength: // 467
562 case ESCHER_Prop_lineEndArrowWidth: // 468
563 case ESCHER_Prop_lineEndArrowLength: // 469
564 case ESCHER_Prop_lineJoinStyle: // 470
565 case ESCHER_Prop_lineEndCapStyle: // 471
567 sal_uInt32 nValue;
568 sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
570 if ( rProps.GetOpt( ESCHER_Prop_lineColor, nValue ) )
571 impl_AddColor( pAttrList, XML_color, nValue );
573 if ( rProps.GetOpt( ESCHER_Prop_lineWidth, nValue ) )
574 impl_AddInt( pAttrList, XML_weight, nValue );
576 if ( rProps.GetOpt( ESCHER_Prop_lineDashing, nValue ) )
578 const char *pDashStyle = NULL;
579 switch ( nValue )
581 case ESCHER_LineSolid: pDashStyle = "solid"; break;
582 case ESCHER_LineDashSys: pDashStyle = "shortdash"; break;
583 case ESCHER_LineDotSys: pDashStyle = "shortdot"; break;
584 case ESCHER_LineDashDotSys: pDashStyle = "shortdashdot"; break;
585 case ESCHER_LineDashDotDotSys: pDashStyle = "shortdashdotdot"; break;
586 case ESCHER_LineDotGEL: pDashStyle = "dot"; break;
587 case ESCHER_LineDashGEL: pDashStyle = "dash"; break;
588 case ESCHER_LineLongDashGEL: pDashStyle = "longdash"; break;
589 case ESCHER_LineDashDotGEL: pDashStyle = "dashdot"; break;
590 case ESCHER_LineLongDashDotGEL: pDashStyle = "longdashdot"; break;
591 case ESCHER_LineLongDashDotDotGEL: pDashStyle = "longdashdotdot"; break;
593 if ( pDashStyle )
594 pAttrList->add( XML_dashstyle, pDashStyle );
597 if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowhead, nValue ) )
598 impl_AddArrowHead( pAttrList, XML_startarrow, nValue );
600 if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowhead, nValue ) )
601 impl_AddArrowHead( pAttrList, XML_endarrow, nValue );
603 if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowWidth, nValue ) )
604 impl_AddArrowWidth( pAttrList, XML_startarrowwidth, nValue );
606 if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowLength, nValue ) )
607 impl_AddArrowLength( pAttrList, XML_startarrowlength, nValue );
609 if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowWidth, nValue ) )
610 impl_AddArrowWidth( pAttrList, XML_endarrowwidth, nValue );
612 if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowLength, nValue ) )
613 impl_AddArrowLength( pAttrList, XML_endarrowlength, nValue );
615 if ( rProps.GetOpt( ESCHER_Prop_lineJoinStyle, nValue ) )
617 const char *pJoinStyle = NULL;
618 switch ( nValue )
620 case ESCHER_LineJoinBevel: pJoinStyle = "bevel"; break;
621 case ESCHER_LineJoinMiter: pJoinStyle = "miter"; break;
622 case ESCHER_LineJoinRound: pJoinStyle = "round"; break;
624 if ( pJoinStyle )
625 pAttrList->add( XML_joinstyle, pJoinStyle );
628 if ( rProps.GetOpt( ESCHER_Prop_lineEndCapStyle, nValue ) )
630 const char *pEndCap = NULL;
631 switch ( nValue )
633 case ESCHER_LineEndCapRound: pEndCap = "round"; break;
634 case ESCHER_LineEndCapSquare: pEndCap = "square"; break;
635 case ESCHER_LineEndCapFlat: pEndCap = "flat"; break;
637 if ( pEndCap )
638 pAttrList->add( XML_endcap, pEndCap );
641 m_pSerializer->singleElementNS( XML_v, XML_stroke, XFastAttributeListRef( pAttrList ) );
643 bAlreadyWritten[ ESCHER_Prop_lineColor ] = true;
644 bAlreadyWritten[ ESCHER_Prop_lineWidth ] = true;
645 bAlreadyWritten[ ESCHER_Prop_lineDashing ] = true;
646 bAlreadyWritten[ ESCHER_Prop_lineStartArrowhead ] = true;
647 bAlreadyWritten[ ESCHER_Prop_lineEndArrowhead ] = true;
648 bAlreadyWritten[ ESCHER_Prop_lineStartArrowWidth ] = true;
649 bAlreadyWritten[ ESCHER_Prop_lineStartArrowLength ] = true;
650 bAlreadyWritten[ ESCHER_Prop_lineEndArrowWidth ] = true;
651 bAlreadyWritten[ ESCHER_Prop_lineEndArrowLength ] = true;
652 bAlreadyWritten[ ESCHER_Prop_lineJoinStyle ] = true;
653 bAlreadyWritten[ ESCHER_Prop_lineEndCapStyle ] = true;
654 break;
656 case ESCHER_Prop_fHidden:
657 if ( !it->nPropValue )
658 m_pShapeStyle->append( ";visibility:hidden" );
659 break;
660 case ESCHER_Prop_shadowColor:
661 case ESCHER_Prop_fshadowObscured:
663 sal_uInt32 nValue = 0;
664 bool bShadow = false;
665 bool bObscured = false;
666 if ( rProps.GetOpt( ESCHER_Prop_fshadowObscured, nValue ) )
668 bShadow = (( nValue & 0x20002 ) == 0x20002 );
669 bObscured = (( nValue & 0x10001 ) == 0x10001 );
671 if ( bShadow )
673 sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
674 impl_AddBool( pAttrList, XML_on, bShadow );
675 impl_AddBool( pAttrList, XML_obscured, bObscured );
677 if ( rProps.GetOpt( ESCHER_Prop_shadowColor, nValue ) )
678 impl_AddColor( pAttrList, XML_color, nValue );
680 m_pSerializer->singleElementNS( XML_v, XML_shadow, XFastAttributeListRef( pAttrList ) );
681 bAlreadyWritten[ ESCHER_Prop_fshadowObscured ] = true;
682 bAlreadyWritten[ ESCHER_Prop_shadowColor ] = true;
685 break;
686 default:
687 #if OSL_DEBUG_LEVEL > 0
688 fprintf( stderr, "TODO VMLExport::Commit(), unimplemented id: %d, value: %" SAL_PRIuUINT32 ", data: [%" SAL_PRIuUINT32 ", %p]\n",
689 nId, it->nPropValue, it->nPropSize, it->pBuf );
690 if ( it->nPropSize )
692 const sal_uInt8 *pIt = it->pBuf;
693 fprintf( stderr, " ( " );
694 for ( int nCount = it->nPropSize; nCount; --nCount )
696 fprintf( stderr, "%02x ", *pIt );
697 ++pIt;
699 fprintf( stderr, ")\n" );
701 #endif
702 break;
706 m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_POSTPONE );
709 OString VMLExport::ShapeIdString( sal_uInt32 nId )
711 return OStringBuffer( 20 ).append( "shape_" ).append( sal_Int64( nId ) ).makeStringAndClear();
714 void VMLExport::AddLineDimensions( const Rectangle& rRectangle )
716 // style
717 if ( m_pShapeStyle->getLength() )
718 m_pShapeStyle->append( ";" );
720 m_pShapeStyle->append( "position:absolute" );
722 switch ( m_nShapeFlags & 0xC0 )
724 case 0x40: m_pShapeStyle->append( ";flip:y" ); break;
725 case 0x80: m_pShapeStyle->append( ";flip:x" ); break;
726 case 0xC0: m_pShapeStyle->append( ";flip:xy" ); break;
729 // the actual dimensions
730 OString aLeft, aTop, aRight, aBottom;
732 if ( mnGroupLevel == 1 )
734 const OString aPt( "pt" );
735 aLeft = OString::valueOf( double( rRectangle.Left() ) / 20 ) + aPt;
736 aTop = OString::valueOf( double( rRectangle.Top() ) / 20 ) + aPt;
737 aRight = OString::valueOf( double( rRectangle.Right() ) / 20 ) + aPt;
738 aBottom = OString::valueOf( double( rRectangle.Bottom() ) / 20 ) + aPt;
740 else
742 aLeft = OString::valueOf( rRectangle.Left() );
743 aTop = OString::valueOf( rRectangle.Top() );
744 aRight = OString::valueOf( rRectangle.Right() );
745 aBottom = OString::valueOf( rRectangle.Bottom() );
748 m_pShapeAttrList->add( XML_from,
749 OStringBuffer( 20 ).append( aLeft )
750 .append( "," ).append( aTop )
751 .makeStringAndClear() );
753 m_pShapeAttrList->add( XML_to,
754 OStringBuffer( 20 ).append( aRight )
755 .append( "," ).append( aBottom )
756 .makeStringAndClear() );
759 void VMLExport::AddRectangleDimensions( OStringBuffer& rBuffer, const Rectangle& rRectangle )
761 if ( rBuffer.getLength() )
762 rBuffer.append( ";" );
764 rBuffer.append( "position:absolute;" );
766 if ( mnGroupLevel == 1 )
768 rBuffer.append( "margin-left:" ).append( double( rRectangle.Left() ) / 20 )
769 .append( "pt;margin-top:" ).append( double( rRectangle.Top() ) / 20 )
770 .append( "pt;width:" ).append( double( rRectangle.Right() - rRectangle.Left() ) / 20 )
771 .append( "pt;height:" ).append( double( rRectangle.Bottom() - rRectangle.Top() ) / 20 )
772 .append( "pt" );
774 else
776 rBuffer.append( "left:" ).append( rRectangle.Left() )
777 .append( ";top:" ).append( rRectangle.Top() )
778 .append( ";width:" ).append( rRectangle.Right() - rRectangle.Left() )
779 .append( ";height:" ).append( rRectangle.Bottom() - rRectangle.Top() );
783 void VMLExport::AddShapeAttribute( sal_Int32 nAttribute, const OString& rValue )
785 m_pShapeAttrList->add( nAttribute, rValue );
788 extern const char* pShapeTypes[];
790 sal_Int32 VMLExport::StartShape()
792 if ( m_nShapeType == ESCHER_ShpInst_Nil )
793 return -1;
795 // some of the shapes have their own name ;-)
796 sal_Int32 nShapeElement = -1;
797 bool bReferToShapeType = false;
798 switch ( m_nShapeType )
800 case ESCHER_ShpInst_NotPrimitive: nShapeElement = XML_shape; break;
801 case ESCHER_ShpInst_Rectangle: nShapeElement = XML_rect; break;
802 case ESCHER_ShpInst_RoundRectangle: nShapeElement = XML_roundrect; break;
803 case ESCHER_ShpInst_Ellipse: nShapeElement = XML_oval; break;
804 case ESCHER_ShpInst_Arc: nShapeElement = XML_arc; break;
805 case ESCHER_ShpInst_Line: nShapeElement = XML_line; break;
806 default:
807 if ( m_nShapeType < ESCHER_ShpInst_COUNT )
809 nShapeElement = XML_shape;
811 // a predefined shape?
812 const char* pShapeType = pShapeTypes[ m_nShapeType ];
813 if ( pShapeType )
815 bReferToShapeType = true;
816 if ( !m_pShapeTypeWritten[ m_nShapeType ] )
818 m_pSerializer->write( pShapeType );
819 m_pShapeTypeWritten[ m_nShapeType ] = true;
822 else
824 // rectangle is probably the best fallback...
825 nShapeElement = XML_rect;
828 break;
831 // add style
832 m_pShapeAttrList->add( XML_style, m_pShapeStyle->makeStringAndClear() );
834 if ( nShapeElement >= 0 )
836 if ( bReferToShapeType )
838 m_pShapeAttrList->add( XML_type, OStringBuffer( 20 )
839 .append( "shapetype_" ).append( sal_Int32( m_nShapeType ) )
840 .makeStringAndClear() );
843 // start of the shape
844 m_pSerializer->startElementNS( XML_v, nShapeElement, XFastAttributeListRef( m_pShapeAttrList ) );
847 // now check if we have some text and we have a text exporter registered
848 const SdrTextObj* pTxtObj = PTR_CAST(SdrTextObj, m_pSdrObject);
849 if (pTxtObj && m_pTextExport)
851 const OutlinerParaObject* pParaObj = 0;
852 bool bOwnParaObj = false;
855 #i13885#
856 When the object is actively being edited, that text is not set into
857 the objects normal text object, but lives in a separate object.
859 if (pTxtObj->IsTextEditActive())
861 pParaObj = pTxtObj->GetEditOutlinerParaObject();
862 bOwnParaObj = true;
864 else
866 pParaObj = pTxtObj->GetOutlinerParaObject();
869 if( pParaObj )
871 // this is reached only in case some text is attached to the shape
872 m_pTextExport->WriteOutliner(*pParaObj);
873 if( bOwnParaObj )
874 delete pParaObj;
878 return nShapeElement;
881 void VMLExport::EndShape( sal_Int32 nShapeElement )
883 if ( nShapeElement >= 0 )
885 // end of the shape
886 m_pSerializer->endElementNS( XML_v, nShapeElement );
890 sal_uInt32 VMLExport::AddSdrObject( const SdrObject& rObj )
892 m_pSdrObject = &rObj;
893 return EscherEx::AddSdrObject(rObj);
896 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */