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