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
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>
35 #include <rtl/strbuf.hxx>
36 #include <rtl/ustring.hxx>
38 #include <tools/stream.hxx>
43 using rtl::OStringBuffer
;
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.
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
55 class SvNullStream
: public SvStream
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() {}
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
] )
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" );
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
);
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
) );
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
) );
171 void VMLExport::LeaveGroup()
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
)
190 const char *pArrowHead
= NULL
;
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;
202 pAttrList
->add( nElement
, pArrowHead
);
205 static void impl_AddArrowLength( sax_fastparser::FastAttributeList
*pAttrList
, sal_Int32 nElement
, sal_uInt32 nValue
)
210 const char *pArrowLength
= NULL
;
213 case ESCHER_LineShortArrow
: pArrowLength
= "short"; break;
214 case ESCHER_LineMediumLenArrow
: pArrowLength
= "medium"; break;
215 case ESCHER_LineLongArrow
: pArrowLength
= "long"; break;
219 pAttrList
->add( nElement
, pArrowLength
);
222 static void impl_AddArrowWidth( sax_fastparser::FastAttributeList
*pAttrList
, sal_Int32 nElement
, sal_uInt32 nValue
)
227 const char *pArrowWidth
= NULL
;
230 case ESCHER_LineNarrowArrow
: pArrowWidth
= "narrow"; break;
231 case ESCHER_LineMediumWidthArrow
: pArrowWidth
= "medium"; break;
232 case ESCHER_LineWideArrow
: pArrowWidth
= "wide"; break;
236 pAttrList
->add( nElement
, pArrowWidth
);
239 static void impl_AddBool( sax_fastparser::FastAttributeList
*pAttrList
, sal_Int32 nElement
, bool bValue
)
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" );
254 if ( !pAttrList
|| ( nColor
& 0xFF000000 ) )
257 nColor
= ( ( nColor
& 0xFF ) << 16 ) + ( nColor
& 0xFF00 ) + ( ( nColor
& 0xFF0000 ) >> 16 );
259 const char *pColor
= NULL
;
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;
281 snprintf( pRgbColor
, sizeof( pRgbColor
), "#%06x", static_cast< unsigned int >( nColor
) ); // not too handy to use OString::valueOf() here :-(
287 pAttrList
->add( nElement
, pColor
);
290 static void impl_AddInt( sax_fastparser::FastAttributeList
*pAttrList
, sal_Int32 nElement
, sal_uInt32 nValue
)
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;
305 inline sal_Int32
impl_GetPointComponent( const sal_uInt8
* &pVal
, sal_uInt16 nPointSize
)
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;
328 void VMLExport::Commit( EscherPropertyContainer
& rProps
, const Rectangle
& rRect
)
330 if ( m_nShapeType
== ESCHER_ShpInst_Nil
)
333 // postpone the output of the embedded elements so that they are written
335 m_pSerializer
->mark();
338 if ( m_nShapeType
== ESCHER_ShpInst_Line
)
339 AddLineDimensions( rRect
);
341 AddRectangleDimensions( *m_pShapeStyle
, rRect
);
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
] )
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;
368 m_pSerializer
->singleElementNS( XML_w10
, XML_wrap
,
369 FSNS( XML_w10
, XML_type
), pWrapType
,
372 bAlreadyWritten
[ ESCHER_Prop_WrapText
] = true;
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
);
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;
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
);
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;
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
);
448 for ( ; nSegments
; --nSegments
)
450 sal_uInt16 nSeg
= impl_GetUInt16( pSegmentIt
);
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
);
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
);
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
);
483 case 0xaa00: // nofill
484 aPath
.append( "nf" );
486 case 0xab00: // nostroke
487 aPath
.append( "ns" );
489 case 0x6001: // close
496 #if OSL_DEBUG_LEVEL > 0
497 fprintf( stderr
, "TODO: unhandled segment '%x' in the path\n", nSeg
);
503 if ( aPath
.getLength() )
504 m_pShapeAttrList
->add( XML_path
, aPath
.getStr() );
506 #if OSL_DEBUG_LEVEL > 0
508 fprintf( stderr
, "TODO: unhandled shape path, missing either pVertices or pSegmentInfo.\n" );
511 bAlreadyWritten
[ ESCHER_Prop_pVertices
] = true;
512 bAlreadyWritten
[ ESCHER_Prop_pSegmentInfo
] = true;
515 case ESCHER_Prop_fillType
: // 384
516 case ESCHER_Prop_fillColor
: // 385
517 case ESCHER_Prop_fillBackColor
: // 387
518 case ESCHER_Prop_fNoFillHitTest
: // 447
521 sax_fastparser::FastAttributeList
*pAttrList
= m_pSerializer
->createAttrList();
523 if ( rProps
.GetOpt( ESCHER_Prop_fillType
, nValue
) )
525 const char *pFillType
= NULL
;
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;
539 #if OSL_DEBUG_LEVEL > 0
540 fprintf( stderr
, "TODO: unhandled fill type\n" );
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;
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
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
;
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;
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
;
630 case ESCHER_LineJoinBevel
: pJoinStyle
= "bevel"; break;
631 case ESCHER_LineJoinMiter
: pJoinStyle
= "miter"; break;
632 case ESCHER_LineJoinRound
: pJoinStyle
= "round"; break;
635 pAttrList
->add( XML_joinstyle
, pJoinStyle
);
638 if ( rProps
.GetOpt( ESCHER_Prop_lineEndCapStyle
, nValue
) )
640 const char *pEndCap
= NULL
;
643 case ESCHER_LineEndCapRound
: pEndCap
= "round"; break;
644 case ESCHER_LineEndCapSquare
: pEndCap
= "square"; break;
645 case ESCHER_LineEndCapFlat
: pEndCap
= "flat"; break;
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;
666 case ESCHER_Prop_fHidden
:
667 m_pShapeStyle
->append( ";visibility:hidden" );
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
);
675 const sal_uInt8
*pIt
= it
->pBuf
;
676 fprintf( stderr
, " ( " );
677 for ( int nCount
= it
->nPropSize
; nCount
; --nCount
)
679 fprintf( stderr
, "%02x ", *pIt
);
682 fprintf( stderr
, ")\n" );
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
)
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
;
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 )
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
)
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;
790 if ( m_nShapeType
< ESCHER_ShpInst_COUNT
)
792 nShapeElement
= XML_shape
;
794 // a predefined shape?
795 const char* pShapeType
= pShapeTypes
[ m_nShapeType
];
798 bReferToShapeType
= true;
799 if ( !m_pShapeTypeWritten
[ m_nShapeType
] )
801 m_pSerializer
->write( pShapeType
);
802 m_pShapeTypeWritten
[ m_nShapeType
] = true;
807 // rectangle is probably the best fallback...
808 nShapeElement
= XML_rect
;
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 )
838 m_pSerializer
->endElementNS( XML_v
, nShapeElement
);