bump product version to 6.3.0.0.beta1
[LibreOffice.git] / oox / source / export / vmlexport.cxx
blobeaf761a5d16800ee222dc68533030a82bf8a59df
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 <svl/itemset.hxx>
23 #include <oox/export/drawingml.hxx>
24 #include <oox/export/vmlexport.hxx>
25 #include <sax/fastattribs.hxx>
27 #include <oox/token/tokens.hxx>
29 #include <rtl/strbuf.hxx>
30 #include <rtl/ustring.hxx>
31 #include <sal/log.hxx>
33 #include <tools/stream.hxx>
34 #include <comphelper/sequenceashashmap.hxx>
35 #include <svx/svdotext.hxx>
36 #include <svx/svdograf.hxx>
37 #include <svx/sdmetitm.hxx>
38 #include <vcl/cvtgrf.hxx>
39 #include <filter/msfilter/msdffimp.hxx>
40 #include <filter/msfilter/util.hxx>
41 #include <filter/msfilter/escherex.hxx>
43 #include <com/sun/star/beans/XPropertySet.hpp>
44 #include <com/sun/star/beans/XPropertySetInfo.hpp>
45 #include <com/sun/star/drawing/XShape.hpp>
46 #include <com/sun/star/text/HoriOrientation.hpp>
47 #include <com/sun/star/text/VertOrientation.hpp>
48 #include <com/sun/star/text/RelOrientation.hpp>
50 #include <cstdio>
52 using namespace sax_fastparser;
53 using namespace oox::vml;
54 using namespace com::sun::star;
56 static const sal_Int32 Tag_Container = 44444;
57 static const sal_Int32 Tag_Commit = 44445;
59 VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr const & pSerializer, VMLTextExport* pTextExport )
60 : EscherEx( std::make_shared<EscherExGlobal>(), nullptr, /*bOOXML=*/true )
61 , m_pSerializer( pSerializer )
62 , m_pTextExport( pTextExport )
63 , m_eHOri( 0 )
64 , m_eVOri( 0 )
65 , m_eHRel( 0 )
66 , m_eVRel( 0 )
67 , m_bInline( false )
68 , m_pSdrObject( nullptr )
69 , m_pShapeAttrList( nullptr )
70 , m_nShapeType( ESCHER_ShpInst_Nil )
71 , m_nShapeFlags(ShapeFlag::NONE)
72 , m_ShapeStyle( 200 )
73 , m_aShapeTypeWritten( ESCHER_ShpInst_COUNT )
74 , m_bSkipwzName( false )
75 , m_bUseHashMarkForType( false )
76 , m_bOverrideShapeIdGeneration( false )
77 , m_nShapeIDCounter( 0 )
79 mnGroupLevel = 1;
82 void VMLExport::SetFS( const ::sax_fastparser::FSHelperPtr& pSerializer )
84 m_pSerializer = pSerializer;
87 VMLExport::~VMLExport()
89 delete mpOutStrm;
90 mpOutStrm = nullptr;
93 void VMLExport::OpenContainer( sal_uInt16 nEscherContainer, int nRecInstance )
95 EscherEx::OpenContainer( nEscherContainer, nRecInstance );
97 if ( nEscherContainer == ESCHER_SpContainer )
99 // opening a shape container
100 SAL_WARN_IF(m_nShapeType != ESCHER_ShpInst_Nil, "oox.vml", "opening shape inside of a shape!");
101 m_nShapeType = ESCHER_ShpInst_Nil;
102 m_pShapeAttrList = FastSerializerHelper::createAttrList();
104 m_ShapeStyle.setLength(0);
105 m_ShapeStyle.ensureCapacity(200);
107 // postpone the output so that we are able to write even the elements
108 // that we learn inside Commit()
109 m_pSerializer->mark(Tag_Container);
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(Tag_Container);
122 EndShape( nShapeElement );
124 // cleanup
125 m_nShapeType = ESCHER_ShpInst_Nil;
126 m_pShapeAttrList = nullptr;
129 EscherEx::CloseContainer();
132 sal_uInt32 VMLExport::EnterGroup( const OUString& rShapeName, const tools::Rectangle* pRect )
134 sal_uInt32 nShapeId = GenerateShapeId();
136 OStringBuffer aStyle( 200 );
137 FastAttributeList *pAttrList = FastSerializerHelper::createAttrList();
139 pAttrList->add( XML_id, ShapeIdString( nShapeId ) );
141 if ( rShapeName.getLength() )
142 pAttrList->add( XML_alt, OUStringToOString( rShapeName, RTL_TEXTENCODING_UTF8 ) );
144 bool rbAbsolutePos = true;
145 //editAs
146 OUString rEditAs = EscherEx::GetEditAs();
147 if (!rEditAs.isEmpty())
149 pAttrList->add(XML_editas, OUStringToOString( rEditAs, RTL_TEXTENCODING_UTF8 ));
150 rbAbsolutePos = false;
153 // style
154 if ( pRect )
155 AddRectangleDimensions( aStyle, *pRect, rbAbsolutePos );
157 if ( !aStyle.isEmpty() )
158 pAttrList->add( XML_style, aStyle.makeStringAndClear() );
160 // coordorigin/coordsize
161 if ( pRect && ( mnGroupLevel == 1 ) )
163 pAttrList->add( XML_coordorigin,
164 OStringBuffer( 20 ).append( sal_Int32( pRect->Left() ) )
165 .append( "," ).append( sal_Int32( pRect->Top() ) )
166 .makeStringAndClear() );
168 pAttrList->add( XML_coordsize,
169 OStringBuffer( 20 ).append( sal_Int32( pRect->Right() ) - sal_Int32( pRect->Left() ) )
170 .append( "," ).append( sal_Int32( pRect->Bottom() ) - sal_Int32( pRect->Top() ) )
171 .makeStringAndClear() );
174 m_pSerializer->startElementNS( XML_v, XML_group, XFastAttributeListRef( pAttrList ) );
176 mnGroupLevel++;
177 return nShapeId;
180 void VMLExport::LeaveGroup()
182 --mnGroupLevel;
183 m_pSerializer->endElementNS( XML_v, XML_group );
186 void VMLExport::AddShape( sal_uInt32 nShapeType, ShapeFlag nShapeFlags, sal_uInt32 nShapeId )
188 m_nShapeType = nShapeType;
189 m_nShapeFlags = nShapeFlags;
191 m_sShapeId = ShapeIdString( nShapeId );
192 // If shape is a watermark object - should keep the original shape's name
193 // because Microsoft detects if it is a watermark by the actual name
194 if (!IsWaterMarkShape(m_pSdrObject->GetName()))
196 // Not a watermark object
197 m_pShapeAttrList->add( XML_id, m_sShapeId );
199 else
201 // A watermark object - store the optional shape ID
202 m_pShapeAttrList->add( XML_id, OUStringToOString(m_pSdrObject->GetName(), RTL_TEXTENCODING_UTF8) );
203 // also ('o:spid')
204 m_pShapeAttrList->addNS( XML_o, XML_spid, m_sShapeId );
208 bool VMLExport::IsWaterMarkShape(const OUString& rStr)
210 if (rStr.isEmpty() ) return false;
212 return rStr.match("PowerPlusWaterMarkObject") || rStr.match("WordPictureWatermark");
215 void VMLExport::OverrideShapeIDGen(bool bOverrideShapeIdGen, const OString& sShapeIDPrefix)
217 m_bOverrideShapeIdGeneration = bOverrideShapeIdGen;
218 if(bOverrideShapeIdGen)
220 assert(!sShapeIDPrefix.isEmpty());
221 m_sShapeIDPrefix = sShapeIDPrefix;
223 else
224 m_sShapeIDPrefix.clear();
227 static void impl_AddArrowHead( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
229 if ( !pAttrList )
230 return;
232 const char *pArrowHead = nullptr;
233 switch ( nValue )
235 case ESCHER_LineNoEnd: pArrowHead = "none"; break;
236 case ESCHER_LineArrowEnd: pArrowHead = "block"; break;
237 case ESCHER_LineArrowStealthEnd: pArrowHead = "classic"; break;
238 case ESCHER_LineArrowDiamondEnd: pArrowHead = "diamond"; break;
239 case ESCHER_LineArrowOvalEnd: pArrowHead = "oval"; break;
240 case ESCHER_LineArrowOpenEnd: pArrowHead = "open"; break;
243 if ( pArrowHead )
244 pAttrList->add( nElement, pArrowHead );
247 static void impl_AddArrowLength( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
249 if ( !pAttrList )
250 return;
252 const char *pArrowLength = nullptr;
253 switch ( nValue )
255 case ESCHER_LineShortArrow: pArrowLength = "short"; break;
256 case ESCHER_LineMediumLenArrow: pArrowLength = "medium"; break;
257 case ESCHER_LineLongArrow: pArrowLength = "long"; break;
260 if ( pArrowLength )
261 pAttrList->add( nElement, pArrowLength );
264 static void impl_AddArrowWidth( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
266 if ( !pAttrList )
267 return;
269 const char *pArrowWidth = nullptr;
270 switch ( nValue )
272 case ESCHER_LineNarrowArrow: pArrowWidth = "narrow"; break;
273 case ESCHER_LineMediumWidthArrow: pArrowWidth = "medium"; break;
274 case ESCHER_LineWideArrow: pArrowWidth = "wide"; break;
277 if ( pArrowWidth )
278 pAttrList->add( nElement, pArrowWidth );
281 static void impl_AddBool( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, bool bValue )
283 if ( !pAttrList )
284 return;
286 pAttrList->add( nElement, bValue? "t": "f" );
289 static void impl_AddColor( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nColor )
291 #if OSL_DEBUG_LEVEL > 0
292 if ( nColor & 0xFF000000 )
293 fprintf( stderr, "TODO: this is not a RGB value!\n" );
294 #endif
296 if ( !pAttrList || ( nColor & 0xFF000000 ) )
297 return;
299 nColor = ( ( nColor & 0xFF ) << 16 ) + ( nColor & 0xFF00 ) + ( ( nColor & 0xFF0000 ) >> 16 );
301 const char *pColor = nullptr;
302 char pRgbColor[10];
303 switch ( nColor )
305 case 0x000000: pColor = "black"; break;
306 case 0xC0C0C0: pColor = "silver"; break;
307 case 0x808080: pColor = "gray"; break;
308 case 0xFFFFFF: pColor = "white"; break;
309 case 0x800000: pColor = "maroon"; break;
310 case 0xFF0000: pColor = "red"; break;
311 case 0x800080: pColor = "purple"; break;
312 case 0xFF00FF: pColor = "fuchsia"; break;
313 case 0x008000: pColor = "green"; break;
314 case 0x00FF00: pColor = "lime"; break;
315 case 0x808000: pColor = "olive"; break;
316 case 0xFFFF00: pColor = "yellow"; break;
317 case 0x000080: pColor = "navy"; break;
318 case 0x0000FF: pColor = "blue"; break;
319 case 0x008080: pColor = "teal"; break;
320 case 0x00FFFF: pColor = "aqua"; break;
321 default:
323 snprintf( pRgbColor, sizeof( pRgbColor ), "#%06x", static_cast< unsigned int >( nColor ) ); // not too handy to use OString::valueOf() here :-(
324 pColor = pRgbColor;
326 break;
329 pAttrList->add( nElement, pColor );
332 static void impl_AddInt( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
334 if ( !pAttrList )
335 return;
337 pAttrList->add( nElement, OString::number( nValue ).getStr() );
340 static sal_uInt16 impl_GetUInt16( const sal_uInt8* &pVal )
342 sal_uInt16 nRet = *pVal++;
343 nRet += ( *pVal++ ) << 8;
344 return nRet;
347 static sal_Int32 impl_GetPointComponent( const sal_uInt8* &pVal, sal_uInt16 nPointSize )
349 sal_Int32 nRet = 0;
350 if ( ( nPointSize == 0xfff0 ) || ( nPointSize == 4 ) )
352 sal_uInt16 nUnsigned = *pVal++;
353 nUnsigned += ( *pVal++ ) << 8;
355 nRet = sal_Int16( nUnsigned );
357 else if ( nPointSize == 8 )
359 sal_uInt32 nUnsigned = *pVal++;
360 nUnsigned += ( *pVal++ ) << 8;
361 nUnsigned += ( *pVal++ ) << 16;
362 nUnsigned += ( *pVal++ ) << 24;
364 nRet = nUnsigned;
367 return nRet;
370 void VMLExport::AddSdrObjectVMLObject( const SdrObject& rObj)
372 m_pSdrObject = &rObj;
374 void VMLExport::Commit( EscherPropertyContainer& rProps, const tools::Rectangle& rRect )
376 if ( m_nShapeType == ESCHER_ShpInst_Nil )
377 return;
379 // postpone the output of the embedded elements so that they are written
380 // inside the shapes
381 m_pSerializer->mark(Tag_Commit);
383 // dimensions
384 if ( m_nShapeType == ESCHER_ShpInst_Line )
385 AddLineDimensions( rRect );
386 else
388 if ( IsWaterMarkShape( m_pSdrObject->GetName() ) )
390 // Watermark need some padding to be compatible with MSO
391 long nPaddingY = 0;
392 const SfxItemSet& rSet = m_pSdrObject->GetMergedItemSet();
393 if ( const SdrMetricItem* pItem = rSet.GetItem( SDRATTR_TEXT_UPPERDIST ) )
394 nPaddingY += pItem->GetValue();
396 tools::Rectangle aRect( rRect );
397 aRect.setHeight( aRect.getHeight() + nPaddingY );
398 AddRectangleDimensions( m_ShapeStyle, aRect );
400 else
401 AddRectangleDimensions( m_ShapeStyle, rRect );
404 // properties
405 bool bAlreadyWritten[ 0xFFF ];
406 memset( bAlreadyWritten, 0, sizeof( bAlreadyWritten ) );
407 const EscherProperties &rOpts = rProps.GetOpts();
408 for (auto const& opt : rOpts)
410 sal_uInt16 nId = ( opt.nPropId & 0x0FFF );
412 if ( bAlreadyWritten[ nId ] )
413 continue;
415 switch ( nId )
417 case ESCHER_Prop_WrapText: // 133
419 const char *pWrapType = nullptr;
420 switch ( opt.nPropValue )
422 case ESCHER_WrapSquare:
423 case ESCHER_WrapByPoints: pWrapType = "square"; break; // these two are equivalent according to the docu
424 case ESCHER_WrapNone: pWrapType = "none"; break;
425 case ESCHER_WrapTopBottom: pWrapType = "topAndBottom"; break;
426 case ESCHER_WrapThrough: pWrapType = "through"; break;
428 if ( pWrapType )
429 m_pSerializer->singleElementNS(XML_w10, XML_wrap, XML_type, pWrapType);
431 bAlreadyWritten[ ESCHER_Prop_WrapText ] = true;
432 break;
434 // coordorigin
435 case ESCHER_Prop_geoLeft: // 320
436 case ESCHER_Prop_geoTop: // 321
438 sal_uInt32 nLeft = 0, nTop = 0;
440 if ( nId == ESCHER_Prop_geoLeft )
442 nLeft = opt.nPropValue;
443 rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
445 else
447 nTop = opt.nPropValue;
448 rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
450 if(nTop!=0 && nLeft!=0)
451 m_pShapeAttrList->add( XML_coordorigin,
452 OStringBuffer( 20 ).append( sal_Int32( nLeft ) )
453 .append( "," ).append( sal_Int32( nTop ) )
454 .makeStringAndClear() );
456 bAlreadyWritten[ ESCHER_Prop_geoLeft ] = true;
457 bAlreadyWritten[ ESCHER_Prop_geoTop ] = true;
458 break;
460 // coordsize
461 case ESCHER_Prop_geoRight: // 322
462 case ESCHER_Prop_geoBottom: // 323
464 sal_uInt32 nLeft = 0, nRight = 0, nTop = 0, nBottom = 0;
465 rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
466 rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
468 if ( nId == ESCHER_Prop_geoRight )
470 nRight = opt.nPropValue;
471 rProps.GetOpt( ESCHER_Prop_geoBottom, nBottom );
473 else
475 nBottom = opt.nPropValue;
476 rProps.GetOpt( ESCHER_Prop_geoRight, nRight );
479 if(nTop!=0 && nLeft!=0 && nBottom!=0 && nRight!=0 )
480 m_pShapeAttrList->add( XML_coordsize,
481 OStringBuffer( 20 ).append( sal_Int32( nRight ) - sal_Int32( nLeft ) )
482 .append( "," ).append( sal_Int32( nBottom ) - sal_Int32( nTop ) )
483 .makeStringAndClear() );
485 bAlreadyWritten[ ESCHER_Prop_geoRight ] = true;
486 bAlreadyWritten[ ESCHER_Prop_geoBottom ] = true;
487 break;
489 case ESCHER_Prop_pVertices: // 325
490 case ESCHER_Prop_pSegmentInfo: // 326
492 EscherPropSortStruct aVertices;
493 EscherPropSortStruct aSegments;
495 if ( rProps.GetOpt( ESCHER_Prop_pVertices, aVertices ) &&
496 rProps.GetOpt( ESCHER_Prop_pSegmentInfo, aSegments ) )
498 const sal_uInt8 *pVerticesIt = aVertices.nProp.data() + 6;
499 const sal_uInt8 *pSegmentIt = aSegments.nProp.data();
500 OStringBuffer aPath( 512 );
502 sal_uInt16 nPointSize = aVertices.nProp[4] + ( aVertices.nProp[5] << 8 );
504 // number of segments
505 sal_uInt16 nSegments = impl_GetUInt16( pSegmentIt );
506 pSegmentIt += 4;
508 for ( ; nSegments; --nSegments )
510 sal_uInt16 nSeg = impl_GetUInt16( pSegmentIt );
512 // The segment type is stored in the upper 3 bits
513 // and segment count is stored in the lower 13
514 // bits.
515 unsigned char nSegmentType = (nSeg & 0xE000) >> 13;
516 unsigned short nSegmentCount = nSeg & 0x03FF;
518 switch (nSegmentType)
520 case msopathMoveTo:
522 sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
523 sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
524 if (nX >= 0 && nY >= 0 )
525 aPath.append( "m" ).append( nX ).append( "," ).append( nY );
526 break;
528 case msopathClientEscape:
529 break;
530 case msopathEscape:
532 // If the segment type is msopathEscape, the lower 13 bits are
533 // divided in a 5 bit escape code and 8 bit
534 // vertex count (not segment count!)
535 unsigned char nEscapeCode = (nSegmentCount & 0x1F00) >> 8;
536 unsigned char nVertexCount = nSegmentCount & 0x00FF;
537 pVerticesIt += nVertexCount;
539 switch (nEscapeCode)
541 case 0xa: // nofill
542 aPath.append( "nf" );
543 break;
544 case 0xb: // nostroke
545 aPath.append( "ns" );
546 break;
549 break;
551 case msopathLineTo:
552 for (unsigned short i = 0; i < nSegmentCount; ++i)
554 sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
555 sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
556 aPath.append( "l" ).append( nX ).append( "," ).append( nY );
558 break;
559 case msopathCurveTo:
560 for (unsigned short i = 0; i < nSegmentCount; ++i)
562 sal_Int32 nX1 = impl_GetPointComponent( pVerticesIt, nPointSize );
563 sal_Int32 nY1 = impl_GetPointComponent( pVerticesIt, nPointSize );
564 sal_Int32 nX2 = impl_GetPointComponent( pVerticesIt, nPointSize );
565 sal_Int32 nY2 = impl_GetPointComponent( pVerticesIt, nPointSize );
566 sal_Int32 nX3 = impl_GetPointComponent( pVerticesIt, nPointSize );
567 sal_Int32 nY3 = impl_GetPointComponent( pVerticesIt, nPointSize );
568 aPath.append( "c" ).append( nX1 ).append( "," ).append( nY1 ).append( "," )
569 .append( nX2 ).append( "," ).append( nY2 ).append( "," )
570 .append( nX3 ).append( "," ).append( nY3 );
572 break;
573 case msopathClose:
574 aPath.append( "x" );
575 break;
576 case msopathEnd:
577 aPath.append( "e" );
578 break;
579 default:
580 SAL_WARN("oox", "Totally b0rked");
581 break;
582 case msopathInvalid:
583 SAL_WARN("oox", "Invalid - should never be found");
584 break;
587 OString pathString = aPath.makeStringAndClear();
588 if ( !aPath.isEmpty() && pathString != "xe" )
589 m_pShapeAttrList->add( XML_path, pathString );
591 else
592 SAL_WARN("oox.vml", "unhandled shape path, missing either pVertices or pSegmentInfo.");
594 bAlreadyWritten[ ESCHER_Prop_pVertices ] = true;
595 bAlreadyWritten[ ESCHER_Prop_pSegmentInfo ] = true;
596 break;
598 case ESCHER_Prop_fillType: // 384
599 case ESCHER_Prop_fillColor: // 385
600 case ESCHER_Prop_fillBackColor: // 387
601 case ESCHER_Prop_fillBlip: // 390
602 case ESCHER_Prop_fNoFillHitTest: // 447
603 case ESCHER_Prop_fillOpacity: // 386
605 sal_uInt32 nValue;
606 sax_fastparser::FastAttributeList* pAttrList
607 = FastSerializerHelper::createAttrList();
609 bool imageData = false;
610 EscherPropSortStruct aStruct;
611 const SdrGrafObj* pSdrGrafObj = dynamic_cast<const SdrGrafObj*>(m_pSdrObject);
613 if (pSdrGrafObj && pSdrGrafObj->isSignatureLine() && m_pTextExport)
615 sax_fastparser::FastAttributeList* pAttrListSignatureLine
616 = FastSerializerHelper::createAttrList();
617 pAttrListSignatureLine->add(XML_issignatureline, "t");
618 if (!pSdrGrafObj->getSignatureLineId().isEmpty())
620 pAttrListSignatureLine->add(
621 XML_id, OUStringToOString(pSdrGrafObj->getSignatureLineId(),
622 RTL_TEXTENCODING_UTF8));
624 if (!pSdrGrafObj->getSignatureLineSuggestedSignerName().isEmpty())
626 pAttrListSignatureLine->add(
627 FSNS(XML_o, XML_suggestedsigner),
628 OUStringToOString(
629 pSdrGrafObj->getSignatureLineSuggestedSignerName(),
630 RTL_TEXTENCODING_UTF8));
632 if (!pSdrGrafObj->getSignatureLineSuggestedSignerTitle().isEmpty())
634 pAttrListSignatureLine->add(
635 FSNS(XML_o, XML_suggestedsigner2),
636 OUStringToOString(
637 pSdrGrafObj->getSignatureLineSuggestedSignerTitle(),
638 RTL_TEXTENCODING_UTF8));
640 if (!pSdrGrafObj->getSignatureLineSuggestedSignerEmail().isEmpty())
642 pAttrListSignatureLine->add(
643 FSNS(XML_o, XML_suggestedsigneremail),
644 OUStringToOString(
645 pSdrGrafObj->getSignatureLineSuggestedSignerEmail(),
646 RTL_TEXTENCODING_UTF8));
648 if (!pSdrGrafObj->getSignatureLineSigningInstructions().isEmpty())
650 pAttrListSignatureLine->add(XML_signinginstructionsset, "t");
651 pAttrListSignatureLine->add(
652 FSNS(XML_o, XML_signinginstructions),
653 OUStringToOString(
654 pSdrGrafObj->getSignatureLineSigningInstructions(),
655 RTL_TEXTENCODING_UTF8));
657 pAttrListSignatureLine->add(
658 XML_showsigndate,
659 pSdrGrafObj->isSignatureLineShowSignDate() ? "t" : "f");
660 pAttrListSignatureLine->add(
661 XML_allowcomments,
662 pSdrGrafObj->isSignatureLineCanAddComment() ? "t" : "f");
664 m_pSerializer->singleElementNS(
665 XML_o, XML_signatureline,
666 XFastAttributeListRef(pAttrListSignatureLine));
668 // Get signature line graphic
669 const uno::Reference<graphic::XGraphic>& xGraphic
670 = pSdrGrafObj->getSignatureLineUnsignedGraphic();
671 Graphic aGraphic(xGraphic);
673 BitmapChecksum nChecksum = aGraphic.GetChecksum();
674 OUString aImageId = m_pTextExport->FindRelId(nChecksum);
675 if (aImageId.isEmpty())
677 aImageId = m_pTextExport->GetDrawingML().WriteImage(aGraphic);
678 m_pTextExport->CacheRelId(nChecksum, aImageId);
680 pAttrList->add(FSNS(XML_r, XML_id),
681 OUStringToOString(aImageId, RTL_TEXTENCODING_UTF8));
682 imageData = true;
684 else if (rProps.GetOpt(ESCHER_Prop_fillBlip, aStruct) && m_pTextExport)
686 SvMemoryStream aStream;
687 // The first bytes are WW8-specific, we're only interested in the PNG
688 int nHeaderSize = 25;
689 aStream.WriteBytes(aStruct.nProp.data() + nHeaderSize,
690 aStruct.nProp.size() - nHeaderSize);
691 aStream.Seek(0);
692 Graphic aGraphic;
693 GraphicConverter::Import(aStream, aGraphic);
695 BitmapChecksum nChecksum = aGraphic.GetChecksum();
696 OUString aImageId = m_pTextExport->FindRelId(nChecksum);
697 if (aImageId.isEmpty())
699 aImageId = m_pTextExport->GetDrawingML().WriteImage(aGraphic);
700 m_pTextExport->CacheRelId(nChecksum, aImageId);
702 pAttrList->add(FSNS(XML_r, XML_id),
703 OUStringToOString(aImageId, RTL_TEXTENCODING_UTF8));
704 imageData = true;
707 if (rProps.GetOpt(ESCHER_Prop_fNoFillHitTest, nValue))
708 impl_AddBool(pAttrList, FSNS(XML_o, XML_detectmouseclick), nValue != 0);
710 if (imageData)
711 m_pSerializer->singleElementNS( XML_v, XML_imagedata, XFastAttributeListRef( pAttrList ) );
712 else
714 if ( rProps.GetOpt( ESCHER_Prop_fillType, nValue ) )
716 const char *pFillType = nullptr;
717 switch ( nValue )
719 case ESCHER_FillSolid: pFillType = "solid"; break;
720 // TODO case ESCHER_FillPattern: pFillType = ""; break;
721 case ESCHER_FillTexture: pFillType = "tile"; break;
722 // TODO case ESCHER_FillPicture: pFillType = ""; break;
723 // TODO case ESCHER_FillShade: pFillType = ""; break;
724 // TODO case ESCHER_FillShadeCenter: pFillType = ""; break;
725 // TODO case ESCHER_FillShadeShape: pFillType = ""; break;
726 // TODO case ESCHER_FillShadeScale: pFillType = ""; break;
727 // TODO case ESCHER_FillShadeTitle: pFillType = ""; break;
728 // TODO case ESCHER_FillBackground: pFillType = ""; break;
729 default:
730 SAL_INFO("oox.vml", "Unhandled fill type: " << nValue);
731 break;
733 if ( pFillType )
734 pAttrList->add( XML_type, pFillType );
736 else if (!rProps.GetOpt(ESCHER_Prop_fillColor, nValue))
737 pAttrList->add( XML_on, "false" );
739 if ( rProps.GetOpt( ESCHER_Prop_fillColor, nValue ) )
740 impl_AddColor( m_pShapeAttrList, XML_fillcolor, nValue );
742 if ( rProps.GetOpt( ESCHER_Prop_fillBackColor, nValue ) )
743 impl_AddColor( pAttrList, XML_color2, nValue );
746 if (rProps.GetOpt(ESCHER_Prop_fillOpacity, nValue))
747 // Partly undo the transformation at the end of EscherPropertyContainer::CreateFillProperties(): VML opacity is 0..1.
748 pAttrList->add(XML_opacity, OString::number(double((nValue * 100) >> 16) / 100));
749 m_pSerializer->singleElementNS( XML_v, XML_fill, XFastAttributeListRef( pAttrList ) );
753 bAlreadyWritten[ ESCHER_Prop_fillType ] = true;
754 bAlreadyWritten[ ESCHER_Prop_fillColor ] = true;
755 bAlreadyWritten[ ESCHER_Prop_fillBackColor ] = true;
756 bAlreadyWritten[ ESCHER_Prop_fillBlip ] = true;
757 bAlreadyWritten[ ESCHER_Prop_fNoFillHitTest ] = true;
758 bAlreadyWritten[ ESCHER_Prop_fillOpacity ] = true;
759 break;
761 case ESCHER_Prop_lineColor: // 448
762 case ESCHER_Prop_lineWidth: // 459
763 case ESCHER_Prop_lineDashing: // 462
764 case ESCHER_Prop_lineStartArrowhead: // 464
765 case ESCHER_Prop_lineEndArrowhead: // 465
766 case ESCHER_Prop_lineStartArrowWidth: // 466
767 case ESCHER_Prop_lineStartArrowLength: // 467
768 case ESCHER_Prop_lineEndArrowWidth: // 468
769 case ESCHER_Prop_lineEndArrowLength: // 469
770 case ESCHER_Prop_lineJoinStyle: // 470
771 case ESCHER_Prop_lineEndCapStyle: // 471
773 sal_uInt32 nValue;
774 sax_fastparser::FastAttributeList *pAttrList = FastSerializerHelper::createAttrList();
776 if ( rProps.GetOpt( ESCHER_Prop_lineColor, nValue ) )
777 impl_AddColor( pAttrList, XML_color, nValue );
779 if ( rProps.GetOpt( ESCHER_Prop_lineWidth, nValue ) )
780 impl_AddInt( pAttrList, XML_weight, nValue );
782 if ( rProps.GetOpt( ESCHER_Prop_lineDashing, nValue ) )
784 const char *pDashStyle = nullptr;
785 switch ( nValue )
787 case ESCHER_LineSolid: pDashStyle = "solid"; break;
788 case ESCHER_LineDashSys: pDashStyle = "shortdash"; break;
789 case ESCHER_LineDotSys: pDashStyle = "shortdot"; break;
790 case ESCHER_LineDashDotSys: pDashStyle = "shortdashdot"; break;
791 case ESCHER_LineDashDotDotSys: pDashStyle = "shortdashdotdot"; break;
792 case ESCHER_LineDotGEL: pDashStyle = "dot"; break;
793 case ESCHER_LineDashGEL: pDashStyle = "dash"; break;
794 case ESCHER_LineLongDashGEL: pDashStyle = "longdash"; break;
795 case ESCHER_LineDashDotGEL: pDashStyle = "dashdot"; break;
796 case ESCHER_LineLongDashDotGEL: pDashStyle = "longdashdot"; break;
797 case ESCHER_LineLongDashDotDotGEL: pDashStyle = "longdashdotdot"; break;
799 if ( pDashStyle )
800 pAttrList->add( XML_dashstyle, pDashStyle );
803 if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowhead, nValue ) )
804 impl_AddArrowHead( pAttrList, XML_startarrow, nValue );
806 if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowhead, nValue ) )
807 impl_AddArrowHead( pAttrList, XML_endarrow, nValue );
809 if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowWidth, nValue ) )
810 impl_AddArrowWidth( pAttrList, XML_startarrowwidth, nValue );
812 if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowLength, nValue ) )
813 impl_AddArrowLength( pAttrList, XML_startarrowlength, nValue );
815 if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowWidth, nValue ) )
816 impl_AddArrowWidth( pAttrList, XML_endarrowwidth, nValue );
818 if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowLength, nValue ) )
819 impl_AddArrowLength( pAttrList, XML_endarrowlength, nValue );
821 if ( rProps.GetOpt( ESCHER_Prop_lineJoinStyle, nValue ) )
823 const char *pJoinStyle = nullptr;
824 switch ( nValue )
826 case ESCHER_LineJoinBevel: pJoinStyle = "bevel"; break;
827 case ESCHER_LineJoinMiter: pJoinStyle = "miter"; break;
828 case ESCHER_LineJoinRound: pJoinStyle = "round"; break;
830 if ( pJoinStyle )
831 pAttrList->add( XML_joinstyle, pJoinStyle );
834 if ( rProps.GetOpt( ESCHER_Prop_lineEndCapStyle, nValue ) )
836 const char *pEndCap = nullptr;
837 switch ( nValue )
839 case ESCHER_LineEndCapRound: pEndCap = "round"; break;
840 case ESCHER_LineEndCapSquare: pEndCap = "square"; break;
841 case ESCHER_LineEndCapFlat: pEndCap = "flat"; break;
843 if ( pEndCap )
844 pAttrList->add( XML_endcap, pEndCap );
847 m_pSerializer->singleElementNS( XML_v, XML_stroke, XFastAttributeListRef( pAttrList ) );
849 bAlreadyWritten[ ESCHER_Prop_lineColor ] = true;
850 bAlreadyWritten[ ESCHER_Prop_lineWidth ] = true;
851 bAlreadyWritten[ ESCHER_Prop_lineDashing ] = true;
852 bAlreadyWritten[ ESCHER_Prop_lineStartArrowhead ] = true;
853 bAlreadyWritten[ ESCHER_Prop_lineEndArrowhead ] = true;
854 bAlreadyWritten[ ESCHER_Prop_lineStartArrowWidth ] = true;
855 bAlreadyWritten[ ESCHER_Prop_lineStartArrowLength ] = true;
856 bAlreadyWritten[ ESCHER_Prop_lineEndArrowWidth ] = true;
857 bAlreadyWritten[ ESCHER_Prop_lineEndArrowLength ] = true;
858 bAlreadyWritten[ ESCHER_Prop_lineJoinStyle ] = true;
859 bAlreadyWritten[ ESCHER_Prop_lineEndCapStyle ] = true;
860 break;
862 case ESCHER_Prop_fHidden:
863 if ( !opt.nPropValue )
864 m_ShapeStyle.append( ";visibility:hidden" );
865 break;
866 case ESCHER_Prop_shadowColor:
867 case ESCHER_Prop_fshadowObscured:
869 sal_uInt32 nValue = 0;
870 bool bShadow = false;
871 bool bObscured = false;
872 if ( rProps.GetOpt( ESCHER_Prop_fshadowObscured, nValue ) )
874 bShadow = (( nValue & 0x20002 ) == 0x20002 );
875 bObscured = (( nValue & 0x10001 ) == 0x10001 );
877 if ( bShadow )
879 sax_fastparser::FastAttributeList *pAttrList = FastSerializerHelper::createAttrList();
880 impl_AddBool( pAttrList, XML_on, bShadow );
881 impl_AddBool( pAttrList, XML_obscured, bObscured );
883 if ( rProps.GetOpt( ESCHER_Prop_shadowColor, nValue ) )
884 impl_AddColor( pAttrList, XML_color, nValue );
886 m_pSerializer->singleElementNS( XML_v, XML_shadow, XFastAttributeListRef( pAttrList ) );
887 bAlreadyWritten[ ESCHER_Prop_fshadowObscured ] = true;
888 bAlreadyWritten[ ESCHER_Prop_shadowColor ] = true;
891 break;
892 case ESCHER_Prop_gtextUNICODE:
893 case ESCHER_Prop_gtextFont:
895 EscherPropSortStruct aUnicode;
896 if (rProps.GetOpt(ESCHER_Prop_gtextUNICODE, aUnicode))
898 SvMemoryStream aStream;
900 if(!opt.nProp.empty())
902 aStream.WriteBytes(opt.nProp.data(), opt.nProp.size());
905 aStream.Seek(0);
906 OUString aTextPathString = SvxMSDffManager::MSDFFReadZString(aStream, opt.nProp.size(), true);
907 aStream.Seek(0);
909 m_pSerializer->singleElementNS(XML_v, XML_path, XML_textpathok, "t");
911 sax_fastparser::FastAttributeList* pAttrList = FastSerializerHelper::createAttrList();
912 pAttrList->add(XML_on, "t");
913 pAttrList->add(XML_fitshape, "t");
914 pAttrList->add(XML_string, OUStringToOString(aTextPathString, RTL_TEXTENCODING_UTF8));
915 EscherPropSortStruct aFont;
916 OUString aStyle;
917 if (rProps.GetOpt(ESCHER_Prop_gtextFont, aFont))
919 aStream.WriteBytes(aFont.nProp.data(), aFont.nProp.size());
920 aStream.Seek(0);
921 OUString aTextPathFont = SvxMSDffManager::MSDFFReadZString(aStream, aFont.nProp.size(), true);
922 aStyle += "font-family:\"" + aTextPathFont + "\"";
924 sal_uInt32 nSize;
925 if (rProps.GetOpt(ESCHER_Prop_gtextSize, nSize))
927 float nSizeF = static_cast<sal_Int32>(nSize) / 65536.0;
928 OUString aSize = OUString::number(nSizeF);
929 aStyle += ";font-size:" + aSize + "pt";
931 if (IsWaterMarkShape(m_pSdrObject->GetName()))
932 pAttrList->add(XML_trim, "t");
934 if (!aStyle.isEmpty())
935 pAttrList->add(XML_style, OUStringToOString(aStyle, RTL_TEXTENCODING_UTF8));
936 m_pSerializer->singleElementNS(XML_v, XML_textpath, XFastAttributeListRef(pAttrList));
939 bAlreadyWritten[ESCHER_Prop_gtextUNICODE] = true;
940 bAlreadyWritten[ESCHER_Prop_gtextFont] = true;
942 break;
943 case ESCHER_Prop_Rotation:
945 // The higher half of the variable contains the angle.
946 m_ShapeStyle.append(";rotation:").append(double(opt.nPropValue >> 16));
947 bAlreadyWritten[ESCHER_Prop_Rotation] = true;
949 break;
950 case ESCHER_Prop_fNoLineDrawDash:
952 // See DffPropertyReader::ApplyLineAttributes().
953 impl_AddBool( m_pShapeAttrList, XML_stroked, (opt.nPropValue & 8) != 0 );
954 bAlreadyWritten[ESCHER_Prop_fNoLineDrawDash] = true;
956 break;
957 case ESCHER_Prop_wzName:
959 SvMemoryStream aStream;
961 if(!opt.nProp.empty())
963 aStream.WriteBytes(opt.nProp.data(), opt.nProp.size());
966 aStream.Seek(0);
967 OUString idStr = SvxMSDffManager::MSDFFReadZString(aStream, opt.nProp.size(), true);
968 aStream.Seek(0);
969 if (!IsWaterMarkShape(m_pSdrObject->GetName()) && !m_bSkipwzName)
970 m_pShapeAttrList->add(XML_ID, OUStringToOString(idStr, RTL_TEXTENCODING_UTF8).getStr());
972 bAlreadyWritten[ESCHER_Prop_wzName] = true;
974 break;
975 default:
976 #if OSL_DEBUG_LEVEL > 0
977 const size_t opt_nProp_size(opt.nProp.size());
978 const sal_uInt8 opt_nProp_empty(0);
979 fprintf( stderr, "TODO VMLExport::Commit(), unimplemented id: %d, value: %" SAL_PRIuUINT32 ", data: [%zu, %p]\n",
980 nId,
981 opt.nPropValue,
982 opt_nProp_size,
983 0 == opt_nProp_size ? &opt_nProp_empty : opt.nProp.data());
984 if ( opt.nProp.size() )
986 const sal_uInt8 *pIt = opt.nProp.data();
987 fprintf( stderr, " ( " );
988 for ( int nCount = opt.nProp.size(); nCount; --nCount )
990 fprintf( stderr, "%02x ", *pIt );
991 ++pIt;
993 fprintf( stderr, ")\n" );
995 #endif
996 break;
1000 m_pSerializer->mergeTopMarks(Tag_Commit, sax_fastparser::MergeMarks::POSTPONE );
1003 OString VMLExport::ShapeIdString( sal_uInt32 nId )
1005 if(m_bOverrideShapeIdGeneration)
1006 return m_sShapeIDPrefix + OString::number( nId );
1007 else
1008 return "shape_" + OString::number( nId );
1011 void VMLExport::AddFlipXY( )
1013 if (m_nShapeFlags & (ShapeFlag::FlipH | ShapeFlag::FlipV))
1015 m_ShapeStyle.append( ";flip:" );
1017 if (m_nShapeFlags & ShapeFlag::FlipH)
1018 m_ShapeStyle.append( "x" );
1020 if (m_nShapeFlags & ShapeFlag::FlipV)
1021 m_ShapeStyle.append( "y" );
1025 void VMLExport::AddLineDimensions( const tools::Rectangle& rRectangle )
1027 // style
1028 if (!m_ShapeStyle.isEmpty())
1029 m_ShapeStyle.append( ";" );
1031 m_ShapeStyle.append( "position:absolute" );
1033 AddFlipXY();
1035 // the actual dimensions
1036 OString aLeft, aTop, aRight, aBottom;
1038 if ( mnGroupLevel == 1 )
1040 const OString aPt( "pt" );
1041 aLeft = OString::number( double( rRectangle.Left() ) / 20 ) + aPt;
1042 aTop = OString::number( double( rRectangle.Top() ) / 20 ) + aPt;
1043 aRight = OString::number( double( rRectangle.Right() ) / 20 ) + aPt;
1044 aBottom = OString::number( double( rRectangle.Bottom() ) / 20 ) + aPt;
1046 else
1048 aLeft = OString::number( rRectangle.Left() );
1049 aTop = OString::number( rRectangle.Top() );
1050 aRight = OString::number( rRectangle.Right() );
1051 aBottom = OString::number( rRectangle.Bottom() );
1054 m_pShapeAttrList->add( XML_from,
1055 OStringBuffer( 20 ).append( aLeft )
1056 .append( "," ).append( aTop )
1057 .makeStringAndClear() );
1059 m_pShapeAttrList->add( XML_to,
1060 OStringBuffer( 20 ).append( aRight )
1061 .append( "," ).append( aBottom )
1062 .makeStringAndClear() );
1065 void VMLExport::AddRectangleDimensions( OStringBuffer& rBuffer, const tools::Rectangle& rRectangle, bool rbAbsolutePos)
1067 if ( !rBuffer.isEmpty() )
1068 rBuffer.append( ";" );
1070 if (rbAbsolutePos && !m_bInline)
1072 rBuffer.append( "position:absolute;" );
1075 if(m_bInline)
1077 rBuffer.append( "width:" ).append( double( rRectangle.Right() - rRectangle.Left() ) / 20 )
1078 .append( "pt;height:" ).append( double( rRectangle.Bottom() - rRectangle.Top() ) / 20 )
1079 .append( "pt" );
1081 else if ( mnGroupLevel == 1 )
1083 rBuffer.append( "margin-left:" ).append( double( rRectangle.Left() ) / 20 )
1084 .append( "pt;margin-top:" ).append( double( rRectangle.Top() ) / 20 )
1085 .append( "pt;width:" ).append( double( rRectangle.Right() - rRectangle.Left() ) / 20 )
1086 .append( "pt;height:" ).append( double( rRectangle.Bottom() - rRectangle.Top() ) / 20 )
1087 .append( "pt" );
1089 else
1091 rBuffer.append( "left:" ).append( rRectangle.Left() )
1092 .append( ";top:" ).append( rRectangle.Top() )
1093 .append( ";width:" ).append( rRectangle.Right() - rRectangle.Left() )
1094 .append( ";height:" ).append( rRectangle.Bottom() - rRectangle.Top() );
1097 AddFlipXY();
1100 void VMLExport::AddShapeAttribute( sal_Int32 nAttribute, const OString& rValue )
1102 m_pShapeAttrList->add( nAttribute, rValue );
1105 static std::vector<OString> lcl_getShapeTypes()
1107 std::vector<OString> aRet;
1109 OUString aPath("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/filter/vml-shape-types");
1110 rtl::Bootstrap::expandMacros(aPath);
1111 SvFileStream aStream(aPath, StreamMode::READ);
1112 if (aStream.GetError() != ERRCODE_NONE)
1113 SAL_WARN("oox", "failed to open vml-shape-types");
1114 OString aLine;
1115 bool bNotDone = aStream.ReadLine(aLine);
1116 while (bNotDone)
1118 // Filter out comments.
1119 if (!aLine.startsWith("/"))
1120 aRet.push_back(aLine);
1121 bNotDone = aStream.ReadLine(aLine);
1123 return aRet;
1126 static bool lcl_isTextBox(const SdrObject* pSdrObject)
1128 uno::Reference<beans::XPropertySet> xPropertySet(const_cast<SdrObject*>(pSdrObject)->getUnoShape(), uno::UNO_QUERY);
1129 if (xPropertySet.is())
1131 uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
1132 return xPropertySetInfo->hasPropertyByName("TextBox") && xPropertySet->getPropertyValue("TextBox").get<bool>();
1134 return false;
1137 static OUString lcl_getAnchorIdFromGrabBag(const SdrObject* pSdrObject)
1139 OUString aResult;
1141 uno::Reference<beans::XPropertySet> xShape(const_cast<SdrObject*>(pSdrObject)->getUnoShape(), uno::UNO_QUERY);
1142 if (xShape->getPropertySetInfo()->hasPropertyByName("InteropGrabBag"))
1144 comphelper::SequenceAsHashMap aInteropGrabBag(xShape->getPropertyValue("InteropGrabBag"));
1145 if (aInteropGrabBag.find("AnchorId") != aInteropGrabBag.end())
1146 aInteropGrabBag["AnchorId"] >>= aResult;
1149 return aResult;
1152 sal_uInt32 VMLExport::GenerateShapeId()
1154 if(!m_bOverrideShapeIdGeneration)
1155 return EscherEx::GenerateShapeId();
1156 else
1157 return m_nShapeIDCounter++;
1160 sal_Int32 VMLExport::StartShape()
1162 if ( m_nShapeType == ESCHER_ShpInst_Nil )
1163 return -1;
1165 // some of the shapes have their own name ;-)
1166 sal_Int32 nShapeElement = -1;
1167 bool bReferToShapeType = false;
1168 switch ( m_nShapeType )
1170 case ESCHER_ShpInst_NotPrimitive: nShapeElement = XML_shape; break;
1171 case ESCHER_ShpInst_Rectangle: nShapeElement = XML_rect; break;
1172 case ESCHER_ShpInst_RoundRectangle: nShapeElement = XML_roundrect; break;
1173 case ESCHER_ShpInst_Ellipse: nShapeElement = XML_oval; break;
1174 case ESCHER_ShpInst_Arc: nShapeElement = XML_arc; break;
1175 case ESCHER_ShpInst_Line: nShapeElement = XML_line; break;
1176 case ESCHER_ShpInst_HostControl:
1178 // We don't have a shape definition for host control in presetShapeDefinitions.xml
1179 // So use a definition copied from DOCX file created with MSO
1180 bReferToShapeType = true;
1181 nShapeElement = XML_shape;
1182 if ( !m_aShapeTypeWritten[ m_nShapeType ] )
1184 OStringBuffer sShapeType;
1185 sShapeType.append("<v:shapetype id=\"shapetype_").append(OString::number(m_nShapeType)).
1186 append("\" coordsize=\"21600,21600\" o:spt=\"").append(OString::number(m_nShapeType)).
1187 append("\" path=\"m,l,21600l21600,21600l21600,xe\">\n").
1188 append("<v:stroke joinstyle=\"miter\"/>\n"
1189 "<v:path shadowok=\"f\" o:extrusionok=\"f\" strokeok=\"f\" fillok=\"f\" o:connecttype=\"rect\"/>\n"
1190 "<o:lock v:ext=\"edit\" shapetype=\"t\"/>\n"
1191 "</v:shapetype>");
1192 m_pSerializer->write(sShapeType.makeStringAndClear().getStr());
1193 m_aShapeTypeWritten[ m_nShapeType ] = true;
1195 break;
1197 case ESCHER_ShpInst_PictureFrame:
1199 // We don't have a shape definition for picture frame in presetShapeDefinitions.xml
1200 // So use a definition copied from DOCX file created with MSO
1201 bReferToShapeType = true;
1202 nShapeElement = XML_shape;
1203 if ( !m_aShapeTypeWritten[ m_nShapeType ] )
1205 OStringBuffer sShapeType;
1206 sShapeType.append("<v:shapetype id=\"shapetype_").append(OString::number(m_nShapeType)).
1207 append("\" coordsize=\"21600,21600\" o:spt=\"").append(OString::number(m_nShapeType)).
1208 append("\" o:preferrelative=\"t\" path=\"m@4@5l@4@11@9@11@9@5xe\" filled=\"f\" stroked=\"f\">\n").
1209 append("<v:stroke joinstyle=\"miter\"/>\n"
1210 "<v:formulas>\n"
1211 "<v:f eqn=\"if lineDrawn pixelLineWidth 0\"/>\n"
1212 "<v:f eqn=\"sum @0 1 0\"/>\n"
1213 "<v:f eqn=\"sum 0 0 @1\"/>\n"
1214 "<v:f eqn=\"prod @2 1 2\"/>\n"
1215 "<v:f eqn=\"prod @3 21600 pixelWidth\"/>\n"
1216 "<v:f eqn=\"prod @3 21600 pixelHeight\"/>\n"
1217 "<v:f eqn=\"sum @0 0 1\"/>\n"
1218 "<v:f eqn=\"prod @6 1 2\"/>\n"
1219 "<v:f eqn=\"prod @7 21600 pixelWidth\"/>\n"
1220 "<v:f eqn=\"sum @8 21600 0\"/>\n"
1221 "<v:f eqn=\"prod @7 21600 pixelHeight\"/>\n"
1222 "<v:f eqn=\"sum @10 21600 0\"/>\n"
1223 "</v:formulas>\n"
1224 "<v:path o:extrusionok=\"f\" gradientshapeok=\"t\" o:connecttype=\"rect\"/>\n"
1225 "<o:lock v:ext=\"edit\" aspectratio=\"t\"/>\n"
1226 "</v:shapetype>");
1227 m_pSerializer->write(sShapeType.makeStringAndClear().getStr());
1228 m_aShapeTypeWritten[ m_nShapeType ] = true;
1230 break;
1232 default:
1233 if ( m_nShapeType < ESCHER_ShpInst_COUNT )
1235 nShapeElement = XML_shape;
1237 // a predefined shape?
1238 static std::vector<OString> aShapeTypes = lcl_getShapeTypes();
1239 OString aShapeType = aShapeTypes[ m_nShapeType ];
1240 if ( aShapeType != "NULL" )
1242 bReferToShapeType = true;
1243 if ( !m_aShapeTypeWritten[ m_nShapeType ] )
1245 m_pSerializer->write( aShapeType.getStr() );
1246 m_aShapeTypeWritten[ m_nShapeType ] = true;
1249 else
1251 // rectangle is probably the best fallback...
1252 nShapeElement = XML_rect;
1255 break;
1258 // anchoring
1259 switch (m_eHOri)
1261 case text::HoriOrientation::LEFT:
1262 m_ShapeStyle.append(";mso-position-horizontal:left");
1263 break;
1264 case text::HoriOrientation::CENTER:
1265 m_ShapeStyle.append(";mso-position-horizontal:center");
1266 break;
1267 case text::HoriOrientation::RIGHT:
1268 m_ShapeStyle.append(";mso-position-horizontal:right");
1269 break;
1270 case text::HoriOrientation::INSIDE:
1271 m_ShapeStyle.append(";mso-position-horizontal:inside");
1272 break;
1273 case text::HoriOrientation::OUTSIDE:
1274 m_ShapeStyle.append(";mso-position-horizontal:outside");
1275 break;
1276 default:
1277 case text::HoriOrientation::NONE:
1278 break;
1280 switch (m_eHRel)
1282 case text::RelOrientation::PAGE_PRINT_AREA:
1283 m_ShapeStyle.append(";mso-position-horizontal-relative:margin");
1284 break;
1285 case text::RelOrientation::PAGE_FRAME:
1286 case text::RelOrientation::PAGE_LEFT:
1287 case text::RelOrientation::PAGE_RIGHT:
1288 m_ShapeStyle.append(";mso-position-horizontal-relative:page");
1289 break;
1290 case text::RelOrientation::CHAR:
1291 m_ShapeStyle.append(";mso-position-horizontal-relative:char");
1292 break;
1293 default:
1294 break;
1297 switch (m_eVOri)
1299 case text::VertOrientation::TOP:
1300 case text::VertOrientation::LINE_TOP:
1301 case text::VertOrientation::CHAR_TOP:
1302 m_ShapeStyle.append(";mso-position-vertical:top");
1303 break;
1304 case text::VertOrientation::CENTER:
1305 case text::VertOrientation::LINE_CENTER:
1306 m_ShapeStyle.append(";mso-position-vertical:center");
1307 break;
1308 case text::VertOrientation::BOTTOM:
1309 case text::VertOrientation::LINE_BOTTOM:
1310 case text::VertOrientation::CHAR_BOTTOM:
1311 m_ShapeStyle.append(";mso-position-vertical:bottom");
1312 break;
1313 default:
1314 case text::VertOrientation::NONE:
1315 break;
1317 switch (m_eVRel)
1319 case text::RelOrientation::PAGE_PRINT_AREA:
1320 m_ShapeStyle.append(";mso-position-vertical-relative:margin");
1321 break;
1322 case text::RelOrientation::PAGE_FRAME:
1323 m_ShapeStyle.append(";mso-position-vertical-relative:page");
1324 break;
1325 default:
1326 break;
1329 // add style
1330 m_pShapeAttrList->add( XML_style, m_ShapeStyle.makeStringAndClear() );
1332 OUString sAnchorId = lcl_getAnchorIdFromGrabBag(m_pSdrObject);
1333 if (!sAnchorId.isEmpty())
1334 m_pShapeAttrList->addNS(XML_wp14, XML_anchorId, OUStringToOString(sAnchorId, RTL_TEXTENCODING_UTF8));
1336 if ( nShapeElement >= 0 && !m_pShapeAttrList->hasAttribute( XML_type ) && bReferToShapeType )
1338 OStringBuffer sTypeBuffer( 20 );
1339 if (m_bUseHashMarkForType)
1340 sTypeBuffer.append("#");
1341 m_pShapeAttrList->add( XML_type, sTypeBuffer
1342 .append( "shapetype_" ).append( sal_Int32( m_nShapeType ) )
1343 .makeStringAndClear() );
1346 // start of the shape
1347 m_pSerializer->startElementNS( XML_v, nShapeElement, XFastAttributeListRef( m_pShapeAttrList ) );
1349 // now check if we have some editeng text (not associated textbox) and we have a text exporter registered
1350 const SdrTextObj* pTxtObj = dynamic_cast<const SdrTextObj*>( m_pSdrObject );
1351 if (pTxtObj && m_pTextExport && msfilter::util::HasTextBoxContent(m_nShapeType) && !IsWaterMarkShape(m_pSdrObject->GetName()) && !lcl_isTextBox(m_pSdrObject))
1353 const OutlinerParaObject* pParaObj = nullptr;
1354 bool bOwnParaObj = false;
1357 #i13885#
1358 When the object is actively being edited, that text is not set into
1359 the objects normal text object, but lives in a separate object.
1361 if (pTxtObj->IsTextEditActive())
1363 pParaObj = pTxtObj->GetEditOutlinerParaObject().release();
1364 bOwnParaObj = true;
1366 else
1368 pParaObj = pTxtObj->GetOutlinerParaObject();
1371 if( pParaObj )
1373 // this is reached only in case some text is attached to the shape
1374 m_pSerializer->startElementNS(XML_v, XML_textbox);
1375 m_pTextExport->WriteOutliner(*pParaObj);
1376 m_pSerializer->endElementNS(XML_v, XML_textbox);
1377 if( bOwnParaObj )
1378 delete pParaObj;
1382 return nShapeElement;
1385 void VMLExport::EndShape( sal_Int32 nShapeElement )
1387 if ( nShapeElement >= 0 )
1389 if (m_pTextExport && lcl_isTextBox(m_pSdrObject))
1391 uno::Reference<beans::XPropertySet> xPropertySet(const_cast<SdrObject*>(m_pSdrObject)->getUnoShape(), uno::UNO_QUERY);
1392 comphelper::SequenceAsHashMap aCustomShapeProperties(xPropertySet->getPropertyValue("CustomShapeGeometry"));
1393 sax_fastparser::FastAttributeList* pTextboxAttrList = FastSerializerHelper::createAttrList();
1394 if (aCustomShapeProperties.find("TextPreRotateAngle") != aCustomShapeProperties.end())
1396 sal_Int32 nTextRotateAngle = aCustomShapeProperties["TextPreRotateAngle"].get<sal_Int32>();
1397 if (nTextRotateAngle == -270)
1398 pTextboxAttrList->add(XML_style, "mso-layout-flow-alt:bottom-to-top");
1400 sax_fastparser::XFastAttributeListRef xTextboxAttrList(pTextboxAttrList);
1401 pTextboxAttrList = nullptr;
1402 m_pSerializer->startElementNS(XML_v, XML_textbox, xTextboxAttrList);
1404 m_pTextExport->WriteVMLTextBox(uno::Reference<drawing::XShape>(xPropertySet, uno::UNO_QUERY_THROW));
1406 m_pSerializer->endElementNS(XML_v, XML_textbox);
1409 // end of the shape
1410 m_pSerializer->endElementNS( XML_v, nShapeElement );
1414 OString const & VMLExport::AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri, sal_Int16 eVOri, sal_Int16 eHRel, sal_Int16 eVRel, const bool bOOxmlExport )
1416 m_pSdrObject = &rObj;
1417 m_eHOri = eHOri;
1418 m_eVOri = eVOri;
1419 m_eHRel = eHRel;
1420 m_eVRel = eVRel;
1421 m_bInline = false;
1422 EscherEx::AddSdrObject(rObj, bOOxmlExport);
1423 return m_sShapeId;
1426 OString const & VMLExport::AddInlineSdrObject( const SdrObject& rObj, const bool bOOxmlExport )
1428 m_pSdrObject = &rObj;
1429 m_eHOri = -1;
1430 m_eVOri = -1;
1431 m_eHRel = -1;
1432 m_eVRel = -1;
1433 m_bInline = true;
1434 EscherEx::AddSdrObject(rObj, bOOxmlExport);
1435 return m_sShapeId;
1438 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */