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 <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>
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
)
68 , m_pSdrObject( nullptr )
69 , m_pShapeAttrList( nullptr )
70 , m_nShapeType( ESCHER_ShpInst_Nil
)
71 , m_nShapeFlags(ShapeFlag::NONE
)
73 , m_aShapeTypeWritten( ESCHER_ShpInst_COUNT
)
74 , m_bSkipwzName( false )
75 , m_bUseHashMarkForType( false )
76 , m_bOverrideShapeIdGeneration( false )
77 , m_nShapeIDCounter( 0 )
82 void VMLExport::SetFS( const ::sax_fastparser::FSHelperPtr
& pSerializer
)
84 m_pSerializer
= pSerializer
;
87 VMLExport::~VMLExport()
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
);
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;
146 OUString rEditAs
= EscherEx::GetEditAs();
147 if (!rEditAs
.isEmpty())
149 pAttrList
->add(XML_editas
, OUStringToOString( rEditAs
, RTL_TEXTENCODING_UTF8
));
150 rbAbsolutePos
= false;
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
) );
180 void VMLExport::LeaveGroup()
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
);
201 // A watermark object - store the optional shape ID
202 m_pShapeAttrList
->add( XML_id
, OUStringToOString(m_pSdrObject
->GetName(), RTL_TEXTENCODING_UTF8
) );
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
;
224 m_sShapeIDPrefix
.clear();
227 static void impl_AddArrowHead( sax_fastparser::FastAttributeList
*pAttrList
, sal_Int32 nElement
, sal_uInt32 nValue
)
232 const char *pArrowHead
= nullptr;
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;
244 pAttrList
->add( nElement
, pArrowHead
);
247 static void impl_AddArrowLength( sax_fastparser::FastAttributeList
*pAttrList
, sal_Int32 nElement
, sal_uInt32 nValue
)
252 const char *pArrowLength
= nullptr;
255 case ESCHER_LineShortArrow
: pArrowLength
= "short"; break;
256 case ESCHER_LineMediumLenArrow
: pArrowLength
= "medium"; break;
257 case ESCHER_LineLongArrow
: pArrowLength
= "long"; break;
261 pAttrList
->add( nElement
, pArrowLength
);
264 static void impl_AddArrowWidth( sax_fastparser::FastAttributeList
*pAttrList
, sal_Int32 nElement
, sal_uInt32 nValue
)
269 const char *pArrowWidth
= nullptr;
272 case ESCHER_LineNarrowArrow
: pArrowWidth
= "narrow"; break;
273 case ESCHER_LineMediumWidthArrow
: pArrowWidth
= "medium"; break;
274 case ESCHER_LineWideArrow
: pArrowWidth
= "wide"; break;
278 pAttrList
->add( nElement
, pArrowWidth
);
281 static void impl_AddBool( sax_fastparser::FastAttributeList
*pAttrList
, sal_Int32 nElement
, bool bValue
)
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" );
296 if ( !pAttrList
|| ( nColor
& 0xFF000000 ) )
299 nColor
= ( ( nColor
& 0xFF ) << 16 ) + ( nColor
& 0xFF00 ) + ( ( nColor
& 0xFF0000 ) >> 16 );
301 const char *pColor
= nullptr;
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;
323 snprintf( pRgbColor
, sizeof( pRgbColor
), "#%06x", static_cast< unsigned int >( nColor
) ); // not too handy to use OString::valueOf() here :-(
329 pAttrList
->add( nElement
, pColor
);
332 static void impl_AddInt( sax_fastparser::FastAttributeList
*pAttrList
, sal_Int32 nElement
, sal_uInt32 nValue
)
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;
347 static sal_Int32
impl_GetPointComponent( const sal_uInt8
* &pVal
, sal_uInt16 nPointSize
)
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;
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
)
379 // postpone the output of the embedded elements so that they are written
381 m_pSerializer
->mark(Tag_Commit
);
384 if ( m_nShapeType
== ESCHER_ShpInst_Line
)
385 AddLineDimensions( rRect
);
388 if ( IsWaterMarkShape( m_pSdrObject
->GetName() ) )
390 // Watermark need some padding to be compatible with MSO
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
);
401 AddRectangleDimensions( m_ShapeStyle
, rRect
);
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
] )
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;
429 m_pSerializer
->singleElementNS(XML_w10
, XML_wrap
, XML_type
, pWrapType
);
431 bAlreadyWritten
[ ESCHER_Prop_WrapText
] = true;
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
);
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;
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
);
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;
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
);
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
515 unsigned char nSegmentType
= (nSeg
& 0xE000) >> 13;
516 unsigned short nSegmentCount
= nSeg
& 0x03FF;
518 switch (nSegmentType
)
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
);
528 case msopathClientEscape
:
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
;
542 aPath
.append( "nf" );
544 case 0xb: // nostroke
545 aPath
.append( "ns" );
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
);
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
);
580 SAL_WARN("oox", "Totally b0rked");
583 SAL_WARN("oox", "Invalid - should never be found");
587 OString pathString
= aPath
.makeStringAndClear();
588 if ( !aPath
.isEmpty() && pathString
!= "xe" )
589 m_pShapeAttrList
->add( XML_path
, pathString
);
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;
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
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
),
629 pSdrGrafObj
->getSignatureLineSuggestedSignerName(),
630 RTL_TEXTENCODING_UTF8
));
632 if (!pSdrGrafObj
->getSignatureLineSuggestedSignerTitle().isEmpty())
634 pAttrListSignatureLine
->add(
635 FSNS(XML_o
, XML_suggestedsigner2
),
637 pSdrGrafObj
->getSignatureLineSuggestedSignerTitle(),
638 RTL_TEXTENCODING_UTF8
));
640 if (!pSdrGrafObj
->getSignatureLineSuggestedSignerEmail().isEmpty())
642 pAttrListSignatureLine
->add(
643 FSNS(XML_o
, XML_suggestedsigneremail
),
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
),
654 pSdrGrafObj
->getSignatureLineSigningInstructions(),
655 RTL_TEXTENCODING_UTF8
));
657 pAttrListSignatureLine
->add(
659 pSdrGrafObj
->isSignatureLineShowSignDate() ? "t" : "f");
660 pAttrListSignatureLine
->add(
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
));
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
);
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
));
707 if (rProps
.GetOpt(ESCHER_Prop_fNoFillHitTest
, nValue
))
708 impl_AddBool(pAttrList
, FSNS(XML_o
, XML_detectmouseclick
), nValue
!= 0);
711 m_pSerializer
->singleElementNS( XML_v
, XML_imagedata
, XFastAttributeListRef( pAttrList
) );
714 if ( rProps
.GetOpt( ESCHER_Prop_fillType
, nValue
) )
716 const char *pFillType
= nullptr;
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;
730 SAL_INFO("oox.vml", "Unhandled fill type: " << nValue
);
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;
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
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;
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;
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;
826 case ESCHER_LineJoinBevel
: pJoinStyle
= "bevel"; break;
827 case ESCHER_LineJoinMiter
: pJoinStyle
= "miter"; break;
828 case ESCHER_LineJoinRound
: pJoinStyle
= "round"; break;
831 pAttrList
->add( XML_joinstyle
, pJoinStyle
);
834 if ( rProps
.GetOpt( ESCHER_Prop_lineEndCapStyle
, nValue
) )
836 const char *pEndCap
= nullptr;
839 case ESCHER_LineEndCapRound
: pEndCap
= "round"; break;
840 case ESCHER_LineEndCapSquare
: pEndCap
= "square"; break;
841 case ESCHER_LineEndCapFlat
: pEndCap
= "flat"; break;
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;
862 case ESCHER_Prop_fHidden
:
863 if ( !opt
.nPropValue
)
864 m_ShapeStyle
.append( ";visibility:hidden" );
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 );
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;
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());
906 OUString aTextPathString
= SvxMSDffManager::MSDFFReadZString(aStream
, opt
.nProp
.size(), true);
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
;
917 if (rProps
.GetOpt(ESCHER_Prop_gtextFont
, aFont
))
919 aStream
.WriteBytes(aFont
.nProp
.data(), aFont
.nProp
.size());
921 OUString aTextPathFont
= SvxMSDffManager::MSDFFReadZString(aStream
, aFont
.nProp
.size(), true);
922 aStyle
+= "font-family:\"" + aTextPathFont
+ "\"";
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;
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;
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;
957 case ESCHER_Prop_wzName
:
959 SvMemoryStream aStream
;
961 if(!opt
.nProp
.empty())
963 aStream
.WriteBytes(opt
.nProp
.data(), opt
.nProp
.size());
967 OUString idStr
= SvxMSDffManager::MSDFFReadZString(aStream
, opt
.nProp
.size(), true);
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;
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",
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
);
993 fprintf( stderr
, ")\n" );
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
);
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
)
1028 if (!m_ShapeStyle
.isEmpty())
1029 m_ShapeStyle
.append( ";" );
1031 m_ShapeStyle
.append( "position:absolute" );
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
;
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;" );
1077 rBuffer
.append( "width:" ).append( double( rRectangle
.Right() - rRectangle
.Left() ) / 20 )
1078 .append( "pt;height:" ).append( double( rRectangle
.Bottom() - rRectangle
.Top() ) / 20 )
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 )
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() );
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");
1115 bool bNotDone
= aStream
.ReadLine(aLine
);
1118 // Filter out comments.
1119 if (!aLine
.startsWith("/"))
1120 aRet
.push_back(aLine
);
1121 bNotDone
= aStream
.ReadLine(aLine
);
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>();
1137 static OUString
lcl_getAnchorIdFromGrabBag(const SdrObject
* pSdrObject
)
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
;
1152 sal_uInt32
VMLExport::GenerateShapeId()
1154 if(!m_bOverrideShapeIdGeneration
)
1155 return EscherEx::GenerateShapeId();
1157 return m_nShapeIDCounter
++;
1160 sal_Int32
VMLExport::StartShape()
1162 if ( m_nShapeType
== ESCHER_ShpInst_Nil
)
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"
1192 m_pSerializer
->write(sShapeType
.makeStringAndClear().getStr());
1193 m_aShapeTypeWritten
[ m_nShapeType
] = true;
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"
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"
1224 "<v:path o:extrusionok=\"f\" gradientshapeok=\"t\" o:connecttype=\"rect\"/>\n"
1225 "<o:lock v:ext=\"edit\" aspectratio=\"t\"/>\n"
1227 m_pSerializer
->write(sShapeType
.makeStringAndClear().getStr());
1228 m_aShapeTypeWritten
[ m_nShapeType
] = true;
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;
1251 // rectangle is probably the best fallback...
1252 nShapeElement
= XML_rect
;
1261 case text::HoriOrientation::LEFT
:
1262 m_ShapeStyle
.append(";mso-position-horizontal:left");
1264 case text::HoriOrientation::CENTER
:
1265 m_ShapeStyle
.append(";mso-position-horizontal:center");
1267 case text::HoriOrientation::RIGHT
:
1268 m_ShapeStyle
.append(";mso-position-horizontal:right");
1270 case text::HoriOrientation::INSIDE
:
1271 m_ShapeStyle
.append(";mso-position-horizontal:inside");
1273 case text::HoriOrientation::OUTSIDE
:
1274 m_ShapeStyle
.append(";mso-position-horizontal:outside");
1277 case text::HoriOrientation::NONE
:
1282 case text::RelOrientation::PAGE_PRINT_AREA
:
1283 m_ShapeStyle
.append(";mso-position-horizontal-relative:margin");
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");
1290 case text::RelOrientation::CHAR
:
1291 m_ShapeStyle
.append(";mso-position-horizontal-relative:char");
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");
1304 case text::VertOrientation::CENTER
:
1305 case text::VertOrientation::LINE_CENTER
:
1306 m_ShapeStyle
.append(";mso-position-vertical:center");
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");
1314 case text::VertOrientation::NONE
:
1319 case text::RelOrientation::PAGE_PRINT_AREA
:
1320 m_ShapeStyle
.append(";mso-position-vertical-relative:margin");
1322 case text::RelOrientation::PAGE_FRAME
:
1323 m_ShapeStyle
.append(";mso-position-vertical-relative:page");
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;
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();
1368 pParaObj
= pTxtObj
->GetOutlinerParaObject();
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
);
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
);
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
;
1422 EscherEx::AddSdrObject(rObj
, bOOxmlExport
);
1426 OString
const & VMLExport::AddInlineSdrObject( const SdrObject
& rObj
, const bool bOOxmlExport
)
1428 m_pSdrObject
= &rObj
;
1434 EscherEx::AddSdrObject(rObj
, bOOxmlExport
);
1438 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */