1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
)
42 , m_pShapeAttrList( NULL
)
43 , m_nShapeType( ESCHER_ShpInst_Nil
)
45 , m_pShapeStyle( new OStringBuffer( 200 ) )
46 , m_pShapeTypeWritten( new bool[ ESCHER_ShpInst_COUNT
] )
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" );
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
);
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
) );
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
) );
142 void VMLExport::LeaveGroup()
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
)
161 const char *pArrowHead
= NULL
;
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;
173 pAttrList
->add( nElement
, pArrowHead
);
176 static void impl_AddArrowLength( sax_fastparser::FastAttributeList
*pAttrList
, sal_Int32 nElement
, sal_uInt32 nValue
)
181 const char *pArrowLength
= NULL
;
184 case ESCHER_LineShortArrow
: pArrowLength
= "short"; break;
185 case ESCHER_LineMediumLenArrow
: pArrowLength
= "medium"; break;
186 case ESCHER_LineLongArrow
: pArrowLength
= "long"; break;
190 pAttrList
->add( nElement
, pArrowLength
);
193 static void impl_AddArrowWidth( sax_fastparser::FastAttributeList
*pAttrList
, sal_Int32 nElement
, sal_uInt32 nValue
)
198 const char *pArrowWidth
= NULL
;
201 case ESCHER_LineNarrowArrow
: pArrowWidth
= "narrow"; break;
202 case ESCHER_LineMediumWidthArrow
: pArrowWidth
= "medium"; break;
203 case ESCHER_LineWideArrow
: pArrowWidth
= "wide"; break;
207 pAttrList
->add( nElement
, pArrowWidth
);
210 static void impl_AddBool( sax_fastparser::FastAttributeList
*pAttrList
, sal_Int32 nElement
, bool bValue
)
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" );
225 if ( !pAttrList
|| ( nColor
& 0xFF000000 ) )
228 nColor
= ( ( nColor
& 0xFF ) << 16 ) + ( nColor
& 0xFF00 ) + ( ( nColor
& 0xFF0000 ) >> 16 );
230 const char *pColor
= NULL
;
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;
252 snprintf( pRgbColor
, sizeof( pRgbColor
), "#%06x", static_cast< unsigned int >( nColor
) ); // not too handy to use OString::valueOf() here :-(
258 pAttrList
->add( nElement
, pColor
);
261 static void impl_AddInt( sax_fastparser::FastAttributeList
*pAttrList
, sal_Int32 nElement
, sal_uInt32 nValue
)
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;
276 inline sal_Int32
impl_GetPointComponent( const sal_uInt8
* &pVal
, sal_uInt16 nPointSize
)
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;
299 void VMLExport::Commit( EscherPropertyContainer
& rProps
, const Rectangle
& rRect
)
301 if ( m_nShapeType
== ESCHER_ShpInst_Nil
)
304 // postpone the output of the embedded elements so that they are written
306 m_pSerializer
->mark();
309 if ( m_nShapeType
== ESCHER_ShpInst_Line
)
310 AddLineDimensions( rRect
);
312 AddRectangleDimensions( *m_pShapeStyle
, rRect
);
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
] )
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;
339 m_pSerializer
->singleElementNS( XML_v
, XML_wrap
,
340 FSNS( XML_v
, XML_type
), pWrapType
,
343 bAlreadyWritten
[ ESCHER_Prop_WrapText
] = true;
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
);
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;
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
);
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;
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
);
419 for ( ; nSegments
; --nSegments
)
421 sal_uInt16 nSeg
= impl_GetUInt16( pSegmentIt
);
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
);
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
);
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
);
454 case 0xaa00: // nofill
455 aPath
.append( "nf" );
457 case 0xab00: // nostroke
458 aPath
.append( "ns" );
460 case 0x6001: // close
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
);
478 if ( aPath
.getLength() )
479 m_pShapeAttrList
->add( XML_path
, aPath
.getStr() );
481 #if OSL_DEBUG_LEVEL > 0
483 fprintf( stderr
, "TODO: unhandled shape path, missing either pVertices or pSegmentInfo.\n" );
486 bAlreadyWritten
[ ESCHER_Prop_pVertices
] = true;
487 bAlreadyWritten
[ ESCHER_Prop_pSegmentInfo
] = true;
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
497 sax_fastparser::FastAttributeList
*pAttrList
= m_pSerializer
->createAttrList();
499 if ( rProps
.GetOpt( ESCHER_Prop_fillType
, nValue
) )
501 const char *pFillType
= NULL
;
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;
515 #if OSL_DEBUG_LEVEL > 0
516 fprintf( stderr
, "TODO: unhandled fill type\n" );
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
);
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;
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
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
;
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;
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
;
620 case ESCHER_LineJoinBevel
: pJoinStyle
= "bevel"; break;
621 case ESCHER_LineJoinMiter
: pJoinStyle
= "miter"; break;
622 case ESCHER_LineJoinRound
: pJoinStyle
= "round"; break;
625 pAttrList
->add( XML_joinstyle
, pJoinStyle
);
628 if ( rProps
.GetOpt( ESCHER_Prop_lineEndCapStyle
, nValue
) )
630 const char *pEndCap
= NULL
;
633 case ESCHER_LineEndCapRound
: pEndCap
= "round"; break;
634 case ESCHER_LineEndCapSquare
: pEndCap
= "square"; break;
635 case ESCHER_LineEndCapFlat
: pEndCap
= "flat"; break;
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;
656 case ESCHER_Prop_fHidden
:
657 if ( !it
->nPropValue
)
658 m_pShapeStyle
->append( ";visibility:hidden" );
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 );
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;
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
);
692 const sal_uInt8
*pIt
= it
->pBuf
;
693 fprintf( stderr
, " ( " );
694 for ( int nCount
= it
->nPropSize
; nCount
; --nCount
)
696 fprintf( stderr
, "%02x ", *pIt
);
699 fprintf( stderr
, ")\n" );
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
)
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
;
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 )
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
)
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;
807 if ( m_nShapeType
< ESCHER_ShpInst_COUNT
)
809 nShapeElement
= XML_shape
;
811 // a predefined shape?
812 const char* pShapeType
= pShapeTypes
[ m_nShapeType
];
815 bReferToShapeType
= true;
816 if ( !m_pShapeTypeWritten
[ m_nShapeType
] )
818 m_pSerializer
->write( pShapeType
);
819 m_pShapeTypeWritten
[ m_nShapeType
] = true;
824 // rectangle is probably the best fallback...
825 nShapeElement
= XML_rect
;
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;
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();
866 pParaObj
= pTxtObj
->GetOutlinerParaObject();
871 // this is reached only in case some text is attached to the shape
872 m_pTextExport
->WriteOutliner(*pParaObj
);
878 return nShapeElement
;
881 void VMLExport::EndShape( sal_Int32 nShapeElement
)
883 if ( nShapeElement
>= 0 )
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: */