bump product version to 4.1.6.2
[LibreOffice.git] / oox / source / export / drawingml.cxx
blobeae46e046856968b0fca7f9edf86973a17248307
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "oox/core/xmlfilterbase.hxx"
21 #include "oox/export/drawingml.hxx"
22 #include "oox/export/utils.hxx"
23 #include <oox/token/tokens.hxx>
25 #include <cstdio>
26 #include <com/sun/star/awt/CharSet.hpp>
27 #include <com/sun/star/awt/FontDescriptor.hpp>
28 #include <com/sun/star/awt/FontSlant.hpp>
29 #include <com/sun/star/awt/FontWeight.hpp>
30 #include <com/sun/star/awt/FontUnderline.hpp>
31 #include <com/sun/star/awt/Gradient.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/beans/XPropertyState.hpp>
34 #include <com/sun/star/beans/Property.hpp>
35 #include <com/sun/star/beans/XPropertySetInfo.hpp>
36 #include <com/sun/star/container/XEnumerationAccess.hpp>
37 #include <com/sun/star/container/XIndexAccess.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/drawing/XShape.hpp>
46 #include <com/sun/star/drawing/FillStyle.hpp>
47 #include <com/sun/star/geometry/IntegerRectangle2D.hpp>
48 #include <com/sun/star/i18n/ScriptType.hpp>
49 #include <com/sun/star/io/XOutputStream.hpp>
50 #include <com/sun/star/style/LineSpacing.hpp>
51 #include <com/sun/star/style/LineSpacingMode.hpp>
52 #include <com/sun/star/style/ParagraphAdjust.hpp>
53 #include <com/sun/star/text/WritingMode.hpp>
54 #include <com/sun/star/text/GraphicCrop.hpp>
55 #include <com/sun/star/text/XText.hpp>
56 #include <com/sun/star/text/XTextContent.hpp>
57 #include <com/sun/star/text/XTextField.hpp>
58 #include <com/sun/star/text/XTextRange.hpp>
59 #include <tools/stream.hxx>
60 #include <tools/string.hxx>
61 #include <unotools/fontdefs.hxx>
62 #include <vcl/cvtgrf.hxx>
63 #include <vcl/graph.hxx>
64 #include <svtools/grfmgr.hxx>
65 #include <rtl/strbuf.hxx>
66 #include <sfx2/app.hxx>
67 #include <svl/languageoptions.hxx>
68 #include <filter/msfilter/escherex.hxx>
69 #include <filter/msfilter/util.hxx>
70 #include <editeng/svxenum.hxx>
71 #include <svx/unoapi.hxx>
72 #include <svx/svdoashp.hxx>
74 using namespace ::com::sun::star;
75 using namespace ::com::sun::star::beans;
76 using namespace ::com::sun::star::drawing;
77 using namespace ::com::sun::star::i18n;
78 using namespace ::com::sun::star::style;
79 using namespace ::com::sun::star::text;
80 using namespace ::com::sun::star::uno;
81 using ::com::sun::star::beans::PropertyState;
82 using ::com::sun::star::beans::PropertyValue;
83 using ::com::sun::star::beans::XPropertySet;
84 using ::com::sun::star::beans::XPropertyState;
85 using ::com::sun::star::container::XEnumeration;
86 using ::com::sun::star::container::XEnumerationAccess;
87 using ::com::sun::star::container::XIndexAccess;
88 using ::com::sun::star::geometry::IntegerRectangle2D;
89 using ::com::sun::star::io::XOutputStream;
90 using ::com::sun::star::style::LineSpacing;
91 using ::com::sun::star::text::XText;
92 using ::com::sun::star::text::XTextContent;
93 using ::com::sun::star::text::XTextField;
94 using ::com::sun::star::text::XTextRange;
95 using ::sax_fastparser::FSHelperPtr;
97 DBG(extern void dump_pset(Reference< XPropertySet > rXPropSet));
99 namespace oox {
100 namespace drawingml {
102 #define GETA(propName) \
103 GetProperty( rXPropSet, String( #propName ) )
105 #define GETAD(propName) \
106 ( GetPropertyAndState( rXPropSet, rXPropState, String( #propName ), eState ) && eState == beans::PropertyState_DIRECT_VALUE )
108 #define GET(variable, propName) \
109 if ( GETA(propName) ) \
110 mAny >>= variable;
112 // not thread safe
113 int DrawingML::mnImageCounter = 1;
115 void DrawingML::ResetCounters()
117 mnImageCounter = 1;
120 bool DrawingML::GetProperty( Reference< XPropertySet > rXPropSet, OUString aName )
122 bool bRetValue = false;
124 try {
125 mAny = rXPropSet->getPropertyValue( aName );
126 if ( mAny.hasValue() )
127 bRetValue = true;
128 } catch( const Exception& ) { /* printf ("exception when trying to get value of property: %s\n", USS(aName)); */ }
130 return bRetValue;
133 bool DrawingML::GetPropertyAndState( Reference< XPropertySet > rXPropSet, Reference< XPropertyState > rXPropState, String aName, PropertyState& eState )
135 bool bRetValue = false;
137 try {
138 mAny = rXPropSet->getPropertyValue( aName );
139 if ( mAny.hasValue() ) {
140 bRetValue = true;
141 eState = rXPropState->getPropertyState( aName );
143 } catch( const Exception& ) { /* printf ("exception when trying to get value of property: %s\n", USS(aName)); */ }
145 return bRetValue;
148 void DrawingML::WriteColor( sal_uInt32 nColor )
150 OString sColor = OString::valueOf( ( sal_Int64 ) nColor, 16 );
151 if( sColor.getLength() < 6 ) {
152 OStringBuffer sBuf( "0" );
153 int remains = 5 - sColor.getLength();
155 while( remains > 0 ) {
156 sBuf.append( "0" );
157 remains--;
160 sBuf.append( sColor );
162 sColor = sBuf.getStr();
164 mpFS->singleElementNS( XML_a, XML_srgbClr, XML_val, sColor.getStr(), FSEND );
167 void DrawingML::WriteSolidFill( sal_uInt32 nColor )
169 mpFS->startElementNS( XML_a, XML_solidFill, FSEND );
170 WriteColor( nColor );
171 mpFS->endElementNS( XML_a, XML_solidFill );
174 void DrawingML::WriteSolidFill( Reference< XPropertySet > rXPropSet )
176 if ( GetProperty( rXPropSet, "FillColor" ) )
177 WriteSolidFill( *((sal_uInt32*) mAny.getValue()) & 0xffffff );
180 void DrawingML::WriteGradientStop( sal_uInt16 nStop, sal_uInt32 nColor )
182 mpFS->startElementNS( XML_a, XML_gs,
183 XML_pos, I32S( nStop * 1000 ),
184 FSEND );
185 WriteColor( nColor );
186 mpFS->endElementNS( XML_a, XML_gs );
189 sal_uInt32 DrawingML::ColorWithIntensity( sal_uInt32 nColor, sal_uInt32 nIntensity )
191 return ( ( ( nColor & 0xff ) * nIntensity ) / 100 )
192 | ( ( ( ( ( nColor & 0xff00 ) >> 8 ) * nIntensity ) / 100 ) << 8 )
193 | ( ( ( ( ( nColor & 0xff0000 ) >> 8 ) * nIntensity ) / 100 ) << 8 );
196 void DrawingML::WriteGradientFill( Reference< XPropertySet > rXPropSet )
198 awt::Gradient aGradient;
199 if( GETA( FillGradient ) ) {
200 aGradient = *static_cast< const awt::Gradient* >( mAny.getValue() );
202 mpFS->startElementNS( XML_a, XML_gradFill, FSEND );
204 switch( aGradient.Style ) {
205 default:
206 case GradientStyle_LINEAR:
207 mpFS->startElementNS( XML_a, XML_gsLst, FSEND );
208 WriteGradientStop( 0, 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;
216 case GradientStyle_AXIAL:
217 mpFS->startElementNS( XML_a, XML_gsLst, FSEND );
218 WriteGradientStop( 0, ColorWithIntensity( aGradient.EndColor, aGradient.EndIntensity ) );
219 WriteGradientStop( 50, ColorWithIntensity( aGradient.StartColor, aGradient.StartIntensity ) );
220 WriteGradientStop( 100, ColorWithIntensity( aGradient.EndColor, aGradient.EndIntensity ) );
221 mpFS->endElementNS( XML_a, XML_gsLst );
222 mpFS->singleElementNS( XML_a, XML_lin,
223 XML_ang, I32S( ( ( ( 3600 - aGradient.Angle + 900 ) * 6000 ) % 21600000 ) ),
224 FSEND );
225 break;
227 /* I don't see how to apply transformation to gradients, so
228 * elliptical will end as radial and square as
229 * rectangular. also position offsets are not applied */
230 case GradientStyle_RADIAL:
231 case GradientStyle_ELLIPTICAL:
232 case GradientStyle_RECT:
233 case GradientStyle_SQUARE:
234 mpFS->startElementNS( XML_a, XML_gsLst, FSEND );
235 WriteGradientStop( 0, ColorWithIntensity( aGradient.EndColor, aGradient.EndIntensity ) );
236 WriteGradientStop( 100, ColorWithIntensity( aGradient.StartColor, aGradient.StartIntensity ) );
237 mpFS->endElementNS( XML_a, XML_gsLst );
238 mpFS->singleElementNS( XML_a, XML_path,
239 XML_path, ( aGradient.Style == awt::GradientStyle_RADIAL || aGradient.Style == awt::GradientStyle_ELLIPTICAL ) ? "circle" : "rect",
240 FSEND );
241 break;
244 mpFS->endElementNS( XML_a, XML_gradFill );
249 void DrawingML::WriteLineArrow( Reference< XPropertySet > rXPropSet, sal_Bool bLineStart )
251 ESCHER_LineEnd eLineEnd;
252 sal_Int32 nArrowLength;
253 sal_Int32 nArrowWidth;
255 if ( EscherPropertyContainer::GetLineArrow( bLineStart, rXPropSet, eLineEnd, nArrowLength, nArrowWidth ) ) {
256 const char* len;
257 const char* type;
258 const char* width;
260 switch( nArrowLength ) {
261 case ESCHER_LineShortArrow:
262 len = "sm";
263 break;
264 default:
265 case ESCHER_LineMediumLenArrow:
266 len = "med";
267 break;
268 case ESCHER_LineLongArrow:
269 len = "lg";
270 break;
273 switch( eLineEnd ) {
274 default:
275 case ESCHER_LineNoEnd:
276 type = "none";
277 break;
278 case ESCHER_LineArrowEnd:
279 type = "triangle";
280 break;
281 case ESCHER_LineArrowStealthEnd:
282 type = "stealth";
283 break;
284 case ESCHER_LineArrowDiamondEnd:
285 type = "diamond";
286 break;
287 case ESCHER_LineArrowOvalEnd:
288 type = "oval";
289 break;
290 case ESCHER_LineArrowOpenEnd:
291 type = "arrow";
292 break;
295 switch( nArrowWidth ) {
296 case ESCHER_LineNarrowArrow:
297 width = "sm";
298 break;
299 default:
300 case ESCHER_LineMediumWidthArrow:
301 width = "med";
302 break;
303 case ESCHER_LineWideArrow:
304 width = "lg";
305 break;
308 mpFS->singleElementNS( XML_a, bLineStart ? XML_headEnd : XML_tailEnd,
309 XML_len, len,
310 XML_type, type,
311 XML_w, width,
312 FSEND );
316 void DrawingML::WriteOutline( Reference< XPropertySet > rXPropSet )
318 drawing::LineStyle aLineStyle( drawing::LineStyle_NONE );
320 GET( aLineStyle, LineStyle );
322 sal_uInt32 nLineWidth = 0;
323 sal_uInt32 nColor = 0;
324 sal_Bool bColorSet = sal_False;
325 const char* cap = NULL;
326 drawing::LineDash aLineDash;
327 sal_Bool bDashSet = sal_False;
328 bool bNoFill = false;
330 GET( nLineWidth, LineWidth );
332 switch( aLineStyle ) {
333 case drawing::LineStyle_NONE:
334 bNoFill = true;
335 break;
336 case drawing::LineStyle_DASH:
337 if( GETA( LineDash ) ) {
338 aLineDash = *(drawing::LineDash*) mAny.getValue();
339 bDashSet = sal_True;
340 if( aLineDash.Style == DashStyle_ROUND || aLineDash.Style == DashStyle_ROUNDRELATIVE )
341 cap = "rnd";
343 DBG(printf("dash dots: %d dashes: %d dotlen: %d dashlen: %d distance: %d\n",
344 int( aLineDash.Dots ), int( aLineDash.Dashes ), int( aLineDash.DotLen ), int( aLineDash.DashLen ), int( aLineDash.Distance )));
346 /* fallthru intended */
347 case drawing::LineStyle_SOLID:
348 default:
349 if ( GETA( LineColor ) ) {
350 nColor = *((sal_uInt32*) mAny.getValue()) & 0xffffff;
351 bColorSet = sal_True;
353 break;
356 mpFS->startElementNS( XML_a, XML_ln,
357 XML_cap, cap,
358 XML_w, nLineWidth > 1 ? I64S( MM100toEMU( nLineWidth ) ) : NULL,
359 FSEND );
360 if( bColorSet )
361 WriteSolidFill( nColor );
363 if( bDashSet ) {
364 mpFS->startElementNS( XML_a, XML_custDash, FSEND );
365 int i;
366 for( i = 0; i < aLineDash.Dots; i ++ )
367 mpFS->singleElementNS( XML_a, XML_ds,
368 XML_d, aLineDash.DotLen ? I64S( aLineDash.DotLen*1000 ) : "100000",
369 XML_sp, I64S( aLineDash.Distance*1000 ),
370 FSEND );
371 for( i = 0; i < aLineDash.Dashes; i ++ )
372 mpFS->singleElementNS( XML_a, XML_ds,
373 XML_d, aLineDash.DashLen ? I64S( aLineDash.DashLen*1000 ) : "100000",
374 XML_sp, I64S( aLineDash.Distance*1000 ),
375 FSEND );
376 mpFS->endElementNS( XML_a, XML_custDash );
379 if( !bNoFill && nLineWidth > 1 && GETA( LineJoint ) ) {
380 LineJoint eLineJoint;
382 mAny >>= eLineJoint;
383 switch( eLineJoint ) {
384 case LineJoint_NONE:
385 case LineJoint_MIDDLE:
386 case LineJoint_BEVEL:
387 mpFS->singleElementNS( XML_a, XML_bevel, FSEND );
388 break;
389 default:
390 case LineJoint_MITER:
391 mpFS->singleElementNS( XML_a, XML_miter, FSEND );
392 break;
393 case LineJoint_ROUND:
394 mpFS->singleElementNS( XML_a, XML_round, FSEND );
395 break;
399 if( !bNoFill )
401 WriteLineArrow( rXPropSet, sal_True );
402 WriteLineArrow( rXPropSet, sal_False );
404 else
406 mpFS->singleElementNS( XML_a, XML_noFill, FSEND );
409 mpFS->endElementNS( XML_a, XML_ln );
412 OUString DrawingML::WriteImage( const OUString& rURL )
414 OString aURLBS(OUStringToOString(rURL, RTL_TEXTENCODING_UTF8));
416 const char aURLBegin[] = "vnd.sun.star.GraphicObject:";
417 sal_Int32 index = aURLBS.indexOf(aURLBegin);
419 if ( index != -1 )
421 DBG(printf ("begin: %ld %s\n", long( sizeof( aURLBegin ) ), USS( rURL ) + RTL_CONSTASCII_LENGTH( aURLBegin ) ));
422 Graphic aGraphic = GraphicObject( aURLBS.copy(RTL_CONSTASCII_LENGTH(aURLBegin)) ).GetTransformedGraphic ();
424 return WriteImage( aGraphic );
425 } else {
426 // add link to relations
429 return OUString();
432 const char* DrawingML::GetComponentDir()
434 switch ( meDocumentType )
436 case DOCUMENT_DOCX: return "word";
437 case DOCUMENT_PPTX: return "ppt";
438 case DOCUMENT_XLSX: return "xl";
441 return "unknown";
444 const char* DrawingML::GetRelationCompPrefix()
446 switch ( meDocumentType )
448 case DOCUMENT_DOCX: return "";
449 case DOCUMENT_PPTX:
450 case DOCUMENT_XLSX: return "../";
453 return "unknown";
456 OUString DrawingML::WriteImage( const Graphic& rGraphic )
458 GfxLink aLink = rGraphic.GetLink ();
459 OUString sMediaType;
460 const char* pExtension = "";
461 OUString sRelId;
463 SvMemoryStream aStream;
464 const void* aData = aLink.GetData();
465 sal_Size nDataSize = aLink.GetDataSize();
467 switch ( aLink.GetType() ) {
468 case GFX_LINK_TYPE_NATIVE_GIF:
469 sMediaType = "image/gif";
470 pExtension = ".gif";
471 break;
472 case GFX_LINK_TYPE_NATIVE_JPG:
473 sMediaType = "image/jpeg";
474 pExtension = ".jpeg";
475 break;
476 case GFX_LINK_TYPE_NATIVE_PNG:
477 sMediaType = "image/png";
478 pExtension = ".png";
479 break;
480 case GFX_LINK_TYPE_NATIVE_TIF:
481 sMediaType = "image/tiff";
482 pExtension = ".tiff";
483 break;
484 case GFX_LINK_TYPE_NATIVE_WMF:
485 sMediaType = "image/x-wmf";
486 pExtension = ".wmf";
487 break;
488 case GFX_LINK_TYPE_NATIVE_MET:
489 sMediaType = "image/x-met";
490 pExtension = ".met";
491 break;
492 case GFX_LINK_TYPE_NATIVE_PCT:
493 sMediaType = "image/x-pict";
494 pExtension = ".pct";
495 break;
496 default: {
497 GraphicType aType = rGraphic.GetType();
498 if ( aType == GRAPHIC_BITMAP ) {
499 GraphicConverter::Export( aStream, rGraphic, CVT_PNG );
500 sMediaType = "image/png";
501 pExtension = ".png";
502 } else if ( aType == GRAPHIC_GDIMETAFILE ) {
503 GraphicConverter::Export( aStream, rGraphic, CVT_EMF );
504 sMediaType = "image/x-emf";
505 pExtension = ".emf";
506 } else {
507 OSL_TRACE( "unhandled graphic type" );
508 break;
511 aData = aStream.GetData();
512 nDataSize = aStream.GetEndOfData();
513 break;
517 Reference< XOutputStream > xOutStream = mpFB->openFragmentStream( OUStringBuffer()
518 .appendAscii( GetComponentDir() )
519 .appendAscii( "/media/image" )
520 .append( (sal_Int32) mnImageCounter )
521 .appendAscii( pExtension )
522 .makeStringAndClear(),
523 sMediaType );
524 xOutStream->writeBytes( Sequence< sal_Int8 >( (const sal_Int8*) aData, nDataSize ) );
525 xOutStream->closeOutput();
527 sRelId = mpFB->addRelation( mpFS->getOutputStream(),
528 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
529 OUStringBuffer()
530 .appendAscii( GetRelationCompPrefix() )
531 .appendAscii( "media/image" )
532 .append( (sal_Int32) mnImageCounter ++ )
533 .appendAscii( pExtension )
534 .makeStringAndClear() );
536 return sRelId;
539 OUString DrawingML::WriteBlip( Reference< XPropertySet > rXPropSet, OUString& rURL, const Graphic *pGraphic )
541 OUString sRelId = pGraphic ? WriteImage( *pGraphic ) : WriteImage( rURL );
542 sal_Int16 nBright = 0;
543 sal_Int32 nContrast = 0;
545 GET( nBright, AdjustLuminance );
546 GET( nContrast, AdjustContrast );
548 mpFS->startElementNS( XML_a, XML_blip,
549 FSNS( XML_r, XML_embed), OUStringToOString( sRelId, RTL_TEXTENCODING_UTF8 ).getStr(),
550 FSEND );
551 if( nBright || nContrast )
552 mpFS->singleElementNS( XML_a, XML_lum,
553 XML_bright, nBright ? I32S( nBright*1000 ) : NULL,
554 XML_contrast, nContrast ? I32S( nContrast*1000 ) : NULL,
555 FSEND );
557 mpFS->endElementNS( XML_a, XML_blip );
559 return sRelId;
562 void DrawingML::WriteBlipMode( Reference< XPropertySet > rXPropSet )
564 BitmapMode eBitmapMode( BitmapMode_NO_REPEAT );
565 if (GetProperty( rXPropSet, "FillBitmapMode" ) )
566 mAny >>= eBitmapMode;
568 DBG(printf("fill bitmap mode: %d\n", eBitmapMode));
570 switch (eBitmapMode) {
571 case BitmapMode_REPEAT:
572 mpFS->singleElementNS( XML_a, XML_tile, FSEND );
573 break;
574 case BitmapMode_STRETCH:
575 mpFS->startElementNS( XML_a, XML_stretch, FSEND );
576 mpFS->singleElementNS( XML_a, XML_fillRect, FSEND );
577 mpFS->endElementNS( XML_a, XML_stretch );
578 break;
579 default:
584 void DrawingML::WriteBlipFill( Reference< XPropertySet > rXPropSet, OUString sURLPropName )
586 WriteBlipFill( rXPropSet, sURLPropName, XML_a );
589 void DrawingML::WriteBlipFill( Reference< XPropertySet > rXPropSet, OUString sURLPropName, sal_Int32 nXmlNamespace )
591 if ( GetProperty( rXPropSet, sURLPropName ) ) {
592 OUString aURL;
593 mAny >>= aURL;
595 DBG(printf ("URL: %s\n", OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr() ));
597 if( aURL.isEmpty() )
598 return;
600 mpFS->startElementNS( nXmlNamespace , XML_blipFill, FSEND );
602 WriteBlip( rXPropSet, aURL );
604 if( sURLPropName == "FillBitmapURL" )
605 WriteBlipMode( rXPropSet );
606 else if( GetProperty( rXPropSet, "FillBitmapStretch" ) ) {
607 bool bStretch = false;
608 mAny >>= bStretch;
610 if( bStretch )
611 WriteStretch();
614 mpFS->endElementNS( nXmlNamespace, XML_blipFill );
618 void DrawingML::WriteSrcRect( Reference< XPropertySet > rXPropSet, const OUString& rURL )
620 Size aOriginalSize( GraphicObject::CreateGraphicObjectFromURL( rURL ).GetPrefSize() );
622 if ( GetProperty( rXPropSet, "GraphicCrop" ) )
624 ::com::sun::star::text::GraphicCrop aGraphicCropStruct;
625 mAny >>= aGraphicCropStruct;
627 if ( (0 != aGraphicCropStruct.Left) || (0 != aGraphicCropStruct.Top) || (0 != aGraphicCropStruct.Right) || (0 != aGraphicCropStruct.Bottom) )
629 mpFS->singleElementNS( XML_a, XML_srcRect,
630 XML_l, I32S(((aGraphicCropStruct.Left) * 100000)/aOriginalSize.Width()),
631 XML_t, I32S(((aGraphicCropStruct.Top) * 100000)/aOriginalSize.Height()),
632 XML_r, I32S(((aGraphicCropStruct.Right) * 100000)/aOriginalSize.Width()),
633 XML_b, I32S(((aGraphicCropStruct.Bottom) * 100000)/aOriginalSize.Height()),
634 FSEND );
639 void DrawingML::WriteStretch()
641 mpFS->startElementNS( XML_a, XML_stretch, FSEND );
642 mpFS->singleElementNS( XML_a, XML_fillRect, FSEND );
643 mpFS->endElementNS( XML_a, XML_stretch );
646 void DrawingML::WriteTransformation( const Rectangle& rRect,
647 sal_Int32 nXmlNamespace, sal_Bool bFlipH, sal_Bool bFlipV, sal_Int32 nRotation )
649 mpFS->startElementNS( nXmlNamespace, XML_xfrm,
650 XML_flipH, bFlipH ? "1" : NULL,
651 XML_flipV, bFlipV ? "1" : NULL,
652 XML_rot, (nRotation % 21600000) ? I32S( nRotation ) : NULL,
653 FSEND );
655 mpFS->singleElementNS( XML_a, XML_off, XML_x, IS( MM100toEMU( rRect.Left() ) ), XML_y, IS( MM100toEMU( rRect.Top() ) ), FSEND );
656 mpFS->singleElementNS( XML_a, XML_ext, XML_cx, IS( MM100toEMU( rRect.GetWidth() ) ), XML_cy, IS( MM100toEMU( rRect.GetHeight() ) ), FSEND );
658 mpFS->endElementNS( nXmlNamespace, XML_xfrm );
661 void DrawingML::WriteShapeTransformation( Reference< XShape > rXShape, sal_Int32 nXmlNamespace, sal_Bool bFlipH, sal_Bool bFlipV, sal_Bool bSuppressRotation )
663 DBG(printf( "write shape transformation\n" ));
665 sal_Int32 nRotation=0;
666 awt::Point aPos = rXShape->getPosition();
667 awt::Size aSize = rXShape->getSize();
669 if ( aSize.Width < 0 )
670 aSize.Width = 1000;
671 if ( aSize.Height < 0 )
672 aSize.Height = 1000;
673 if (!bSuppressRotation)
675 SdrObject* pShape = (SdrObject*) GetSdrObjectFromXShape( rXShape );
676 nRotation=pShape->GetRotateAngle();
677 int faccos=bFlipV ? -1 : 1;
678 int facsin=bFlipH ? -1 : 1;
679 aPos.X-=(1-faccos*cos(nRotation*F_PI18000))*aSize.Width/2-facsin*sin(nRotation*F_PI18000)*aSize.Height/2;
680 aPos.Y-=(1-faccos*cos(nRotation*F_PI18000))*aSize.Height/2+facsin*sin(nRotation*F_PI18000)*aSize.Width/2;
682 if (!bSuppressRotation)
684 if (bFlipV) {nRotation=(nRotation+18000)%36000;}
686 WriteTransformation( Rectangle( Point( aPos.X, aPos.Y ), Size( aSize.Width, aSize.Height ) ), nXmlNamespace, bFlipH, bFlipV, PPTX_EXPORT_ROTATE_CLOCKWISIFY(nRotation) );
689 void DrawingML::WriteRunProperties( Reference< XPropertySet > rRun, sal_Bool bIsField )
691 Reference< XPropertySet > rXPropSet( rRun, UNO_QUERY );
692 Reference< XPropertyState > rXPropState( rRun, UNO_QUERY );
693 OUString usLanguage;
694 PropertyState eState;
695 sal_Int16 nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
696 sal_Bool bComplex = ( nScriptType == ScriptType::COMPLEX );
697 const char* bold = NULL;
698 const char* italic = NULL;
699 const char* underline = NULL;
700 sal_Int32 nSize = 1800;
701 sal_Int32 nCharEscapement = 0;
703 if( GETAD( CharHeight ) )
704 nSize = (sal_Int32) (100*(*((float*) mAny.getValue())));
706 if ( ( bComplex && GETAD( CharWeightComplex ) ) || GETAD( CharWeight ) )
707 if ( *((float*) mAny.getValue()) >= awt::FontWeight::SEMIBOLD )
708 bold = "1";
710 if ( ( bComplex && GETAD( CharPostureComplex ) ) || GETAD( CharPosture ) )
711 switch ( *((awt::FontSlant*) mAny.getValue()) )
713 case awt::FontSlant_OBLIQUE :
714 case awt::FontSlant_ITALIC :
715 italic = "1";
716 break;
717 default:
718 break;
721 if ( GETAD( CharUnderline ) )
722 switch ( *((sal_Int16*) mAny.getValue()) )
724 case awt::FontUnderline::SINGLE :
725 underline = "sng";
726 break;
727 case awt::FontUnderline::DOUBLE :
728 underline = "dbl";
729 break;
730 case awt::FontUnderline::DOTTED :
731 underline = "dotted";
732 break;
733 case awt::FontUnderline::DASH :
734 underline = "dash";
735 break;
736 case awt::FontUnderline::LONGDASH :
737 underline = "dashLong";
738 break;
739 case awt::FontUnderline::DASHDOT :
740 underline = "dotDash";
741 break;
742 case awt::FontUnderline::DASHDOTDOT :
743 underline = "dotDotDash";
744 break;
745 case awt::FontUnderline::WAVE :
746 underline = "wavy";
747 break;
748 case awt::FontUnderline::DOUBLEWAVE :
749 underline = "wavyDbl";
750 break;
751 case awt::FontUnderline::BOLD :
752 underline = "heavy";
753 break;
754 case awt::FontUnderline::BOLDDOTTED :
755 underline = "dottedHeavy";
756 break;
757 case awt::FontUnderline::BOLDDASH :
758 underline = "dashHeavy";
759 break;
760 case awt::FontUnderline::BOLDLONGDASH :
761 underline = "dashLongHeavy";
762 break;
763 case awt::FontUnderline::BOLDDASHDOT :
764 underline = "dotDashHeavy";
765 break;
766 case awt::FontUnderline::BOLDDASHDOTDOT :
767 underline = "dotDotDashHeavy";
768 break;
769 case awt::FontUnderline::BOLDWAVE :
770 underline = "wavyHeavy";
771 break;
774 if( GETA( CharLocale ) ) {
775 com::sun::star::lang::Locale eLocale;
776 mAny >>= eLocale;
778 OUStringBuffer usLanguageBuffer = eLocale.Language;
779 if( !eLocale.Country.isEmpty() ) {
780 usLanguageBuffer.appendAscii( "-" );
781 usLanguageBuffer.append( eLocale.Country );
784 if( usLanguageBuffer.getLength() )
785 usLanguage = usLanguageBuffer.makeStringAndClear();
788 if( GETAD( CharEscapement ) )
789 mAny >>= nCharEscapement;
791 if( nCharEscapement && GETAD( CharEscapementHeight ) ) {
792 sal_uInt32 nCharEscapementHeight = 0;
793 mAny >>= nCharEscapementHeight;
794 nSize = (nSize * nCharEscapementHeight) / 100;
795 // MSO uses default ~58% size
796 nSize = (nSize / 0.58);
799 mpFS->startElementNS( XML_a, XML_rPr,
800 XML_b, bold,
801 XML_i, italic,
802 XML_lang, usLanguage.isEmpty() ? NULL : USS( usLanguage ),
803 XML_sz, nSize == 1800 ? NULL : IS( nSize ),
804 XML_u, underline,
805 XML_baseline, nCharEscapement == 0 ? NULL : IS( nCharEscapement*1000 ),
806 FSEND );
808 // mso doesn't like text color to be placed after typeface
809 if( GETAD( CharColor ) ) {
810 sal_uInt32 color = *((sal_uInt32*) mAny.getValue());
811 DBG(printf("run color: %x auto: %x\n", static_cast<unsigned int>( color ), static_cast<unsigned int>( COL_AUTO )));
813 if( color == COL_AUTO ) { // nCharColor depends to the background color
814 sal_Bool bIsDark = sal_False;
815 GET( bIsDark, IsBackgroundDark );
816 color = bIsDark ? 0xffffff : 0x000000;
818 color &= 0xffffff;
820 // TODO: special handle embossed/engraved
822 WriteSolidFill( color );
825 if( GETAD( CharFontName ) ) {
826 const char* pitch = NULL;
827 const char* charset = NULL;
828 OUString usTypeface;
830 mAny >>= usTypeface;
831 OUString aSubstName( GetSubsFontName( usTypeface, SUBSFONT_ONLYONE | SUBSFONT_MS ) );
833 mpFS->singleElementNS( XML_a, XML_latin,
834 XML_typeface, USS(aSubstName.getLength() ? aSubstName : usTypeface),
835 XML_pitchFamily, pitch,
836 XML_charset, charset,
837 FSEND );
840 if( ( bComplex && GETAD( CharFontNameComplex ) ) || ( !bComplex && GETAD( CharFontNameAsian ) ) ) {
841 const char* pitch = NULL;
842 const char* charset = NULL;
843 OUString usTypeface;
845 mAny >>= usTypeface;
846 OUString aSubstName( GetSubsFontName( usTypeface, SUBSFONT_ONLYONE | SUBSFONT_MS ) );
848 mpFS->singleElementNS( XML_a, bComplex ? XML_cs : XML_ea,
849 XML_typeface, USS(aSubstName.getLength() ? aSubstName : usTypeface),
850 XML_pitchFamily, pitch,
851 XML_charset, charset,
852 FSEND );
855 if( bIsField ) {
856 Reference< XTextField > rXTextField;
857 GET( rXTextField, TextField );
858 if( rXTextField.is() )
859 rXPropSet.set( rXTextField, UNO_QUERY );
862 // field properties starts here
863 if( GETA( URL ) ) {
864 OUString sURL;
866 mAny >>= sURL;
867 if( !sURL.isEmpty() ) {
868 OUString sRelId = mpFB->addRelation( mpFS->getOutputStream(),
869 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
870 sURL, true );
872 mpFS->singleElementNS( XML_a, XML_hlinkClick,
873 FSNS( XML_r,XML_id ), USS( sRelId ),
874 FSEND );
878 mpFS->endElementNS( XML_a, XML_rPr );
881 const char* DrawingML::GetFieldType( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > rRun, sal_Bool& bIsField )
883 const char* sType = NULL;
884 Reference< XPropertySet > rXPropSet( rRun, UNO_QUERY );
885 OUString aFieldType;
887 if( GETA( TextPortionType ) ) {
888 aFieldType = OUString( *(OUString*)mAny.getValue() );
889 DBG(printf ("field type: %s\n", USS(aFieldType) ));
892 if( aFieldType == "TextField" ) {
893 Reference< XTextField > rXTextField;
894 GET( rXTextField, TextField );
895 if( rXTextField.is() ) {
896 bIsField = sal_True;
897 rXPropSet.set( rXTextField, UNO_QUERY );
898 if( rXPropSet.is() ) {
899 OUString aFieldKind( rXTextField->getPresentation( sal_True ) );
900 DBG(printf ("field kind: %s\n", USS(aFieldKind) ));
901 if( aFieldKind == "Page" ) {
902 return "slidenum";
904 // else if( aFieldKind == "URL" ) {
905 // do not return here
906 // and make URL field text run with hyperlink property later
907 // }
912 return sType;
915 void DrawingML::GetUUID( OStringBuffer& rBuffer )
917 Sequence< sal_uInt8 > aSeq( 16 );
918 static char cDigits[17] = "0123456789ABCDEF";
919 rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True );
920 int i;
922 rBuffer.append( '{' );
923 for( i = 0; i < 4; i++ ) {
924 rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
925 rBuffer.append( cDigits[ aSeq[i] & 0xf ] );
927 rBuffer.append( '-' );
928 for( ; i < 6; i++ ) {
929 rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
930 rBuffer.append( cDigits[ aSeq[i] & 0xf ] );
932 rBuffer.append( '-' );
933 for( ; i < 8; i++ ) {
934 rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
935 rBuffer.append( cDigits[ aSeq[i] & 0xf ] );
937 rBuffer.append( '-' );
938 for( ; i < 10; i++ ) {
939 rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
940 rBuffer.append( cDigits[ aSeq[i] & 0xf ] );
942 rBuffer.append( '-' );
943 for( ; i < 16; i++ ) {
944 rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
945 rBuffer.append( cDigits[ aSeq[i] & 0xf ] );
947 rBuffer.append( '}' );
950 void DrawingML::WriteRun( Reference< XTextRange > rRun )
952 const char* sFieldType;
953 sal_Bool bIsField = sal_False;
954 OUString sText = rRun->getString();
956 if( sText.isEmpty()) {
957 Reference< XPropertySet > xPropSet( rRun, UNO_QUERY );
959 try {
960 if( !xPropSet.is() || !( xPropSet->getPropertyValue( "PlaceholderText" ) >>= sText ) )
961 return;
962 if( sText.isEmpty() )
963 return;
965 catch (const Exception &) {
966 return;
970 sFieldType = GetFieldType( rRun, bIsField );
971 if( ( sFieldType != NULL ) ) {
972 OStringBuffer sUUID(39);
974 GetUUID( sUUID );
975 mpFS->startElementNS( XML_a, XML_fld,
976 XML_id, sUUID.getStr(),
977 XML_type, sFieldType,
978 FSEND );
979 } else
980 mpFS->startElementNS( XML_a, XML_r, FSEND );
982 Reference< XPropertySet > xPropSet( rRun, uno::UNO_QUERY );
983 WriteRunProperties( xPropSet, bIsField );
985 mpFS->startElementNS( XML_a, XML_t, FSEND );
986 mpFS->writeEscaped( sText );
987 mpFS->endElementNS( XML_a, XML_t );
989 if( sFieldType )
990 mpFS->endElementNS( XML_a, XML_fld );
991 else
992 mpFS->endElementNS( XML_a, XML_r );
995 #define AUTONUM(x) \
996 if( bPBoth ) \
997 pAutoNumType = #x "ParenBoth"; \
998 else if( bPBehind ) \
999 pAutoNumType = #x "ParenR"; \
1000 else if( bSDot ) \
1001 pAutoNumType = #x "Period";
1003 inline static const char* GetAutoNumType( sal_Int16 nNumberingType, bool bSDot, bool bPBehind, bool bPBoth )
1005 const char* pAutoNumType = NULL;
1007 switch( (SvxExtNumType)nNumberingType )
1009 case SVX_NUM_CHARS_UPPER_LETTER_N :
1010 case SVX_NUM_CHARS_UPPER_LETTER :
1011 AUTONUM( alphaUc );
1012 break;
1013 case SVX_NUM_CHARS_LOWER_LETTER_N :
1014 case SVX_NUM_CHARS_LOWER_LETTER :
1015 AUTONUM( alphaLc );
1016 break;
1017 case SVX_NUM_ROMAN_UPPER :
1018 AUTONUM( romanUc );
1019 break;
1020 case SVX_NUM_ROMAN_LOWER :
1021 AUTONUM( romanLc );
1022 break;
1023 case SVX_NUM_ARABIC :
1024 AUTONUM( arabic )
1025 else
1026 pAutoNumType = "arabicPlain";
1027 break;
1028 default:
1029 break;
1032 return pAutoNumType;
1035 void DrawingML::WriteParagraphNumbering( Reference< XPropertySet > rXPropSet, sal_Int16 nLevel )
1037 if( nLevel >= 0 && GETA( NumberingRules ) )
1039 Reference< XIndexAccess > rXIndexAccess;
1041 if ( ( mAny >>= rXIndexAccess ) && nLevel < rXIndexAccess->getCount() )
1043 DBG(printf ("numbering rules\n"));
1045 Sequence< PropertyValue > aPropertySequence;
1046 rXIndexAccess->getByIndex( nLevel ) >>= aPropertySequence;
1048 const PropertyValue* pPropValue = aPropertySequence.getArray();
1050 sal_Int32 nPropertyCount = aPropertySequence.getLength();
1052 if ( nPropertyCount ) {
1054 sal_Int16 nNumberingType = -1;
1055 bool bSDot = false;
1056 bool bPBehind = false;
1057 bool bPBoth = false;
1058 sal_Unicode aBulletChar = 0x2022; // a bullet
1059 awt::FontDescriptor aFontDesc;
1060 bool bHasFontDesc = false;
1061 OUString aGraphicURL;
1062 sal_Int16 nBulletRelSize = 0;
1064 for ( sal_Int32 i = 0; i < nPropertyCount; i++ ) {
1065 const void* pValue = pPropValue[ i ].Value.getValue();
1066 if ( pValue ) {
1067 OUString aPropName( pPropValue[ i ].Name );
1068 DBG(printf ("pro name: %s\n", OUStringToOString( aPropName, RTL_TEXTENCODING_UTF8 ).getStr()));
1069 if ( aPropName == "NumberingType" )
1070 nNumberingType = *( (sal_Int16*)pValue );
1071 else if ( aPropName == "Prefix" ) {
1072 if( *(OUString*)pValue == ")")
1073 bPBoth = true;
1074 } else if ( aPropName == "Suffix" ) {
1075 if( *(OUString*)pValue == ".")
1076 bSDot = true;
1077 else if( *(OUString*)pValue == ")")
1078 bPBehind = true;
1079 } else if ( aPropName == "BulletChar" )
1081 aBulletChar = String ( *( (String*)pValue ) ).GetChar( 0 );
1082 //printf ("bullet char: %d\n", aBulletChar.getStr());
1084 else if ( aPropName == "BulletFont" )
1086 aFontDesc = *( (awt::FontDescriptor*)pValue );
1087 bHasFontDesc = true;
1089 // Our numbullet dialog has set the wrong textencoding for our "StarSymbol" font,
1090 // instead of a Unicode encoding the encoding RTL_TEXTENCODING_SYMBOL was used.
1091 // Because there might exist a lot of damaged documemts I added this two lines
1092 // which fixes the bullet problem for the export.
1093 if ( aFontDesc.Name == "StarSymbol" )
1094 aFontDesc.CharSet = RTL_TEXTENCODING_MS_1252;
1096 } else if ( aPropName == "BulletRelSize" ) {
1097 nBulletRelSize = *( (sal_Int16*)pValue );
1098 } else if ( aPropName == "GraphicURL" ) {
1099 aGraphicURL = ( *(OUString*)pValue );
1100 DBG(printf ("graphic url: %s\n", OUStringToOString( aGraphicURL, RTL_TEXTENCODING_UTF8 ).getStr()));
1101 } else if ( aPropName == "GraphicSize" )
1103 if ( pPropValue[ i ].Value.getValueType() == ::getCppuType( (awt::Size*)0) )
1105 // don't cast awt::Size to Size as on 64-bits they are not the same.
1106 ::com::sun::star::awt::Size aSize;
1107 pPropValue[ i ].Value >>= aSize;
1108 //aBuGraSize.nA = aSize.Width;
1109 //aBuGraSize.nB = aSize.Height;
1110 DBG(printf("graphic size: %dx%d\n", int( aSize.Width ), int( aSize.Height )));
1116 const char* pAutoNumType = GetAutoNumType( nNumberingType, bSDot, bPBehind, bPBoth );
1118 if( nLevel >= 0 ) {
1119 if( !aGraphicURL.isEmpty() ) {
1120 OUString sRelId = WriteImage( aGraphicURL );
1122 mpFS->startElementNS( XML_a, XML_buBlip, FSEND );
1123 mpFS->singleElementNS( XML_a, XML_blip, FSNS( XML_r, XML_embed ), USS( sRelId ), FSEND );
1124 mpFS->endElementNS( XML_a, XML_buBlip );
1125 } else {
1126 if( nBulletRelSize && nBulletRelSize != 100 )
1127 mpFS->singleElementNS( XML_a, XML_buSzPct,
1128 XML_val, IS( std::min( (sal_Int32)25000, std::max( (sal_Int32)400000, 1000*( (sal_Int32)nBulletRelSize ) ) ) ), FSEND );
1129 if( bHasFontDesc )
1130 mpFS->singleElementNS( XML_a, XML_buFont,
1131 XML_typeface, OUStringToOString( aFontDesc.Name, RTL_TEXTENCODING_UTF8 ).getStr(),
1132 XML_charset, (aFontDesc.CharSet == awt::CharSet::SYMBOL) ? "2" : NULL,
1133 FSEND );
1135 if( pAutoNumType )
1136 mpFS->singleElementNS( XML_a, XML_buAutoNum, XML_type, pAutoNumType, FSEND );
1137 else {
1138 aBulletChar = SubstituteBullet( aBulletChar, aFontDesc );
1139 mpFS->singleElementNS( XML_a, XML_buChar, XML_char, USS( OUString( aBulletChar ) ), FSEND );
1148 const char* DrawingML::GetAlignment( sal_Int32 nAlignment )
1150 const char* sAlignment = NULL;
1152 switch( nAlignment ) {
1153 case style::ParagraphAdjust_CENTER:
1154 sAlignment = "ctr";
1155 break;
1156 case style::ParagraphAdjust_RIGHT:
1157 sAlignment = "r";
1158 break;
1159 case style::ParagraphAdjust_BLOCK:
1160 sAlignment = "just";
1161 break;
1162 default:
1166 return sAlignment;
1169 void DrawingML::WriteLinespacing( LineSpacing& rSpacing )
1171 if( rSpacing.Mode == LineSpacingMode::PROP )
1172 mpFS->singleElementNS( XML_a, XML_spcPct,
1173 XML_val, I32S( ((sal_Int32)rSpacing.Height)*1000 ),
1174 FSEND );
1175 else
1176 mpFS->singleElementNS( XML_a, XML_spcPts,
1177 XML_val, I32S( rSpacing.Height ),
1178 FSEND );
1181 void DrawingML::WriteParagraphProperties( Reference< XTextContent > rParagraph )
1183 Reference< XPropertySet > rXPropSet( rParagraph, UNO_QUERY );
1184 Reference< XPropertyState > rXPropState( rParagraph, UNO_QUERY );
1185 PropertyState eState;
1187 if( !rXPropSet.is() || !rXPropState.is() )
1188 return;
1190 sal_Int16 nLevel = -1;
1191 GET( nLevel, NumberingLevel );
1193 sal_Int16 nAlignment( style::ParagraphAdjust_LEFT );
1194 GET( nAlignment, ParaAdjust );
1196 sal_Bool bHasLinespacing = sal_False;
1197 LineSpacing aLineSpacing;
1198 if( GETAD( ParaLineSpacing ) )
1199 bHasLinespacing = ( mAny >>= aLineSpacing );
1201 if( nLevel != -1
1202 || nAlignment != style::ParagraphAdjust_LEFT
1203 || bHasLinespacing ) {
1204 mpFS->startElementNS( XML_a, XML_pPr,
1205 XML_lvl, nLevel > 0 ? I32S( nLevel ) : NULL,
1206 XML_marL, NULL,
1207 XML_algn, GetAlignment( nAlignment ),
1208 FSEND );
1210 if( bHasLinespacing ) {
1211 mpFS->startElementNS( XML_a, XML_lnSpc, FSEND );
1212 WriteLinespacing( aLineSpacing );
1213 mpFS->endElementNS( XML_a, XML_lnSpc );
1216 WriteParagraphNumbering( rXPropSet, nLevel );
1218 mpFS->endElementNS( XML_a, XML_pPr );
1222 void DrawingML::WriteParagraph( Reference< XTextContent > rParagraph )
1224 Reference< XEnumerationAccess > access( rParagraph, UNO_QUERY );
1225 if( !access.is() )
1226 return;
1228 Reference< XEnumeration > enumeration( access->createEnumeration() );
1229 if( !enumeration.is() )
1230 return;
1232 mpFS->startElementNS( XML_a, XML_p, FSEND );
1234 sal_Bool bPropertiesWritten = sal_False;
1235 while( enumeration->hasMoreElements() ) {
1236 Reference< XTextRange > run;
1237 Any any ( enumeration->nextElement() );
1239 if (any >>= run) {
1240 if( !bPropertiesWritten ) {
1241 WriteParagraphProperties( rParagraph );
1242 bPropertiesWritten = sal_True;
1244 WriteRun( run );
1247 mpFS->singleElementNS( XML_a, XML_endParaRPr, FSEND );
1249 mpFS->endElementNS( XML_a, XML_p );
1252 void DrawingML::WriteText( Reference< XInterface > rXIface )
1254 Reference< XText > xXText( rXIface, UNO_QUERY );
1255 Reference< XPropertySet > rXPropSet( rXIface, UNO_QUERY );
1257 if( !xXText.is() )
1258 return;
1260 #define DEFLRINS 254
1261 #define DEFTBINS 127
1262 sal_Int32 nLeft, nRight, nTop, nBottom;
1263 nLeft = nRight = DEFLRINS;
1264 nTop = nBottom = DEFTBINS;
1266 // top inset looks a bit different compared to ppt export
1267 // check if something related doesn't work as expected
1268 GET( nLeft, TextLeftDistance );
1269 GET( nRight, TextRightDistance );
1270 GET( nTop, TextUpperDistance );
1271 GET( nBottom, TextLowerDistance );
1273 TextVerticalAdjust eVerticalAlignment( TextVerticalAdjust_TOP );
1274 const char* sVerticalAlignment = NULL;
1275 GET( eVerticalAlignment, TextVerticalAdjust );
1276 switch( eVerticalAlignment ) {
1277 case TextVerticalAdjust_BOTTOM:
1278 sVerticalAlignment = "b";
1279 break;
1280 case TextVerticalAdjust_CENTER:
1281 sVerticalAlignment = "ctr";
1282 break;
1283 case TextVerticalAdjust_TOP:
1284 default:
1288 const char* sWritingMode = NULL;
1289 sal_Bool bVertical = sal_False;
1290 if( GETA( TextWritingMode ) ) {
1291 WritingMode eMode;
1293 if( ( mAny >>= eMode ) && eMode == WritingMode_TB_RL ) {
1294 sWritingMode = "vert";
1295 bVertical = sal_True;
1299 if ( GETA( CustomShapeGeometry ) )
1301 Sequence< PropertyValue > aProps;
1302 if ( mAny >>= aProps )
1304 for ( sal_Int32 i = 0, nElems = aProps.getLength(); i < nElems; ++i )
1306 sal_Int32 nTextRotateAngle = 0;
1307 if ( aProps[ i ].Name.equals( "TextPreRotateAngle" ) && ( aProps[ i ].Value >>= nTextRotateAngle ) )
1309 if ( nTextRotateAngle == -90 )
1311 sWritingMode = "vert";
1312 bVertical = sal_True;
1314 break;
1320 TextHorizontalAdjust eHorizontalAlignment( TextHorizontalAdjust_CENTER );
1321 bool bHorizontalCenter = false;
1322 GET( eHorizontalAlignment, TextHorizontalAdjust );
1323 if( eHorizontalAlignment == TextHorizontalAdjust_CENTER )
1324 bHorizontalCenter = true;
1325 else if( bVertical && eHorizontalAlignment == TextHorizontalAdjust_LEFT )
1326 sVerticalAlignment = "b";
1328 sal_Bool bHasWrap = sal_False;
1329 sal_Bool bWrap = sal_False;
1330 if( GETA( TextWordWrap ) ) {
1331 mAny >>= bWrap;
1332 bHasWrap = sal_True;
1335 mpFS->singleElementNS( XML_a, XML_bodyPr,
1336 XML_wrap, bHasWrap && !bWrap ? "none" : NULL,
1337 XML_lIns, (nLeft != DEFLRINS) ? IS( MM100toEMU( nLeft ) ) : NULL,
1338 XML_rIns, (nRight != DEFLRINS) ? IS( MM100toEMU( nRight ) ) : NULL,
1339 XML_tIns, (nTop != DEFTBINS) ? IS( MM100toEMU( nTop ) ) : NULL,
1340 XML_bIns, (nBottom != DEFTBINS) ? IS( MM100toEMU( nBottom ) ) : NULL,
1341 XML_anchor, sVerticalAlignment,
1342 XML_anchorCtr, bHorizontalCenter ? "1" : NULL,
1343 XML_vert, sWritingMode,
1344 FSEND );
1346 Reference< XEnumerationAccess > access( xXText, UNO_QUERY );
1347 if( !access.is() )
1348 return;
1350 Reference< XEnumeration > enumeration( access->createEnumeration() );
1351 if( !enumeration.is() )
1352 return;
1354 while( enumeration->hasMoreElements() ) {
1355 Reference< XTextContent > paragraph;
1356 Any any ( enumeration->nextElement() );
1358 if( any >>= paragraph)
1359 WriteParagraph( paragraph );
1364 void DrawingML::WritePresetShape( const char* pShape )
1366 mpFS->startElementNS( XML_a, XML_prstGeom,
1367 XML_prst, pShape,
1368 FSEND );
1369 mpFS->singleElementNS( XML_a, XML_avLst, FSEND );
1370 mpFS->endElementNS( XML_a, XML_prstGeom );
1373 void DrawingML::WritePresetShape( const char* pShape, MSO_SPT eShapeType, sal_Bool bPredefinedHandlesUsed, sal_Int32 nAdjustmentsWhichNeedsToBeConverted, const PropertyValue& rProp )
1375 mpFS->startElementNS( XML_a, XML_prstGeom,
1376 XML_prst, pShape,
1377 FSEND );
1378 mpFS->startElementNS( XML_a, XML_avLst, FSEND );
1380 Sequence< drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentSeq;
1381 if ( ( rProp.Value >>= aAdjustmentSeq )
1382 && eShapeType != mso_sptActionButtonForwardNext // we have adjustments values for these type of shape, but MSO doesn't like them
1383 && eShapeType != mso_sptActionButtonBackPrevious // so they are now disabled
1385 DBG(printf("adj seq len: %d\n", int( aAdjustmentSeq.getLength() )));
1386 if ( bPredefinedHandlesUsed )
1387 EscherPropertyContainer::LookForPolarHandles( eShapeType, nAdjustmentsWhichNeedsToBeConverted );
1389 sal_Int32 nValue, nLength = aAdjustmentSeq.getLength();
1390 for( sal_Int32 i=0; i < nLength; i++ )
1391 if( EscherPropertyContainer::GetAdjustmentValue( aAdjustmentSeq[ i ], i, nAdjustmentsWhichNeedsToBeConverted, nValue ) )
1392 mpFS->singleElementNS( XML_a, XML_gd,
1393 XML_name, aAdjustmentSeq[ i ].Name.getLength() > 0 ? USS(aAdjustmentSeq[ i ].Name) : (nLength > 1 ? OString( "adj" + OString::valueOf( i + 1 ) ).getStr() : "adj"),
1394 XML_fmla, OString("val " + OString::valueOf( nValue )).getStr(),
1395 FSEND );
1398 mpFS->endElementNS( XML_a, XML_avLst );
1399 mpFS->endElementNS( XML_a, XML_prstGeom );
1402 void DrawingML::WritePolyPolygon( const PolyPolygon& rPolyPolygon )
1404 if( rPolyPolygon.Count() < 1 )
1405 return;
1407 mpFS->startElementNS( XML_a, XML_custGeom, FSEND );
1408 mpFS->singleElementNS( XML_a, XML_avLst, FSEND );
1409 mpFS->singleElementNS( XML_a, XML_gdLst, FSEND );
1410 mpFS->singleElementNS( XML_a, XML_ahLst, FSEND );
1411 mpFS->singleElementNS( XML_a, XML_rect,
1412 XML_l, "0",
1413 XML_t, "0",
1414 XML_r, "r",
1415 XML_b, "b",
1416 FSEND );
1418 mpFS->startElementNS( XML_a, XML_pathLst, FSEND );
1420 for( sal_uInt16 i = 0; i < rPolyPolygon.Count(); i ++ ) {
1422 const Polygon& rPoly = rPolyPolygon[ i ];
1423 Rectangle aRect( rPoly.GetBoundRect() );
1424 sal_Bool bBezier = sal_False;
1426 mpFS->startElementNS( XML_a, XML_path,
1427 XML_w, I64S( aRect.GetWidth() ),
1428 XML_h, I64S( aRect.GetHeight() ),
1429 FSEND );
1431 if( rPoly.GetSize() > 0 )
1433 mpFS->startElementNS( XML_a, XML_moveTo, FSEND );
1435 mpFS->singleElementNS( XML_a, XML_pt,
1436 XML_x, I64S( rPoly[ 0 ].X() - aRect.Left() ),
1437 XML_y, I64S( rPoly[ 0 ].Y() - aRect.Top() ),
1438 FSEND );
1440 mpFS->endElementNS( XML_a, XML_moveTo );
1443 for( sal_uInt16 j = 1; j < rPoly.GetSize(); j ++ )
1445 enum PolyFlags flags = rPoly.GetFlags(j);
1446 if( flags == POLY_CONTROL && !bBezier )
1448 mpFS->startElementNS( XML_a, XML_cubicBezTo, FSEND );
1449 bBezier = sal_True;
1451 else if( flags == POLY_NORMAL && !bBezier )
1452 mpFS->startElementNS( XML_a, XML_lnTo, FSEND );
1454 mpFS->singleElementNS( XML_a, XML_pt,
1455 XML_x, I64S( rPoly[j].X() - aRect.Left() ),
1456 XML_y, I64S( rPoly[j].Y() - aRect.Top() ),
1457 FSEND );
1459 if( ( flags == POLY_NORMAL || flags == POLY_SYMMTR ) && bBezier )
1461 mpFS->endElementNS( XML_a, XML_cubicBezTo );
1462 bBezier = sal_False;
1464 else if( flags == POLY_NORMAL && !bBezier )
1465 mpFS->endElementNS( XML_a, XML_lnTo );
1466 else if( bBezier && ( j % 3 ) == 0 )
1468 // //a:cubicBezTo can only contain 3 //a:pt elements, so we
1469 // need to break things up...
1470 mpFS->endElementNS( XML_a, XML_cubicBezTo );
1471 mpFS->startElementNS( XML_a, XML_cubicBezTo, FSEND );
1475 mpFS->endElementNS( XML_a, XML_path );
1478 mpFS->endElementNS( XML_a, XML_pathLst );
1480 mpFS->endElementNS( XML_a, XML_custGeom );
1483 void DrawingML::WriteConnectorConnections( EscherConnectorListEntry& rConnectorEntry, sal_Int32 nStartID, sal_Int32 nEndID )
1485 if( nStartID != -1 )
1486 mpFS->singleElementNS( XML_a, XML_stCxn,
1487 XML_id, I32S( nStartID ),
1488 XML_idx, I64S( rConnectorEntry.GetConnectorRule( sal_True ) ),
1489 FSEND );
1490 if( nEndID != -1 )
1491 mpFS->singleElementNS( XML_a, XML_endCxn,
1492 XML_id, I32S( nEndID ),
1493 XML_idx, I64S( rConnectorEntry.GetConnectorRule( sal_False ) ),
1494 FSEND );
1497 sal_Unicode DrawingML::SubstituteBullet( sal_Unicode cBulletId, ::com::sun::star::awt::FontDescriptor& rFontDesc )
1499 if ( rFontDesc.Name.equalsIgnoreAsciiCase("starsymbol") || rFontDesc.Name.equalsIgnoreAsciiCase("opensymbol") )
1501 rtl_TextEncoding eCharSet = rFontDesc.CharSet;
1502 cBulletId = msfilter::util::bestFitOpenSymbolToMSFont(cBulletId, eCharSet, rFontDesc.Name);
1503 rFontDesc.CharSet = eCharSet;
1506 return cBulletId;
1509 sax_fastparser::FSHelperPtr DrawingML::CreateOutputStream (
1510 const OUString& sFullStream,
1511 const OUString& sRelativeStream,
1512 const Reference< XOutputStream >& xParentRelation,
1513 const char* sContentType,
1514 const char* sRelationshipType,
1515 OUString* pRelationshipId )
1517 OUString sRelationshipId;
1518 if (xParentRelation.is())
1519 sRelationshipId = GetFB()->addRelation( xParentRelation, OUString::createFromAscii( sRelationshipType), sRelativeStream );
1520 else
1521 sRelationshipId = GetFB()->addRelation( OUString::createFromAscii( sRelationshipType ), sRelativeStream );
1523 if( pRelationshipId )
1524 *pRelationshipId = sRelationshipId;
1526 sax_fastparser::FSHelperPtr p = GetFB()->openFragmentStreamWithSerializer( sFullStream, OUString::createFromAscii( sContentType ) );
1528 return p;
1531 void DrawingML::WriteFill( Reference< XPropertySet > xPropSet )
1533 if ( !GetProperty( xPropSet, "FillStyle" ) )
1534 return;
1535 FillStyle aFillStyle( FillStyle_NONE );
1536 xPropSet->getPropertyValue( "FillStyle" ) >>= aFillStyle;
1538 if( aFillStyle == FillStyle_HATCH )
1539 return;
1541 if ( aFillStyle == FillStyle_SOLID && GetProperty( xPropSet, "FillTransparence" ) )
1543 // map full transparent background to no fill
1544 sal_Int16 nVal = 0;
1545 xPropSet->getPropertyValue( "FillTransparence" ) >>= nVal;
1546 if ( nVal == 100 )
1547 aFillStyle = FillStyle_NONE;
1550 switch( aFillStyle )
1552 case FillStyle_SOLID :
1553 WriteSolidFill( xPropSet );
1554 break;
1555 case FillStyle_GRADIENT :
1556 WriteGradientFill( xPropSet );
1557 break;
1558 case FillStyle_BITMAP :
1559 WriteBlipFill( xPropSet, "FillBitmapURL" );
1560 break;
1561 case FillStyle_NONE:
1562 mpFS->singleElementNS( XML_a, XML_noFill, FSEND );
1563 break;
1564 default:
1568 return;
1574 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */