Branch libreoffice-5-0-4
[LibreOffice.git] / oox / source / export / vmlexport.cxx
blobd90ff82e5e9303440d5ff6c5743174f13b1e923d
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 <config_folders.h>
21 #include "rtl/bootstrap.hxx"
22 #include <oox/export/vmlexport.hxx>
24 #include <oox/token/tokens.hxx>
26 #include <rtl/strbuf.hxx>
27 #include <rtl/ustring.hxx>
29 #include <tools/stream.hxx>
30 #include <comphelper/sequenceashashmap.hxx>
31 #include <svx/svdotext.hxx>
32 #include <vcl/cvtgrf.hxx>
33 #include <filter/msfilter/msdffimp.hxx>
34 #include <filter/msfilter/util.hxx>
35 #include <filter/msfilter/escherex.hxx>
37 #include <com/sun/star/drawing/XShape.hpp>
38 #include <com/sun/star/text/HoriOrientation.hpp>
39 #include <com/sun/star/text/VertOrientation.hpp>
40 #include <com/sun/star/text/RelOrientation.hpp>
42 #include <cstdio>
44 using namespace sax_fastparser;
45 using namespace oox::vml;
46 using namespace com::sun::star;
48 VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr pSerializer, VMLTextExport* pTextExport )
49 : EscherEx( EscherExGlobalRef(new EscherExGlobal(0)), 0, /*bOOXML=*/true )
50 , m_pSerializer( pSerializer )
51 , m_pTextExport( pTextExport )
52 , m_eHOri( 0 )
53 , m_eVOri( 0 )
54 , m_eHRel( 0 )
55 , m_eVRel( 0 )
56 , m_pNdTopLeft( 0 )
57 , m_pSdrObject( 0 )
58 , m_pShapeAttrList( NULL )
59 , m_nShapeType( ESCHER_ShpInst_Nil )
60 , m_nShapeFlags(0)
61 , m_pShapeStyle( new OStringBuffer( 200 ) )
62 , m_pShapeTypeWritten( new bool[ ESCHER_ShpInst_COUNT ] )
64 mnGroupLevel = 1;
65 memset( m_pShapeTypeWritten, 0, ESCHER_ShpInst_COUNT * sizeof( bool ) );
68 void VMLExport::SetFS( ::sax_fastparser::FSHelperPtr pSerializer )
70 m_pSerializer = pSerializer;
73 VMLExport::~VMLExport()
75 delete mpOutStrm, mpOutStrm = NULL;
76 delete m_pShapeStyle, m_pShapeStyle = NULL;
77 delete[] m_pShapeTypeWritten, m_pShapeTypeWritten = NULL;
80 void VMLExport::OpenContainer( sal_uInt16 nEscherContainer, int nRecInstance )
82 EscherEx::OpenContainer( nEscherContainer, nRecInstance );
84 if ( nEscherContainer == ESCHER_SpContainer )
86 // opening a shape container
87 #if OSL_DEBUG_LEVEL > 0
88 if ( m_nShapeType != ESCHER_ShpInst_Nil )
89 fprintf( stderr, "Warning! VMLExport::OpenContainer(): opening shape inside a shape.\n" );
90 #endif
91 m_nShapeType = ESCHER_ShpInst_Nil;
92 m_pShapeAttrList = FastSerializerHelper::createAttrList();
94 if ( !m_pShapeStyle->isEmpty() )
95 m_pShapeStyle->makeStringAndClear();
97 m_pShapeStyle->ensureCapacity( 200 );
99 // postpone the output so that we are able to write even the elements
100 // that we learn inside Commit()
101 m_pSerializer->mark();
105 void VMLExport::CloseContainer()
107 if ( mRecTypes.back() == ESCHER_SpContainer )
109 // write the shape now when we have all the info
110 sal_Int32 nShapeElement = StartShape();
112 m_pSerializer->mergeTopMarks();
114 EndShape( nShapeElement );
116 // cleanup
117 m_nShapeType = ESCHER_ShpInst_Nil;
118 m_pShapeAttrList = NULL;
121 EscherEx::CloseContainer();
124 sal_uInt32 VMLExport::EnterGroup( const OUString& rShapeName, const Rectangle* pRect )
126 sal_uInt32 nShapeId = GenerateShapeId();
128 OStringBuffer aStyle( 200 );
129 FastAttributeList *pAttrList = FastSerializerHelper::createAttrList();
131 pAttrList->add( XML_id, ShapeIdString( nShapeId ) );
133 if ( rShapeName.getLength() )
134 pAttrList->add( XML_alt, OUStringToOString( rShapeName, RTL_TEXTENCODING_UTF8 ) );
136 bool rbAbsolutePos = true;
137 //editAs
138 OUString rEditAs = EscherEx::GetEditAs();
139 if (!rEditAs.isEmpty())
141 pAttrList->add(XML_editas, OUStringToOString( rEditAs, RTL_TEXTENCODING_UTF8 ));
142 rbAbsolutePos = false;
145 // style
146 if ( pRect )
147 AddRectangleDimensions( aStyle, *pRect, rbAbsolutePos );
149 if ( !aStyle.isEmpty() )
150 pAttrList->add( XML_style, aStyle.makeStringAndClear() );
152 // coordorigin/coordsize
153 if ( pRect && ( mnGroupLevel == 1 ) )
155 pAttrList->add( XML_coordorigin,
156 OStringBuffer( 20 ).append( sal_Int32( pRect->Left() ) )
157 .append( "," ).append( sal_Int32( pRect->Top() ) )
158 .makeStringAndClear() );
160 pAttrList->add( XML_coordsize,
161 OStringBuffer( 20 ).append( sal_Int32( pRect->Right() ) - sal_Int32( pRect->Left() ) )
162 .append( "," ).append( sal_Int32( pRect->Bottom() ) - sal_Int32( pRect->Top() ) )
163 .makeStringAndClear() );
166 m_pSerializer->startElementNS( XML_v, XML_group, XFastAttributeListRef( pAttrList ) );
168 mnGroupLevel++;
169 return nShapeId;
172 void VMLExport::LeaveGroup()
174 --mnGroupLevel;
175 m_pSerializer->endElementNS( XML_v, XML_group );
178 void VMLExport::AddShape( sal_uInt32 nShapeType, sal_uInt32 nShapeFlags, sal_uInt32 nShapeId )
180 m_nShapeType = nShapeType;
181 m_nShapeFlags = nShapeFlags;
182 // If shape is a watermark object - should keep the original shape's name
183 // because Microsoft detects if it is a watermark by the actual name
184 if (!IsWaterMarkShape(m_pSdrObject->GetName()))
186 // Not a watermark object
187 m_pShapeAttrList->add( XML_id, ShapeIdString( nShapeId ) );
189 else
191 // A watermark object - store the optional shape ID also ('o:spid')
192 m_pShapeAttrList->add( XML_id, OUStringToOString(m_pSdrObject->GetName(), RTL_TEXTENCODING_UTF8) );
196 bool VMLExport::IsWaterMarkShape(const OUString& rStr)
198 if (rStr.isEmpty() ) return false;
200 if (rStr.match(OUString("PowerPlusWaterMarkObject")) || rStr.match(OUString("WordPictureWatermark")))
201 return true;
202 else
203 return false;
206 static void impl_AddArrowHead( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
208 if ( !pAttrList )
209 return;
211 const char *pArrowHead = NULL;
212 switch ( nValue )
214 case ESCHER_LineNoEnd: pArrowHead = "none"; break;
215 case ESCHER_LineArrowEnd: pArrowHead = "block"; break;
216 case ESCHER_LineArrowStealthEnd: pArrowHead = "classic"; break;
217 case ESCHER_LineArrowDiamondEnd: pArrowHead = "diamond"; break;
218 case ESCHER_LineArrowOvalEnd: pArrowHead = "oval"; break;
219 case ESCHER_LineArrowOpenEnd: pArrowHead = "open"; break;
222 if ( pArrowHead )
223 pAttrList->add( nElement, pArrowHead );
226 static void impl_AddArrowLength( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
228 if ( !pAttrList )
229 return;
231 const char *pArrowLength = NULL;
232 switch ( nValue )
234 case ESCHER_LineShortArrow: pArrowLength = "short"; break;
235 case ESCHER_LineMediumLenArrow: pArrowLength = "medium"; break;
236 case ESCHER_LineLongArrow: pArrowLength = "long"; break;
239 if ( pArrowLength )
240 pAttrList->add( nElement, pArrowLength );
243 static void impl_AddArrowWidth( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
245 if ( !pAttrList )
246 return;
248 const char *pArrowWidth = NULL;
249 switch ( nValue )
251 case ESCHER_LineNarrowArrow: pArrowWidth = "narrow"; break;
252 case ESCHER_LineMediumWidthArrow: pArrowWidth = "medium"; break;
253 case ESCHER_LineWideArrow: pArrowWidth = "wide"; break;
256 if ( pArrowWidth )
257 pAttrList->add( nElement, pArrowWidth );
260 static void impl_AddBool( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, bool bValue )
262 if ( !pAttrList )
263 return;
265 pAttrList->add( nElement, bValue? "t": "f" );
268 static void impl_AddColor( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nColor )
270 #if OSL_DEBUG_LEVEL > 0
271 if ( nColor & 0xFF000000 )
272 fprintf( stderr, "TODO: this is not a RGB value!\n" );
273 #endif
275 if ( !pAttrList || ( nColor & 0xFF000000 ) )
276 return;
278 nColor = ( ( nColor & 0xFF ) << 16 ) + ( nColor & 0xFF00 ) + ( ( nColor & 0xFF0000 ) >> 16 );
280 const char *pColor = NULL;
281 char pRgbColor[10];
282 switch ( nColor )
284 case 0x000000: pColor = "black"; break;
285 case 0xC0C0C0: pColor = "silver"; break;
286 case 0x808080: pColor = "gray"; break;
287 case 0xFFFFFF: pColor = "white"; break;
288 case 0x800000: pColor = "maroon"; break;
289 case 0xFF0000: pColor = "red"; break;
290 case 0x800080: pColor = "purple"; break;
291 case 0xFF00FF: pColor = "fuchsia"; break;
292 case 0x008000: pColor = "green"; break;
293 case 0x00FF00: pColor = "lime"; break;
294 case 0x808000: pColor = "olive"; break;
295 case 0xFFFF00: pColor = "yellow"; break;
296 case 0x000080: pColor = "navy"; break;
297 case 0x0000FF: pColor = "blue"; break;
298 case 0x008080: pColor = "teal"; break;
299 case 0x00FFFF: pColor = "aqua"; break;
300 default:
302 snprintf( pRgbColor, sizeof( pRgbColor ), "#%06x", static_cast< unsigned int >( nColor ) ); // not too handy to use OString::valueOf() here :-(
303 pColor = pRgbColor;
305 break;
308 pAttrList->add( nElement, pColor );
311 static void impl_AddInt( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
313 if ( !pAttrList )
314 return;
316 pAttrList->add( nElement, OString::number( nValue ).getStr() );
319 inline sal_uInt16 impl_GetUInt16( const sal_uInt8* &pVal )
321 sal_uInt16 nRet = *pVal++;
322 nRet += ( *pVal++ ) << 8;
323 return nRet;
326 inline sal_Int32 impl_GetPointComponent( const sal_uInt8* &pVal, sal_uInt16 nPointSize )
328 sal_Int32 nRet = 0;
329 if ( ( nPointSize == 0xfff0 ) || ( nPointSize == 4 ) )
331 sal_uInt16 nUnsigned = *pVal++;
332 nUnsigned += ( *pVal++ ) << 8;
334 nRet = sal_Int16( nUnsigned );
336 else if ( nPointSize == 8 )
338 sal_uInt32 nUnsigned = *pVal++;
339 nUnsigned += ( *pVal++ ) << 8;
340 nUnsigned += ( *pVal++ ) << 16;
341 nUnsigned += ( *pVal++ ) << 24;
343 nRet = nUnsigned;
346 return nRet;
349 void VMLExport::AddSdrObjectVMLObject( const SdrObject& rObj)
351 m_pSdrObject = &rObj;
353 void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect )
355 if ( m_nShapeType == ESCHER_ShpInst_Nil )
356 return;
358 // postpone the output of the embedded elements so that they are written
359 // inside the shapes
360 m_pSerializer->mark();
362 // dimensions
363 if ( m_nShapeType == ESCHER_ShpInst_Line )
364 AddLineDimensions( rRect );
365 else
366 AddRectangleDimensions( *m_pShapeStyle, rRect );
368 // properties
369 bool bAlreadyWritten[ 0xFFF ];
370 memset( bAlreadyWritten, 0, sizeof( bAlreadyWritten ) );
371 const EscherProperties &rOpts = rProps.GetOpts();
372 for ( EscherProperties::const_iterator it = rOpts.begin(); it != rOpts.end(); ++it )
374 sal_uInt16 nId = ( it->nPropId & 0x0FFF );
376 if ( bAlreadyWritten[ nId ] )
377 continue;
379 switch ( nId )
381 case ESCHER_Prop_WrapText: // 133
383 const char *pWrapType = NULL;
384 switch ( it->nPropValue )
386 case ESCHER_WrapSquare:
387 case ESCHER_WrapByPoints: pWrapType = "square"; break; // these two are equivalent according to the docu
388 case ESCHER_WrapNone: pWrapType = "none"; break;
389 case ESCHER_WrapTopBottom: pWrapType = "topAndBottom"; break;
390 case ESCHER_WrapThrough: pWrapType = "through"; break;
392 if ( pWrapType )
393 m_pSerializer->singleElementNS( XML_w10, XML_wrap,
394 XML_type, pWrapType,
395 FSEND );
397 bAlreadyWritten[ ESCHER_Prop_WrapText ] = true;
398 break;
400 // coordorigin
401 case ESCHER_Prop_geoLeft: // 320
402 case ESCHER_Prop_geoTop: // 321
404 sal_uInt32 nLeft = 0, nTop = 0;
406 if ( nId == ESCHER_Prop_geoLeft )
408 nLeft = it->nPropValue;
409 rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
411 else
413 nTop = it->nPropValue;
414 rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
416 if(nTop!=0 && nLeft!=0)
417 m_pShapeAttrList->add( XML_coordorigin,
418 OStringBuffer( 20 ).append( sal_Int32( nLeft ) )
419 .append( "," ).append( sal_Int32( nTop ) )
420 .makeStringAndClear() );
422 bAlreadyWritten[ ESCHER_Prop_geoLeft ] = true;
423 bAlreadyWritten[ ESCHER_Prop_geoTop ] = true;
424 break;
426 // coordsize
427 case ESCHER_Prop_geoRight: // 322
428 case ESCHER_Prop_geoBottom: // 323
430 sal_uInt32 nLeft = 0, nRight = 0, nTop = 0, nBottom = 0;
431 rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
432 rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
434 if ( nId == ESCHER_Prop_geoRight )
436 nRight = it->nPropValue;
437 rProps.GetOpt( ESCHER_Prop_geoBottom, nBottom );
439 else
441 nBottom = it->nPropValue;
442 rProps.GetOpt( ESCHER_Prop_geoRight, nRight );
445 if(nTop!=0 && nLeft!=0 && nBottom!=0 && nRight!=0 )
446 m_pShapeAttrList->add( XML_coordsize,
447 OStringBuffer( 20 ).append( sal_Int32( nRight ) - sal_Int32( nLeft ) )
448 .append( "," ).append( sal_Int32( nBottom ) - sal_Int32( nTop ) )
449 .makeStringAndClear() );
451 bAlreadyWritten[ ESCHER_Prop_geoRight ] = true;
452 bAlreadyWritten[ ESCHER_Prop_geoBottom ] = true;
453 break;
455 case ESCHER_Prop_pVertices: // 325
456 case ESCHER_Prop_pSegmentInfo: // 326
458 EscherPropSortStruct aVertices;
459 EscherPropSortStruct aSegments;
461 if ( rProps.GetOpt( ESCHER_Prop_pVertices, aVertices ) &&
462 rProps.GetOpt( ESCHER_Prop_pSegmentInfo, aSegments ) )
464 const sal_uInt8 *pVerticesIt = aVertices.pBuf + 6;
465 const sal_uInt8 *pSegmentIt = aSegments.pBuf;
466 OStringBuffer aPath( 512 );
468 sal_uInt16 nPointSize = aVertices.pBuf[4] + ( aVertices.pBuf[5] << 8 );
470 // number of segments
471 sal_uInt16 nSegments = impl_GetUInt16( pSegmentIt );
472 pSegmentIt += 4;
474 for ( ; nSegments; --nSegments )
476 sal_uInt16 nSeg = impl_GetUInt16( pSegmentIt );
478 // The segment type is stored in the upper 3 bits
479 // and segment count is stored in the lower 13
480 // bits.
481 unsigned char nSegmentType = (nSeg & 0xE000) >> 13;
482 unsigned short nSegmentCount = nSeg & 0x03FF;
484 switch (nSegmentType)
486 case msopathMoveTo:
488 sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
489 sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
490 if (nX >= 0 && nY >= 0 )
491 aPath.append( "m" ).append( nX ).append( "," ).append( nY );
492 break;
494 case msopathClientEscape:
495 break;
496 case msopathEscape:
498 // If the segment type is msopathEscape, the lower 13 bits are
499 // divided in a 5 bit escape code and 8 bit
500 // vertex count (not segment count!)
501 unsigned char nEscapeCode = (nSegmentCount & 0x1F00) >> 8;
502 unsigned char nVertexCount = nSegmentCount & 0x00FF;
503 pVerticesIt += nVertexCount;
505 switch (nEscapeCode)
507 case 0xa: // nofill
508 aPath.append( "nf" );
509 break;
510 case 0xb: // nostroke
511 aPath.append( "ns" );
512 break;
515 break;
517 case msopathLineTo:
518 for (unsigned short i = 0; i < nSegmentCount; ++i)
520 sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
521 sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
522 aPath.append( "l" ).append( nX ).append( "," ).append( nY );
524 break;
525 case msopathCurveTo:
526 for (unsigned short i = 0; i < nSegmentCount; ++i)
528 sal_Int32 nX1 = impl_GetPointComponent( pVerticesIt, nPointSize );
529 sal_Int32 nY1 = impl_GetPointComponent( pVerticesIt, nPointSize );
530 sal_Int32 nX2 = impl_GetPointComponent( pVerticesIt, nPointSize );
531 sal_Int32 nY2 = impl_GetPointComponent( pVerticesIt, nPointSize );
532 sal_Int32 nX3 = impl_GetPointComponent( pVerticesIt, nPointSize );
533 sal_Int32 nY3 = impl_GetPointComponent( pVerticesIt, nPointSize );
534 aPath.append( "c" ).append( nX1 ).append( "," ).append( nY1 ).append( "," )
535 .append( nX2 ).append( "," ).append( nY2 ).append( "," )
536 .append( nX3 ).append( "," ).append( nY3 );
538 break;
539 case msopathClose:
540 aPath.append( "x" );
541 break;
542 case msopathEnd:
543 aPath.append( "e" );
544 break;
545 default:
546 SAL_WARN("oox", "Totally b0rked\n");
547 break;
548 case msopathInvalid:
549 SAL_WARN("oox", "Invalid - should never be found");
550 break;
553 OString pathString = aPath.makeStringAndClear();
554 if ( !aPath.isEmpty() && pathString != "xe" )
555 m_pShapeAttrList->add( XML_path, pathString );
557 #if OSL_DEBUG_LEVEL > 0
558 else
559 fprintf( stderr, "TODO: unhandled shape path, missing either pVertices or pSegmentInfo.\n" );
560 #endif
562 bAlreadyWritten[ ESCHER_Prop_pVertices ] = true;
563 bAlreadyWritten[ ESCHER_Prop_pSegmentInfo ] = true;
564 break;
566 case ESCHER_Prop_fillType: // 384
567 case ESCHER_Prop_fillColor: // 385
568 case ESCHER_Prop_fillBackColor: // 387
569 case ESCHER_Prop_fillBlip: // 390
570 case ESCHER_Prop_fNoFillHitTest: // 447
571 case ESCHER_Prop_fillOpacity: // 386
573 sal_uInt32 nValue;
574 sax_fastparser::FastAttributeList *pAttrList = FastSerializerHelper::createAttrList();
576 bool imageData = false;
577 EscherPropSortStruct aStruct;
578 if ( rProps.GetOpt( ESCHER_Prop_fillBlip, aStruct ) && m_pTextExport)
580 SvMemoryStream aStream;
581 int nHeaderSize = 25; // The first bytes are WW8-specific, we're only interested in the PNG
582 aStream.Write(aStruct.pBuf + nHeaderSize, aStruct.nPropSize - nHeaderSize);
583 aStream.Seek(0);
584 Graphic aGraphic;
585 GraphicConverter::Import(aStream, aGraphic);
587 BitmapChecksum nChecksum = aGraphic.GetChecksum();
588 OUString aImageId = m_pTextExport->FindRelId(nChecksum);
589 if (aImageId.isEmpty())
591 aImageId = m_pTextExport->GetDrawingML().WriteImage( aGraphic );
592 m_pTextExport->CacheRelId(nChecksum, aImageId);
594 pAttrList->add(FSNS(XML_r, XML_id), OUStringToOString(aImageId, RTL_TEXTENCODING_UTF8));
595 imageData = true;
598 if ( rProps.GetOpt( ESCHER_Prop_fNoFillHitTest, nValue ) )
599 impl_AddBool( pAttrList, FSNS(XML_o, XML_detectmouseclick), nValue != 0 );
601 if (imageData)
602 m_pSerializer->singleElementNS( XML_v, XML_imagedata, XFastAttributeListRef( pAttrList ) );
603 else
605 if ( rProps.GetOpt( ESCHER_Prop_fillType, nValue ) )
607 const char *pFillType = NULL;
608 switch ( nValue )
610 case ESCHER_FillSolid: pFillType = "solid"; break;
611 // TODO case ESCHER_FillPattern: pFillType = ""; break;
612 case ESCHER_FillTexture: pFillType = "tile"; break;
613 // TODO case ESCHER_FillPicture: pFillType = ""; break;
614 // TODO case ESCHER_FillShade: pFillType = ""; break;
615 // TODO case ESCHER_FillShadeCenter: pFillType = ""; break;
616 // TODO case ESCHER_FillShadeShape: pFillType = ""; break;
617 // TODO case ESCHER_FillShadeScale: pFillType = ""; break;
618 // TODO case ESCHER_FillShadeTitle: pFillType = ""; break;
619 // TODO case ESCHER_FillBackground: pFillType = ""; break;
620 default:
621 #if OSL_DEBUG_LEVEL > 0
622 fprintf( stderr, "TODO: unhandled fill type\n" );
623 #endif
624 break;
626 if ( pFillType )
627 pAttrList->add( XML_type, pFillType );
629 else if (!rProps.GetOpt(ESCHER_Prop_fillColor, nValue))
630 pAttrList->add( XML_on, "false" );
632 if ( rProps.GetOpt( ESCHER_Prop_fillColor, nValue ) )
633 impl_AddColor( m_pShapeAttrList, XML_fillcolor, nValue );
635 if ( rProps.GetOpt( ESCHER_Prop_fillBackColor, nValue ) )
636 impl_AddColor( pAttrList, XML_color2, nValue );
639 if (rProps.GetOpt(ESCHER_Prop_fillOpacity, nValue))
640 // Partly undo the transformation at the end of EscherPropertyContainer::CreateFillProperties(): VML opacity is 0..1.
641 pAttrList->add(XML_opacity, OString::number(double((nValue * 100) >> 16) / 100));
642 m_pSerializer->singleElementNS( XML_v, XML_fill, XFastAttributeListRef( pAttrList ) );
646 bAlreadyWritten[ ESCHER_Prop_fillType ] = true;
647 bAlreadyWritten[ ESCHER_Prop_fillColor ] = true;
648 bAlreadyWritten[ ESCHER_Prop_fillBackColor ] = true;
649 bAlreadyWritten[ ESCHER_Prop_fillBlip ] = true;
650 bAlreadyWritten[ ESCHER_Prop_fNoFillHitTest ] = true;
651 bAlreadyWritten[ ESCHER_Prop_fillOpacity ] = true;
652 break;
654 case ESCHER_Prop_lineColor: // 448
655 case ESCHER_Prop_lineWidth: // 459
656 case ESCHER_Prop_lineDashing: // 462
657 case ESCHER_Prop_lineStartArrowhead: // 464
658 case ESCHER_Prop_lineEndArrowhead: // 465
659 case ESCHER_Prop_lineStartArrowWidth: // 466
660 case ESCHER_Prop_lineStartArrowLength: // 467
661 case ESCHER_Prop_lineEndArrowWidth: // 468
662 case ESCHER_Prop_lineEndArrowLength: // 469
663 case ESCHER_Prop_lineJoinStyle: // 470
664 case ESCHER_Prop_lineEndCapStyle: // 471
666 sal_uInt32 nValue;
667 sax_fastparser::FastAttributeList *pAttrList = FastSerializerHelper::createAttrList();
669 if ( rProps.GetOpt( ESCHER_Prop_lineColor, nValue ) )
670 impl_AddColor( pAttrList, XML_color, nValue );
672 if ( rProps.GetOpt( ESCHER_Prop_lineWidth, nValue ) )
673 impl_AddInt( pAttrList, XML_weight, nValue );
675 if ( rProps.GetOpt( ESCHER_Prop_lineDashing, nValue ) )
677 const char *pDashStyle = NULL;
678 switch ( nValue )
680 case ESCHER_LineSolid: pDashStyle = "solid"; break;
681 case ESCHER_LineDashSys: pDashStyle = "shortdash"; break;
682 case ESCHER_LineDotSys: pDashStyle = "shortdot"; break;
683 case ESCHER_LineDashDotSys: pDashStyle = "shortdashdot"; break;
684 case ESCHER_LineDashDotDotSys: pDashStyle = "shortdashdotdot"; break;
685 case ESCHER_LineDotGEL: pDashStyle = "dot"; break;
686 case ESCHER_LineDashGEL: pDashStyle = "dash"; break;
687 case ESCHER_LineLongDashGEL: pDashStyle = "longdash"; break;
688 case ESCHER_LineDashDotGEL: pDashStyle = "dashdot"; break;
689 case ESCHER_LineLongDashDotGEL: pDashStyle = "longdashdot"; break;
690 case ESCHER_LineLongDashDotDotGEL: pDashStyle = "longdashdotdot"; break;
692 if ( pDashStyle )
693 pAttrList->add( XML_dashstyle, pDashStyle );
696 if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowhead, nValue ) )
697 impl_AddArrowHead( pAttrList, XML_startarrow, nValue );
699 if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowhead, nValue ) )
700 impl_AddArrowHead( pAttrList, XML_endarrow, nValue );
702 if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowWidth, nValue ) )
703 impl_AddArrowWidth( pAttrList, XML_startarrowwidth, nValue );
705 if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowLength, nValue ) )
706 impl_AddArrowLength( pAttrList, XML_startarrowlength, nValue );
708 if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowWidth, nValue ) )
709 impl_AddArrowWidth( pAttrList, XML_endarrowwidth, nValue );
711 if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowLength, nValue ) )
712 impl_AddArrowLength( pAttrList, XML_endarrowlength, nValue );
714 if ( rProps.GetOpt( ESCHER_Prop_lineJoinStyle, nValue ) )
716 const char *pJoinStyle = NULL;
717 switch ( nValue )
719 case ESCHER_LineJoinBevel: pJoinStyle = "bevel"; break;
720 case ESCHER_LineJoinMiter: pJoinStyle = "miter"; break;
721 case ESCHER_LineJoinRound: pJoinStyle = "round"; break;
723 if ( pJoinStyle )
724 pAttrList->add( XML_joinstyle, pJoinStyle );
727 if ( rProps.GetOpt( ESCHER_Prop_lineEndCapStyle, nValue ) )
729 const char *pEndCap = NULL;
730 switch ( nValue )
732 case ESCHER_LineEndCapRound: pEndCap = "round"; break;
733 case ESCHER_LineEndCapSquare: pEndCap = "square"; break;
734 case ESCHER_LineEndCapFlat: pEndCap = "flat"; break;
736 if ( pEndCap )
737 pAttrList->add( XML_endcap, pEndCap );
740 m_pSerializer->singleElementNS( XML_v, XML_stroke, XFastAttributeListRef( pAttrList ) );
742 bAlreadyWritten[ ESCHER_Prop_lineColor ] = true;
743 bAlreadyWritten[ ESCHER_Prop_lineWidth ] = true;
744 bAlreadyWritten[ ESCHER_Prop_lineDashing ] = true;
745 bAlreadyWritten[ ESCHER_Prop_lineStartArrowhead ] = true;
746 bAlreadyWritten[ ESCHER_Prop_lineEndArrowhead ] = true;
747 bAlreadyWritten[ ESCHER_Prop_lineStartArrowWidth ] = true;
748 bAlreadyWritten[ ESCHER_Prop_lineStartArrowLength ] = true;
749 bAlreadyWritten[ ESCHER_Prop_lineEndArrowWidth ] = true;
750 bAlreadyWritten[ ESCHER_Prop_lineEndArrowLength ] = true;
751 bAlreadyWritten[ ESCHER_Prop_lineJoinStyle ] = true;
752 bAlreadyWritten[ ESCHER_Prop_lineEndCapStyle ] = true;
753 break;
755 case ESCHER_Prop_fHidden:
756 if ( !it->nPropValue )
757 m_pShapeStyle->append( ";visibility:hidden" );
758 break;
759 case ESCHER_Prop_shadowColor:
760 case ESCHER_Prop_fshadowObscured:
762 sal_uInt32 nValue = 0;
763 bool bShadow = false;
764 bool bObscured = false;
765 if ( rProps.GetOpt( ESCHER_Prop_fshadowObscured, nValue ) )
767 bShadow = (( nValue & 0x20002 ) == 0x20002 );
768 bObscured = (( nValue & 0x10001 ) == 0x10001 );
770 if ( bShadow )
772 sax_fastparser::FastAttributeList *pAttrList = FastSerializerHelper::createAttrList();
773 impl_AddBool( pAttrList, XML_on, bShadow );
774 impl_AddBool( pAttrList, XML_obscured, bObscured );
776 if ( rProps.GetOpt( ESCHER_Prop_shadowColor, nValue ) )
777 impl_AddColor( pAttrList, XML_color, nValue );
779 m_pSerializer->singleElementNS( XML_v, XML_shadow, XFastAttributeListRef( pAttrList ) );
780 bAlreadyWritten[ ESCHER_Prop_fshadowObscured ] = true;
781 bAlreadyWritten[ ESCHER_Prop_shadowColor ] = true;
784 break;
785 case ESCHER_Prop_gtextUNICODE:
786 case ESCHER_Prop_gtextFont:
788 EscherPropSortStruct aUnicode;
789 if (rProps.GetOpt(ESCHER_Prop_gtextUNICODE, aUnicode))
791 SvMemoryStream aStream;
792 aStream.Write(it->pBuf, it->nPropSize);
793 aStream.Seek(0);
794 OUString aTextPathString = SvxMSDffManager::MSDFFReadZString(aStream, it->nPropSize, true);
795 aStream.Seek(0);
797 m_pSerializer->singleElementNS( XML_v, XML_path,
798 XML_textpathok, "t",
799 FSEND );
801 sax_fastparser::FastAttributeList* pAttrList = FastSerializerHelper::createAttrList();
802 pAttrList->add(XML_on, "t");
803 pAttrList->add(XML_fitshape, "t");
804 pAttrList->add(XML_string, OUStringToOString(aTextPathString, RTL_TEXTENCODING_UTF8));
805 EscherPropSortStruct aFont;
806 OUString aStyle;
807 if (rProps.GetOpt(ESCHER_Prop_gtextFont, aFont))
809 aStream.Write(aFont.pBuf, aFont.nPropSize);
810 aStream.Seek(0);
811 OUString aTextPathFont = SvxMSDffManager::MSDFFReadZString(aStream, aFont.nPropSize, true);
812 aStyle += "font-family:\"" + aTextPathFont + "\"";
814 if (!aStyle.isEmpty())
815 pAttrList->add(XML_style, OUStringToOString(aStyle, RTL_TEXTENCODING_UTF8));
816 m_pSerializer->singleElementNS(XML_v, XML_textpath, XFastAttributeListRef(pAttrList));
819 bAlreadyWritten[ESCHER_Prop_gtextUNICODE] = true;
820 bAlreadyWritten[ESCHER_Prop_gtextFont] = true;
822 break;
823 case ESCHER_Prop_Rotation:
825 // The higher half of the variable contains the angle.
826 m_pShapeStyle->append(";rotation:").append(double(it->nPropValue >> 16));
827 bAlreadyWritten[ESCHER_Prop_Rotation] = true;
829 break;
830 case ESCHER_Prop_fNoLineDrawDash:
832 // See DffPropertyReader::ApplyLineAttributes().
833 impl_AddBool( m_pShapeAttrList, XML_stroked, (it->nPropValue & 8) != 0 );
834 bAlreadyWritten[ESCHER_Prop_fNoLineDrawDash] = true;
836 break;
837 case ESCHER_Prop_wzName:
839 SvMemoryStream aStream;
840 aStream.Write(it->pBuf, it->nPropSize);
841 aStream.Seek(0);
842 OUString idStr = SvxMSDffManager::MSDFFReadZString(aStream, it->nPropSize, true);
843 aStream.Seek(0);
844 if (!IsWaterMarkShape(m_pSdrObject->GetName()))
845 m_pShapeAttrList->add(XML_ID, OUStringToOString(idStr, RTL_TEXTENCODING_UTF8).getStr());
847 bAlreadyWritten[ESCHER_Prop_wzName] = true;
849 break;
850 default:
851 #if OSL_DEBUG_LEVEL > 0
852 fprintf( stderr, "TODO VMLExport::Commit(), unimplemented id: %d, value: %" SAL_PRIuUINT32 ", data: [%" SAL_PRIuUINT32 ", %p]\n",
853 nId, it->nPropValue, it->nPropSize, it->pBuf );
854 if ( it->nPropSize )
856 const sal_uInt8 *pIt = it->pBuf;
857 fprintf( stderr, " ( " );
858 for ( int nCount = it->nPropSize; nCount; --nCount )
860 fprintf( stderr, "%02x ", *pIt );
861 ++pIt;
863 fprintf( stderr, ")\n" );
865 #endif
866 break;
870 m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_POSTPONE );
873 OString VMLExport::ShapeIdString( sal_uInt32 nId )
875 return OStringBuffer( 20 ).append( "shape_" ).append( sal_Int64( nId ) ).makeStringAndClear();
878 void VMLExport::AddFlipXY( )
880 const sal_uInt32 nFlipHandV = SHAPEFLAG_FLIPH + SHAPEFLAG_FLIPV;
881 switch ( m_nShapeFlags & nFlipHandV )
883 case SHAPEFLAG_FLIPH: m_pShapeStyle->append( ";flip:x" ); break;
884 case SHAPEFLAG_FLIPV: m_pShapeStyle->append( ";flip:y" ); break;
885 case (nFlipHandV): m_pShapeStyle->append( ";flip:xy" ); break;
889 void VMLExport::AddLineDimensions( const Rectangle& rRectangle )
891 // style
892 if ( !m_pShapeStyle->isEmpty() )
893 m_pShapeStyle->append( ";" );
895 m_pShapeStyle->append( "position:absolute" );
897 AddFlipXY();
899 // the actual dimensions
900 OString aLeft, aTop, aRight, aBottom;
902 if ( mnGroupLevel == 1 )
904 const OString aPt( "pt" );
905 aLeft = OString::number( double( rRectangle.Left() ) / 20 ) + aPt;
906 aTop = OString::number( double( rRectangle.Top() ) / 20 ) + aPt;
907 aRight = OString::number( double( rRectangle.Right() ) / 20 ) + aPt;
908 aBottom = OString::number( double( rRectangle.Bottom() ) / 20 ) + aPt;
910 else
912 aLeft = OString::number( rRectangle.Left() );
913 aTop = OString::number( rRectangle.Top() );
914 aRight = OString::number( rRectangle.Right() );
915 aBottom = OString::number( rRectangle.Bottom() );
918 m_pShapeAttrList->add( XML_from,
919 OStringBuffer( 20 ).append( aLeft )
920 .append( "," ).append( aTop )
921 .makeStringAndClear() );
923 m_pShapeAttrList->add( XML_to,
924 OStringBuffer( 20 ).append( aRight )
925 .append( "," ).append( aBottom )
926 .makeStringAndClear() );
929 void VMLExport::AddRectangleDimensions( OStringBuffer& rBuffer, const Rectangle& rRectangle, bool rbAbsolutePos)
931 if ( !rBuffer.isEmpty() )
932 rBuffer.append( ";" );
934 if (rbAbsolutePos)
936 rBuffer.append( "position:absolute;" );
939 if ( mnGroupLevel == 1 )
941 rBuffer.append( "margin-left:" ).append( double( rRectangle.Left() ) / 20 )
942 .append( "pt;margin-top:" ).append( double( rRectangle.Top() ) / 20 )
943 .append( "pt;width:" ).append( double( rRectangle.Right() - rRectangle.Left() ) / 20 )
944 .append( "pt;height:" ).append( double( rRectangle.Bottom() - rRectangle.Top() ) / 20 )
945 .append( "pt" );
947 else
949 rBuffer.append( "left:" ).append( rRectangle.Left() )
950 .append( ";top:" ).append( rRectangle.Top() )
951 .append( ";width:" ).append( rRectangle.Right() - rRectangle.Left() )
952 .append( ";height:" ).append( rRectangle.Bottom() - rRectangle.Top() );
955 AddFlipXY();
958 void VMLExport::AddShapeAttribute( sal_Int32 nAttribute, const OString& rValue )
960 m_pShapeAttrList->add( nAttribute, rValue );
963 std::vector<OString> lcl_getShapeTypes()
965 std::vector<OString> aRet;
967 OUString aPath("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/filter/vml-shape-types");
968 rtl::Bootstrap::expandMacros(aPath);
969 SvFileStream aStream(aPath, StreamMode::READ);
970 if (aStream.GetError() != ERRCODE_NONE)
971 SAL_WARN("oox", "failed to open vml-shape-types");
972 OString aLine;
973 bool bNotDone = aStream.ReadLine(aLine);
974 while (bNotDone)
976 // Filter out comments.
977 if (!aLine.startsWith("/"))
978 aRet.push_back(aLine);
979 bNotDone = aStream.ReadLine(aLine);
981 return aRet;
984 bool lcl_isTextBox(const SdrObject* pSdrObject)
986 uno::Reference<beans::XPropertySet> xPropertySet(const_cast<SdrObject*>(pSdrObject)->getUnoShape(), uno::UNO_QUERY);
987 if (xPropertySet.is())
989 uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
990 return xPropertySetInfo->hasPropertyByName("TextBox") && xPropertySet->getPropertyValue("TextBox").get<bool>();
992 return false;
995 OUString lcl_getAnchorIdFromGrabBag(const SdrObject* pSdrObject)
997 OUString aResult;
999 uno::Reference<beans::XPropertySet> xShape(const_cast<SdrObject*>(pSdrObject)->getUnoShape(), uno::UNO_QUERY);
1000 if (xShape->getPropertySetInfo()->hasPropertyByName("InteropGrabBag"))
1002 comphelper::SequenceAsHashMap aInteropGrabBag(xShape->getPropertyValue("InteropGrabBag"));
1003 if (aInteropGrabBag.find("AnchorId") != aInteropGrabBag.end())
1004 aInteropGrabBag["AnchorId"] >>= aResult;
1007 return aResult;
1010 sal_Int32 VMLExport::StartShape()
1012 if ( m_nShapeType == ESCHER_ShpInst_Nil )
1013 return -1;
1015 // some of the shapes have their own name ;-)
1016 sal_Int32 nShapeElement = -1;
1017 bool bReferToShapeType = false;
1018 switch ( m_nShapeType )
1020 case ESCHER_ShpInst_NotPrimitive: nShapeElement = XML_shape; break;
1021 case ESCHER_ShpInst_Rectangle: nShapeElement = XML_rect; break;
1022 case ESCHER_ShpInst_RoundRectangle: nShapeElement = XML_roundrect; break;
1023 case ESCHER_ShpInst_Ellipse: nShapeElement = XML_oval; break;
1024 case ESCHER_ShpInst_Arc: nShapeElement = XML_arc; break;
1025 case ESCHER_ShpInst_Line: nShapeElement = XML_line; break;
1026 default:
1027 if ( m_nShapeType < ESCHER_ShpInst_COUNT )
1029 nShapeElement = XML_shape;
1031 // a predefined shape?
1032 static std::vector<OString> aShapeTypes = lcl_getShapeTypes();
1033 OString aShapeType = aShapeTypes[ m_nShapeType ];
1034 if ( aShapeType != "NULL" )
1036 bReferToShapeType = true;
1037 if ( !m_pShapeTypeWritten[ m_nShapeType ] )
1039 m_pSerializer->write( aShapeType.getStr() );
1040 m_pShapeTypeWritten[ m_nShapeType ] = true;
1043 else
1045 // rectangle is probably the best fallback...
1046 nShapeElement = XML_rect;
1049 break;
1052 // anchoring
1053 switch (m_eHOri)
1055 case text::HoriOrientation::LEFT:
1056 m_pShapeStyle->append(";mso-position-horizontal:left");
1057 break;
1058 case text::HoriOrientation::CENTER:
1059 m_pShapeStyle->append(";mso-position-horizontal:center");
1060 break;
1061 case text::HoriOrientation::RIGHT:
1062 m_pShapeStyle->append(";mso-position-horizontal:right");
1063 break;
1064 case text::HoriOrientation::INSIDE:
1065 m_pShapeStyle->append(";mso-position-horizontal:inside");
1066 break;
1067 case text::HoriOrientation::OUTSIDE:
1068 m_pShapeStyle->append(";mso-position-horizontal:outside");
1069 break;
1070 default:
1071 case text::HoriOrientation::NONE:
1072 break;
1074 switch (m_eHRel)
1076 case text::RelOrientation::PAGE_PRINT_AREA:
1077 m_pShapeStyle->append(";mso-position-horizontal-relative:margin");
1078 break;
1079 case text::RelOrientation::PAGE_FRAME:
1080 case text::RelOrientation::PAGE_LEFT:
1081 case text::RelOrientation::PAGE_RIGHT:
1082 m_pShapeStyle->append(";mso-position-horizontal-relative:page");
1083 break;
1084 case text::RelOrientation::CHAR:
1085 m_pShapeStyle->append(";mso-position-horizontal-relative:char");
1086 break;
1087 default:
1088 break;
1091 switch (m_eVOri)
1093 case text::VertOrientation::TOP:
1094 case text::VertOrientation::LINE_TOP:
1095 case text::VertOrientation::CHAR_TOP:
1096 m_pShapeStyle->append(";mso-position-vertical:top");
1097 break;
1098 case text::VertOrientation::CENTER:
1099 case text::VertOrientation::LINE_CENTER:
1100 m_pShapeStyle->append(";mso-position-vertical:center");
1101 break;
1102 case text::VertOrientation::BOTTOM:
1103 case text::VertOrientation::LINE_BOTTOM:
1104 case text::VertOrientation::CHAR_BOTTOM:
1105 m_pShapeStyle->append(";mso-position-vertical:bottom");
1106 break;
1107 default:
1108 case text::VertOrientation::NONE:
1109 break;
1111 switch (m_eVRel)
1113 case text::RelOrientation::PAGE_PRINT_AREA:
1114 m_pShapeStyle->append(";mso-position-vertical-relative:margin");
1115 break;
1116 case text::RelOrientation::PAGE_FRAME:
1117 m_pShapeStyle->append(";mso-position-vertical-relative:page");
1118 break;
1119 default:
1120 break;
1123 // add style
1124 m_pShapeAttrList->add( XML_style, m_pShapeStyle->makeStringAndClear() );
1126 OUString sAnchorId = lcl_getAnchorIdFromGrabBag(m_pSdrObject);
1127 if (!sAnchorId.isEmpty())
1128 m_pShapeAttrList->addNS(XML_wp14, XML_anchorId, OUStringToOString(sAnchorId, RTL_TEXTENCODING_UTF8));
1130 if ( nShapeElement >= 0 && !m_pShapeAttrList->hasAttribute( XML_type ) && bReferToShapeType )
1132 m_pShapeAttrList->add( XML_type, OStringBuffer( 20 )
1133 .append( "shapetype_" ).append( sal_Int32( m_nShapeType ) )
1134 .makeStringAndClear() );
1137 // start of the shape
1138 m_pSerializer->startElementNS( XML_v, nShapeElement, XFastAttributeListRef( m_pShapeAttrList ) );
1140 // now check if we have some editeng text (not associated textbox) and we have a text exporter registered
1141 const SdrTextObj* pTxtObj = PTR_CAST(SdrTextObj, m_pSdrObject);
1142 if (pTxtObj && m_pTextExport && msfilter::util::HasTextBoxContent(m_nShapeType) && !IsWaterMarkShape(m_pSdrObject->GetName()) && !lcl_isTextBox(m_pSdrObject))
1144 const OutlinerParaObject* pParaObj = 0;
1145 bool bOwnParaObj = false;
1148 #i13885#
1149 When the object is actively being edited, that text is not set into
1150 the objects normal text object, but lives in a separate object.
1152 if (pTxtObj->IsTextEditActive())
1154 pParaObj = pTxtObj->GetEditOutlinerParaObject();
1155 bOwnParaObj = true;
1157 else
1159 pParaObj = pTxtObj->GetOutlinerParaObject();
1162 if( pParaObj )
1164 // this is reached only in case some text is attached to the shape
1165 m_pSerializer->startElementNS(XML_v, XML_textbox, FSEND);
1166 m_pTextExport->WriteOutliner(*pParaObj);
1167 m_pSerializer->endElementNS(XML_v, XML_textbox);
1168 if( bOwnParaObj )
1169 delete pParaObj;
1173 return nShapeElement;
1176 void VMLExport::EndShape( sal_Int32 nShapeElement )
1178 if ( nShapeElement >= 0 )
1180 if (m_pTextExport && lcl_isTextBox(m_pSdrObject))
1182 uno::Reference<beans::XPropertySet> xPropertySet(const_cast<SdrObject*>(m_pSdrObject)->getUnoShape(), uno::UNO_QUERY);
1183 comphelper::SequenceAsHashMap aCustomShapeProperties(xPropertySet->getPropertyValue("CustomShapeGeometry"));
1184 sax_fastparser::FastAttributeList* pTextboxAttrList = FastSerializerHelper::createAttrList();
1185 if (aCustomShapeProperties.find("TextPreRotateAngle") != aCustomShapeProperties.end())
1187 sal_Int32 nTextRotateAngle = aCustomShapeProperties["TextPreRotateAngle"].get<sal_Int32>();
1188 if (nTextRotateAngle == -270)
1189 pTextboxAttrList->add(XML_style, "mso-layout-flow-alt:bottom-to-top");
1191 sax_fastparser::XFastAttributeListRef xTextboxAttrList(pTextboxAttrList);
1192 pTextboxAttrList = 0;
1193 m_pSerializer->startElementNS(XML_v, XML_textbox, xTextboxAttrList);
1195 m_pTextExport->WriteVMLTextBox(uno::Reference<drawing::XShape>(xPropertySet, uno::UNO_QUERY_THROW));
1197 m_pSerializer->endElementNS(XML_v, XML_textbox);
1200 // end of the shape
1201 m_pSerializer->endElementNS( XML_v, nShapeElement );
1205 sal_uInt32 VMLExport::AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri, sal_Int16 eVOri, sal_Int16 eHRel, sal_Int16 eVRel, const Point* pNdTopLeft, const bool bOOxmlExport )
1207 m_pSdrObject = &rObj;
1208 m_eHOri = eHOri;
1209 m_eVOri = eVOri;
1210 m_eHRel = eHRel;
1211 m_eVRel = eVRel;
1212 m_pNdTopLeft = pNdTopLeft;
1213 return EscherEx::AddSdrObject(rObj, bOOxmlExport);
1216 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */