Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <oox/export/vmlexport.hxx>
21 :
22 : #include <oox/token/tokens.hxx>
23 :
24 : #include <rtl/strbuf.hxx>
25 : #include <rtl/ustring.hxx>
26 :
27 : #include <tools/stream.hxx>
28 : #include <svx/svdotext.hxx>
29 : #include <vcl/cvtgrf.hxx>
30 : #include <filter/msfilter/msdffimp.hxx>
31 : #include <filter/msfilter/escherex.hxx>
32 :
33 : #include <com/sun/star/text/HoriOrientation.hpp>
34 : #include <com/sun/star/text/VertOrientation.hpp>
35 : #include <com/sun/star/text/RelOrientation.hpp>
36 :
37 : #include <cstdio>
38 :
39 :
40 : using namespace sax_fastparser;
41 : using namespace oox::vml;
42 : using namespace com::sun::star;
43 :
44 272 : VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr pSerializer, VMLTextExport* pTextExport )
45 272 : : EscherEx( EscherExGlobalRef(new EscherExGlobal(0)), 0, /*bOOXML=*/true )
46 : , m_pSerializer( pSerializer )
47 : , m_pTextExport( pTextExport )
48 : , m_eHOri( 0 )
49 : , m_eVOri( 0 )
50 : , m_eHRel( 0 )
51 : , m_eVRel( 0 )
52 : , m_pNdTopLeft( 0 )
53 : , m_pSdrObject( 0 )
54 : , m_pShapeAttrList( NULL )
55 : , m_nShapeType( ESCHER_ShpInst_Nil )
56 : , m_nShapeFlags(0)
57 272 : , m_pShapeStyle( new OStringBuffer( 200 ) )
58 816 : , m_pShapeTypeWritten( new bool[ ESCHER_ShpInst_COUNT ] )
59 : {
60 272 : mnGroupLevel = 1;
61 272 : memset( m_pShapeTypeWritten, 0, ESCHER_ShpInst_COUNT * sizeof( bool ) );
62 272 : }
63 :
64 312 : void VMLExport::SetFS( ::sax_fastparser::FSHelperPtr pSerializer )
65 : {
66 312 : m_pSerializer = pSerializer;
67 312 : }
68 :
69 816 : VMLExport::~VMLExport()
70 : {
71 272 : delete mpOutStrm, mpOutStrm = NULL;
72 272 : delete m_pShapeStyle, m_pShapeStyle = NULL;
73 272 : delete[] m_pShapeTypeWritten, m_pShapeTypeWritten = NULL;
74 544 : }
75 :
76 367 : void VMLExport::OpenContainer( sal_uInt16 nEscherContainer, int nRecInstance )
77 : {
78 367 : EscherEx::OpenContainer( nEscherContainer, nRecInstance );
79 :
80 367 : if ( nEscherContainer == ESCHER_SpContainer )
81 : {
82 : // opening a shape container
83 : #if OSL_DEBUG_LEVEL > 0
84 : if ( m_nShapeType != ESCHER_ShpInst_Nil )
85 : fprintf( stderr, "Warning! VMLExport::OpenContainer(): opening shape inside a shape.\n" );
86 : #endif
87 367 : m_nShapeType = ESCHER_ShpInst_Nil;
88 367 : m_pShapeAttrList = m_pSerializer->createAttrList();
89 :
90 367 : if ( !m_pShapeStyle->isEmpty() )
91 0 : m_pShapeStyle->makeStringAndClear();
92 :
93 367 : m_pShapeStyle->ensureCapacity( 200 );
94 :
95 : // postpone the output so that we are able to write even the elements
96 : // that we learn inside Commit()
97 367 : m_pSerializer->mark();
98 : }
99 367 : }
100 :
101 367 : void VMLExport::CloseContainer()
102 : {
103 367 : if ( mRecTypes.back() == ESCHER_SpContainer )
104 : {
105 : // write the shape now when we have all the info
106 367 : sal_Int32 nShapeElement = StartShape();
107 :
108 367 : m_pSerializer->mergeTopMarks();
109 :
110 367 : EndShape( nShapeElement );
111 :
112 : // cleanup
113 367 : m_nShapeType = ESCHER_ShpInst_Nil;
114 367 : m_pShapeAttrList = NULL;
115 : }
116 :
117 367 : EscherEx::CloseContainer();
118 367 : }
119 :
120 21 : sal_uInt32 VMLExport::EnterGroup( const OUString& rShapeName, const Rectangle* pRect )
121 : {
122 21 : sal_uInt32 nShapeId = GenerateShapeId();
123 :
124 21 : OStringBuffer aStyle( 200 );
125 21 : FastAttributeList *pAttrList = m_pSerializer->createAttrList();
126 :
127 21 : pAttrList->add( XML_id, ShapeIdString( nShapeId ) );
128 :
129 21 : if ( rShapeName.getLength() )
130 13 : pAttrList->add( XML_alt, OUStringToOString( rShapeName, RTL_TEXTENCODING_UTF8 ) );
131 :
132 21 : bool rbAbsolutePos = true;
133 : //editAs
134 42 : OUString rEditAs = EscherEx::GetEditAs();
135 21 : if (!rEditAs.isEmpty())
136 : {
137 4 : pAttrList->add(XML_editas, OUStringToOString( rEditAs, RTL_TEXTENCODING_UTF8 ));
138 4 : rbAbsolutePos = false;
139 : }
140 :
141 : // style
142 21 : if ( pRect )
143 21 : AddRectangleDimensions( aStyle, *pRect, rbAbsolutePos );
144 :
145 21 : if ( !aStyle.isEmpty() )
146 21 : pAttrList->add( XML_style, aStyle.makeStringAndClear() );
147 :
148 : // coordorigin/coordsize
149 21 : if ( pRect && ( mnGroupLevel == 1 ) )
150 : {
151 : pAttrList->add( XML_coordorigin,
152 34 : OStringBuffer( 20 ).append( sal_Int32( pRect->Left() ) )
153 34 : .append( "," ).append( sal_Int32( pRect->Top() ) )
154 17 : .makeStringAndClear() );
155 :
156 : pAttrList->add( XML_coordsize,
157 34 : OStringBuffer( 20 ).append( sal_Int32( pRect->Right() ) - sal_Int32( pRect->Left() ) )
158 34 : .append( "," ).append( sal_Int32( pRect->Bottom() ) - sal_Int32( pRect->Top() ) )
159 17 : .makeStringAndClear() );
160 : }
161 :
162 21 : m_pSerializer->startElementNS( XML_v, XML_group, XFastAttributeListRef( pAttrList ) );
163 :
164 21 : mnGroupLevel++;
165 42 : return nShapeId;
166 : }
167 :
168 21 : void VMLExport::LeaveGroup()
169 : {
170 21 : --mnGroupLevel;
171 21 : m_pSerializer->endElementNS( XML_v, XML_group );
172 21 : }
173 :
174 367 : void VMLExport::AddShape( sal_uInt32 nShapeType, sal_uInt32 nShapeFlags, sal_uInt32 nShapeId )
175 : {
176 367 : m_nShapeType = nShapeType;
177 367 : m_nShapeFlags = nShapeFlags;
178 : // If shape is a watermark object - should keep the original shape's name
179 : // because Microsoft detects if it is a watermark by the actual name
180 367 : if (!IsWaterMarkShape(m_pSdrObject->GetName()))
181 : {
182 : // Not a watermark object
183 363 : m_pShapeAttrList->add( XML_id, ShapeIdString( nShapeId ) );
184 : }
185 : else
186 : {
187 : // A watermark object - store the optional shape ID also ('o:spid')
188 4 : m_pShapeAttrList->add( XML_id, OUStringToOString(m_pSdrObject->GetName(), RTL_TEXTENCODING_UTF8) );
189 : }
190 367 : }
191 :
192 929 : bool VMLExport::IsWaterMarkShape(const OUString& rStr)
193 : {
194 929 : if (rStr.isEmpty() ) return false;
195 :
196 583 : if (rStr.match(OUString("PowerPlusWaterMarkObject")) || rStr.match(OUString("WordPictureWatermark")))
197 14 : return true;
198 : else
199 569 : return false;
200 : }
201 :
202 24 : static void impl_AddArrowHead( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
203 : {
204 24 : if ( !pAttrList )
205 24 : return;
206 :
207 24 : const char *pArrowHead = NULL;
208 24 : switch ( nValue )
209 : {
210 0 : case ESCHER_LineNoEnd: pArrowHead = "none"; break;
211 20 : case ESCHER_LineArrowEnd: pArrowHead = "block"; break;
212 1 : case ESCHER_LineArrowStealthEnd: pArrowHead = "classic"; break;
213 2 : case ESCHER_LineArrowDiamondEnd: pArrowHead = "diamond"; break;
214 0 : case ESCHER_LineArrowOvalEnd: pArrowHead = "oval"; break;
215 1 : case ESCHER_LineArrowOpenEnd: pArrowHead = "open"; break;
216 : }
217 :
218 24 : if ( pArrowHead )
219 24 : pAttrList->add( nElement, pArrowHead );
220 : }
221 :
222 24 : static void impl_AddArrowLength( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
223 : {
224 24 : if ( !pAttrList )
225 24 : return;
226 :
227 24 : const char *pArrowLength = NULL;
228 24 : switch ( nValue )
229 : {
230 0 : case ESCHER_LineShortArrow: pArrowLength = "short"; break;
231 24 : case ESCHER_LineMediumLenArrow: pArrowLength = "medium"; break;
232 0 : case ESCHER_LineLongArrow: pArrowLength = "long"; break;
233 : }
234 :
235 24 : if ( pArrowLength )
236 24 : pAttrList->add( nElement, pArrowLength );
237 : }
238 :
239 24 : static void impl_AddArrowWidth( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
240 : {
241 24 : if ( !pAttrList )
242 24 : return;
243 :
244 24 : const char *pArrowWidth = NULL;
245 24 : switch ( nValue )
246 : {
247 0 : case ESCHER_LineNarrowArrow: pArrowWidth = "narrow"; break;
248 24 : case ESCHER_LineMediumWidthArrow: pArrowWidth = "medium"; break;
249 0 : case ESCHER_LineWideArrow: pArrowWidth = "wide"; break;
250 : }
251 :
252 24 : if ( pArrowWidth )
253 24 : pAttrList->add( nElement, pArrowWidth );
254 : }
255 :
256 590 : static void impl_AddBool( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, bool bValue )
257 : {
258 590 : if ( !pAttrList )
259 590 : return;
260 :
261 590 : pAttrList->add( nElement, bValue? "t": "f" );
262 : }
263 :
264 573 : static void impl_AddColor( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nColor )
265 : {
266 : #if OSL_DEBUG_LEVEL > 0
267 : if ( nColor & 0xFF000000 )
268 : fprintf( stderr, "TODO: this is not a RGB value!\n" );
269 : #endif
270 :
271 573 : if ( !pAttrList || ( nColor & 0xFF000000 ) )
272 573 : return;
273 :
274 573 : nColor = ( ( nColor & 0xFF ) << 16 ) + ( nColor & 0xFF00 ) + ( ( nColor & 0xFF0000 ) >> 16 );
275 :
276 573 : const char *pColor = NULL;
277 : char pRgbColor[10];
278 573 : switch ( nColor )
279 : {
280 113 : case 0x000000: pColor = "black"; break;
281 1 : case 0xC0C0C0: pColor = "silver"; break;
282 3 : case 0x808080: pColor = "gray"; break;
283 34 : case 0xFFFFFF: pColor = "white"; break;
284 0 : case 0x800000: pColor = "maroon"; break;
285 24 : case 0xFF0000: pColor = "red"; break;
286 0 : case 0x800080: pColor = "purple"; break;
287 0 : case 0xFF00FF: pColor = "fuchsia"; break;
288 0 : case 0x008000: pColor = "green"; break;
289 0 : case 0x00FF00: pColor = "lime"; break;
290 0 : case 0x808000: pColor = "olive"; break;
291 4 : case 0xFFFF00: pColor = "yellow"; break;
292 0 : case 0x000080: pColor = "navy"; break;
293 5 : case 0x0000FF: pColor = "blue"; break;
294 0 : case 0x008080: pColor = "teal"; break;
295 20 : case 0x00FFFF: pColor = "aqua"; break;
296 : default:
297 : {
298 369 : snprintf( pRgbColor, sizeof( pRgbColor ), "#%06x", static_cast< unsigned int >( nColor ) ); // not too handy to use OString::valueOf() here :-(
299 369 : pColor = pRgbColor;
300 : }
301 369 : break;
302 : }
303 :
304 573 : pAttrList->add( nElement, pColor );
305 : }
306 :
307 73 : static void impl_AddInt( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
308 : {
309 73 : if ( !pAttrList )
310 73 : return;
311 :
312 73 : pAttrList->add( nElement, OString::number( nValue ).getStr() );
313 : }
314 :
315 2137 : inline sal_uInt16 impl_GetUInt16( const sal_uInt8* &pVal )
316 : {
317 2137 : sal_uInt16 nRet = *pVal++;
318 2137 : nRet += ( *pVal++ ) << 8;
319 2137 : return nRet;
320 : }
321 :
322 2868 : inline sal_Int32 impl_GetPointComponent( const sal_uInt8* &pVal, sal_uInt16 nPointSize )
323 : {
324 2868 : sal_Int32 nRet = 0;
325 2868 : if ( ( nPointSize == 0xfff0 ) || ( nPointSize == 4 ) )
326 : {
327 2616 : sal_uInt16 nUnsigned = *pVal++;
328 2616 : nUnsigned += ( *pVal++ ) << 8;
329 :
330 2616 : nRet = sal_Int16( nUnsigned );
331 : }
332 252 : else if ( nPointSize == 8 )
333 : {
334 252 : sal_uInt32 nUnsigned = *pVal++;
335 252 : nUnsigned += ( *pVal++ ) << 8;
336 252 : nUnsigned += ( *pVal++ ) << 16;
337 252 : nUnsigned += ( *pVal++ ) << 24;
338 :
339 252 : nRet = nUnsigned;
340 : }
341 :
342 2868 : return nRet;
343 : }
344 :
345 367 : void VMLExport::AddSdrObjectVMLObject( const SdrObject& rObj)
346 : {
347 367 : m_pSdrObject = &rObj;
348 367 : }
349 367 : void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect )
350 : {
351 367 : if ( m_nShapeType == ESCHER_ShpInst_Nil )
352 441 : return;
353 :
354 : // postpone the output of the embedded elements so that they are written
355 : // inside the shapes
356 293 : m_pSerializer->mark();
357 :
358 : // dimensions
359 293 : if ( m_nShapeType == ESCHER_ShpInst_Line )
360 4 : AddLineDimensions( rRect );
361 : else
362 289 : AddRectangleDimensions( *m_pShapeStyle, rRect );
363 :
364 : // properties
365 : bool bAlreadyWritten[ 0xFFF ];
366 293 : memset( bAlreadyWritten, 0, sizeof( bAlreadyWritten ) );
367 293 : const EscherProperties &rOpts = rProps.GetOpts();
368 5137 : for ( EscherProperties::const_iterator it = rOpts.begin(); it != rOpts.end(); ++it )
369 : {
370 4844 : sal_uInt16 nId = ( it->nPropId & 0x0FFF );
371 :
372 4844 : if ( bAlreadyWritten[ nId ] )
373 1406 : continue;
374 :
375 3438 : switch ( nId )
376 : {
377 : case ESCHER_Prop_WrapText: // 133
378 : {
379 287 : const char *pWrapType = NULL;
380 287 : switch ( it->nPropValue )
381 : {
382 : case ESCHER_WrapSquare:
383 81 : case ESCHER_WrapByPoints: pWrapType = "square"; break; // these two are equivalent according to the docu
384 206 : case ESCHER_WrapNone: pWrapType = "none"; break;
385 0 : case ESCHER_WrapTopBottom: pWrapType = "topAndBottom"; break;
386 0 : case ESCHER_WrapThrough: pWrapType = "through"; break;
387 : }
388 287 : if ( pWrapType )
389 : m_pSerializer->singleElementNS( XML_w10, XML_wrap,
390 : XML_type, pWrapType,
391 287 : FSEND );
392 : }
393 287 : bAlreadyWritten[ ESCHER_Prop_WrapText ] = true;
394 287 : break;
395 :
396 : // coordorigin
397 : case ESCHER_Prop_geoLeft: // 320
398 : case ESCHER_Prop_geoTop: // 321
399 : {
400 17 : sal_uInt32 nLeft = 0, nTop = 0;
401 :
402 17 : if ( nId == ESCHER_Prop_geoLeft )
403 : {
404 17 : nLeft = it->nPropValue;
405 17 : rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
406 : }
407 : else
408 : {
409 0 : nTop = it->nPropValue;
410 0 : rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
411 : }
412 17 : if(nTop!=0 && nLeft!=0)
413 : m_pShapeAttrList->add( XML_coordorigin,
414 0 : OStringBuffer( 20 ).append( sal_Int32( nLeft ) )
415 0 : .append( "," ).append( sal_Int32( nTop ) )
416 0 : .makeStringAndClear() );
417 : }
418 17 : bAlreadyWritten[ ESCHER_Prop_geoLeft ] = true;
419 17 : bAlreadyWritten[ ESCHER_Prop_geoTop ] = true;
420 17 : break;
421 :
422 : // coordsize
423 : case ESCHER_Prop_geoRight: // 322
424 : case ESCHER_Prop_geoBottom: // 323
425 : {
426 93 : sal_uInt32 nLeft = 0, nRight = 0, nTop = 0, nBottom = 0;
427 93 : rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
428 93 : rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
429 :
430 93 : if ( nId == ESCHER_Prop_geoRight )
431 : {
432 93 : nRight = it->nPropValue;
433 93 : rProps.GetOpt( ESCHER_Prop_geoBottom, nBottom );
434 : }
435 : else
436 : {
437 0 : nBottom = it->nPropValue;
438 0 : rProps.GetOpt( ESCHER_Prop_geoRight, nRight );
439 : }
440 :
441 93 : if(nTop!=0 && nLeft!=0 && nBottom!=0 && nRight!=0 )
442 : m_pShapeAttrList->add( XML_coordsize,
443 0 : OStringBuffer( 20 ).append( sal_Int32( nRight ) - sal_Int32( nLeft ) )
444 0 : .append( "," ).append( sal_Int32( nBottom ) - sal_Int32( nTop ) )
445 0 : .makeStringAndClear() );
446 : }
447 93 : bAlreadyWritten[ ESCHER_Prop_geoRight ] = true;
448 93 : bAlreadyWritten[ ESCHER_Prop_geoBottom ] = true;
449 93 : break;
450 :
451 : case ESCHER_Prop_pVertices: // 325
452 : case ESCHER_Prop_pSegmentInfo: // 326
453 : {
454 : EscherPropSortStruct aVertices;
455 : EscherPropSortStruct aSegments;
456 :
457 186 : if ( rProps.GetOpt( ESCHER_Prop_pVertices, aVertices ) &&
458 93 : rProps.GetOpt( ESCHER_Prop_pSegmentInfo, aSegments ) )
459 : {
460 93 : const sal_uInt8 *pVerticesIt = aVertices.pBuf + 6;
461 93 : const sal_uInt8 *pSegmentIt = aSegments.pBuf;
462 93 : OStringBuffer aPath( 512 );
463 :
464 93 : sal_uInt16 nPointSize = aVertices.pBuf[4] + ( aVertices.pBuf[5] << 8 );
465 :
466 : // number of segments
467 93 : sal_uInt16 nSegments = impl_GetUInt16( pSegmentIt );
468 93 : pSegmentIt += 4;
469 :
470 2137 : for ( ; nSegments; --nSegments )
471 : {
472 2044 : sal_uInt16 nSeg = impl_GetUInt16( pSegmentIt );
473 2044 : switch ( nSeg )
474 : {
475 : case 0x4000: // moveto
476 : {
477 131 : sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
478 131 : sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
479 131 : if (nX >= 0 && nY >= 0 )
480 114 : aPath.append( "m" ).append( nX ).append( "," ).append( nY );
481 : }
482 131 : break;
483 : case 0xb300:
484 : case 0xac00:
485 912 : break;
486 : case 0x0001: // lineto
487 : {
488 600 : sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
489 600 : sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
490 600 : aPath.append( "l" ).append( nX ).append( "," ).append( nY );
491 : }
492 600 : break;
493 : case 0x2001: // curveto
494 : {
495 198 : sal_Int32 nX1 = impl_GetPointComponent( pVerticesIt, nPointSize );
496 198 : sal_Int32 nY1 = impl_GetPointComponent( pVerticesIt, nPointSize );
497 198 : sal_Int32 nX2 = impl_GetPointComponent( pVerticesIt, nPointSize );
498 198 : sal_Int32 nY2 = impl_GetPointComponent( pVerticesIt, nPointSize );
499 198 : sal_Int32 nX3 = impl_GetPointComponent( pVerticesIt, nPointSize );
500 198 : sal_Int32 nY3 = impl_GetPointComponent( pVerticesIt, nPointSize );
501 198 : aPath.append( "c" ).append( nX1 ).append( "," ).append( nY1 ).append( "," )
502 198 : .append( nX2 ).append( "," ).append( nY2 ).append( "," )
503 198 : .append( nX3 ).append( "," ).append( nY3 );
504 : }
505 198 : break;
506 : case 0xaa00: // nofill
507 0 : aPath.append( "nf" );
508 0 : break;
509 : case 0xab00: // nostroke
510 0 : aPath.append( "ns" );
511 0 : break;
512 : case 0x6001: // close
513 93 : aPath.append( "x" );
514 93 : break;
515 : case 0x8000: // end
516 93 : aPath.append( "e" );
517 93 : break;
518 : default:
519 : // See EscherPropertyContainer::CreateCustomShapeProperties, by default nSeg is simply the number of points.
520 126 : for (int i = 0; i < nSeg; ++i)
521 : {
522 109 : sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nPointSize);
523 109 : sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nPointSize);
524 109 : if (nX >= 0 && nY >= 0 )
525 0 : aPath.append("l").append(nX).append(",").append(nY);
526 : }
527 17 : break;
528 : }
529 : }
530 93 : OString pathString = aPath.makeStringAndClear();
531 93 : if ( !aPath.isEmpty() && pathString != "xe" )
532 0 : m_pShapeAttrList->add( XML_path, pathString );
533 : }
534 : #if OSL_DEBUG_LEVEL > 0
535 : else
536 : fprintf( stderr, "TODO: unhandled shape path, missing either pVertices or pSegmentInfo.\n" );
537 : #endif
538 : }
539 93 : bAlreadyWritten[ ESCHER_Prop_pVertices ] = true;
540 93 : bAlreadyWritten[ ESCHER_Prop_pSegmentInfo ] = true;
541 93 : break;
542 :
543 : case ESCHER_Prop_fillType: // 384
544 : case ESCHER_Prop_fillColor: // 385
545 : case ESCHER_Prop_fillBackColor: // 387
546 : case ESCHER_Prop_fillBlip: // 390
547 : case ESCHER_Prop_fNoFillHitTest: // 447
548 : case ESCHER_Prop_fillOpacity: // 386
549 : {
550 : sal_uInt32 nValue;
551 293 : sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
552 :
553 293 : if ( rProps.GetOpt( ESCHER_Prop_fillType, nValue ) )
554 : {
555 159 : const char *pFillType = NULL;
556 159 : switch ( nValue )
557 : {
558 132 : case ESCHER_FillSolid: pFillType = "solid"; break;
559 : // TODO case ESCHER_FillPattern: pFillType = ""; break;
560 0 : case ESCHER_FillTexture: pFillType = "tile"; break;
561 : // TODO case ESCHER_FillPicture: pFillType = ""; break;
562 : // TODO case ESCHER_FillShade: pFillType = ""; break;
563 : // TODO case ESCHER_FillShadeCenter: pFillType = ""; break;
564 : // TODO case ESCHER_FillShadeShape: pFillType = ""; break;
565 : // TODO case ESCHER_FillShadeScale: pFillType = ""; break;
566 : // TODO case ESCHER_FillShadeTitle: pFillType = ""; break;
567 : // TODO case ESCHER_FillBackground: pFillType = ""; break;
568 : default:
569 : #if OSL_DEBUG_LEVEL > 0
570 : fprintf( stderr, "TODO: unhandled fill type\n" );
571 : #endif
572 27 : break;
573 : }
574 159 : if ( pFillType )
575 132 : pAttrList->add( XML_type, pFillType );
576 : }
577 134 : else if (!rProps.GetOpt(ESCHER_Prop_fillColor, nValue))
578 130 : pAttrList->add( XML_on, "false" );
579 :
580 293 : if ( rProps.GetOpt( ESCHER_Prop_fillColor, nValue ) )
581 139 : impl_AddColor( m_pShapeAttrList, XML_fillcolor, nValue );
582 :
583 293 : if ( rProps.GetOpt( ESCHER_Prop_fillBackColor, nValue ) )
584 139 : impl_AddColor( pAttrList, XML_color2, nValue );
585 :
586 293 : bool imageData = false;
587 : EscherPropSortStruct aStruct;
588 293 : if ( rProps.GetOpt( ESCHER_Prop_fillBlip, aStruct ) && m_pTextExport)
589 : {
590 24 : SvMemoryStream aStream;
591 24 : int nHeaderSize = 25; // The first bytes are WW8-specific, we're only interested in the PNG
592 24 : aStream.Write(aStruct.pBuf + nHeaderSize, aStruct.nPropSize - nHeaderSize);
593 24 : aStream.Seek(0);
594 48 : Graphic aGraphic;
595 24 : GraphicConverter::Import(aStream, aGraphic);
596 48 : OUString aImageId = m_pTextExport->GetDrawingML().WriteImage( aGraphic );
597 24 : pAttrList->add(FSNS(XML_r, XML_id), OUStringToOString(aImageId, RTL_TEXTENCODING_UTF8));
598 48 : imageData = true;
599 : }
600 :
601 293 : if ( rProps.GetOpt( ESCHER_Prop_fNoFillHitTest, nValue ) )
602 293 : impl_AddBool( pAttrList, FSNS(XML_o, XML_detectmouseclick), nValue != 0 );
603 :
604 293 : if (rProps.GetOpt(ESCHER_Prop_fillOpacity, nValue))
605 : // Partly undo the transformation at the end of EscherPropertyContainer::CreateFillProperties(): VML opacity is 0..1.
606 2 : pAttrList->add(XML_opacity, OString::number(double((nValue * 100) >> 16) / 100));
607 :
608 293 : if (imageData)
609 24 : m_pSerializer->singleElementNS( XML_v, XML_imagedata, XFastAttributeListRef( pAttrList ) );
610 : else
611 269 : m_pSerializer->singleElementNS( XML_v, XML_fill, XFastAttributeListRef( pAttrList ) );
612 : }
613 293 : bAlreadyWritten[ ESCHER_Prop_fillType ] = true;
614 293 : bAlreadyWritten[ ESCHER_Prop_fillColor ] = true;
615 293 : bAlreadyWritten[ ESCHER_Prop_fillBackColor ] = true;
616 293 : bAlreadyWritten[ ESCHER_Prop_fillBlip ] = true;
617 293 : bAlreadyWritten[ ESCHER_Prop_fNoFillHitTest ] = true;
618 293 : bAlreadyWritten[ ESCHER_Prop_fillOpacity ] = true;
619 293 : break;
620 :
621 : case ESCHER_Prop_lineColor: // 448
622 : case ESCHER_Prop_lineWidth: // 459
623 : case ESCHER_Prop_lineDashing: // 462
624 : case ESCHER_Prop_lineStartArrowhead: // 464
625 : case ESCHER_Prop_lineEndArrowhead: // 465
626 : case ESCHER_Prop_lineStartArrowWidth: // 466
627 : case ESCHER_Prop_lineStartArrowLength: // 467
628 : case ESCHER_Prop_lineEndArrowWidth: // 468
629 : case ESCHER_Prop_lineEndArrowLength: // 469
630 : case ESCHER_Prop_lineJoinStyle: // 470
631 : case ESCHER_Prop_lineEndCapStyle: // 471
632 : {
633 : sal_uInt32 nValue;
634 293 : sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
635 :
636 293 : if ( rProps.GetOpt( ESCHER_Prop_lineColor, nValue ) )
637 293 : impl_AddColor( pAttrList, XML_color, nValue );
638 :
639 293 : if ( rProps.GetOpt( ESCHER_Prop_lineWidth, nValue ) )
640 73 : impl_AddInt( pAttrList, XML_weight, nValue );
641 :
642 293 : if ( rProps.GetOpt( ESCHER_Prop_lineDashing, nValue ) )
643 : {
644 4 : const char *pDashStyle = NULL;
645 4 : switch ( nValue )
646 : {
647 0 : case ESCHER_LineSolid: pDashStyle = "solid"; break;
648 0 : case ESCHER_LineDashSys: pDashStyle = "shortdash"; break;
649 0 : case ESCHER_LineDotSys: pDashStyle = "shortdot"; break;
650 0 : case ESCHER_LineDashDotSys: pDashStyle = "shortdashdot"; break;
651 0 : case ESCHER_LineDashDotDotSys: pDashStyle = "shortdashdotdot"; break;
652 0 : case ESCHER_LineDotGEL: pDashStyle = "dot"; break;
653 2 : case ESCHER_LineDashGEL: pDashStyle = "dash"; break;
654 2 : case ESCHER_LineLongDashGEL: pDashStyle = "longdash"; break;
655 0 : case ESCHER_LineDashDotGEL: pDashStyle = "dashdot"; break;
656 0 : case ESCHER_LineLongDashDotGEL: pDashStyle = "longdashdot"; break;
657 0 : case ESCHER_LineLongDashDotDotGEL: pDashStyle = "longdashdotdot"; break;
658 : }
659 4 : if ( pDashStyle )
660 4 : pAttrList->add( XML_dashstyle, pDashStyle );
661 : }
662 :
663 293 : if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowhead, nValue ) )
664 6 : impl_AddArrowHead( pAttrList, XML_startarrow, nValue );
665 :
666 293 : if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowhead, nValue ) )
667 18 : impl_AddArrowHead( pAttrList, XML_endarrow, nValue );
668 :
669 293 : if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowWidth, nValue ) )
670 6 : impl_AddArrowWidth( pAttrList, XML_startarrowwidth, nValue );
671 :
672 293 : if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowLength, nValue ) )
673 6 : impl_AddArrowLength( pAttrList, XML_startarrowlength, nValue );
674 :
675 293 : if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowWidth, nValue ) )
676 18 : impl_AddArrowWidth( pAttrList, XML_endarrowwidth, nValue );
677 :
678 293 : if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowLength, nValue ) )
679 18 : impl_AddArrowLength( pAttrList, XML_endarrowlength, nValue );
680 :
681 293 : if ( rProps.GetOpt( ESCHER_Prop_lineJoinStyle, nValue ) )
682 : {
683 293 : const char *pJoinStyle = NULL;
684 293 : switch ( nValue )
685 : {
686 42 : case ESCHER_LineJoinBevel: pJoinStyle = "bevel"; break;
687 23 : case ESCHER_LineJoinMiter: pJoinStyle = "miter"; break;
688 228 : case ESCHER_LineJoinRound: pJoinStyle = "round"; break;
689 : }
690 293 : if ( pJoinStyle )
691 293 : pAttrList->add( XML_joinstyle, pJoinStyle );
692 : }
693 :
694 293 : if ( rProps.GetOpt( ESCHER_Prop_lineEndCapStyle, nValue ) )
695 : {
696 293 : const char *pEndCap = NULL;
697 293 : switch ( nValue )
698 : {
699 2 : case ESCHER_LineEndCapRound: pEndCap = "round"; break;
700 5 : case ESCHER_LineEndCapSquare: pEndCap = "square"; break;
701 286 : case ESCHER_LineEndCapFlat: pEndCap = "flat"; break;
702 : }
703 293 : if ( pEndCap )
704 293 : pAttrList->add( XML_endcap, pEndCap );
705 : }
706 :
707 293 : m_pSerializer->singleElementNS( XML_v, XML_stroke, XFastAttributeListRef( pAttrList ) );
708 : }
709 293 : bAlreadyWritten[ ESCHER_Prop_lineColor ] = true;
710 293 : bAlreadyWritten[ ESCHER_Prop_lineWidth ] = true;
711 293 : bAlreadyWritten[ ESCHER_Prop_lineDashing ] = true;
712 293 : bAlreadyWritten[ ESCHER_Prop_lineStartArrowhead ] = true;
713 293 : bAlreadyWritten[ ESCHER_Prop_lineEndArrowhead ] = true;
714 293 : bAlreadyWritten[ ESCHER_Prop_lineStartArrowWidth ] = true;
715 293 : bAlreadyWritten[ ESCHER_Prop_lineStartArrowLength ] = true;
716 293 : bAlreadyWritten[ ESCHER_Prop_lineEndArrowWidth ] = true;
717 293 : bAlreadyWritten[ ESCHER_Prop_lineEndArrowLength ] = true;
718 293 : bAlreadyWritten[ ESCHER_Prop_lineJoinStyle ] = true;
719 293 : bAlreadyWritten[ ESCHER_Prop_lineEndCapStyle ] = true;
720 293 : break;
721 :
722 : case ESCHER_Prop_fHidden:
723 0 : if ( !it->nPropValue )
724 0 : m_pShapeStyle->append( ";visibility:hidden" );
725 0 : break;
726 : case ESCHER_Prop_shadowColor:
727 : case ESCHER_Prop_fshadowObscured:
728 : {
729 293 : sal_uInt32 nValue = 0;
730 293 : bool bShadow = false;
731 293 : bool bObscured = false;
732 293 : if ( rProps.GetOpt( ESCHER_Prop_fshadowObscured, nValue ) )
733 : {
734 293 : bShadow = (( nValue & 0x20002 ) == 0x20002 );
735 293 : bObscured = (( nValue & 0x10001 ) == 0x10001 );
736 : }
737 293 : if ( bShadow )
738 : {
739 2 : sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
740 2 : impl_AddBool( pAttrList, XML_on, bShadow );
741 2 : impl_AddBool( pAttrList, XML_obscured, bObscured );
742 :
743 2 : if ( rProps.GetOpt( ESCHER_Prop_shadowColor, nValue ) )
744 2 : impl_AddColor( pAttrList, XML_color, nValue );
745 :
746 2 : m_pSerializer->singleElementNS( XML_v, XML_shadow, XFastAttributeListRef( pAttrList ) );
747 2 : bAlreadyWritten[ ESCHER_Prop_fshadowObscured ] = true;
748 2 : bAlreadyWritten[ ESCHER_Prop_shadowColor ] = true;
749 : }
750 : }
751 293 : break;
752 : case ESCHER_Prop_gtextUNICODE:
753 : case ESCHER_Prop_gtextFont:
754 : {
755 : EscherPropSortStruct aUnicode;
756 3 : if (rProps.GetOpt(ESCHER_Prop_gtextUNICODE, aUnicode))
757 : {
758 3 : SvMemoryStream aStream;
759 3 : aStream.Write(it->pBuf, it->nPropSize);
760 3 : aStream.Seek(0);
761 6 : OUString aTextPathString = SvxMSDffManager::MSDFFReadZString(aStream, it->nPropSize, true);
762 3 : aStream.Seek(0);
763 :
764 : m_pSerializer->singleElementNS( XML_v, XML_path,
765 : XML_textpathok, "t",
766 3 : FSEND );
767 :
768 3 : sax_fastparser::FastAttributeList* pAttrList = m_pSerializer->createAttrList();
769 3 : pAttrList->add(XML_on, "t");
770 3 : pAttrList->add(XML_fitshape, "t");
771 3 : pAttrList->add(XML_string, OUStringToOString(aTextPathString, RTL_TEXTENCODING_UTF8));
772 : EscherPropSortStruct aFont;
773 6 : OUString aStyle;
774 3 : if (rProps.GetOpt(ESCHER_Prop_gtextFont, aFont))
775 : {
776 3 : aStream.Write(aFont.pBuf, aFont.nPropSize);
777 3 : aStream.Seek(0);
778 3 : OUString aTextPathFont = SvxMSDffManager::MSDFFReadZString(aStream, aFont.nPropSize, true);
779 3 : aStyle += "font-family:\"" + aTextPathFont + "\"";
780 : }
781 3 : if (!aStyle.isEmpty())
782 3 : pAttrList->add(XML_style, OUStringToOString(aStyle, RTL_TEXTENCODING_UTF8));
783 6 : m_pSerializer->singleElementNS(XML_v, XML_textpath, XFastAttributeListRef(pAttrList));
784 : }
785 :
786 3 : bAlreadyWritten[ESCHER_Prop_gtextUNICODE] = true;
787 3 : bAlreadyWritten[ESCHER_Prop_gtextFont] = true;
788 : }
789 3 : break;
790 : case ESCHER_Prop_Rotation:
791 : {
792 : // The higher half of the variable contains the angle.
793 34 : m_pShapeStyle->append(";rotation:").append(double(it->nPropValue >> 16));
794 34 : bAlreadyWritten[ESCHER_Prop_Rotation] = true;
795 : }
796 34 : break;
797 : case ESCHER_Prop_fNoLineDrawDash:
798 : {
799 : // See DffPropertyReader::ApplyLineAttributes().
800 293 : impl_AddBool( m_pShapeAttrList, XML_stroked, (it->nPropValue & 8) != 0 );
801 293 : bAlreadyWritten[ESCHER_Prop_fNoLineDrawDash] = true;
802 : }
803 293 : break;
804 : case ESCHER_Prop_wzName:
805 : {
806 217 : SvMemoryStream aStream;
807 217 : aStream.Write(it->pBuf, it->nPropSize);
808 217 : aStream.Seek(0);
809 434 : OUString idStr = SvxMSDffManager::MSDFFReadZString(aStream, it->nPropSize, true);
810 217 : aStream.Seek(0);
811 217 : if (!IsWaterMarkShape(m_pSdrObject->GetName()))
812 213 : m_pShapeAttrList->add(XML_ID, OUStringToOString(idStr, RTL_TEXTENCODING_UTF8));
813 :
814 434 : bAlreadyWritten[ESCHER_Prop_wzName] = true;
815 : }
816 217 : break;
817 : default:
818 : #if OSL_DEBUG_LEVEL > 0
819 : fprintf( stderr, "TODO VMLExport::Commit(), unimplemented id: %d, value: %" SAL_PRIuUINT32 ", data: [%" SAL_PRIuUINT32 ", %p]\n",
820 : nId, it->nPropValue, it->nPropSize, it->pBuf );
821 : if ( it->nPropSize )
822 : {
823 : const sal_uInt8 *pIt = it->pBuf;
824 : fprintf( stderr, " ( " );
825 : for ( int nCount = it->nPropSize; nCount; --nCount )
826 : {
827 : fprintf( stderr, "%02x ", *pIt );
828 : ++pIt;
829 : }
830 : fprintf( stderr, ")\n" );
831 : }
832 : #endif
833 1522 : break;
834 : }
835 : }
836 :
837 293 : m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_POSTPONE );
838 : }
839 :
840 384 : OString VMLExport::ShapeIdString( sal_uInt32 nId )
841 : {
842 384 : return OStringBuffer( 20 ).append( "shape_" ).append( sal_Int64( nId ) ).makeStringAndClear();
843 : }
844 :
845 314 : void VMLExport::AddFlipXY( )
846 : {
847 314 : const sal_uInt32 nFlipHandV = SHAPEFLAG_FLIPH + SHAPEFLAG_FLIPV;
848 314 : switch ( m_nShapeFlags & nFlipHandV )
849 : {
850 1 : case SHAPEFLAG_FLIPH: m_pShapeStyle->append( ";flip:x" ); break;
851 24 : case SHAPEFLAG_FLIPV: m_pShapeStyle->append( ";flip:y" ); break;
852 2 : case (nFlipHandV): m_pShapeStyle->append( ";flip:xy" ); break;
853 : }
854 314 : }
855 :
856 4 : void VMLExport::AddLineDimensions( const Rectangle& rRectangle )
857 : {
858 : // style
859 4 : if ( !m_pShapeStyle->isEmpty() )
860 0 : m_pShapeStyle->append( ";" );
861 :
862 4 : m_pShapeStyle->append( "position:absolute" );
863 :
864 4 : AddFlipXY();
865 :
866 : // the actual dimensions
867 8 : OString aLeft, aTop, aRight, aBottom;
868 :
869 4 : if ( mnGroupLevel == 1 )
870 : {
871 4 : const OString aPt( "pt" );
872 4 : aLeft = OString::number( double( rRectangle.Left() ) / 20 ) + aPt;
873 4 : aTop = OString::number( double( rRectangle.Top() ) / 20 ) + aPt;
874 4 : aRight = OString::number( double( rRectangle.Right() ) / 20 ) + aPt;
875 4 : aBottom = OString::number( double( rRectangle.Bottom() ) / 20 ) + aPt;
876 : }
877 : else
878 : {
879 0 : aLeft = OString::number( rRectangle.Left() );
880 0 : aTop = OString::number( rRectangle.Top() );
881 0 : aRight = OString::number( rRectangle.Right() );
882 0 : aBottom = OString::number( rRectangle.Bottom() );
883 : }
884 :
885 : m_pShapeAttrList->add( XML_from,
886 8 : OStringBuffer( 20 ).append( aLeft )
887 4 : .append( "," ).append( aTop )
888 4 : .makeStringAndClear() );
889 :
890 : m_pShapeAttrList->add( XML_to,
891 8 : OStringBuffer( 20 ).append( aRight )
892 4 : .append( "," ).append( aBottom )
893 8 : .makeStringAndClear() );
894 4 : }
895 :
896 310 : void VMLExport::AddRectangleDimensions( OStringBuffer& rBuffer, const Rectangle& rRectangle, bool rbAbsolutePos)
897 : {
898 310 : if ( !rBuffer.isEmpty() )
899 0 : rBuffer.append( ";" );
900 :
901 310 : if (rbAbsolutePos)
902 : {
903 306 : rBuffer.append( "position:absolute;" );
904 : }
905 :
906 310 : if ( mnGroupLevel == 1 )
907 : {
908 126 : rBuffer.append( "margin-left:" ).append( double( rRectangle.Left() ) / 20 )
909 252 : .append( "pt;margin-top:" ).append( double( rRectangle.Top() ) / 20 )
910 252 : .append( "pt;width:" ).append( double( rRectangle.Right() - rRectangle.Left() ) / 20 )
911 252 : .append( "pt;height:" ).append( double( rRectangle.Bottom() - rRectangle.Top() ) / 20 )
912 126 : .append( "pt" );
913 : }
914 : else
915 : {
916 184 : rBuffer.append( "left:" ).append( rRectangle.Left() )
917 368 : .append( ";top:" ).append( rRectangle.Top() )
918 368 : .append( ";width:" ).append( rRectangle.Right() - rRectangle.Left() )
919 368 : .append( ";height:" ).append( rRectangle.Bottom() - rRectangle.Top() );
920 : }
921 :
922 310 : AddFlipXY();
923 310 : }
924 :
925 0 : void VMLExport::AddShapeAttribute( sal_Int32 nAttribute, const OString& rValue )
926 : {
927 0 : m_pShapeAttrList->add( nAttribute, rValue );
928 0 : }
929 :
930 : extern const char* pShapeTypes[];
931 :
932 367 : sal_Int32 VMLExport::StartShape()
933 : {
934 367 : if ( m_nShapeType == ESCHER_ShpInst_Nil )
935 74 : return -1;
936 :
937 : // some of the shapes have their own name ;-)
938 293 : sal_Int32 nShapeElement = -1;
939 293 : bool bReferToShapeType = false;
940 293 : switch ( m_nShapeType )
941 : {
942 76 : case ESCHER_ShpInst_NotPrimitive: nShapeElement = XML_shape; break;
943 24 : case ESCHER_ShpInst_Rectangle: nShapeElement = XML_rect; break;
944 0 : case ESCHER_ShpInst_RoundRectangle: nShapeElement = XML_roundrect; break;
945 2 : case ESCHER_ShpInst_Ellipse: nShapeElement = XML_oval; break;
946 0 : case ESCHER_ShpInst_Arc: nShapeElement = XML_arc; break;
947 4 : case ESCHER_ShpInst_Line: nShapeElement = XML_line; break;
948 : default:
949 187 : if ( m_nShapeType < ESCHER_ShpInst_COUNT )
950 : {
951 187 : nShapeElement = XML_shape;
952 :
953 : // a predefined shape?
954 187 : const char* pShapeType = pShapeTypes[ m_nShapeType ];
955 187 : if ( pShapeType )
956 : {
957 159 : bReferToShapeType = true;
958 159 : if ( !m_pShapeTypeWritten[ m_nShapeType ] )
959 : {
960 21 : m_pSerializer->write( pShapeType );
961 21 : m_pShapeTypeWritten[ m_nShapeType ] = true;
962 : }
963 : }
964 : else
965 : {
966 : // rectangle is probably the best fallback...
967 28 : nShapeElement = XML_rect;
968 : }
969 : }
970 187 : break;
971 : }
972 :
973 : // anchoring
974 293 : switch (m_eHOri)
975 : {
976 : case text::HoriOrientation::LEFT:
977 0 : m_pShapeStyle->append(";mso-position-horizontal:left");
978 0 : break;
979 : case text::HoriOrientation::CENTER:
980 4 : m_pShapeStyle->append(";mso-position-horizontal:center");
981 4 : break;
982 : case text::HoriOrientation::RIGHT:
983 0 : m_pShapeStyle->append(";mso-position-horizontal:right");
984 0 : break;
985 : case text::HoriOrientation::INSIDE:
986 0 : m_pShapeStyle->append(";mso-position-horizontal:inside");
987 0 : break;
988 : case text::HoriOrientation::OUTSIDE:
989 0 : m_pShapeStyle->append(";mso-position-horizontal:outside");
990 0 : break;
991 : default:
992 : case text::HoriOrientation::NONE:
993 289 : break;
994 : }
995 293 : switch (m_eHRel)
996 : {
997 : case text::RelOrientation::PAGE_PRINT_AREA:
998 0 : m_pShapeStyle->append(";mso-position-horizontal-relative:margin");
999 0 : break;
1000 : case text::RelOrientation::PAGE_FRAME:
1001 : case text::RelOrientation::PAGE_LEFT:
1002 : case text::RelOrientation::PAGE_RIGHT:
1003 0 : m_pShapeStyle->append(";mso-position-horizontal-relative:page");
1004 0 : break;
1005 : case text::RelOrientation::CHAR:
1006 0 : m_pShapeStyle->append(";mso-position-horizontal-relative:char");
1007 0 : break;
1008 : default:
1009 293 : break;
1010 : }
1011 :
1012 293 : switch (m_eVOri)
1013 : {
1014 : case text::VertOrientation::TOP:
1015 : case text::VertOrientation::LINE_TOP:
1016 : case text::VertOrientation::CHAR_TOP:
1017 0 : m_pShapeStyle->append(";mso-position-vertical:top");
1018 0 : break;
1019 : case text::VertOrientation::CENTER:
1020 : case text::VertOrientation::LINE_CENTER:
1021 4 : m_pShapeStyle->append(";mso-position-vertical:center");
1022 4 : break;
1023 : case text::VertOrientation::BOTTOM:
1024 : case text::VertOrientation::LINE_BOTTOM:
1025 : case text::VertOrientation::CHAR_BOTTOM:
1026 0 : m_pShapeStyle->append(";mso-position-vertical:bottom");
1027 0 : break;
1028 : default:
1029 : case text::VertOrientation::NONE:
1030 289 : break;
1031 : }
1032 293 : switch (m_eVRel)
1033 : {
1034 : case text::RelOrientation::PAGE_PRINT_AREA:
1035 4 : m_pShapeStyle->append(";mso-position-vertical-relative:margin");
1036 4 : break;
1037 : case text::RelOrientation::PAGE_FRAME:
1038 0 : m_pShapeStyle->append(";mso-position-vertical-relative:page");
1039 0 : break;
1040 : default:
1041 289 : break;
1042 : }
1043 :
1044 : // add style
1045 293 : m_pShapeAttrList->add( XML_style, m_pShapeStyle->makeStringAndClear() );
1046 :
1047 293 : if ( nShapeElement >= 0 && !m_pShapeAttrList->hasAttribute( XML_type ) )
1048 : {
1049 293 : if ( bReferToShapeType )
1050 : {
1051 : m_pShapeAttrList->add( XML_type, OStringBuffer( 20 )
1052 318 : .append( "shapetype_" ).append( sal_Int32( m_nShapeType ) )
1053 159 : .makeStringAndClear() );
1054 : }
1055 :
1056 : // start of the shape
1057 293 : m_pSerializer->startElementNS( XML_v, nShapeElement, XFastAttributeListRef( m_pShapeAttrList ) );
1058 : }
1059 : else
1060 : {
1061 : // start of the shape
1062 0 : m_pSerializer->startElementNS( XML_v, nShapeElement, XFastAttributeListRef( m_pShapeAttrList ) );
1063 : }
1064 :
1065 : // now check if we have some text and we have a text exporter registered
1066 293 : const SdrTextObj* pTxtObj = PTR_CAST(SdrTextObj, m_pSdrObject);
1067 293 : if (pTxtObj && m_pTextExport && m_nShapeType != ESCHER_ShpInst_TextPlainText)
1068 : {
1069 291 : const OutlinerParaObject* pParaObj = 0;
1070 291 : bool bOwnParaObj = false;
1071 :
1072 : /*
1073 : #i13885#
1074 : When the object is actively being edited, that text is not set into
1075 : the objects normal text object, but lives in a separate object.
1076 : */
1077 291 : if (pTxtObj->IsTextEditActive())
1078 : {
1079 0 : pParaObj = pTxtObj->GetEditOutlinerParaObject();
1080 0 : bOwnParaObj = true;
1081 : }
1082 : else
1083 : {
1084 291 : pParaObj = pTxtObj->GetOutlinerParaObject();
1085 : }
1086 :
1087 291 : if( pParaObj )
1088 : {
1089 : // this is reached only in case some text is attached to the shape
1090 87 : m_pSerializer->startElementNS(XML_v, XML_textbox, FSEND);
1091 87 : m_pTextExport->WriteOutliner(*pParaObj);
1092 87 : m_pSerializer->endElementNS(XML_v, XML_textbox);
1093 87 : if( bOwnParaObj )
1094 0 : delete pParaObj;
1095 : }
1096 : }
1097 :
1098 293 : return nShapeElement;
1099 : }
1100 :
1101 367 : void VMLExport::EndShape( sal_Int32 nShapeElement )
1102 : {
1103 367 : if ( nShapeElement >= 0 )
1104 : {
1105 : // end of the shape
1106 293 : m_pSerializer->endElementNS( XML_v, nShapeElement );
1107 : }
1108 367 : }
1109 :
1110 162 : 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 )
1111 : {
1112 162 : m_pSdrObject = &rObj;
1113 162 : m_eHOri = eHOri;
1114 162 : m_eVOri = eVOri;
1115 162 : m_eHRel = eHRel;
1116 162 : m_eVRel = eVRel;
1117 162 : m_pNdTopLeft = pNdTopLeft;
1118 162 : return EscherEx::AddSdrObject(rObj, bOOxmlExport);
1119 177 : }
1120 :
1121 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|