merge the formfield patch from ooo-build
[ooovba.git] / oox / source / export / vmlexport.cxx
blobd22e6010f3c2ac06de342bf8e0a5e1676b51cc69
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile$
10 * $Revision$
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include <oox/export/vmlexport.hxx>
33 #include <tokens.hxx>
35 #include <rtl/strbuf.hxx>
36 #include <rtl/ustring.hxx>
38 #include <tools/stream.hxx>
40 #include <cstdio>
42 using rtl::OString;
43 using rtl::OStringBuffer;
44 using rtl::OUString;
45 using rtl::OUStringBuffer;
47 using namespace sax_fastparser;
48 using namespace oox::vml;
50 /// Implementation of an empty stream that silently succeeds, but does nothing.
51 ///
52 /// In fact, this is a hack. The right solution is to abstract EscherEx to be
53 /// able to work without SvStream; but at the moment it is better to live with
54 /// this I guess.
55 class SvNullStream : public SvStream
57 protected:
58 virtual sal_Size GetData( void* pData, sal_Size nSize ) { memset( pData, 0, nSize ); return nSize; }
59 virtual sal_Size PutData( const void*, sal_Size nSize ) { return nSize; }
60 virtual sal_Size SeekPos( sal_Size nPos ) { return nPos; }
61 virtual void SetSize( sal_Size ) {}
62 virtual void FlushData() {}
64 public:
65 SvNullStream() : SvStream() {}
66 virtual ~SvNullStream() {}
69 VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr pSerializer )
70 : EscherEx( *( new SvNullStream ), 0 ),
71 m_pSerializer( pSerializer ),
72 m_pShapeAttrList( NULL ),
73 m_nShapeType( ESCHER_ShpInst_Nil ),
74 m_pShapeStyle( new OStringBuffer( 200 ) ),
75 m_pShapeTypeWritten( new bool[ ESCHER_ShpInst_COUNT ] )
77 mnGroupLevel = 1;
78 memset( m_pShapeTypeWritten, 0, ESCHER_ShpInst_COUNT * sizeof( bool ) );
81 VMLExport::~VMLExport()
83 delete mpOutStrm, mpOutStrm = NULL;
84 delete m_pShapeStyle, m_pShapeStyle = NULL;
85 delete[] m_pShapeTypeWritten, m_pShapeTypeWritten = NULL;
88 void VMLExport::OpenContainer( UINT16 nEscherContainer, int nRecInstance )
90 EscherEx::OpenContainer( nEscherContainer, nRecInstance );
92 if ( nEscherContainer == ESCHER_SpContainer )
94 // opening a shape container
95 #if OSL_DEBUG_LEVEL > 0
96 if ( m_nShapeType != ESCHER_ShpInst_Nil )
97 fprintf( stderr, "Warning! VMLExport::OpenContainer(): opening shape inside a shape.\n" );
98 #endif
99 m_nShapeType = ESCHER_ShpInst_Nil;
100 m_pShapeAttrList = m_pSerializer->createAttrList();
102 if ( m_pShapeStyle->getLength() )
103 m_pShapeStyle->makeStringAndClear();
105 m_pShapeStyle->ensureCapacity( 200 );
107 // postpone the ouput so that we are able to write even the elements
108 // that we learn inside Commit()
109 m_pSerializer->mark();
113 void VMLExport::CloseContainer()
115 if ( mRecTypes.back() == ESCHER_SpContainer )
117 // write the shape now when we have all the info
118 sal_Int32 nShapeElement = StartShape();
120 m_pSerializer->mergeTopMarks();
122 EndShape( nShapeElement );
124 // cleanup
125 m_nShapeType = ESCHER_ShpInst_Nil;
126 m_pShapeAttrList = NULL;
129 EscherEx::CloseContainer();
132 UINT32 VMLExport::EnterGroup( const String& rShapeName, const Rectangle* pRect )
134 UINT32 nShapeId = GetShapeID();
136 OStringBuffer aStyle( 200 );
137 FastAttributeList *pAttrList = m_pSerializer->createAttrList();
139 pAttrList->add( XML_id, ShapeIdString( nShapeId ) );
141 if ( rShapeName.Len() )
142 pAttrList->add( XML_alt, OUStringToOString( OUString( rShapeName ), RTL_TEXTENCODING_UTF8 ) );
144 // style
145 if ( pRect )
146 AddRectangleDimensions( aStyle, *pRect );
148 if ( aStyle.getLength() )
149 pAttrList->add( XML_style, aStyle.makeStringAndClear() );
151 // coordorigin/coordsize
152 if ( pRect && ( mnGroupLevel == 1 ) )
154 pAttrList->add( XML_coordorigin,
155 OStringBuffer( 20 ).append( sal_Int32( pRect->Left() ) )
156 .append( "," ).append( sal_Int32( pRect->Top() ) )
157 .makeStringAndClear() );
159 pAttrList->add( XML_coordsize,
160 OStringBuffer( 20 ).append( sal_Int32( pRect->Right() ) - sal_Int32( pRect->Left() ) )
161 .append( "," ).append( sal_Int32( pRect->Bottom() ) - sal_Int32( pRect->Top() ) )
162 .makeStringAndClear() );
165 m_pSerializer->startElementNS( XML_v, XML_group, XFastAttributeListRef( pAttrList ) );
167 mnGroupLevel++;
168 return nShapeId;
171 void VMLExport::LeaveGroup()
173 --mnGroupLevel;
174 m_pSerializer->endElementNS( XML_v, XML_group );
177 void VMLExport::AddShape( UINT32 nShapeType, UINT32 nShapeFlags, UINT32 nShapeId )
179 m_nShapeType = nShapeType;
180 m_nShapeFlags = nShapeFlags;
182 m_pShapeAttrList->add( XML_id, ShapeIdString( nShapeId ) );
185 static void impl_AddArrowHead( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
187 if ( !pAttrList )
188 return;
190 const char *pArrowHead = NULL;
191 switch ( nValue )
193 case ESCHER_LineNoEnd: pArrowHead = "none"; break;
194 case ESCHER_LineArrowEnd: pArrowHead = "block"; break;
195 case ESCHER_LineArrowStealthEnd: pArrowHead = "classic"; break;
196 case ESCHER_LineArrowDiamondEnd: pArrowHead = "diamond"; break;
197 case ESCHER_LineArrowOvalEnd: pArrowHead = "oval"; break;
198 case ESCHER_LineArrowOpenEnd: pArrowHead = "open"; break;
201 if ( pArrowHead )
202 pAttrList->add( nElement, pArrowHead );
205 static void impl_AddArrowLength( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
207 if ( !pAttrList )
208 return;
210 const char *pArrowLength = NULL;
211 switch ( nValue )
213 case ESCHER_LineShortArrow: pArrowLength = "short"; break;
214 case ESCHER_LineMediumLenArrow: pArrowLength = "medium"; break;
215 case ESCHER_LineLongArrow: pArrowLength = "long"; break;
218 if ( pArrowLength )
219 pAttrList->add( nElement, pArrowLength );
222 static void impl_AddArrowWidth( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
224 if ( !pAttrList )
225 return;
227 const char *pArrowWidth = NULL;
228 switch ( nValue )
230 case ESCHER_LineNarrowArrow: pArrowWidth = "narrow"; break;
231 case ESCHER_LineMediumWidthArrow: pArrowWidth = "medium"; break;
232 case ESCHER_LineWideArrow: pArrowWidth = "wide"; break;
235 if ( pArrowWidth )
236 pAttrList->add( nElement, pArrowWidth );
239 static void impl_AddBool( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, bool bValue )
241 if ( !pAttrList )
242 return;
244 pAttrList->add( nElement, bValue? "t": "f" );
247 static void impl_AddColor( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nColor )
249 #if OSL_DEBUG_LEVEL > 0
250 if ( nColor & 0xFF000000 )
251 fprintf( stderr, "TODO: this is not a RGB value!\n" );
252 #endif
254 if ( !pAttrList || ( nColor & 0xFF000000 ) )
255 return;
257 nColor = ( ( nColor & 0xFF ) << 16 ) + ( nColor & 0xFF00 ) + ( ( nColor & 0xFF0000 ) >> 16 );
259 const char *pColor = NULL;
260 char pRgbColor[10];
261 switch ( nColor )
263 case 0x000000: pColor = "black"; break;
264 case 0xC0C0C0: pColor = "silver"; break;
265 case 0x808080: pColor = "gray"; break;
266 case 0xFFFFFF: pColor = "white"; break;
267 case 0x800000: pColor = "maroon"; break;
268 case 0xFF0000: pColor = "red"; break;
269 case 0x800080: pColor = "purple"; break;
270 case 0xFF00FF: pColor = "fuchsia"; break;
271 case 0x008000: pColor = "green"; break;
272 case 0x00FF00: pColor = "lime"; break;
273 case 0x808000: pColor = "olive"; break;
274 case 0xFFFF00: pColor = "yellow"; break;
275 case 0x000080: pColor = "navy"; break;
276 case 0x0000FF: pColor = "blue"; break;
277 case 0x008080: pColor = "teal"; break;
278 case 0x00FFFF: pColor = "aqua"; break;
279 default:
281 snprintf( pRgbColor, sizeof( pRgbColor ), "#%06x", static_cast< unsigned int >( nColor ) ); // not too handy to use OString::valueOf() here :-(
282 pColor = pRgbColor;
284 break;
287 pAttrList->add( nElement, pColor );
290 static void impl_AddInt( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
292 if ( !pAttrList )
293 return;
295 pAttrList->add( nElement, OString::valueOf( static_cast< sal_Int32 >( nValue ) ).getStr() );
298 inline sal_uInt16 impl_GetUInt16( const sal_uInt8* &pVal )
300 sal_uInt16 nRet = *pVal++;
301 nRet += ( *pVal++ ) << 8;
302 return nRet;
305 inline sal_Int32 impl_GetPointComponent( const sal_uInt8* &pVal, sal_uInt16 nPointSize )
307 sal_Int32 nRet = 0;
308 if ( ( nPointSize == 0xfff0 ) || ( nPointSize == 4 ) )
310 sal_uInt16 nUnsigned = *pVal++;
311 nUnsigned += ( *pVal++ ) << 8;
313 nRet = sal_Int16( nUnsigned );
315 else if ( nPointSize == 8 )
317 sal_uInt32 nUnsigned = *pVal++;
318 nUnsigned += ( *pVal++ ) << 8;
319 nUnsigned += ( *pVal++ ) << 16;
320 nUnsigned += ( *pVal++ ) << 24;
322 nRet = nUnsigned;
325 return nRet;
328 void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect )
330 if ( m_nShapeType == ESCHER_ShpInst_Nil )
331 return;
333 // postpone the output of the embedded elements so that they are written
334 // inside the shapes
335 m_pSerializer->mark();
337 // dimensions
338 if ( m_nShapeType == ESCHER_ShpInst_Line )
339 AddLineDimensions( rRect );
340 else
341 AddRectangleDimensions( *m_pShapeStyle, rRect );
343 // properties
344 bool bAlreadyWritten[ 0xFFF ];
345 memset( bAlreadyWritten, 0, sizeof( bAlreadyWritten ) );
346 const EscherProperties &rOpts = rProps.GetOpts();
347 for ( EscherProperties::const_iterator it = rOpts.begin(); it != rOpts.end(); ++it )
349 sal_uInt16 nId = ( it->nPropId & 0x0FFF );
351 if ( bAlreadyWritten[ nId ] )
352 continue;
354 switch ( nId )
356 case ESCHER_Prop_WrapText: // 133
358 const char *pWrapType = NULL;
359 switch ( it->nPropValue )
361 case ESCHER_WrapSquare:
362 case ESCHER_WrapByPoints: pWrapType = "square"; break; // these two are equivalent according to the docu
363 case ESCHER_WrapNone: pWrapType = "none"; break;
364 case ESCHER_WrapTopBottom: pWrapType = "topAndBottom"; break;
365 case ESCHER_WrapThrough: pWrapType = "through"; break;
367 if ( pWrapType )
368 m_pSerializer->singleElementNS( XML_w10, XML_wrap,
369 FSNS( XML_w10, XML_type ), pWrapType,
370 FSEND );
372 bAlreadyWritten[ ESCHER_Prop_WrapText ] = true;
373 break;
375 // coordorigin
376 case ESCHER_Prop_geoLeft: // 320
377 case ESCHER_Prop_geoTop: // 321
379 sal_uInt32 nLeft = 0, nTop = 0;
381 if ( nId == ESCHER_Prop_geoLeft )
383 nLeft = it->nPropValue;
384 rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
386 else
388 nTop = it->nPropValue;
389 rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
392 m_pShapeAttrList->add( XML_coordorigin,
393 OStringBuffer( 20 ).append( sal_Int32( nLeft ) )
394 .append( "," ).append( sal_Int32( nTop ) )
395 .makeStringAndClear() );
397 bAlreadyWritten[ ESCHER_Prop_geoLeft ] = true;
398 bAlreadyWritten[ ESCHER_Prop_geoTop ] = true;
399 break;
401 // coordsize
402 case ESCHER_Prop_geoRight: // 322
403 case ESCHER_Prop_geoBottom: // 323
405 sal_uInt32 nLeft = 0, nRight = 0, nTop = 0, nBottom = 0;
406 rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
407 rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
409 if ( nId == ESCHER_Prop_geoRight )
411 nRight = it->nPropValue;
412 rProps.GetOpt( ESCHER_Prop_geoBottom, nBottom );
414 else
416 nBottom = it->nPropValue;
417 rProps.GetOpt( ESCHER_Prop_geoRight, nRight );
420 m_pShapeAttrList->add( XML_coordsize,
421 OStringBuffer( 20 ).append( sal_Int32( nRight ) - sal_Int32( nLeft ) )
422 .append( "," ).append( sal_Int32( nBottom ) - sal_Int32( nTop ) )
423 .makeStringAndClear() );
425 bAlreadyWritten[ ESCHER_Prop_geoRight ] = true;
426 bAlreadyWritten[ ESCHER_Prop_geoBottom ] = true;
427 break;
429 case ESCHER_Prop_pVertices: // 325
430 case ESCHER_Prop_pSegmentInfo: // 326
432 EscherPropSortStruct aVertices;
433 EscherPropSortStruct aSegments;
435 if ( rProps.GetOpt( ESCHER_Prop_pVertices, aVertices ) &&
436 rProps.GetOpt( ESCHER_Prop_pSegmentInfo, aSegments ) )
438 const sal_uInt8 *pVerticesIt = aVertices.pBuf + 6;
439 const sal_uInt8 *pSegmentIt = aSegments.pBuf;
440 OStringBuffer aPath( 512 );
442 sal_uInt16 nPointSize = aVertices.pBuf[4] + ( aVertices.pBuf[5] << 8 );
444 // number of segments
445 sal_uInt16 nSegments = impl_GetUInt16( pSegmentIt );
446 pSegmentIt += 4;
448 for ( ; nSegments; --nSegments )
450 sal_uInt16 nSeg = impl_GetUInt16( pSegmentIt );
451 switch ( nSeg )
453 case 0x4000: // moveto
455 sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
456 sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
457 aPath.append( "m" ).append( nX ).append( "," ).append( nY );
459 break;
460 case 0xb300:
461 case 0xac00:
462 break;
463 case 0x0001: // lineto
465 sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
466 sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
467 aPath.append( "l" ).append( nX ).append( "," ).append( nY );
469 break;
470 case 0x2001: // curveto
472 sal_Int32 nX1 = impl_GetPointComponent( pVerticesIt, nPointSize );
473 sal_Int32 nY1 = impl_GetPointComponent( pVerticesIt, nPointSize );
474 sal_Int32 nX2 = impl_GetPointComponent( pVerticesIt, nPointSize );
475 sal_Int32 nY2 = impl_GetPointComponent( pVerticesIt, nPointSize );
476 sal_Int32 nX3 = impl_GetPointComponent( pVerticesIt, nPointSize );
477 sal_Int32 nY3 = impl_GetPointComponent( pVerticesIt, nPointSize );
478 aPath.append( "c" ).append( nX1 ).append( "," ).append( nY1 ).append( "," )
479 .append( nX2 ).append( "," ).append( nY2 ).append( "," )
480 .append( nX3 ).append( "," ).append( nY3 );
482 break;
483 case 0xaa00: // nofill
484 aPath.append( "nf" );
485 break;
486 case 0xab00: // nostroke
487 aPath.append( "ns" );
488 break;
489 case 0x6001: // close
490 aPath.append( "x" );
491 break;
492 case 0x8000: // end
493 aPath.append( "e" );
494 break;
495 default:
496 #if OSL_DEBUG_LEVEL > 0
497 fprintf( stderr, "TODO: unhandled segment '%x' in the path\n", nSeg );
498 #endif
499 break;
503 if ( aPath.getLength() )
504 m_pShapeAttrList->add( XML_path, aPath.getStr() );
506 #if OSL_DEBUG_LEVEL > 0
507 else
508 fprintf( stderr, "TODO: unhandled shape path, missing either pVertices or pSegmentInfo.\n" );
509 #endif
511 bAlreadyWritten[ ESCHER_Prop_pVertices ] = true;
512 bAlreadyWritten[ ESCHER_Prop_pSegmentInfo ] = true;
513 break;
515 case ESCHER_Prop_fillType: // 384
516 case ESCHER_Prop_fillColor: // 385
517 case ESCHER_Prop_fillBackColor: // 387
518 case ESCHER_Prop_fNoFillHitTest: // 447
520 sal_uInt32 nValue;
521 sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
523 if ( rProps.GetOpt( ESCHER_Prop_fillType, nValue ) )
525 const char *pFillType = NULL;
526 switch ( nValue )
528 case ESCHER_FillSolid: pFillType = "solid"; break;
529 // TODO case ESCHER_FillPattern: pFillType = ""; break;
530 // TODO case ESCHER_FillTexture: pFillType = ""; break;
531 // TODO case ESCHER_FillPicture: pFillType = ""; break;
532 // TODO case ESCHER_FillShade: pFillType = ""; break;
533 // TODO case ESCHER_FillShadeCenter: pFillType = ""; break;
534 // TODO case ESCHER_FillShadeShape: pFillType = ""; break;
535 // TODO case ESCHER_FillShadeScale: pFillType = ""; break;
536 // TODO case ESCHER_FillShadeTitle: pFillType = ""; break;
537 // TODO case ESCHER_FillBackground: pFillType = ""; break;
538 default:
539 #if OSL_DEBUG_LEVEL > 0
540 fprintf( stderr, "TODO: unhandled fill type\n" );
541 #endif
542 break;
544 if ( pFillType )
545 pAttrList->add( XML_type, pFillType );
548 if ( rProps.GetOpt( ESCHER_Prop_fillColor, nValue ) )
549 impl_AddColor( pAttrList, XML_color, nValue );
551 if ( rProps.GetOpt( ESCHER_Prop_fillBackColor, nValue ) )
552 impl_AddColor( pAttrList, XML_color2, nValue );
554 if ( rProps.GetOpt( ESCHER_Prop_fNoFillHitTest, nValue ) )
555 impl_AddBool( pAttrList, XML_detectmouseclick, nValue );
557 m_pSerializer->singleElementNS( XML_v, XML_fill, XFastAttributeListRef( pAttrList ) );
559 bAlreadyWritten[ ESCHER_Prop_fillType ] = true;
560 bAlreadyWritten[ ESCHER_Prop_fillColor ] = true;
561 bAlreadyWritten[ ESCHER_Prop_fillBackColor ] = true;
562 bAlreadyWritten[ ESCHER_Prop_fNoFillHitTest ] = true;
563 break;
565 case ESCHER_Prop_lineColor: // 448
566 case ESCHER_Prop_lineWidth: // 459
567 case ESCHER_Prop_lineDashing: // 462
568 case ESCHER_Prop_lineStartArrowhead: // 464
569 case ESCHER_Prop_lineEndArrowhead: // 465
570 case ESCHER_Prop_lineStartArrowWidth: // 466
571 case ESCHER_Prop_lineStartArrowLength: // 467
572 case ESCHER_Prop_lineEndArrowWidth: // 468
573 case ESCHER_Prop_lineEndArrowLength: // 469
574 case ESCHER_Prop_lineJoinStyle: // 470
575 case ESCHER_Prop_lineEndCapStyle: // 471
577 sal_uInt32 nValue;
578 sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
580 if ( rProps.GetOpt( ESCHER_Prop_lineColor, nValue ) )
581 impl_AddColor( pAttrList, XML_color, nValue );
583 if ( rProps.GetOpt( ESCHER_Prop_lineWidth, nValue ) )
584 impl_AddInt( pAttrList, XML_weight, nValue );
586 if ( rProps.GetOpt( ESCHER_Prop_lineDashing, nValue ) )
588 const char *pDashStyle = NULL;
589 switch ( nValue )
591 case ESCHER_LineSolid: pDashStyle = "solid"; break;
592 case ESCHER_LineDashSys: pDashStyle = "shortdash"; break;
593 case ESCHER_LineDotSys: pDashStyle = "shortdot"; break;
594 case ESCHER_LineDashDotSys: pDashStyle = "shortdashdot"; break;
595 case ESCHER_LineDashDotDotSys: pDashStyle = "shortdashdotdot"; break;
596 case ESCHER_LineDotGEL: pDashStyle = "dot"; break;
597 case ESCHER_LineDashGEL: pDashStyle = "dash"; break;
598 case ESCHER_LineLongDashGEL: pDashStyle = "longdash"; break;
599 case ESCHER_LineDashDotGEL: pDashStyle = "dashdot"; break;
600 case ESCHER_LineLongDashDotGEL: pDashStyle = "longdashdot"; break;
601 case ESCHER_LineLongDashDotDotGEL: pDashStyle = "longdashdotdot"; break;
603 if ( pDashStyle )
604 pAttrList->add( XML_dashstyle, pDashStyle );
607 if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowhead, nValue ) )
608 impl_AddArrowHead( pAttrList, XML_startarrow, nValue );
610 if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowhead, nValue ) )
611 impl_AddArrowHead( pAttrList, XML_endarrow, nValue );
613 if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowWidth, nValue ) )
614 impl_AddArrowWidth( pAttrList, XML_startarrowwidth, nValue );
616 if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowLength, nValue ) )
617 impl_AddArrowLength( pAttrList, XML_startarrowlength, nValue );
619 if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowWidth, nValue ) )
620 impl_AddArrowWidth( pAttrList, XML_endarrowwidth, nValue );
622 if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowLength, nValue ) )
623 impl_AddArrowLength( pAttrList, XML_endarrowlength, nValue );
625 if ( rProps.GetOpt( ESCHER_Prop_lineJoinStyle, nValue ) )
627 const char *pJoinStyle = NULL;
628 switch ( nValue )
630 case ESCHER_LineJoinBevel: pJoinStyle = "bevel"; break;
631 case ESCHER_LineJoinMiter: pJoinStyle = "miter"; break;
632 case ESCHER_LineJoinRound: pJoinStyle = "round"; break;
634 if ( pJoinStyle )
635 pAttrList->add( XML_joinstyle, pJoinStyle );
638 if ( rProps.GetOpt( ESCHER_Prop_lineEndCapStyle, nValue ) )
640 const char *pEndCap = NULL;
641 switch ( nValue )
643 case ESCHER_LineEndCapRound: pEndCap = "round"; break;
644 case ESCHER_LineEndCapSquare: pEndCap = "square"; break;
645 case ESCHER_LineEndCapFlat: pEndCap = "flat"; break;
647 if ( pEndCap )
648 pAttrList->add( XML_endcap, pEndCap );
651 m_pSerializer->singleElementNS( XML_v, XML_stroke, XFastAttributeListRef( pAttrList ) );
653 bAlreadyWritten[ ESCHER_Prop_lineColor ] = true;
654 bAlreadyWritten[ ESCHER_Prop_lineWidth ] = true;
655 bAlreadyWritten[ ESCHER_Prop_lineDashing ] = true;
656 bAlreadyWritten[ ESCHER_Prop_lineStartArrowhead ] = true;
657 bAlreadyWritten[ ESCHER_Prop_lineEndArrowhead ] = true;
658 bAlreadyWritten[ ESCHER_Prop_lineStartArrowWidth ] = true;
659 bAlreadyWritten[ ESCHER_Prop_lineStartArrowLength ] = true;
660 bAlreadyWritten[ ESCHER_Prop_lineEndArrowWidth ] = true;
661 bAlreadyWritten[ ESCHER_Prop_lineEndArrowLength ] = true;
662 bAlreadyWritten[ ESCHER_Prop_lineJoinStyle ] = true;
663 bAlreadyWritten[ ESCHER_Prop_lineEndCapStyle ] = true;
664 break;
666 case ESCHER_Prop_fHidden:
667 m_pShapeStyle->append( ";visibility:hidden" );
668 break;
669 default:
670 #if OSL_DEBUG_LEVEL > 0
671 fprintf( stderr, "TODO VMLExport::Commit(), unimplemented id: %d, value: %d, data: [%d, %p]\n",
672 it->nPropId, it->nPropValue, it->nPropSize, it->pBuf );
673 if ( it->nPropSize )
675 const sal_uInt8 *pIt = it->pBuf;
676 fprintf( stderr, " ( " );
677 for ( int nCount = it->nPropSize; nCount; --nCount )
679 fprintf( stderr, "%02x ", *pIt );
680 ++pIt;
682 fprintf( stderr, ")\n" );
684 #endif
685 break;
689 m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_POSTPONE );
692 OString VMLExport::ShapeIdString( sal_uInt32 nId )
694 return OStringBuffer( 20 ).append( "shape_" ).append( sal_Int64( nId ) ).makeStringAndClear();
697 void VMLExport::AddLineDimensions( const Rectangle& rRectangle )
699 // style
700 if ( m_pShapeStyle->getLength() )
701 m_pShapeStyle->append( ";" );
703 m_pShapeStyle->append( "position:absolute" );
705 switch ( m_nShapeFlags & 0xC0 )
707 case 0x40: m_pShapeStyle->append( ";flip:y" ); break;
708 case 0x80: m_pShapeStyle->append( ";flip:x" ); break;
709 case 0xC0: m_pShapeStyle->append( ";flip:xy" ); break;
712 // the actual dimensions
713 OString aLeft, aTop, aRight, aBottom;
715 if ( mnGroupLevel == 1 )
717 const OString aPt( "pt" );
718 aLeft = OString::valueOf( double( rRectangle.Left() ) / 20 ) + aPt;
719 aTop = OString::valueOf( double( rRectangle.Top() ) / 20 ) + aPt;
720 aRight = OString::valueOf( double( rRectangle.Right() ) / 20 ) + aPt;
721 aBottom = OString::valueOf( double( rRectangle.Bottom() ) / 20 ) + aPt;
723 else
725 aLeft = OString::valueOf( rRectangle.Left() );
726 aTop = OString::valueOf( rRectangle.Top() );
727 aRight = OString::valueOf( rRectangle.Right() );
728 aBottom = OString::valueOf( rRectangle.Bottom() );
731 m_pShapeAttrList->add( XML_from,
732 OStringBuffer( 20 ).append( aLeft )
733 .append( "," ).append( aTop )
734 .makeStringAndClear() );
736 m_pShapeAttrList->add( XML_to,
737 OStringBuffer( 20 ).append( aRight )
738 .append( "," ).append( aBottom )
739 .makeStringAndClear() );
742 void VMLExport::AddRectangleDimensions( rtl::OStringBuffer& rBuffer, const Rectangle& rRectangle )
744 if ( rBuffer.getLength() )
745 rBuffer.append( ";" );
747 rBuffer.append( "position:absolute;" );
749 if ( mnGroupLevel == 1 )
751 rBuffer.append( "margin-left:" ).append( double( rRectangle.Left() ) / 20 )
752 .append( "pt;margin-top:" ).append( double( rRectangle.Top() ) / 20 )
753 .append( "pt;width:" ).append( double( rRectangle.Right() - rRectangle.Left() ) / 20 )
754 .append( "pt;height:" ).append( double( rRectangle.Bottom() - rRectangle.Top() ) / 20 )
755 .append( "pt" );
757 else
759 rBuffer.append( "left:" ).append( rRectangle.Left() )
760 .append( ";top:" ).append( rRectangle.Top() )
761 .append( ";width:" ).append( rRectangle.Right() - rRectangle.Left() )
762 .append( ";height:" ).append( rRectangle.Bottom() - rRectangle.Top() );
766 void VMLExport::AddShapeAttribute( sal_Int32 nAttribute, const rtl::OString& rValue )
768 m_pShapeAttrList->add( nAttribute, rValue );
771 extern const char* pShapeTypes[];
773 sal_Int32 VMLExport::StartShape()
775 if ( m_nShapeType == ESCHER_ShpInst_Nil )
776 return -1;
778 // some of the shapes have their own name ;-)
779 sal_Int32 nShapeElement = -1;
780 bool bReferToShapeType = false;
781 switch ( m_nShapeType )
783 case ESCHER_ShpInst_NotPrimitive: nShapeElement = XML_shape; break;
784 case ESCHER_ShpInst_Rectangle: nShapeElement = XML_rect; break;
785 case ESCHER_ShpInst_RoundRectangle: nShapeElement = XML_roundrect; break;
786 case ESCHER_ShpInst_Ellipse: nShapeElement = XML_oval; break;
787 case ESCHER_ShpInst_Arc: nShapeElement = XML_arc; break;
788 case ESCHER_ShpInst_Line: nShapeElement = XML_line; break;
789 default:
790 if ( m_nShapeType < ESCHER_ShpInst_COUNT )
792 nShapeElement = XML_shape;
794 // a predefined shape?
795 const char* pShapeType = pShapeTypes[ m_nShapeType ];
796 if ( pShapeType )
798 bReferToShapeType = true;
799 if ( !m_pShapeTypeWritten[ m_nShapeType ] )
801 m_pSerializer->write( pShapeType );
802 m_pShapeTypeWritten[ m_nShapeType ] = true;
805 else
807 // rectangle is probably the best fallback...
808 nShapeElement = XML_rect;
811 break;
814 // add style
815 m_pShapeAttrList->add( XML_style, m_pShapeStyle->makeStringAndClear() );
817 if ( nShapeElement >= 0 )
819 if ( bReferToShapeType )
821 m_pShapeAttrList->add( XML_type, OStringBuffer( 20 )
822 .append( "shapetype_" ).append( sal_Int32( m_nShapeType ) )
823 .makeStringAndClear() );
826 // start of the shape
827 m_pSerializer->startElementNS( XML_v, nShapeElement, XFastAttributeListRef( m_pShapeAttrList ) );
830 return nShapeElement;
833 void VMLExport::EndShape( sal_Int32 nShapeElement )
835 if ( nShapeElement >= 0 )
837 // end of the shape
838 m_pSerializer->endElementNS( XML_v, nShapeElement );