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 :
31 : #include <cstdio>
32 :
33 : using rtl::OString;
34 : using rtl::OStringBuffer;
35 : using rtl::OUString;
36 : using rtl::OUStringBuffer;
37 :
38 : using namespace sax_fastparser;
39 : using namespace oox::vml;
40 :
41 48 : VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr pSerializer, VMLTextExport* pTextExport )
42 48 : : EscherEx( EscherExGlobalRef(new EscherExGlobal(0)), 0 ),
43 : m_pSerializer( pSerializer ),
44 : m_pTextExport( pTextExport ),
45 : m_pSdrObject( 0 ),
46 : m_pShapeAttrList( NULL ),
47 : m_nShapeType( ESCHER_ShpInst_Nil ),
48 48 : m_pShapeStyle( new OStringBuffer( 200 ) ),
49 144 : m_pShapeTypeWritten( new bool[ ESCHER_ShpInst_COUNT ] )
50 : {
51 48 : mnGroupLevel = 1;
52 48 : memset( m_pShapeTypeWritten, 0, ESCHER_ShpInst_COUNT * sizeof( bool ) );
53 48 : }
54 :
55 144 : VMLExport::~VMLExport()
56 : {
57 48 : delete mpOutStrm, mpOutStrm = NULL;
58 48 : delete m_pShapeStyle, m_pShapeStyle = NULL;
59 48 : delete[] m_pShapeTypeWritten, m_pShapeTypeWritten = NULL;
60 96 : }
61 :
62 0 : void VMLExport::OpenContainer( sal_uInt16 nEscherContainer, int nRecInstance )
63 : {
64 0 : EscherEx::OpenContainer( nEscherContainer, nRecInstance );
65 :
66 0 : if ( nEscherContainer == ESCHER_SpContainer )
67 : {
68 : // opening a shape container
69 : #if OSL_DEBUG_LEVEL > 0
70 : if ( m_nShapeType != ESCHER_ShpInst_Nil )
71 : fprintf( stderr, "Warning! VMLExport::OpenContainer(): opening shape inside a shape.\n" );
72 : #endif
73 0 : m_nShapeType = ESCHER_ShpInst_Nil;
74 0 : m_pShapeAttrList = m_pSerializer->createAttrList();
75 :
76 0 : if ( m_pShapeStyle->getLength() )
77 0 : m_pShapeStyle->makeStringAndClear();
78 :
79 0 : m_pShapeStyle->ensureCapacity( 200 );
80 :
81 : // postpone the output so that we are able to write even the elements
82 : // that we learn inside Commit()
83 0 : m_pSerializer->mark();
84 : }
85 0 : }
86 :
87 0 : void VMLExport::CloseContainer()
88 : {
89 0 : if ( mRecTypes.back() == ESCHER_SpContainer )
90 : {
91 : // write the shape now when we have all the info
92 0 : sal_Int32 nShapeElement = StartShape();
93 :
94 0 : m_pSerializer->mergeTopMarks();
95 :
96 0 : EndShape( nShapeElement );
97 :
98 : // cleanup
99 0 : m_nShapeType = ESCHER_ShpInst_Nil;
100 0 : m_pShapeAttrList = NULL;
101 : }
102 :
103 0 : EscherEx::CloseContainer();
104 0 : }
105 :
106 0 : sal_uInt32 VMLExport::EnterGroup( const String& rShapeName, const Rectangle* pRect )
107 : {
108 0 : sal_uInt32 nShapeId = GenerateShapeId();
109 :
110 0 : OStringBuffer aStyle( 200 );
111 0 : FastAttributeList *pAttrList = m_pSerializer->createAttrList();
112 :
113 0 : pAttrList->add( XML_id, ShapeIdString( nShapeId ) );
114 :
115 0 : if ( rShapeName.Len() )
116 0 : pAttrList->add( XML_alt, OUStringToOString( OUString( rShapeName ), RTL_TEXTENCODING_UTF8 ) );
117 :
118 : // style
119 0 : if ( pRect )
120 0 : AddRectangleDimensions( aStyle, *pRect );
121 :
122 0 : if ( aStyle.getLength() )
123 0 : pAttrList->add( XML_style, aStyle.makeStringAndClear() );
124 :
125 : // coordorigin/coordsize
126 0 : if ( pRect && ( mnGroupLevel == 1 ) )
127 : {
128 : pAttrList->add( XML_coordorigin,
129 0 : OStringBuffer( 20 ).append( sal_Int32( pRect->Left() ) )
130 0 : .append( "," ).append( sal_Int32( pRect->Top() ) )
131 0 : .makeStringAndClear() );
132 :
133 : pAttrList->add( XML_coordsize,
134 0 : OStringBuffer( 20 ).append( sal_Int32( pRect->Right() ) - sal_Int32( pRect->Left() ) )
135 0 : .append( "," ).append( sal_Int32( pRect->Bottom() ) - sal_Int32( pRect->Top() ) )
136 0 : .makeStringAndClear() );
137 : }
138 :
139 0 : m_pSerializer->startElementNS( XML_v, XML_group, XFastAttributeListRef( pAttrList ) );
140 :
141 0 : mnGroupLevel++;
142 0 : return nShapeId;
143 : }
144 :
145 0 : void VMLExport::LeaveGroup()
146 : {
147 0 : --mnGroupLevel;
148 0 : m_pSerializer->endElementNS( XML_v, XML_group );
149 0 : }
150 :
151 0 : void VMLExport::AddShape( sal_uInt32 nShapeType, sal_uInt32 nShapeFlags, sal_uInt32 nShapeId )
152 : {
153 0 : m_nShapeType = nShapeType;
154 0 : m_nShapeFlags = nShapeFlags;
155 :
156 0 : m_pShapeAttrList->add( XML_id, ShapeIdString( nShapeId ) );
157 0 : }
158 :
159 0 : static void impl_AddArrowHead( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
160 : {
161 0 : if ( !pAttrList )
162 0 : return;
163 :
164 0 : const char *pArrowHead = NULL;
165 0 : switch ( nValue )
166 : {
167 0 : case ESCHER_LineNoEnd: pArrowHead = "none"; break;
168 0 : case ESCHER_LineArrowEnd: pArrowHead = "block"; break;
169 0 : case ESCHER_LineArrowStealthEnd: pArrowHead = "classic"; break;
170 0 : case ESCHER_LineArrowDiamondEnd: pArrowHead = "diamond"; break;
171 0 : case ESCHER_LineArrowOvalEnd: pArrowHead = "oval"; break;
172 0 : case ESCHER_LineArrowOpenEnd: pArrowHead = "open"; break;
173 : }
174 :
175 0 : if ( pArrowHead )
176 0 : pAttrList->add( nElement, pArrowHead );
177 : }
178 :
179 0 : static void impl_AddArrowLength( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
180 : {
181 0 : if ( !pAttrList )
182 0 : return;
183 :
184 0 : const char *pArrowLength = NULL;
185 0 : switch ( nValue )
186 : {
187 0 : case ESCHER_LineShortArrow: pArrowLength = "short"; break;
188 0 : case ESCHER_LineMediumLenArrow: pArrowLength = "medium"; break;
189 0 : case ESCHER_LineLongArrow: pArrowLength = "long"; break;
190 : }
191 :
192 0 : if ( pArrowLength )
193 0 : pAttrList->add( nElement, pArrowLength );
194 : }
195 :
196 0 : static void impl_AddArrowWidth( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
197 : {
198 0 : if ( !pAttrList )
199 0 : return;
200 :
201 0 : const char *pArrowWidth = NULL;
202 0 : switch ( nValue )
203 : {
204 0 : case ESCHER_LineNarrowArrow: pArrowWidth = "narrow"; break;
205 0 : case ESCHER_LineMediumWidthArrow: pArrowWidth = "medium"; break;
206 0 : case ESCHER_LineWideArrow: pArrowWidth = "wide"; break;
207 : }
208 :
209 0 : if ( pArrowWidth )
210 0 : pAttrList->add( nElement, pArrowWidth );
211 : }
212 :
213 0 : static void impl_AddBool( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, bool bValue )
214 : {
215 0 : if ( !pAttrList )
216 0 : return;
217 :
218 0 : pAttrList->add( nElement, bValue? "t": "f" );
219 : }
220 :
221 0 : static void impl_AddColor( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nColor )
222 : {
223 : #if OSL_DEBUG_LEVEL > 0
224 : if ( nColor & 0xFF000000 )
225 : fprintf( stderr, "TODO: this is not a RGB value!\n" );
226 : #endif
227 :
228 0 : if ( !pAttrList || ( nColor & 0xFF000000 ) )
229 0 : return;
230 :
231 0 : nColor = ( ( nColor & 0xFF ) << 16 ) + ( nColor & 0xFF00 ) + ( ( nColor & 0xFF0000 ) >> 16 );
232 :
233 0 : const char *pColor = NULL;
234 : char pRgbColor[10];
235 0 : switch ( nColor )
236 : {
237 0 : case 0x000000: pColor = "black"; break;
238 0 : case 0xC0C0C0: pColor = "silver"; break;
239 0 : case 0x808080: pColor = "gray"; break;
240 0 : case 0xFFFFFF: pColor = "white"; break;
241 0 : case 0x800000: pColor = "maroon"; break;
242 0 : case 0xFF0000: pColor = "red"; break;
243 0 : case 0x800080: pColor = "purple"; break;
244 0 : case 0xFF00FF: pColor = "fuchsia"; break;
245 0 : case 0x008000: pColor = "green"; break;
246 0 : case 0x00FF00: pColor = "lime"; break;
247 0 : case 0x808000: pColor = "olive"; break;
248 0 : case 0xFFFF00: pColor = "yellow"; break;
249 0 : case 0x000080: pColor = "navy"; break;
250 0 : case 0x0000FF: pColor = "blue"; break;
251 0 : case 0x008080: pColor = "teal"; break;
252 0 : case 0x00FFFF: pColor = "aqua"; break;
253 : default:
254 : {
255 0 : snprintf( pRgbColor, sizeof( pRgbColor ), "#%06x", static_cast< unsigned int >( nColor ) ); // not too handy to use OString::valueOf() here :-(
256 0 : pColor = pRgbColor;
257 : }
258 0 : break;
259 : }
260 :
261 0 : pAttrList->add( nElement, pColor );
262 : }
263 :
264 0 : static void impl_AddInt( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
265 : {
266 0 : if ( !pAttrList )
267 0 : return;
268 :
269 0 : pAttrList->add( nElement, OString::valueOf( static_cast< sal_Int32 >( nValue ) ).getStr() );
270 : }
271 :
272 0 : inline sal_uInt16 impl_GetUInt16( const sal_uInt8* &pVal )
273 : {
274 0 : sal_uInt16 nRet = *pVal++;
275 0 : nRet += ( *pVal++ ) << 8;
276 0 : return nRet;
277 : }
278 :
279 0 : inline sal_Int32 impl_GetPointComponent( const sal_uInt8* &pVal, sal_uInt16 nPointSize )
280 : {
281 0 : sal_Int32 nRet = 0;
282 0 : if ( ( nPointSize == 0xfff0 ) || ( nPointSize == 4 ) )
283 : {
284 0 : sal_uInt16 nUnsigned = *pVal++;
285 0 : nUnsigned += ( *pVal++ ) << 8;
286 :
287 0 : nRet = sal_Int16( nUnsigned );
288 : }
289 0 : else if ( nPointSize == 8 )
290 : {
291 0 : sal_uInt32 nUnsigned = *pVal++;
292 0 : nUnsigned += ( *pVal++ ) << 8;
293 0 : nUnsigned += ( *pVal++ ) << 16;
294 0 : nUnsigned += ( *pVal++ ) << 24;
295 :
296 0 : nRet = nUnsigned;
297 : }
298 :
299 0 : return nRet;
300 : }
301 :
302 0 : void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect )
303 : {
304 0 : if ( m_nShapeType == ESCHER_ShpInst_Nil )
305 0 : return;
306 :
307 : // postpone the output of the embedded elements so that they are written
308 : // inside the shapes
309 0 : m_pSerializer->mark();
310 :
311 : // dimensions
312 0 : if ( m_nShapeType == ESCHER_ShpInst_Line )
313 0 : AddLineDimensions( rRect );
314 : else
315 0 : AddRectangleDimensions( *m_pShapeStyle, rRect );
316 :
317 : // properties
318 : bool bAlreadyWritten[ 0xFFF ];
319 0 : memset( bAlreadyWritten, 0, sizeof( bAlreadyWritten ) );
320 0 : const EscherProperties &rOpts = rProps.GetOpts();
321 0 : for ( EscherProperties::const_iterator it = rOpts.begin(); it != rOpts.end(); ++it )
322 : {
323 0 : sal_uInt16 nId = ( it->nPropId & 0x0FFF );
324 :
325 0 : if ( bAlreadyWritten[ nId ] )
326 0 : continue;
327 :
328 0 : switch ( nId )
329 : {
330 : case ESCHER_Prop_WrapText: // 133
331 : {
332 0 : const char *pWrapType = NULL;
333 0 : switch ( it->nPropValue )
334 : {
335 : case ESCHER_WrapSquare:
336 0 : case ESCHER_WrapByPoints: pWrapType = "square"; break; // these two are equivalent according to the docu
337 0 : case ESCHER_WrapNone: pWrapType = "none"; break;
338 0 : case ESCHER_WrapTopBottom: pWrapType = "topAndBottom"; break;
339 0 : case ESCHER_WrapThrough: pWrapType = "through"; break;
340 : }
341 0 : if ( pWrapType )
342 : m_pSerializer->singleElementNS( XML_v, XML_wrap,
343 : FSNS( XML_v, XML_type ), pWrapType,
344 0 : FSEND );
345 : }
346 0 : bAlreadyWritten[ ESCHER_Prop_WrapText ] = true;
347 0 : break;
348 :
349 : // coordorigin
350 : case ESCHER_Prop_geoLeft: // 320
351 : case ESCHER_Prop_geoTop: // 321
352 : {
353 0 : sal_uInt32 nLeft = 0, nTop = 0;
354 :
355 0 : if ( nId == ESCHER_Prop_geoLeft )
356 : {
357 0 : nLeft = it->nPropValue;
358 0 : rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
359 : }
360 : else
361 : {
362 0 : nTop = it->nPropValue;
363 0 : rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
364 : }
365 :
366 : m_pShapeAttrList->add( XML_coordorigin,
367 0 : OStringBuffer( 20 ).append( sal_Int32( nLeft ) )
368 0 : .append( "," ).append( sal_Int32( nTop ) )
369 0 : .makeStringAndClear() );
370 : }
371 0 : bAlreadyWritten[ ESCHER_Prop_geoLeft ] = true;
372 0 : bAlreadyWritten[ ESCHER_Prop_geoTop ] = true;
373 0 : break;
374 :
375 : // coordsize
376 : case ESCHER_Prop_geoRight: // 322
377 : case ESCHER_Prop_geoBottom: // 323
378 : {
379 0 : sal_uInt32 nLeft = 0, nRight = 0, nTop = 0, nBottom = 0;
380 0 : rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
381 0 : rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
382 :
383 0 : if ( nId == ESCHER_Prop_geoRight )
384 : {
385 0 : nRight = it->nPropValue;
386 0 : rProps.GetOpt( ESCHER_Prop_geoBottom, nBottom );
387 : }
388 : else
389 : {
390 0 : nBottom = it->nPropValue;
391 0 : rProps.GetOpt( ESCHER_Prop_geoRight, nRight );
392 : }
393 :
394 : m_pShapeAttrList->add( XML_coordsize,
395 0 : OStringBuffer( 20 ).append( sal_Int32( nRight ) - sal_Int32( nLeft ) )
396 0 : .append( "," ).append( sal_Int32( nBottom ) - sal_Int32( nTop ) )
397 0 : .makeStringAndClear() );
398 : }
399 0 : bAlreadyWritten[ ESCHER_Prop_geoRight ] = true;
400 0 : bAlreadyWritten[ ESCHER_Prop_geoBottom ] = true;
401 0 : break;
402 :
403 : case ESCHER_Prop_pVertices: // 325
404 : case ESCHER_Prop_pSegmentInfo: // 326
405 : {
406 : EscherPropSortStruct aVertices;
407 : EscherPropSortStruct aSegments;
408 :
409 0 : if ( rProps.GetOpt( ESCHER_Prop_pVertices, aVertices ) &&
410 0 : rProps.GetOpt( ESCHER_Prop_pSegmentInfo, aSegments ) )
411 : {
412 0 : const sal_uInt8 *pVerticesIt = aVertices.pBuf + 6;
413 0 : const sal_uInt8 *pSegmentIt = aSegments.pBuf;
414 0 : OStringBuffer aPath( 512 );
415 :
416 0 : sal_uInt16 nPointSize = aVertices.pBuf[4] + ( aVertices.pBuf[5] << 8 );
417 :
418 : // number of segments
419 0 : sal_uInt16 nSegments = impl_GetUInt16( pSegmentIt );
420 0 : pSegmentIt += 4;
421 :
422 0 : for ( ; nSegments; --nSegments )
423 : {
424 0 : sal_uInt16 nSeg = impl_GetUInt16( pSegmentIt );
425 0 : switch ( nSeg )
426 : {
427 : case 0x4000: // moveto
428 : {
429 0 : sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
430 0 : sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
431 0 : aPath.append( "m" ).append( nX ).append( "," ).append( nY );
432 : }
433 0 : break;
434 : case 0xb300:
435 : case 0xac00:
436 0 : break;
437 : case 0x0001: // lineto
438 : {
439 0 : sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
440 0 : sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
441 0 : aPath.append( "l" ).append( nX ).append( "," ).append( nY );
442 : }
443 0 : break;
444 : case 0x2001: // curveto
445 : {
446 0 : sal_Int32 nX1 = impl_GetPointComponent( pVerticesIt, nPointSize );
447 0 : sal_Int32 nY1 = impl_GetPointComponent( pVerticesIt, nPointSize );
448 0 : sal_Int32 nX2 = impl_GetPointComponent( pVerticesIt, nPointSize );
449 0 : sal_Int32 nY2 = impl_GetPointComponent( pVerticesIt, nPointSize );
450 0 : sal_Int32 nX3 = impl_GetPointComponent( pVerticesIt, nPointSize );
451 0 : sal_Int32 nY3 = impl_GetPointComponent( pVerticesIt, nPointSize );
452 0 : aPath.append( "c" ).append( nX1 ).append( "," ).append( nY1 ).append( "," )
453 0 : .append( nX2 ).append( "," ).append( nY2 ).append( "," )
454 0 : .append( nX3 ).append( "," ).append( nY3 );
455 : }
456 0 : break;
457 : case 0xaa00: // nofill
458 0 : aPath.append( "nf" );
459 0 : break;
460 : case 0xab00: // nostroke
461 0 : aPath.append( "ns" );
462 0 : break;
463 : case 0x6001: // close
464 0 : aPath.append( "x" );
465 0 : break;
466 : case 0x8000: // end
467 0 : aPath.append( "e" );
468 0 : break;
469 : default:
470 : // See EscherPropertyContainer::CreateCustomShapeProperties, by default nSeg is simply the number of points.
471 0 : for (int i = 0; i < nSeg; ++i)
472 : {
473 0 : sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nPointSize);
474 0 : sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nPointSize);
475 0 : aPath.append("l").append(nX).append(",").append(nY);
476 : }
477 0 : break;
478 : }
479 : }
480 :
481 0 : if ( aPath.getLength() )
482 0 : m_pShapeAttrList->add( XML_path, aPath.getStr() );
483 : }
484 : #if OSL_DEBUG_LEVEL > 0
485 : else
486 : fprintf( stderr, "TODO: unhandled shape path, missing either pVertices or pSegmentInfo.\n" );
487 : #endif
488 : }
489 0 : bAlreadyWritten[ ESCHER_Prop_pVertices ] = true;
490 0 : bAlreadyWritten[ ESCHER_Prop_pSegmentInfo ] = true;
491 0 : break;
492 :
493 : case ESCHER_Prop_fillType: // 384
494 : case ESCHER_Prop_fillColor: // 385
495 : case ESCHER_Prop_fillBackColor: // 387
496 : case ESCHER_Prop_fillBlip: // 390
497 : case ESCHER_Prop_fNoFillHitTest: // 447
498 : {
499 : sal_uInt32 nValue;
500 0 : sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
501 :
502 0 : if ( rProps.GetOpt( ESCHER_Prop_fillType, nValue ) )
503 : {
504 0 : const char *pFillType = NULL;
505 0 : switch ( nValue )
506 : {
507 0 : case ESCHER_FillSolid: pFillType = "solid"; break;
508 : // TODO case ESCHER_FillPattern: pFillType = ""; break;
509 0 : case ESCHER_FillTexture: pFillType = "tile"; break;
510 : // TODO case ESCHER_FillPicture: pFillType = ""; break;
511 : // TODO case ESCHER_FillShade: pFillType = ""; break;
512 : // TODO case ESCHER_FillShadeCenter: pFillType = ""; break;
513 : // TODO case ESCHER_FillShadeShape: pFillType = ""; break;
514 : // TODO case ESCHER_FillShadeScale: pFillType = ""; break;
515 : // TODO case ESCHER_FillShadeTitle: pFillType = ""; break;
516 : // TODO case ESCHER_FillBackground: pFillType = ""; break;
517 : default:
518 : #if OSL_DEBUG_LEVEL > 0
519 : fprintf( stderr, "TODO: unhandled fill type\n" );
520 : #endif
521 0 : break;
522 : }
523 0 : if ( pFillType )
524 0 : pAttrList->add( XML_type, pFillType );
525 : }
526 :
527 0 : if ( rProps.GetOpt( ESCHER_Prop_fillColor, nValue ) )
528 0 : impl_AddColor( m_pShapeAttrList, XML_fillcolor, nValue );
529 :
530 0 : if ( rProps.GetOpt( ESCHER_Prop_fillBackColor, nValue ) )
531 0 : impl_AddColor( pAttrList, XML_color2, nValue );
532 :
533 : EscherPropSortStruct aStruct;
534 0 : if ( rProps.GetOpt( ESCHER_Prop_fillBlip, aStruct ) && m_pTextExport)
535 : {
536 0 : SvMemoryStream aStream;
537 0 : int nHeaderSize = 25; // The first bytes are WW8-specific, we're only interested in the PNG
538 0 : aStream.Write(aStruct.pBuf + nHeaderSize, aStruct.nPropSize - nHeaderSize);
539 0 : aStream.Seek(0);
540 0 : Graphic aGraphic;
541 0 : GraphicConverter::Import(aStream, aGraphic, CVT_PNG);
542 0 : OUString aImageId = m_pTextExport->GetDrawingML().WriteImage( aGraphic );
543 0 : pAttrList->add(FSNS(XML_r, XML_id), OUStringToOString(aImageId, RTL_TEXTENCODING_UTF8));
544 : }
545 :
546 0 : if ( rProps.GetOpt( ESCHER_Prop_fNoFillHitTest, nValue ) )
547 0 : impl_AddBool( pAttrList, XML_detectmouseclick, nValue );
548 :
549 0 : m_pSerializer->singleElementNS( XML_v, XML_fill, XFastAttributeListRef( pAttrList ) );
550 : }
551 0 : bAlreadyWritten[ ESCHER_Prop_fillType ] = true;
552 0 : bAlreadyWritten[ ESCHER_Prop_fillColor ] = true;
553 0 : bAlreadyWritten[ ESCHER_Prop_fillBackColor ] = true;
554 0 : bAlreadyWritten[ ESCHER_Prop_fillBlip ] = true;
555 0 : bAlreadyWritten[ ESCHER_Prop_fNoFillHitTest ] = true;
556 0 : break;
557 :
558 : case ESCHER_Prop_lineColor: // 448
559 : case ESCHER_Prop_lineWidth: // 459
560 : case ESCHER_Prop_lineDashing: // 462
561 : case ESCHER_Prop_lineStartArrowhead: // 464
562 : case ESCHER_Prop_lineEndArrowhead: // 465
563 : case ESCHER_Prop_lineStartArrowWidth: // 466
564 : case ESCHER_Prop_lineStartArrowLength: // 467
565 : case ESCHER_Prop_lineEndArrowWidth: // 468
566 : case ESCHER_Prop_lineEndArrowLength: // 469
567 : case ESCHER_Prop_lineJoinStyle: // 470
568 : case ESCHER_Prop_lineEndCapStyle: // 471
569 : {
570 : sal_uInt32 nValue;
571 0 : sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
572 :
573 0 : if ( rProps.GetOpt( ESCHER_Prop_lineColor, nValue ) )
574 0 : impl_AddColor( pAttrList, XML_color, nValue );
575 :
576 0 : if ( rProps.GetOpt( ESCHER_Prop_lineWidth, nValue ) )
577 0 : impl_AddInt( pAttrList, XML_weight, nValue );
578 :
579 0 : if ( rProps.GetOpt( ESCHER_Prop_lineDashing, nValue ) )
580 : {
581 0 : const char *pDashStyle = NULL;
582 0 : switch ( nValue )
583 : {
584 0 : case ESCHER_LineSolid: pDashStyle = "solid"; break;
585 0 : case ESCHER_LineDashSys: pDashStyle = "shortdash"; break;
586 0 : case ESCHER_LineDotSys: pDashStyle = "shortdot"; break;
587 0 : case ESCHER_LineDashDotSys: pDashStyle = "shortdashdot"; break;
588 0 : case ESCHER_LineDashDotDotSys: pDashStyle = "shortdashdotdot"; break;
589 0 : case ESCHER_LineDotGEL: pDashStyle = "dot"; break;
590 0 : case ESCHER_LineDashGEL: pDashStyle = "dash"; break;
591 0 : case ESCHER_LineLongDashGEL: pDashStyle = "longdash"; break;
592 0 : case ESCHER_LineDashDotGEL: pDashStyle = "dashdot"; break;
593 0 : case ESCHER_LineLongDashDotGEL: pDashStyle = "longdashdot"; break;
594 0 : case ESCHER_LineLongDashDotDotGEL: pDashStyle = "longdashdotdot"; break;
595 : }
596 0 : if ( pDashStyle )
597 0 : pAttrList->add( XML_dashstyle, pDashStyle );
598 : }
599 :
600 0 : if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowhead, nValue ) )
601 0 : impl_AddArrowHead( pAttrList, XML_startarrow, nValue );
602 :
603 0 : if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowhead, nValue ) )
604 0 : impl_AddArrowHead( pAttrList, XML_endarrow, nValue );
605 :
606 0 : if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowWidth, nValue ) )
607 0 : impl_AddArrowWidth( pAttrList, XML_startarrowwidth, nValue );
608 :
609 0 : if ( rProps.GetOpt( ESCHER_Prop_lineStartArrowLength, nValue ) )
610 0 : impl_AddArrowLength( pAttrList, XML_startarrowlength, nValue );
611 :
612 0 : if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowWidth, nValue ) )
613 0 : impl_AddArrowWidth( pAttrList, XML_endarrowwidth, nValue );
614 :
615 0 : if ( rProps.GetOpt( ESCHER_Prop_lineEndArrowLength, nValue ) )
616 0 : impl_AddArrowLength( pAttrList, XML_endarrowlength, nValue );
617 :
618 0 : if ( rProps.GetOpt( ESCHER_Prop_lineJoinStyle, nValue ) )
619 : {
620 0 : const char *pJoinStyle = NULL;
621 0 : switch ( nValue )
622 : {
623 0 : case ESCHER_LineJoinBevel: pJoinStyle = "bevel"; break;
624 0 : case ESCHER_LineJoinMiter: pJoinStyle = "miter"; break;
625 0 : case ESCHER_LineJoinRound: pJoinStyle = "round"; break;
626 : }
627 0 : if ( pJoinStyle )
628 0 : pAttrList->add( XML_joinstyle, pJoinStyle );
629 : }
630 :
631 0 : if ( rProps.GetOpt( ESCHER_Prop_lineEndCapStyle, nValue ) )
632 : {
633 0 : const char *pEndCap = NULL;
634 0 : switch ( nValue )
635 : {
636 0 : case ESCHER_LineEndCapRound: pEndCap = "round"; break;
637 0 : case ESCHER_LineEndCapSquare: pEndCap = "square"; break;
638 0 : case ESCHER_LineEndCapFlat: pEndCap = "flat"; break;
639 : }
640 0 : if ( pEndCap )
641 0 : pAttrList->add( XML_endcap, pEndCap );
642 : }
643 :
644 0 : m_pSerializer->singleElementNS( XML_v, XML_stroke, XFastAttributeListRef( pAttrList ) );
645 : }
646 0 : bAlreadyWritten[ ESCHER_Prop_lineColor ] = true;
647 0 : bAlreadyWritten[ ESCHER_Prop_lineWidth ] = true;
648 0 : bAlreadyWritten[ ESCHER_Prop_lineDashing ] = true;
649 0 : bAlreadyWritten[ ESCHER_Prop_lineStartArrowhead ] = true;
650 0 : bAlreadyWritten[ ESCHER_Prop_lineEndArrowhead ] = true;
651 0 : bAlreadyWritten[ ESCHER_Prop_lineStartArrowWidth ] = true;
652 0 : bAlreadyWritten[ ESCHER_Prop_lineStartArrowLength ] = true;
653 0 : bAlreadyWritten[ ESCHER_Prop_lineEndArrowWidth ] = true;
654 0 : bAlreadyWritten[ ESCHER_Prop_lineEndArrowLength ] = true;
655 0 : bAlreadyWritten[ ESCHER_Prop_lineJoinStyle ] = true;
656 0 : bAlreadyWritten[ ESCHER_Prop_lineEndCapStyle ] = true;
657 0 : break;
658 :
659 : case ESCHER_Prop_fHidden:
660 0 : if ( !it->nPropValue )
661 0 : m_pShapeStyle->append( ";visibility:hidden" );
662 0 : break;
663 : case ESCHER_Prop_shadowColor:
664 : case ESCHER_Prop_fshadowObscured:
665 : {
666 0 : sal_uInt32 nValue = 0;
667 0 : bool bShadow = false;
668 0 : bool bObscured = false;
669 0 : if ( rProps.GetOpt( ESCHER_Prop_fshadowObscured, nValue ) )
670 : {
671 0 : bShadow = (( nValue & 0x20002 ) == 0x20002 );
672 0 : bObscured = (( nValue & 0x10001 ) == 0x10001 );
673 : }
674 0 : if ( bShadow )
675 : {
676 0 : sax_fastparser::FastAttributeList *pAttrList = m_pSerializer->createAttrList();
677 0 : impl_AddBool( pAttrList, XML_on, bShadow );
678 0 : impl_AddBool( pAttrList, XML_obscured, bObscured );
679 :
680 0 : if ( rProps.GetOpt( ESCHER_Prop_shadowColor, nValue ) )
681 0 : impl_AddColor( pAttrList, XML_color, nValue );
682 :
683 0 : m_pSerializer->singleElementNS( XML_v, XML_shadow, XFastAttributeListRef( pAttrList ) );
684 0 : bAlreadyWritten[ ESCHER_Prop_fshadowObscured ] = true;
685 0 : bAlreadyWritten[ ESCHER_Prop_shadowColor ] = true;
686 : }
687 : }
688 0 : break;
689 : default:
690 : #if OSL_DEBUG_LEVEL > 0
691 : fprintf( stderr, "TODO VMLExport::Commit(), unimplemented id: %d, value: %" SAL_PRIuUINT32 ", data: [%" SAL_PRIuUINT32 ", %p]\n",
692 : nId, it->nPropValue, it->nPropSize, it->pBuf );
693 : if ( it->nPropSize )
694 : {
695 : const sal_uInt8 *pIt = it->pBuf;
696 : fprintf( stderr, " ( " );
697 : for ( int nCount = it->nPropSize; nCount; --nCount )
698 : {
699 : fprintf( stderr, "%02x ", *pIt );
700 : ++pIt;
701 : }
702 : fprintf( stderr, ")\n" );
703 : }
704 : #endif
705 0 : break;
706 : }
707 : }
708 :
709 0 : m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_POSTPONE );
710 : }
711 :
712 0 : OString VMLExport::ShapeIdString( sal_uInt32 nId )
713 : {
714 0 : return OStringBuffer( 20 ).append( "shape_" ).append( sal_Int64( nId ) ).makeStringAndClear();
715 : }
716 :
717 0 : void VMLExport::AddLineDimensions( const Rectangle& rRectangle )
718 : {
719 : // style
720 0 : if ( m_pShapeStyle->getLength() )
721 0 : m_pShapeStyle->append( ";" );
722 :
723 0 : m_pShapeStyle->append( "position:absolute" );
724 :
725 0 : switch ( m_nShapeFlags & 0xC0 )
726 : {
727 0 : case 0x40: m_pShapeStyle->append( ";flip:y" ); break;
728 0 : case 0x80: m_pShapeStyle->append( ";flip:x" ); break;
729 0 : case 0xC0: m_pShapeStyle->append( ";flip:xy" ); break;
730 : }
731 :
732 : // the actual dimensions
733 0 : OString aLeft, aTop, aRight, aBottom;
734 :
735 0 : if ( mnGroupLevel == 1 )
736 : {
737 0 : const OString aPt( "pt" );
738 0 : aLeft = OString::valueOf( double( rRectangle.Left() ) / 20 ) + aPt;
739 0 : aTop = OString::valueOf( double( rRectangle.Top() ) / 20 ) + aPt;
740 0 : aRight = OString::valueOf( double( rRectangle.Right() ) / 20 ) + aPt;
741 0 : aBottom = OString::valueOf( double( rRectangle.Bottom() ) / 20 ) + aPt;
742 : }
743 : else
744 : {
745 0 : aLeft = OString::valueOf( rRectangle.Left() );
746 0 : aTop = OString::valueOf( rRectangle.Top() );
747 0 : aRight = OString::valueOf( rRectangle.Right() );
748 0 : aBottom = OString::valueOf( rRectangle.Bottom() );
749 : }
750 :
751 : m_pShapeAttrList->add( XML_from,
752 0 : OStringBuffer( 20 ).append( aLeft )
753 0 : .append( "," ).append( aTop )
754 0 : .makeStringAndClear() );
755 :
756 : m_pShapeAttrList->add( XML_to,
757 0 : OStringBuffer( 20 ).append( aRight )
758 0 : .append( "," ).append( aBottom )
759 0 : .makeStringAndClear() );
760 0 : }
761 :
762 0 : void VMLExport::AddRectangleDimensions( rtl::OStringBuffer& rBuffer, const Rectangle& rRectangle )
763 : {
764 0 : if ( rBuffer.getLength() )
765 0 : rBuffer.append( ";" );
766 :
767 0 : rBuffer.append( "position:absolute;" );
768 :
769 0 : if ( mnGroupLevel == 1 )
770 : {
771 0 : rBuffer.append( "margin-left:" ).append( double( rRectangle.Left() ) / 20 )
772 0 : .append( "pt;margin-top:" ).append( double( rRectangle.Top() ) / 20 )
773 0 : .append( "pt;width:" ).append( double( rRectangle.Right() - rRectangle.Left() ) / 20 )
774 0 : .append( "pt;height:" ).append( double( rRectangle.Bottom() - rRectangle.Top() ) / 20 )
775 0 : .append( "pt" );
776 : }
777 : else
778 : {
779 0 : rBuffer.append( "left:" ).append( rRectangle.Left() )
780 0 : .append( ";top:" ).append( rRectangle.Top() )
781 0 : .append( ";width:" ).append( rRectangle.Right() - rRectangle.Left() )
782 0 : .append( ";height:" ).append( rRectangle.Bottom() - rRectangle.Top() );
783 : }
784 0 : }
785 :
786 0 : void VMLExport::AddShapeAttribute( sal_Int32 nAttribute, const rtl::OString& rValue )
787 : {
788 0 : m_pShapeAttrList->add( nAttribute, rValue );
789 0 : }
790 :
791 : extern const char* pShapeTypes[];
792 :
793 0 : sal_Int32 VMLExport::StartShape()
794 : {
795 0 : if ( m_nShapeType == ESCHER_ShpInst_Nil )
796 0 : return -1;
797 :
798 : // some of the shapes have their own name ;-)
799 0 : sal_Int32 nShapeElement = -1;
800 0 : bool bReferToShapeType = false;
801 0 : switch ( m_nShapeType )
802 : {
803 0 : case ESCHER_ShpInst_NotPrimitive: nShapeElement = XML_shape; break;
804 0 : case ESCHER_ShpInst_Rectangle: nShapeElement = XML_rect; break;
805 0 : case ESCHER_ShpInst_RoundRectangle: nShapeElement = XML_roundrect; break;
806 0 : case ESCHER_ShpInst_Ellipse: nShapeElement = XML_oval; break;
807 0 : case ESCHER_ShpInst_Arc: nShapeElement = XML_arc; break;
808 0 : case ESCHER_ShpInst_Line: nShapeElement = XML_line; break;
809 : default:
810 0 : if ( m_nShapeType < ESCHER_ShpInst_COUNT )
811 : {
812 0 : nShapeElement = XML_shape;
813 :
814 : // a predefined shape?
815 0 : const char* pShapeType = pShapeTypes[ m_nShapeType ];
816 0 : if ( pShapeType )
817 : {
818 0 : bReferToShapeType = true;
819 0 : if ( !m_pShapeTypeWritten[ m_nShapeType ] )
820 : {
821 0 : m_pSerializer->write( pShapeType );
822 0 : m_pShapeTypeWritten[ m_nShapeType ] = true;
823 : }
824 : }
825 : else
826 : {
827 : // rectangle is probably the best fallback...
828 0 : nShapeElement = XML_rect;
829 : }
830 : }
831 0 : break;
832 : }
833 :
834 : // add style
835 0 : m_pShapeAttrList->add( XML_style, m_pShapeStyle->makeStringAndClear() );
836 :
837 0 : if ( nShapeElement >= 0 )
838 : {
839 0 : if ( bReferToShapeType )
840 : {
841 : m_pShapeAttrList->add( XML_type, OStringBuffer( 20 )
842 0 : .append( "shapetype_" ).append( sal_Int32( m_nShapeType ) )
843 0 : .makeStringAndClear() );
844 : }
845 :
846 : // start of the shape
847 0 : m_pSerializer->startElementNS( XML_v, nShapeElement, XFastAttributeListRef( m_pShapeAttrList ) );
848 : }
849 :
850 : // now check if we have some text and we have a text exporter registered
851 0 : const SdrTextObj* pTxtObj = PTR_CAST(SdrTextObj, m_pSdrObject);
852 0 : if (pTxtObj && m_pTextExport)
853 : {
854 0 : const OutlinerParaObject* pParaObj = 0;
855 0 : bool bOwnParaObj = false;
856 :
857 : /*
858 : #i13885#
859 : When the object is actively being edited, that text is not set into
860 : the objects normal text object, but lives in a seperate object.
861 : */
862 0 : if (pTxtObj->IsTextEditActive())
863 : {
864 0 : pParaObj = pTxtObj->GetEditOutlinerParaObject();
865 0 : bOwnParaObj = true;
866 : }
867 : else
868 : {
869 0 : pParaObj = pTxtObj->GetOutlinerParaObject();
870 : }
871 :
872 0 : if( pParaObj )
873 : {
874 : // this is reached only in case some text is attached to the shape
875 0 : m_pTextExport->WriteOutliner(*pParaObj);
876 0 : if( bOwnParaObj )
877 0 : delete pParaObj;
878 : }
879 : }
880 :
881 0 : return nShapeElement;
882 : }
883 :
884 0 : void VMLExport::EndShape( sal_Int32 nShapeElement )
885 : {
886 0 : if ( nShapeElement >= 0 )
887 : {
888 : // end of the shape
889 0 : m_pSerializer->endElementNS( XML_v, nShapeElement );
890 : }
891 0 : }
892 :
893 0 : sal_uInt32 VMLExport::AddSdrObject( const SdrObject& rObj )
894 : {
895 0 : m_pSdrObject = &rObj;
896 0 : return EscherEx::AddSdrObject(rObj);
897 : }
898 :
899 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|