xref: /aoo41x/main/oox/source/export/drawingml.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "oox/core/xmlfilterbase.hxx"
29 #include "oox/export/drawingml.hxx"
30 #include "oox/export/utils.hxx"
31 
32 #include <cstdio>
33 #include <com/sun/star/awt/CharSet.hpp>
34 #include <com/sun/star/awt/FontDescriptor.hpp>
35 #include <com/sun/star/awt/FontSlant.hpp>
36 #include <com/sun/star/awt/FontWeight.hpp>
37 #include <com/sun/star/awt/FontUnderline.hpp>
38 #include <com/sun/star/awt/Gradient.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/beans/XPropertyState.hpp>
41 #include <com/sun/star/container/XEnumerationAccess.hpp>
42 #include <com/sun/star/drawing/BitmapMode.hpp>
43 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
44 #include <com/sun/star/drawing/LineDash.hpp>
45 #include <com/sun/star/drawing/LineJoint.hpp>
46 #include <com/sun/star/drawing/LineStyle.hpp>
47 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
48 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
49 #include <com/sun/star/i18n/ScriptType.hpp>
50 #include <com/sun/star/io/XOutputStream.hpp>
51 #include <com/sun/star/style/ParagraphAdjust.hpp>
52 #include <com/sun/star/text/XText.hpp>
53 #include <com/sun/star/text/XTextContent.hpp>
54 #include <com/sun/star/text/XTextField.hpp>
55 #include <com/sun/star/text/XTextRange.hpp>
56 #include <tools/stream.hxx>
57 #include <tools/string.hxx>
58 #include <vcl/cvtgrf.hxx>
59 #include <unotools/fontcvt.hxx>
60 #include <vcl/graph.hxx>
61 #include <svtools/grfmgr.hxx>
62 #include <rtl/strbuf.hxx>
63 #include <sfx2/app.hxx>
64 #include <svl/languageoptions.hxx>
65 #include <svx/escherex.hxx>
66 #include <svx/svxenum.hxx>
67 
68 using namespace ::com::sun::star;
69 using namespace ::com::sun::star::uno;
70 using namespace ::com::sun::star::drawing;
71 using namespace ::com::sun::star::i18n;
72 using ::com::sun::star::beans::PropertyState;
73 using ::com::sun::star::beans::PropertyValue;
74 using ::com::sun::star::beans::XPropertySet;
75 using ::com::sun::star::beans::XPropertyState;
76 using ::com::sun::star::container::XEnumeration;
77 using ::com::sun::star::container::XEnumerationAccess;
78 using ::com::sun::star::container::XIndexAccess;
79 using ::com::sun::star::io::XOutputStream;
80 using ::com::sun::star::text::XText;
81 using ::com::sun::star::text::XTextContent;
82 using ::com::sun::star::text::XTextField;
83 using ::com::sun::star::text::XTextRange;
84 using ::rtl::OString;
85 using ::rtl::OStringBuffer;
86 using ::rtl::OUString;
87 using ::rtl::OUStringBuffer;
88 using ::sax_fastparser::FSHelperPtr;
89 
90 DBG(extern void dump_pset(Reference< XPropertySet > rXPropSet));
91 
92 namespace oox {
93 namespace drawingml {
94 
95 #define GETA(propName) \
96     GetProperty( rXPropSet, String( RTL_CONSTASCII_USTRINGPARAM( #propName ) ) )
97 
98 #define GETAD(propName) \
99     ( GetPropertyAndState( rXPropSet, rXPropState, String( RTL_CONSTASCII_USTRINGPARAM( #propName ) ), eState ) && eState == beans::PropertyState_DIRECT_VALUE )
100 
101 #define GET(variable, propName) \
102     if ( GETA(propName) ) \
103         mAny >>= variable;
104 
105 // not thread safe
106 int DrawingML::mnImageCounter = 1;
107 
108 void DrawingML::ResetCounters()
109 {
110     mnImageCounter = 1;
111 }
112 
113 bool DrawingML::GetProperty( Reference< XPropertySet > rXPropSet, String aName )
114 {
115     bool bRetValue = false;
116 
117     try {
118         mAny = rXPropSet->getPropertyValue( aName );
119         if ( mAny.hasValue() )
120             bRetValue = true;
121     } catch( Exception& ) { /* printf ("exception when trying to get value of property: %s\n", ST(aName)); */ }
122 
123     return bRetValue;
124 }
125 
126 bool DrawingML::GetPropertyAndState( Reference< XPropertySet > rXPropSet, Reference< XPropertyState > rXPropState, String aName, PropertyState& eState )
127 {
128     bool bRetValue = false;
129 
130     try {
131         mAny = rXPropSet->getPropertyValue( aName );
132         if ( mAny.hasValue() ) {
133             bRetValue = true;
134             eState = rXPropState->getPropertyState( aName );
135         }
136     } catch( Exception& ) { /* printf ("exception when trying to get value of property: %s\n", ST(aName)); */ }
137 
138     return bRetValue;
139 }
140 
141 void DrawingML::WriteColor( sal_uInt32 nColor )
142 {
143     OString sColor = OString::valueOf( ( sal_Int64 ) nColor, 16 );
144     if( sColor.getLength() < 6 ) {
145         OStringBuffer sBuf( "0" );
146         int remains = 5 - sColor.getLength();
147 
148         while( remains > 0 ) {
149             sBuf.append( "0" );
150             remains--;
151         }
152 
153         sBuf.append( sColor );
154 
155         sColor = sBuf.getStr();
156     }
157     mpFS->singleElementNS( XML_a, XML_srgbClr, XML_val, sColor.getStr(), FSEND );
158 }
159 
160 void DrawingML::WriteSolidFill( sal_uInt32 nColor )
161 {
162     mpFS->startElementNS( XML_a, XML_solidFill, FSEND );
163     WriteColor( nColor );
164     mpFS->endElementNS( XML_a, XML_solidFill );
165 }
166 
167 void DrawingML::WriteSolidFill( Reference< XPropertySet > rXPropSet )
168 {
169     if ( GetProperty( rXPropSet, S( "FillColor" ) ) )
170         WriteSolidFill( *((sal_uInt32*) mAny.getValue()) & 0xffffff );
171 }
172 
173 void DrawingML::WriteGradientStop( sal_uInt16 nStop, sal_uInt32 nColor )
174 {
175     mpFS->startElementNS( XML_a, XML_gs,
176                           XML_pos, I32S( nStop * 1000 ),
177                           FSEND );
178     WriteColor( nColor );
179     mpFS->endElementNS( XML_a, XML_gs );
180 }
181 
182 sal_uInt32 DrawingML::ColorWithIntensity( sal_uInt32 nColor, sal_uInt32 nIntensity )
183 {
184     return ( ( ( nColor & 0xff ) * nIntensity ) / 100 )
185         | ( ( ( ( ( nColor & 0xff00 ) >> 8 ) * nIntensity ) / 100 ) << 8 )
186         | ( ( ( ( ( nColor & 0xff0000 ) >> 8 ) * nIntensity ) / 100 ) << 8 );
187 }
188 
189 void DrawingML::WriteGradientFill( Reference< XPropertySet > rXPropSet )
190 {
191     awt::Gradient aGradient;
192     if( GETA( FillGradient ) ) {
193         aGradient = *static_cast< const awt::Gradient* >( mAny.getValue() );
194 
195         mpFS->startElementNS( XML_a, XML_gradFill, FSEND );
196 
197         switch( aGradient.Style ) {
198             default:
199             case GradientStyle_LINEAR:
200                 mpFS->startElementNS( XML_a, XML_gsLst, FSEND );
201                 WriteGradientStop( 0, ColorWithIntensity( aGradient.StartColor, aGradient.StartIntensity ) );
202                 WriteGradientStop( 100, ColorWithIntensity( aGradient.EndColor, aGradient.EndIntensity ) );
203                 mpFS->endElementNS( XML_a, XML_gsLst );
204                 mpFS->singleElementNS( XML_a, XML_lin,
205                                        XML_ang, I32S( ( ( ( 3600 - aGradient.Angle + 900 ) * 6000 ) % 21600000 ) ),
206                                        FSEND );
207                 break;
208 
209             case GradientStyle_AXIAL:
210                 mpFS->startElementNS( XML_a, XML_gsLst, FSEND );
211                 WriteGradientStop( 0, ColorWithIntensity( aGradient.EndColor, aGradient.EndIntensity ) );
212                 WriteGradientStop( 50, ColorWithIntensity( aGradient.StartColor, aGradient.StartIntensity ) );
213                 WriteGradientStop( 100, ColorWithIntensity( aGradient.EndColor, aGradient.EndIntensity ) );
214                 mpFS->endElementNS( XML_a, XML_gsLst );
215                 mpFS->singleElementNS( XML_a, XML_lin,
216                                        XML_ang, I32S( ( ( ( 3600 - aGradient.Angle + 900 ) * 6000 ) % 21600000 ) ),
217                                        FSEND );
218                 break;
219 
220                 /* I don't see how to apply transformation to gradients, so
221                  * elliptical will end as radial and square as
222                  * rectangular. also position offsets are not applied */
223             case GradientStyle_RADIAL:
224             case GradientStyle_ELLIPTICAL:
225             case GradientStyle_RECT:
226             case GradientStyle_SQUARE:
227                 mpFS->startElementNS( XML_a, XML_gsLst, FSEND );
228                 WriteGradientStop( 0, ColorWithIntensity( aGradient.EndColor, aGradient.EndIntensity ) );
229                 WriteGradientStop( 100, ColorWithIntensity( aGradient.StartColor, aGradient.StartIntensity ) );
230                 mpFS->endElementNS( XML_a, XML_gsLst );
231                 mpFS->singleElementNS( XML_a, XML_path,
232                                        XML_path, ( aGradient.Style == awt::GradientStyle_RADIAL || aGradient.Style == awt::GradientStyle_ELLIPTICAL ) ? "circle" : "rect",
233                                        FSEND );
234                 break;
235         }
236 
237         mpFS->endElementNS( XML_a, XML_gradFill );
238     }
239 
240 }
241 
242 void DrawingML::WriteLineArrow( Reference< XPropertySet > rXPropSet, sal_Bool bLineStart )
243 {
244     ESCHER_LineEnd eLineEnd;
245     sal_Int32 nArrowLength;
246     sal_Int32 nArrowWidth;
247 
248     if ( EscherPropertyContainer::GetLineArrow( bLineStart, rXPropSet, eLineEnd, nArrowLength, nArrowWidth ) ) {
249         const char* len;
250         const char* type;
251         const char* width;
252 
253         switch( nArrowLength ) {
254             case ESCHER_LineShortArrow:
255                 len = "sm";
256                 break;
257             default:
258             case ESCHER_LineMediumLenArrow:
259                 len = "med";
260                 break;
261             case ESCHER_LineLongArrow:
262                 len = "lg";
263                 break;
264         }
265 
266         switch( eLineEnd ) {
267             default:
268             case ESCHER_LineNoEnd:
269                 type = "none";
270                 break;
271             case ESCHER_LineArrowEnd:
272                 type = "triangle";
273                 break;
274             case ESCHER_LineArrowStealthEnd:
275                 type = "stealth";
276                 break;
277             case ESCHER_LineArrowDiamondEnd:
278                 type = "diamond";
279                 break;
280             case ESCHER_LineArrowOvalEnd:
281                 type = "oval";
282                 break;
283             case ESCHER_LineArrowOpenEnd:
284                 type = "arrow";
285                 break;
286         }
287 
288         switch( nArrowWidth ) {
289             case ESCHER_LineNarrowArrow:
290                 width = "sm";
291                 break;
292             default:
293             case ESCHER_LineMediumWidthArrow:
294                 width = "med";
295                 break;
296             case ESCHER_LineWideArrow:
297                 width = "lg";
298                 break;
299         }
300 
301         mpFS->singleElementNS( XML_a, bLineStart ? XML_headEnd : XML_tailEnd,
302                                XML_len, len,
303                                XML_type, type,
304                                XML_w, width,
305                                FSEND );
306     }
307 }
308 
309 void DrawingML::WriteOutline( Reference< XPropertySet > rXPropSet )
310 {
311     drawing::LineStyle aLineStyle( drawing::LineStyle_NONE );
312 
313     GET( aLineStyle, LineStyle );
314 
315     if( aLineStyle == drawing::LineStyle_NONE )
316         return;
317 
318     sal_uInt32 nLineWidth = 0;
319     sal_uInt32 nColor = 0;
320     sal_Bool bColorSet = FALSE;
321     const char* cap = NULL;
322     drawing::LineDash aLineDash;
323     sal_Bool bDashSet = FALSE;
324 
325     GET( nLineWidth, LineWidth );
326 
327     switch( aLineStyle ) {
328         case drawing::LineStyle_DASH:
329             if( GETA( LineDash ) ) {
330                 aLineDash = *(drawing::LineDash*) mAny.getValue();
331                 bDashSet = TRUE;
332                 if( aLineDash.Style == DashStyle_ROUND || aLineDash.Style == DashStyle_ROUNDRELATIVE )
333                     cap = "rnd";
334 
335                 DBG(printf("dash dots: %d dashes: %d dotlen: %d dashlen: %d distance: %d\n",
336                             int( aLineDash.Dots ), int( aLineDash.Dashes ), int( aLineDash.DotLen ), int( aLineDash.DashLen ), int( aLineDash.Distance )));
337             }
338             /* fallthru intended */
339         case drawing::LineStyle_SOLID:
340         default:
341             if ( GETA( LineColor ) ) {
342                 nColor = *((sal_uInt32*) mAny.getValue()) & 0xffffff;
343                 bColorSet = TRUE;
344             }
345             break;
346     }
347 
348     mpFS->startElementNS( XML_a, XML_ln,
349                           XML_cap, cap,
350                           XML_w, nLineWidth > 1 ? I64S( MM100toEMU( nLineWidth ) ) : NULL,
351                           FSEND );
352     if( bColorSet )
353         WriteSolidFill( nColor );
354 
355     if( bDashSet ) {
356         mpFS->startElementNS( XML_a, XML_custDash, FSEND );
357         int i;
358         for( i = 0; i < aLineDash.Dots; i ++ )
359             mpFS->singleElementNS( XML_a, XML_ds,
360                                    XML_d, aLineDash.DotLen ? I64S( aLineDash.DotLen*1000 ) : "100000",
361                                    XML_sp, I64S( aLineDash.Distance*1000 ),
362                                    FSEND );
363         for( i = 0; i < aLineDash.Dashes; i ++ )
364             mpFS->singleElementNS( XML_a, XML_ds,
365                                    XML_d, aLineDash.DashLen ? I64S( aLineDash.DashLen*1000 ) : "100000",
366                                    XML_sp, I64S( aLineDash.Distance*1000 ),
367                                    FSEND );
368         mpFS->endElementNS( XML_a, XML_custDash );
369     }
370 
371     if( nLineWidth > 1 && GETA( LineJoint ) ) {
372         LineJoint eLineJoint;
373 
374         mAny >>= eLineJoint;
375         switch( eLineJoint ) {
376             case LineJoint_NONE:
377             case LineJoint_MIDDLE:
378             case LineJoint_BEVEL:
379                 mpFS->singleElementNS( XML_a, XML_bevel, FSEND );
380                 break;
381             default:
382             case LineJoint_MITER:
383                 mpFS->singleElementNS( XML_a, XML_miter, FSEND );
384                 break;
385             case LineJoint_ROUND:
386                 mpFS->singleElementNS( XML_a, XML_round, FSEND );
387                 break;
388         }
389     }
390 
391     WriteLineArrow( rXPropSet, sal_True );
392     WriteLineArrow( rXPropSet, sal_False );
393 
394     mpFS->endElementNS( XML_a, XML_ln );
395 }
396 
397 OUString DrawingML::WriteImage( const OUString& rURL )
398 {
399     ByteString aURLBS( UniString( rURL ), RTL_TEXTENCODING_UTF8 );
400 
401     const char aURLBegin[] = "vnd.sun.star.GraphicObject:";
402     int index = aURLBS.Search( aURLBegin );
403 
404     if ( index != STRING_NOTFOUND ) {
405         DBG(printf ("begin: %ld %s\n", long( sizeof( aURLBegin ) ), USS( rURL ) + sizeof( aURLBegin ) - 1 ));
406         aURLBS.Erase( 0, sizeof( aURLBegin ) - 1 );
407         Graphic aGraphic = GraphicObject( aURLBS ).GetTransformedGraphic ();
408 
409         return WriteImage( aGraphic );
410     } else {
411         // add link to relations
412     }
413 
414     return OUString();
415 }
416 
417 OUString DrawingML::WriteImage( const Graphic& rGraphic )
418 {
419     GfxLink aLink = rGraphic.GetLink ();
420     OUString sMediaType;
421     const char* sExtension = NULL;
422     OUString sRelId;
423 
424     SvMemoryStream aStream;
425     const void* aData = aLink.GetData();
426     sal_Size nDataSize = aLink.GetDataSize();
427 
428     switch ( aLink.GetType() ) {
429         case GFX_LINK_TYPE_NATIVE_GIF:
430             sMediaType = US( "image/gif" );
431             sExtension = ".gif";
432             break;
433         case GFX_LINK_TYPE_NATIVE_JPG:
434             sMediaType = US( "image/jpeg" );
435             sExtension = ".jpeg";
436             break;
437         case GFX_LINK_TYPE_NATIVE_PNG:
438             sMediaType = US( "image/png" );
439             sExtension = ".png";
440             break;
441         case GFX_LINK_TYPE_NATIVE_TIF:
442             sMediaType = US( "image/tiff" );
443             sExtension = ".tiff";
444             break;
445         case GFX_LINK_TYPE_NATIVE_WMF:
446             sMediaType = US( "image/x-wmf" );
447             sExtension = ".wmf";
448             break;
449         case GFX_LINK_TYPE_NATIVE_MET:
450             sMediaType = US( "image/x-met" );
451             sExtension = ".met";
452             break;
453         case GFX_LINK_TYPE_NATIVE_PCT:
454             sMediaType = US( "image/x-pict" );
455             sExtension = ".pct";
456             break;
457         default: {
458             GraphicType aType = rGraphic.GetType();
459             if ( aType == GRAPHIC_BITMAP ) {
460                 GraphicConverter::Export( aStream, rGraphic, CVT_PNG );
461                 sMediaType = US( "image/png" );
462                 sExtension = ".png";
463             } else if ( aType == GRAPHIC_GDIMETAFILE ) {
464                 GraphicConverter::Export( aStream, rGraphic, CVT_EMF );
465                 sMediaType = US( "image/x-emf" );
466                 sExtension = ".emf";
467             } else {
468                 OSL_TRACE( "unhandled graphic type" );
469                 break;
470             }
471 
472             aData = aStream.GetData();
473             nDataSize = aStream.GetSize();
474             break;
475             }
476     }
477 
478     const char *pComponent = NULL;
479     switch ( meDocumentType )
480     {
481         case DOCUMENT_DOCX: pComponent = "word"; break;
482         case DOCUMENT_PPTX: pComponent = "ppt"; break;
483         case DOCUMENT_XLSX: pComponent = "xl"; break;
484     }
485 
486     Reference< XOutputStream > xOutStream = mpFB->openOutputStream( OUStringBuffer()
487                                                                     .appendAscii( pComponent )
488                                                                     .appendAscii( "/media/image" )
489                                                                     .append( (sal_Int32) mnImageCounter )
490                                                                     .appendAscii( sExtension )
491                                                                     .makeStringAndClear(),
492                                                                     sMediaType );
493     xOutStream->writeBytes( Sequence< sal_Int8 >( (const sal_Int8*) aData, nDataSize ) );
494     xOutStream->closeOutput();
495 
496     const char *pImagePrefix = NULL;
497     switch ( meDocumentType )
498     {
499         case DOCUMENT_DOCX:
500             pImagePrefix = "media/image";
501             break;
502         case DOCUMENT_PPTX:
503         case DOCUMENT_XLSX:
504             pImagePrefix = "../media/image";
505             break;
506     }
507 
508     sRelId = mpFB->addRelation( mpFS->getOutputStream(),
509                                 US( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" ),
510                                 OUStringBuffer()
511                                 .appendAscii( pImagePrefix )
512                                 .append( (sal_Int32) mnImageCounter ++ )
513                                 .appendAscii( sExtension )
514                                 .makeStringAndClear() );
515 
516     return sRelId;
517 }
518 
519 OUString DrawingML::WriteBlip( OUString& rURL )
520 {
521         OUString sRelId = WriteImage( rURL );
522 
523         mpFS->singleElementNS( XML_a, XML_blip,
524                                FSNS( XML_r, XML_embed), OUStringToOString( sRelId, RTL_TEXTENCODING_UTF8 ).getStr(),
525                                FSEND );
526 
527         return sRelId;
528 }
529 
530 void DrawingML::WriteBlipMode( Reference< XPropertySet > rXPropSet )
531 {
532     BitmapMode eBitmapMode( BitmapMode_NO_REPEAT );
533     if (GetProperty( rXPropSet, S( "FillBitmapMode" ) ) )
534         mAny >>= eBitmapMode;
535 
536     DBG(printf("fill bitmap mode: %d\n", eBitmapMode));
537 
538     switch (eBitmapMode) {
539     case BitmapMode_REPEAT:
540         mpFS->singleElementNS( XML_a, XML_tile, FSEND );
541         break;
542     default:
543         ;
544     }
545 }
546 
547 void DrawingML::WriteBlipFill( Reference< XPropertySet > rXPropSet, String sURLPropName )
548 {
549     WriteBlipFill( rXPropSet, sURLPropName, XML_a );
550 }
551 
552 void DrawingML::WriteBlipFill( Reference< XPropertySet > rXPropSet, String sURLPropName, sal_Int32 nXmlNamespace )
553 {
554     if ( GetProperty( rXPropSet, sURLPropName ) ) {
555         OUString aURL;
556         mAny >>= aURL;
557 
558         DBG(printf ("URL: %s\n", OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr() ));
559 
560         if( !aURL.getLength() )
561             return;
562 
563         mpFS->startElementNS( nXmlNamespace , XML_blipFill, FSEND );
564 
565         WriteBlip( aURL );
566 
567         if( sURLPropName == S( "FillBitmapURL" ) )
568             WriteBlipMode( rXPropSet );
569         else if( GetProperty( rXPropSet, S( "FillBitmapStretch" ) ) ) {
570                 bool bStretch = false;
571                 mAny >>= bStretch;
572 
573                 if( bStretch )
574                     WriteStretch();
575         }
576 
577         mpFS->endElementNS( nXmlNamespace, XML_blipFill );
578     }
579 }
580 
581 void DrawingML::WriteStretch()
582 {
583     mpFS->startElementNS( XML_a, XML_stretch, FSEND );
584     mpFS->singleElementNS( XML_a, XML_fillRect, FSEND );
585     mpFS->endElementNS( XML_a, XML_stretch );
586 }
587 
588 void DrawingML::WriteTransformation( const Rectangle& rRect,
589         sal_Bool bFlipH, sal_Bool bFlipV, sal_Int32 nRotation )
590 {
591     mpFS->startElementNS( XML_a, XML_xfrm,
592                           XML_flipH, bFlipH ? "1" : NULL,
593                           XML_flipV, bFlipV ? "1" : NULL,
594                           XML_rot, nRotation ? I32S( nRotation ) : NULL,
595                           FSEND );
596 
597     mpFS->singleElementNS( XML_a, XML_off, XML_x, IS( MM100toEMU( rRect.Left() ) ), XML_y, IS( MM100toEMU( rRect.Top() ) ), FSEND );
598     mpFS->singleElementNS( XML_a, XML_ext, XML_cx, IS( MM100toEMU( rRect.GetWidth() ) ), XML_cy, IS( MM100toEMU( rRect.GetHeight() ) ), FSEND );
599 
600     mpFS->endElementNS( XML_a, XML_xfrm );
601 }
602 
603 void DrawingML::WriteShapeTransformation( Reference< XShape > rXShape, sal_Bool bFlipH, sal_Bool bFlipV, sal_Int32 nRotation )
604 {
605     DBG(printf( "write shape transformation\n" ));
606 
607     awt::Point aPos = rXShape->getPosition();
608     awt::Size aSize = rXShape->getSize();
609 
610     WriteTransformation( Rectangle( Point( aPos.X, aPos.Y ), Size( aSize.Width, aSize.Height ) ), bFlipH, bFlipV, nRotation );
611 }
612 
613 void DrawingML::WriteRunProperties( Reference< XTextRange > rRun )
614 {
615     Reference< XPropertySet > rXPropSet( rRun, UNO_QUERY );
616     Reference< XPropertyState > rXPropState( rRun, UNO_QUERY );
617     OUString usLanguage;
618     PropertyState eState;
619     sal_Int16 nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguage() );
620     sal_Bool bComplex = ( nScriptType == ScriptType::COMPLEX );
621     const char* bold = NULL;
622     const char* italic = NULL;
623     const char* underline = NULL;
624     sal_Int32 nSize = 1800;
625 
626     if( GETAD( CharHeight ) )
627         nSize = (sal_Int32) (100*(*((float*) mAny.getValue())));
628 
629     if ( ( bComplex && GETAD( CharWeightComplex ) ) || GETAD( CharWeight ) )
630         if ( *((float*) mAny.getValue()) >= awt::FontWeight::SEMIBOLD )
631             bold = "1";
632 
633     if ( ( bComplex && GETAD( CharPostureComplex ) ) || GETAD( CharPosture ) )
634         switch ( *((awt::FontSlant*) mAny.getValue()) )
635         {
636             case awt::FontSlant_OBLIQUE :
637             case awt::FontSlant_ITALIC :
638                 italic = "1";
639                 break;
640             default:
641                 break;
642         }
643 
644     if ( GETAD( CharUnderline ) )
645         switch ( *((sal_Int16*) mAny.getValue()) )
646         {
647             case awt::FontUnderline::SINGLE :
648                 underline = "sng";
649                 break;
650             case awt::FontUnderline::DOUBLE :
651                 underline = "dbl";
652                 break;
653             case awt::FontUnderline::DOTTED :
654                 underline = "dotted";
655                 break;
656             case awt::FontUnderline::DASH :
657                 underline = "dash";
658                 break;
659             case awt::FontUnderline::LONGDASH :
660                 underline = "dashLong";
661                 break;
662             case awt::FontUnderline::DASHDOT :
663                 underline = "dotDash";
664                 break;
665             case awt::FontUnderline::DASHDOTDOT :
666                 underline = "dotDotDash";
667                 break;
668             case awt::FontUnderline::WAVE :
669                 underline = "wavy";
670                 break;
671             case awt::FontUnderline::DOUBLEWAVE :
672                 underline = "wavyDbl";
673                 break;
674             case awt::FontUnderline::BOLD :
675                 underline = "heavy";
676                 break;
677             case awt::FontUnderline::BOLDDOTTED :
678                 underline = "dottedHeavy";
679                 break;
680             case awt::FontUnderline::BOLDDASH :
681                 underline = "dashHeavy";
682                 break;
683             case awt::FontUnderline::BOLDLONGDASH :
684                 underline = "dashLongHeavy";
685                 break;
686             case awt::FontUnderline::BOLDDASHDOT :
687                 underline = "dotDashHeavy";
688                 break;
689             case awt::FontUnderline::BOLDDASHDOTDOT :
690                 underline = "dotDotDashHeavy";
691                 break;
692             case awt::FontUnderline::BOLDWAVE :
693                 underline = "wavyHeavy";
694                 break;
695         }
696 
697     if( GETA( CharLocale ) ) {
698         com::sun::star::lang::Locale eLocale;
699         mAny >>= eLocale;
700 
701         OUStringBuffer usLanguageBuffer = eLocale.Language;
702         if( eLocale.Country.getLength() ) {
703             usLanguageBuffer.appendAscii( "-" );
704             usLanguageBuffer.append( eLocale.Country );
705         }
706 
707         if( usLanguageBuffer.getLength() )
708             usLanguage = usLanguageBuffer.makeStringAndClear();
709     }
710 
711     mpFS->startElementNS( XML_a, XML_rPr,
712                           XML_b, bold,
713                           XML_i, italic,
714                           XML_lang, usLanguage.getLength() ? USS( usLanguage ) : NULL,
715                           XML_sz, nSize == 1800 ? NULL : IS( nSize ),
716                           XML_u, underline,
717                           FSEND );
718 
719     // mso doesn't like text color to be placed after typeface
720     if( GETAD( CharColor ) ) {
721         sal_uInt32 color = *((sal_uInt32*) mAny.getValue());
722         DBG(printf("run color: %x auto: %x\n", static_cast<unsigned int>( color ), static_cast<unsigned int>( COL_AUTO )));
723 
724         if( color == COL_AUTO ) { // nCharColor depends to the background color
725             sal_Bool bIsDark = sal_False;
726             GET( bIsDark, IsBackgroundDark );
727             color = bIsDark ? 0xffffff : 0x000000;
728         }
729         color &= 0xffffff;
730 
731         // TODO: special handle embossed/engraved
732 
733         WriteSolidFill( color );
734     }
735 
736     if( GETAD( CharFontName ) ) {
737         const char* typeface = NULL;
738         const char* pitch = NULL;
739         const char* charset = NULL;
740         OUString usTypeface, usPitch, usCharset;
741 
742         mAny >>= usTypeface;
743         String aSubstName( GetSubsFontName( usTypeface, SUBSFONT_ONLYONE | SUBSFONT_MS ) );
744         if( aSubstName.Len() )
745             typeface = ST( aSubstName );
746         else
747             typeface = USS( usTypeface );
748 
749 
750 
751         mpFS->singleElementNS( XML_a, XML_latin,
752                                XML_typeface, typeface,
753                                XML_pitchFamily, pitch,
754                                XML_charset, charset,
755                                FSEND );
756     }
757 
758     if( ( bComplex && GETAD( CharFontNameComplex ) ) || ( !bComplex && GETAD( CharFontNameAsian ) ) ) {
759         const char* typeface = NULL;
760         const char* pitch = NULL;
761         const char* charset = NULL;
762         OUString usTypeface, usPitch, usCharset;
763 
764         mAny >>= usTypeface;
765         String aSubstName( GetSubsFontName( usTypeface, SUBSFONT_ONLYONE | SUBSFONT_MS ) );
766         if( aSubstName.Len() )
767             typeface = ST( aSubstName );
768         else
769             typeface = USS( usTypeface );
770 
771         mpFS->singleElementNS( XML_a, bComplex ? XML_cs : XML_ea,
772                                XML_typeface, typeface,
773                                XML_pitchFamily, pitch,
774                                XML_charset, charset,
775                                FSEND );
776     }
777 
778     mpFS->endElementNS( XML_a, XML_rPr );
779 }
780 
781 const char* DrawingML::GetFieldType( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > rRun )
782 {
783     const char* sType = NULL;
784     Reference< XPropertySet > rXPropSet( rRun, UNO_QUERY );
785     String aFieldType;
786 
787     if( GETA( TextPortionType ) ) {
788         aFieldType = String( *(::rtl::OUString*)mAny.getValue() );
789         DBG(printf ("field type: %s\n", ST(aFieldType) ));
790     }
791 
792     if( aFieldType == S( "TextField" ) ) {
793         Reference< XTextField > rXTextField;
794         GET( rXTextField, TextField );
795         if( rXTextField.is() ) {
796             rXPropSet.set( rXTextField, UNO_QUERY );
797             if( rXPropSet.is() ) {
798                 String aFieldKind( rXTextField->getPresentation( TRUE ) );
799                 DBG(printf ("field kind: %s\n", ST(aFieldKind) ));
800                 if( aFieldKind == S( "Page" ) ) {
801                     return "slidenum";
802                 }
803             }
804         }
805     }
806 
807     return sType;
808 }
809 
810 void DrawingML::GetUUID( OStringBuffer& rBuffer )
811 {
812     Sequence< sal_uInt8 > aSeq( 16 );
813     static char cDigits[17] = "0123456789ABCDEF";
814     rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True );
815     int i;
816 
817     rBuffer.append( '{' );
818     for( i = 0; i < 4; i++ ) {
819         rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
820         rBuffer.append( cDigits[ aSeq[i] && 0xf ] );
821     }
822     rBuffer.append( '-' );
823     for( ; i < 6; i++ ) {
824         rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
825         rBuffer.append( cDigits[ aSeq[i] && 0xf ] );
826     }
827     rBuffer.append( '-' );
828     for( ; i < 8; i++ ) {
829         rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
830         rBuffer.append( cDigits[ aSeq[i] && 0xf ] );
831     }
832     rBuffer.append( '-' );
833     for( ; i < 10; i++ ) {
834         rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
835         rBuffer.append( cDigits[ aSeq[i] && 0xf ] );
836     }
837     rBuffer.append( '-' );
838     for( ; i < 16; i++ ) {
839         rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
840         rBuffer.append( cDigits[ aSeq[i] && 0xf ] );
841     }
842     rBuffer.append( '}' );
843 }
844 
845 void DrawingML::WriteRun( Reference< XTextRange > rRun )
846 {
847     const char* sFieldType;
848     bool bIsField = false;
849     OUString sText = rRun->getString();
850 
851     if( sText.getLength() < 1)
852         return;
853 
854     if( ( sFieldType = GetFieldType( rRun ) ) ) {
855         OStringBuffer sUUID(39);
856 
857         GetUUID( sUUID );
858         mpFS->startElementNS( XML_a, XML_fld,
859                               XML_id, sUUID.getStr(),
860                               XML_type, sFieldType,
861                               FSEND );
862         bIsField = true;
863     } else
864         mpFS->startElementNS( XML_a, XML_r, FSEND );
865 
866     WriteRunProperties( rRun );
867 
868     mpFS->startElementNS( XML_a, XML_t, FSEND );
869     mpFS->writeEscaped( sText );
870     mpFS->endElementNS( XML_a, XML_t );
871 
872     if( bIsField )
873         mpFS->endElementNS( XML_a, XML_fld );
874     else
875         mpFS->endElementNS( XML_a, XML_r );
876 }
877 
878 #define AUTONUM(x) \
879                         if( bPBoth ) \
880                             pAutoNumType = #x "ParenBoth"; \
881                         else if( bPBehind ) \
882                             pAutoNumType = #x "ParenR"; \
883                         else if( bSDot ) \
884                             pAutoNumType = #x "Period";
885 
886 
887 inline static const char* GetAutoNumType( sal_Int16 nNumberingType, bool bSDot, bool bPBehind, bool bPBoth )
888 {
889     const char* pAutoNumType = NULL;
890 
891     switch( (SvxExtNumType)nNumberingType )
892         {
893         case SVX_NUM_CHARS_UPPER_LETTER_N :
894         case SVX_NUM_CHARS_UPPER_LETTER :
895             AUTONUM( alphaUc );
896             break;
897         case SVX_NUM_CHARS_LOWER_LETTER_N :
898         case SVX_NUM_CHARS_LOWER_LETTER :
899             AUTONUM( alphaLc );
900             break;
901         case SVX_NUM_ROMAN_UPPER :
902             AUTONUM( romanUc );
903             break;
904         case SVX_NUM_ROMAN_LOWER :
905             AUTONUM( romanLc );
906             break;
907         case SVX_NUM_ARABIC :
908             AUTONUM( arabic )
909             else
910                 pAutoNumType = "arabicPlain";
911                         break;
912         default:
913             break;
914         }
915 
916     return pAutoNumType;
917 }
918 
919 void DrawingML::WriteParagraphNumbering( Reference< XPropertySet > rXPropSet, sal_Int16 nLevel )
920 {
921     if( nLevel >= 0 && GETA( NumberingRules ) )
922     {
923         Reference< XIndexAccess > rXIndexAccess;
924 
925         if ( ( mAny >>= rXIndexAccess ) && nLevel < rXIndexAccess->getCount() )
926         {
927             DBG(printf ("numbering rules\n"));
928 
929             Sequence< PropertyValue > aPropertySequence;
930             rXIndexAccess->getByIndex( nLevel ) >>= aPropertySequence;
931 
932 
933             const PropertyValue* pPropValue = aPropertySequence.getArray();
934 
935             sal_Int32 nPropertyCount = aPropertySequence.getLength();
936 
937             if ( nPropertyCount ) {
938 
939                 sal_Int16 nNumberingType = -1;
940                 bool bSDot = false;
941                 bool bPBehind = false;
942                 bool bPBoth = false;
943                 sal_Unicode aBulletChar = 0x2022; // a bullet
944                 awt::FontDescriptor aFontDesc;
945                 bool bHasFontDesc = false;
946                 OUString aGraphicURL;
947                 sal_Int16 nBulletRelSize = 0;
948 
949                 for ( sal_Int32 i = 0; i < nPropertyCount; i++ ) {
950                     const void* pValue = pPropValue[ i ].Value.getValue();
951                     if ( pValue ) {
952                         OUString aPropName( pPropValue[ i ].Name );
953                         DBG(printf ("pro name: %s\n", OUStringToOString( aPropName, RTL_TEXTENCODING_UTF8 ).getStr()));
954                         if ( aPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "NumberingType" ) ) )
955                             nNumberingType = *( (sal_Int16*)pValue );
956                         else if ( aPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Prefix" ) ) ) {
957                             if( *(OUString*)pValue == US( ")" ) )
958                                 bPBoth = true;
959                         } else if  ( aPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Suffix" ) ) ) {
960                             if( *(OUString*)pValue == US( "." ) )
961                                 bSDot = true;
962                             else if( *(OUString*)pValue == US( ")" ) )
963                                 bPBehind = true;
964                         } else if ( aPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "BulletChar" ) ) )
965                         {
966                             aBulletChar = String ( *( (String*)pValue ) ).GetChar( 0 );
967                             //printf ("bullet char: %d\n", aBulletChar.getStr());
968                         }
969                         else if ( aPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "BulletFont" ) ) )
970                         {
971                             aFontDesc = *( (awt::FontDescriptor*)pValue );
972                             bHasFontDesc = true;
973 
974                             // Our numbullet dialog has set the wrong textencoding for our "StarSymbol" font,
975                             // instead of a Unicode encoding the encoding RTL_TEXTENCODING_SYMBOL was used.
976                             // Because there might exist a lot of damaged documemts I added this two lines
977                             // which fixes the bullet problem for the export.
978                             if ( aFontDesc.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "StarSymbol" ) ) )
979                                 aFontDesc.CharSet = RTL_TEXTENCODING_MS_1252;
980 
981                         } else if ( aPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "BulletRelSize" ) ) ) {
982                             nBulletRelSize = *( (sal_Int16*)pValue );
983                         } else if ( aPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "GraphicURL" ) ) ) {
984                             aGraphicURL = ( *(OUString*)pValue );
985                             DBG(printf ("graphic url: %s\n", OUStringToOString( aGraphicURL, RTL_TEXTENCODING_UTF8 ).getStr()));
986                         } else if ( aPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "GraphicSize" ) ) )
987                         {
988                             if ( pPropValue[ i ].Value.getValueType() == ::getCppuType( (awt::Size*)0) )
989                             {
990                                 // don't cast awt::Size to Size as on 64-bits they are not the same.
991                                 ::com::sun::star::awt::Size aSize;
992                                 pPropValue[ i ].Value >>= aSize;
993                                 //aBuGraSize.nA = aSize.Width;
994                                 //aBuGraSize.nB = aSize.Height;
995                                 DBG(printf("graphic size: %dx%d\n", int( aSize.Width ), int( aSize.Height )));
996                             }
997                         }
998                     }
999                 }
1000 
1001                 const char* pAutoNumType = GetAutoNumType( nNumberingType, bSDot, bPBehind, bPBoth );
1002 
1003                 if( nLevel >= 0 ) {
1004                     if( aGraphicURL.getLength() > 0 ) {
1005                         OUString sRelId = WriteImage( aGraphicURL );
1006 
1007                         mpFS->startElementNS( XML_a, XML_buBlip, FSEND );
1008                         mpFS->singleElementNS( XML_a, XML_blip, FSNS( XML_r, XML_embed ), USS( sRelId ), FSEND );
1009                         mpFS->endElementNS( XML_a, XML_buBlip );
1010                     } else {
1011                         if( nBulletRelSize && nBulletRelSize != 100 )
1012                             mpFS->singleElementNS( XML_a, XML_buSzPct,
1013                                                    XML_val, IS( 1000*( (sal_Int32)nBulletRelSize ) ), FSEND );
1014                         if( bHasFontDesc )
1015                             mpFS->singleElementNS( XML_a, XML_buFont,
1016                                                    XML_typeface, OUStringToOString( aFontDesc.Name, RTL_TEXTENCODING_UTF8 ).getStr(),
1017                                                    XML_charset, (aFontDesc.CharSet == awt::CharSet::SYMBOL) ? "2" : NULL,
1018                                                    FSEND );
1019 
1020                         if( pAutoNumType )
1021                             mpFS->singleElementNS( XML_a, XML_buAutoNum, XML_type, pAutoNumType, FSEND );
1022                         else {
1023                             aBulletChar = SubstituteBullet( aBulletChar, aFontDesc );
1024                             mpFS->singleElementNS( XML_a, XML_buChar, XML_char, USS( OUString( aBulletChar ) ), FSEND );
1025                         }
1026                     }
1027                 }
1028             }
1029         }
1030     }
1031 }
1032 
1033 const char* DrawingML::GetAlignment( sal_Int32 nAlignment )
1034 {
1035     const char* sAlignment = NULL;
1036 
1037     switch( nAlignment ) {
1038         case style::ParagraphAdjust_CENTER:
1039             sAlignment = "ctr";
1040             break;
1041         case style::ParagraphAdjust_RIGHT:
1042             sAlignment = "r";
1043             break;
1044         case style::ParagraphAdjust_BLOCK:
1045             sAlignment = "just";
1046             break;
1047         default:
1048             ;
1049     }
1050 
1051     return sAlignment;
1052 }
1053 
1054 void DrawingML::WriteParagraphProperties( Reference< XTextContent > rParagraph )
1055 {
1056     Reference< XPropertySet > rXPropSet( rParagraph, UNO_QUERY );
1057     Reference< XPropertyState > rXPropState( rParagraph, UNO_QUERY );
1058 
1059     if( !rXPropSet.is() || !rXPropState.is() )
1060         return;
1061 
1062     sal_Int16 nLevel = -1;
1063     GET( nLevel, NumberingLevel );
1064 
1065     sal_Int32 nLeftMargin = 0;
1066     // fix coordinates
1067     //GET( nLeftMargin, ParaLeftMargin );
1068 
1069     sal_Int16 nAlignment( style::ParagraphAdjust_LEFT );
1070     GET( nAlignment, ParaAdjust );
1071 
1072     if( nLevel != -1
1073             || nLeftMargin > 0
1074             || nAlignment != style::ParagraphAdjust_LEFT ) {
1075         mpFS->startElementNS( XML_a, XML_pPr,
1076                               XML_lvl, nLevel > 0 ? I32S( nLevel ) : NULL,
1077                               XML_marL, nLeftMargin > 0 ? IS( nLeftMargin ) : NULL,
1078                               XML_algn, GetAlignment( nAlignment ),
1079                               FSEND );
1080 
1081         WriteParagraphNumbering( rXPropSet, nLevel );
1082 
1083         mpFS->endElementNS( XML_a, XML_pPr );
1084     }
1085 }
1086 
1087 void DrawingML::WriteParagraph( Reference< XTextContent > rParagraph )
1088 {
1089     Reference< XEnumerationAccess > access( rParagraph, UNO_QUERY );
1090     if( !access.is() )
1091         return;
1092 
1093     Reference< XEnumeration > enumeration( access->createEnumeration() );
1094     if( !enumeration.is() )
1095         return;
1096 
1097     mpFS->startElementNS( XML_a, XML_p, FSEND );
1098 
1099     sal_Bool bPropertiesWritten = FALSE;
1100     while( enumeration->hasMoreElements() ) {
1101         Reference< XTextRange > run;
1102         Any any ( enumeration->nextElement() );
1103 
1104         if (any >>= run) {
1105             if( !bPropertiesWritten && run->getString().getLength() ) {
1106                 WriteParagraphProperties( rParagraph );
1107                 bPropertiesWritten = TRUE;
1108             }
1109             WriteRun( run );
1110         }
1111     }
1112     mpFS->singleElementNS( XML_a, XML_endParaRPr, FSEND );
1113 
1114     mpFS->endElementNS( XML_a, XML_p );
1115 }
1116 
1117 void DrawingML::WriteText( Reference< XShape > rXShape  )
1118 {
1119     Reference< XText > xXText( rXShape, UNO_QUERY );
1120     Reference< XPropertySet > rXPropSet( rXShape, UNO_QUERY );
1121 
1122     if( !xXText.is() )
1123         return;
1124 
1125 #define DEFLRINS 254
1126 #define DEFTBINS 127
1127     sal_Int32 nLeft, nRight, nTop, nBottom;
1128     nLeft = nRight = DEFLRINS;
1129     nTop = nBottom = DEFTBINS;
1130 
1131     // top inset looks a bit different compared to ppt export
1132     // check if something related doesn't work as expected
1133     GET( nLeft, TextLeftDistance );
1134     GET( nRight, TextRightDistance );
1135     GET( nTop, TextUpperDistance );
1136     GET( nBottom, TextLowerDistance );
1137 
1138     TextVerticalAdjust eVerticalAlignment( TextVerticalAdjust_TOP );
1139     const char* sVerticalAlignment = NULL;
1140     GET( eVerticalAlignment, TextVerticalAdjust );
1141     switch( eVerticalAlignment ) {
1142         case TextVerticalAdjust_BOTTOM:
1143             sVerticalAlignment = "b";
1144             break;
1145         case TextVerticalAdjust_CENTER:
1146             sVerticalAlignment = "ctr";
1147             break;
1148         case TextVerticalAdjust_TOP:
1149         default:
1150             ;
1151     }
1152 
1153     TextHorizontalAdjust eHorizontalAlignment( TextHorizontalAdjust_CENTER );
1154     bool bHorizontalCenter = false;
1155     GET( eHorizontalAlignment, TextHorizontalAdjust );
1156     if( eHorizontalAlignment == TextHorizontalAdjust_CENTER )
1157         bHorizontalCenter = true;
1158 
1159     sal_Bool bHasWrap = FALSE;
1160     sal_Bool bWrap = FALSE;
1161     if( GETA( TextWordWrap ) ) {
1162         mAny >>= bWrap;
1163         bHasWrap = TRUE;
1164         //DBG(printf("wrap: %d\n", bWrap));
1165     }
1166 
1167     mpFS->singleElementNS( XML_a, XML_bodyPr,
1168                            XML_wrap, bHasWrap && !bWrap ? "none" : NULL,
1169                            XML_lIns, (nLeft != DEFLRINS) ? IS( MM100toEMU( nLeft ) ) : NULL,
1170                            XML_rIns, (nRight != DEFLRINS) ? IS( MM100toEMU( nRight ) ) : NULL,
1171                            XML_tIns, (nTop != DEFTBINS) ? IS( MM100toEMU( nTop ) ) : NULL,
1172                            XML_bIns, (nBottom != DEFTBINS) ? IS( MM100toEMU( nBottom ) ) : NULL,
1173                            XML_anchor, sVerticalAlignment,
1174                            XML_anchorCtr, bHorizontalCenter ? "1" : NULL,
1175                            FSEND );
1176 
1177     Reference< XEnumerationAccess > access( xXText, UNO_QUERY );
1178     if( !access.is() )
1179         return;
1180 
1181     Reference< XEnumeration > enumeration( access->createEnumeration() );
1182     if( !enumeration.is() )
1183         return;
1184 
1185     while( enumeration->hasMoreElements() ) {
1186         Reference< XTextContent > paragraph;
1187         Any any ( enumeration->nextElement() );
1188 
1189         if( any >>= paragraph)
1190             WriteParagraph( paragraph );
1191     }
1192 
1193 }
1194 
1195 void DrawingML::WritePresetShape( const char* pShape )
1196 {
1197     mpFS->startElementNS( XML_a, XML_prstGeom,
1198                           XML_prst, pShape,
1199                           FSEND );
1200     mpFS->singleElementNS( XML_a, XML_avLst, FSEND );
1201     mpFS->endElementNS(  XML_a, XML_prstGeom );
1202 }
1203 
1204 void DrawingML::WritePresetShape( const char* pShape, MSO_SPT eShapeType, sal_Bool bPredefinedHandlesUsed, sal_Int32 nAdjustmentsWhichNeedsToBeConverted, const PropertyValue& rProp )
1205 {
1206     mpFS->startElementNS( XML_a, XML_prstGeom,
1207                           XML_prst, pShape,
1208                           FSEND );
1209     mpFS->startElementNS( XML_a, XML_avLst, FSEND );
1210 
1211     Sequence< drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentSeq;
1212     if ( rProp.Value >>= aAdjustmentSeq ) {
1213         DBG(printf("adj seq len: %d\n", int( aAdjustmentSeq.getLength() )));
1214         if ( bPredefinedHandlesUsed )
1215             EscherPropertyContainer::LookForPolarHandles( eShapeType, nAdjustmentsWhichNeedsToBeConverted );
1216 
1217         sal_Int32 nValue, nLength = aAdjustmentSeq.getLength();
1218         for( sal_Int32 i=0; i < nLength; i++ )
1219             if( EscherPropertyContainer::GetAdjustmentValue( aAdjustmentSeq[ i ], i, nAdjustmentsWhichNeedsToBeConverted, nValue ) )
1220                 mpFS->singleElementNS( XML_a, XML_gd,
1221                                        XML_name, nLength > 1 ? ( OString( "adj" ) + OString::valueOf( i + 1 ) ).getStr() : "adj",
1222                                        XML_fmla, (OString("val ") + OString::valueOf( nValue )).getStr(),
1223                                        FSEND );
1224     }
1225 
1226     mpFS->endElementNS( XML_a, XML_avLst );
1227     mpFS->endElementNS(  XML_a, XML_prstGeom );
1228 }
1229 
1230 void DrawingML::WritePolyPolygon( const PolyPolygon& rPolyPolygon )
1231 {
1232     if( rPolyPolygon.Count() < 1 )
1233         return;
1234 
1235     mpFS->startElementNS( XML_a, XML_custGeom, FSEND );
1236     mpFS->singleElementNS( XML_a, XML_avLst, FSEND );
1237     mpFS->singleElementNS( XML_a, XML_gdLst, FSEND );
1238     mpFS->singleElementNS( XML_a, XML_ahLst, FSEND );
1239     mpFS->singleElementNS( XML_a, XML_rect,
1240                            XML_l, "0",
1241                            XML_t, "0",
1242                            XML_r, "r",
1243                            XML_b, "b",
1244                            FSEND );
1245 
1246     mpFS->startElementNS( XML_a, XML_pathLst, FSEND );
1247 
1248     for( USHORT i = 0; i < rPolyPolygon.Count(); i ++ ) {
1249 
1250         const Polygon& rPoly = rPolyPolygon[ i ];
1251         Rectangle aRect( rPoly.GetBoundRect() );
1252         sal_Bool bBezier = FALSE;
1253 
1254         mpFS->startElementNS( XML_a, XML_path,
1255                               XML_w, I64S( aRect.GetWidth() ),
1256                               XML_h, I64S( aRect.GetHeight() ),
1257                               FSEND );
1258 
1259         if( rPoly.GetSize() > 0 )
1260         {
1261             mpFS->startElementNS( XML_a, XML_moveTo, FSEND );
1262 
1263             mpFS->singleElementNS( XML_a, XML_pt,
1264                                    XML_x, I64S( rPoly[ 0 ].X() - aRect.Left() ),
1265                                    XML_y, I64S( rPoly[ 0 ].Y() - aRect.Top() ),
1266                                    FSEND );
1267 
1268             mpFS->endElementNS( XML_a, XML_moveTo );
1269         }
1270 
1271         for( USHORT j = 1; j < rPoly.GetSize(); j ++ )
1272         {
1273             enum PolyFlags flags = rPoly.GetFlags(j);
1274             if( flags == POLY_CONTROL && !bBezier )
1275             {
1276                 mpFS->startElementNS( XML_a, XML_cubicBezTo, FSEND );
1277                 bBezier = TRUE;
1278             }
1279             else if( flags == POLY_NORMAL && !bBezier )
1280                 mpFS->startElementNS( XML_a, XML_lnTo, FSEND );
1281 
1282             mpFS->singleElementNS( XML_a, XML_pt,
1283                                    XML_x, I64S( rPoly[j].X() - aRect.Left() ),
1284                                    XML_y, I64S( rPoly[j].Y() - aRect.Top() ),
1285                                    FSEND );
1286 
1287             if( ( flags == POLY_NORMAL || flags == POLY_SYMMTR ) && bBezier )
1288             {
1289                 mpFS->endElementNS( XML_a, XML_cubicBezTo );
1290                 bBezier = FALSE;
1291             }
1292             else if( flags == POLY_NORMAL && !bBezier )
1293                 mpFS->endElementNS( XML_a, XML_lnTo );
1294             else if( bBezier && ( j % 3 ) == 0 )
1295             {
1296                 // //a:cubicBezTo can only contain 3 //a:pt elements, so we
1297                 // need to break things up...
1298                 mpFS->endElementNS( XML_a, XML_cubicBezTo );
1299                 mpFS->startElementNS( XML_a, XML_cubicBezTo, FSEND );
1300             }
1301 //             switch( rPoly.GetFlags(j) ) {
1302 //                 case POLY_NORMAL:
1303 //                     DBG(printf("normal\n"));
1304 //                     break;
1305 //                 case POLY_SMOOTH:
1306 //                     DBG(printf("smooth\n"));
1307 //                     break;
1308 //                 case POLY_CONTROL:
1309 //                     DBG(printf("control\n"));
1310 //                     break;
1311 //                 case POLY_SYMMTR:
1312 //                     DBG(printf("symmtr\n"));
1313 //                         break;
1314 //             }
1315 //             DBG(printf("point %ld %ld\n", rPoly[j].X() - aRect.Left(), rPoly[j].Y() - aRect.Top()));
1316         }
1317 
1318         mpFS->endElementNS( XML_a, XML_path );
1319     }
1320 
1321     mpFS->endElementNS( XML_a, XML_pathLst );
1322 
1323     mpFS->endElementNS(  XML_a, XML_custGeom );
1324 }
1325 
1326 void DrawingML::WriteConnectorConnections( EscherConnectorListEntry& rConnectorEntry, sal_Int32 nStartID, sal_Int32 nEndID )
1327 {
1328     mpFS->singleElementNS( XML_a, XML_stCxn,
1329                            XML_id, I32S( nStartID ),
1330                            XML_idx, I64S( rConnectorEntry.GetConnectorRule( TRUE ) ),
1331                            FSEND );
1332     mpFS->singleElementNS( XML_a, XML_endCxn,
1333                            XML_id, I32S( nEndID ),
1334                            XML_idx, I64S( rConnectorEntry.GetConnectorRule( FALSE ) ),
1335                            FSEND );
1336 }
1337 
1338 // from sw/source/filter/ww8/wrtw8num.cxx for default bullets to export to MS intact
1339 static void lcl_SubstituteBullet(String& rNumStr, rtl_TextEncoding& rChrSet, String& rFontName)
1340 {
1341     sal_Unicode cChar = rNumStr.GetChar(0);
1342     StarSymbolToMSMultiFont *pConvert = CreateStarSymbolToMSMultiFont();
1343     String sFont = pConvert->ConvertChar(cChar);
1344     delete pConvert;
1345     if (sFont.Len())
1346     {
1347         rNumStr = static_cast< sal_Unicode >(cChar | 0xF000);
1348         rFontName = sFont;
1349         rChrSet = RTL_TEXTENCODING_SYMBOL;
1350     }
1351     else if ( (rNumStr.GetChar(0) < 0xE000 || rNumStr.GetChar(0) > 0xF8FF) )
1352     {
1353         /*
1354            Ok we can't fit into a known windows unicode font, but
1355            we are not in the private area, so we are a
1356            standardized symbol, so turn off the symbol bit and
1357            let words own font substitution kick in
1358            */
1359         rChrSet = RTL_TEXTENCODING_UNICODE;
1360         rFontName = ::GetFontToken(rFontName, 0);
1361     }
1362     else
1363     {
1364         /*
1365            Well we don't have an available substition, and we're
1366            in our private area, so give up and show a standard
1367            bullet symbol
1368            */
1369         rFontName.AssignAscii(RTL_CONSTASCII_STRINGPARAM("Wingdings"));
1370         rNumStr = static_cast< sal_Unicode >(0x6C);
1371     }
1372 }
1373 
1374 sal_Unicode DrawingML::SubstituteBullet( sal_Unicode cBulletId, ::com::sun::star::awt::FontDescriptor& rFontDesc )
1375 {
1376     String sNumStr = cBulletId;
1377 
1378     if ( rFontDesc.Name.equalsIgnoreAsciiCaseAscii("starsymbol") ||
1379          rFontDesc.Name.equalsIgnoreAsciiCaseAscii("opensymbol") )  {
1380         String sFontName = rFontDesc.Name;
1381         rtl_TextEncoding aCharSet = rFontDesc.CharSet;
1382 
1383         lcl_SubstituteBullet( sNumStr, aCharSet, sFontName );
1384 
1385         rFontDesc.Name = sFontName;
1386         rFontDesc.CharSet = aCharSet;
1387     }
1388 
1389     return sNumStr.GetChar( 0 );
1390 }
1391 
1392 }
1393 }
1394