Branch libreoffice-5-0-4
[LibreOffice.git] / oox / source / export / drawingml.cxx
blob67a5dadabd3a4d19fb6ae391a20bf759a68bf626
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 <config_folders.h>
21 #include "rtl/bootstrap.hxx"
22 #include "oox/core/xmlfilterbase.hxx"
23 #include "oox/export/drawingml.hxx"
24 #include "oox/export/utils.hxx"
25 #include <oox/drawingml/color.hxx>
26 #include <oox/drawingml/fillproperties.hxx>
27 #include <oox/token/tokens.hxx>
28 #include <oox/drawingml/drawingmltypes.hxx>
30 #include <cstdio>
31 #include <com/sun/star/awt/CharSet.hpp>
32 #include <com/sun/star/awt/FontDescriptor.hpp>
33 #include <com/sun/star/awt/FontSlant.hpp>
34 #include <com/sun/star/awt/FontStrikeout.hpp>
35 #include <com/sun/star/awt/FontWeight.hpp>
36 #include <com/sun/star/awt/FontUnderline.hpp>
37 #include <com/sun/star/awt/Gradient.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/beans/XPropertyState.hpp>
40 #include <com/sun/star/beans/Property.hpp>
41 #include <com/sun/star/beans/XPropertySetInfo.hpp>
42 #include <com/sun/star/container/XEnumerationAccess.hpp>
43 #include <com/sun/star/container/XIndexAccess.hpp>
44 #include <com/sun/star/drawing/BitmapMode.hpp>
45 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
46 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
47 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
48 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
49 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
50 #include <com/sun/star/drawing/LineDash.hpp>
51 #include <com/sun/star/drawing/LineJoint.hpp>
52 #include <com/sun/star/drawing/LineStyle.hpp>
53 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
54 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
55 #include <com/sun/star/drawing/XShape.hpp>
56 #include <com/sun/star/drawing/FillStyle.hpp>
57 #include <com/sun/star/geometry/IntegerRectangle2D.hpp>
58 #include <com/sun/star/i18n/ScriptType.hpp>
59 #include <com/sun/star/io/XOutputStream.hpp>
60 #include <com/sun/star/style/LineSpacing.hpp>
61 #include <com/sun/star/style/LineSpacingMode.hpp>
62 #include <com/sun/star/style/ParagraphAdjust.hpp>
63 #include <com/sun/star/text/WritingMode.hpp>
64 #include <com/sun/star/text/WritingMode2.hpp>
65 #include <com/sun/star/text/GraphicCrop.hpp>
66 #include <com/sun/star/text/XText.hpp>
67 #include <com/sun/star/text/XTextContent.hpp>
68 #include <com/sun/star/text/XTextField.hpp>
69 #include <com/sun/star/text/XTextRange.hpp>
70 #include <com/sun/star/style/CaseMap.hpp>
71 #include <tools/stream.hxx>
72 #include <unotools/fontdefs.hxx>
73 #include <vcl/cvtgrf.hxx>
74 #include <vcl/graph.hxx>
75 #include <vcl/settings.hxx>
76 #include <svtools/grfmgr.hxx>
77 #include <rtl/strbuf.hxx>
78 #include <sfx2/app.hxx>
79 #include <svl/languageoptions.hxx>
80 #include <filter/msfilter/escherex.hxx>
81 #include <filter/msfilter/util.hxx>
82 #include <editeng/outlobj.hxx>
83 #include <editeng/svxenum.hxx>
84 #include <svx/unoapi.hxx>
85 #include <svx/svdoashp.hxx>
86 #include <svx/unoshape.hxx>
88 using namespace ::css;
89 using namespace ::css::beans;
90 using namespace ::css::drawing;
91 using namespace ::css::i18n;
92 using namespace ::css::style;
93 using namespace ::css::text;
94 using namespace ::css::uno;
95 using namespace ::css::container;
96 using namespace ::css::text;
98 using ::css::geometry::IntegerRectangle2D;
99 using ::css::io::XOutputStream;
100 using ::sax_fastparser::FSHelperPtr;
101 using ::sax_fastparser::FastSerializerHelper;
103 namespace oox {
104 namespace drawingml {
106 #define GETA(propName) \
107 GetProperty( rXPropSet, OUString( #propName ) )
109 #define GETAD(propName) \
110 ( GetPropertyAndState( rXPropSet, rXPropState, OUString( #propName ), eState ) && eState == beans::PropertyState_DIRECT_VALUE )
112 #define GET(variable, propName) \
113 if ( GETA(propName) ) \
114 mAny >>= variable;
116 #define CGETAD(propName) \
117 (( bCheckDirect && GetPropertyAndState( rXPropSet, rXPropState, OUString( #propName ), eState ) && eState == beans::PropertyState_DIRECT_VALUE )||GetProperty( rXPropSet, OUString( #propName ) ))
119 // not thread safe
120 int DrawingML::mnImageCounter = 1;
121 int DrawingML::mnWdpImageCounter = 1;
122 std::map<OUString, OUString> DrawingML::maWdpCache;
124 void DrawingML::ResetCounters()
126 mnImageCounter = 1;
127 mnWdpImageCounter = 1;
128 maWdpCache.clear();
131 bool DrawingML::GetProperty( Reference< XPropertySet > rXPropertySet, const OUString& aName )
135 mAny = rXPropertySet->getPropertyValue(aName);
136 if (mAny.hasValue())
137 return true;
139 catch( const Exception& )
141 /* printf ("exception when trying to get value of property: %s\n", USS(aName)); */
143 return false;
146 bool DrawingML::GetPropertyAndState( Reference< XPropertySet > rXPropertySet, Reference< XPropertyState > rXPropertyState, const OUString& aName, PropertyState& eState )
150 mAny = rXPropertySet->getPropertyValue(aName);
151 if (mAny.hasValue())
153 eState = rXPropertyState->getPropertyState(aName);
154 return true;
157 catch( const Exception& )
159 /* printf ("exception when trying to get value of property: %s\n", USS(aName)); */
161 return false;
164 void DrawingML::WriteColor( sal_uInt32 nColor, sal_Int32 nAlpha )
166 // Transparency is a separate element.
167 OString sColor = OString::number( nColor & 0x00FFFFFF, 16 );
168 if( sColor.getLength() < 6 )
170 OStringBuffer sBuf( "0" );
171 int remains = 5 - sColor.getLength();
173 while( remains > 0 )
175 sBuf.append( "0" );
176 remains--;
179 sBuf.append( sColor );
181 sColor = sBuf.getStr();
183 if( nAlpha < MAX_PERCENT )
185 mpFS->startElementNS( XML_a, XML_srgbClr, XML_val, sColor.getStr(), FSEND );
186 mpFS->singleElementNS( XML_a, XML_alpha, XML_val, OString::number(nAlpha), FSEND );
187 mpFS->endElementNS( XML_a, XML_srgbClr );
190 else
192 mpFS->singleElementNS( XML_a, XML_srgbClr, XML_val, sColor.getStr(), FSEND );
196 void DrawingML::WriteColor( const OUString& sColorSchemeName, const Sequence< PropertyValue >& aTransformations )
198 // prevent writing a tag with empty val attribute
199 if( sColorSchemeName.isEmpty() )
200 return;
202 if( aTransformations.hasElements() )
204 mpFS->startElementNS( XML_a, XML_schemeClr,
205 XML_val, USS( sColorSchemeName ),
206 FSEND );
207 WriteColorTransformations( aTransformations );
208 mpFS->endElementNS( XML_a, XML_schemeClr );
210 else
212 mpFS->singleElementNS( XML_a, XML_schemeClr,
213 XML_val, USS( sColorSchemeName ),
214 FSEND );
218 void DrawingML::WriteColorTransformations( const Sequence< PropertyValue >& aTransformations )
220 for( sal_Int32 i = 0; i < aTransformations.getLength(); i++ )
222 sal_Int32 nToken = Color::getColorTransformationToken( aTransformations[i].Name );
223 if( nToken != XML_TOKEN_INVALID && aTransformations[i].Value.hasValue() )
225 sal_Int32 nValue = aTransformations[i].Value.get<sal_Int32>();
226 mpFS->singleElementNS( XML_a, nToken, XML_val, I32S( nValue ), FSEND );
231 void DrawingML::WriteSolidFill( sal_uInt32 nColor, sal_Int32 nAlpha )
233 mpFS->startElementNS( XML_a, XML_solidFill, FSEND );
234 WriteColor( nColor, nAlpha );
235 mpFS->endElementNS( XML_a, XML_solidFill );
238 void DrawingML::WriteSolidFill( const OUString& sSchemeName, const Sequence< PropertyValue >& aTransformations )
240 mpFS->startElementNS( XML_a, XML_solidFill, FSEND );
241 WriteColor( sSchemeName, aTransformations );
242 mpFS->endElementNS( XML_a, XML_solidFill );
245 void DrawingML::WriteSolidFill( Reference< XPropertySet > rXPropSet )
247 // get fill color
248 if ( !GetProperty( rXPropSet, "FillColor" ) )
249 return;
250 sal_uInt32 nFillColor = mAny.get<sal_uInt32>();
252 // get InteropGrabBag and search the relevant attributes
253 OUString sColorFillScheme;
254 sal_uInt32 nOriginalColor = 0;
255 Sequence< PropertyValue > aStyleProperties, aTransformations;
256 if ( GetProperty( rXPropSet, "InteropGrabBag" ) )
258 Sequence< PropertyValue > aGrabBag;
259 mAny >>= aGrabBag;
260 for( sal_Int32 i=0; i < aGrabBag.getLength(); ++i )
262 if( aGrabBag[i].Name == "SpPrSolidFillSchemeClr" )
263 aGrabBag[i].Value >>= sColorFillScheme;
264 else if( aGrabBag[i].Name == "OriginalSolidFillClr" )
265 aGrabBag[i].Value >>= nOriginalColor;
266 else if( aGrabBag[i].Name == "StyleFillRef" )
267 aGrabBag[i].Value >>= aStyleProperties;
268 else if( aGrabBag[i].Name == "SpPrSolidFillSchemeClrTransformations" )
269 aGrabBag[i].Value >>= aTransformations;
273 sal_Int32 nAlpha = MAX_PERCENT;
274 if( GetProperty( rXPropSet, "FillTransparence" ) )
276 sal_Int32 nTransparency = 0;
277 mAny >>= nTransparency;
278 // Calculate alpha value (see oox/source/drawingml/color.cxx : getTransparency())
279 nAlpha = (MAX_PERCENT - ( PER_PERCENT * nTransparency ) );
282 // write XML
283 if ( nFillColor != nOriginalColor )
285 // the user has set a different color for the shape
286 WriteSolidFill( nFillColor & 0xffffff, nAlpha );
288 else if ( !sColorFillScheme.isEmpty() )
290 // the shape had a scheme color and the user didn't change it
291 WriteSolidFill( sColorFillScheme, aTransformations );
293 else if ( aStyleProperties.hasElements() )
295 sal_uInt32 nThemeColor = 0;
296 for( sal_Int32 i=0; i < aStyleProperties.getLength(); ++i )
298 if( aStyleProperties[i].Name == "Color" )
300 aStyleProperties[i].Value >>= nThemeColor;
301 break;
304 if ( nFillColor != nThemeColor )
305 // the shape contains a theme but it wasn't being used
306 WriteSolidFill( nFillColor & 0xffffff, nAlpha );
307 // in case the shape used the style color and the user didn't change it,
308 // we must not write a <a: solidFill> tag.
310 else
312 // the shape had a custom color and the user didn't change it
313 WriteSolidFill( nFillColor & 0xffffff, nAlpha );
317 void DrawingML::WriteGradientStop( sal_uInt16 nStop, sal_uInt32 nColor )
319 mpFS->startElementNS( XML_a, XML_gs,
320 XML_pos, I32S( nStop * 1000 ),
321 FSEND );
322 WriteColor( nColor );
323 mpFS->endElementNS( XML_a, XML_gs );
326 sal_uInt32 DrawingML::ColorWithIntensity( sal_uInt32 nColor, sal_uInt32 nIntensity )
328 return ( ( ( nColor & 0xff ) * nIntensity ) / 100 )
329 | ( ( ( ( ( nColor & 0xff00 ) >> 8 ) * nIntensity ) / 100 ) << 8 )
330 | ( ( ( ( ( nColor & 0xff0000 ) >> 8 ) * nIntensity ) / 100 ) << 8 );
333 bool DrawingML::EqualGradients( awt::Gradient aGradient1, awt::Gradient aGradient2 )
335 return aGradient1.Style == aGradient2.Style &&
336 aGradient1.StartColor == aGradient2.StartColor &&
337 aGradient1.EndColor == aGradient2.EndColor &&
338 aGradient1.Angle == aGradient2.Angle &&
339 aGradient1.Border == aGradient2.Border &&
340 aGradient1.XOffset == aGradient2.XOffset &&
341 aGradient1.YOffset == aGradient2.YOffset &&
342 aGradient1.StartIntensity == aGradient2.StartIntensity &&
343 aGradient1.EndIntensity == aGradient2.EndIntensity &&
344 aGradient1.StepCount == aGradient2.StepCount;
347 void DrawingML::WriteGradientFill( Reference< XPropertySet > rXPropSet )
349 awt::Gradient aGradient;
350 if( GETA( FillGradient ) )
352 aGradient = *static_cast< const awt::Gradient* >( mAny.getValue() );
354 // get InteropGrabBag and search the relevant attributes
355 awt::Gradient aOriginalGradient;
356 Sequence< PropertyValue > aGradientStops;
357 if ( GetProperty( rXPropSet, "InteropGrabBag" ) )
359 Sequence< PropertyValue > aGrabBag;
360 mAny >>= aGrabBag;
361 for( sal_Int32 i=0; i < aGrabBag.getLength(); ++i )
362 if( aGrabBag[i].Name == "GradFillDefinition" )
363 aGrabBag[i].Value >>= aGradientStops;
364 else if( aGrabBag[i].Name == "OriginalGradFill" )
365 aGrabBag[i].Value >>= aOriginalGradient;
368 // check if an ooxml gradient had been imported and if the user has modified it
369 if( EqualGradients( aOriginalGradient, aGradient ) )
371 // If we have no gradient stops that means original gradient were defined by a theme.
372 if( aGradientStops.hasElements() )
374 mpFS->startElementNS( XML_a, XML_gradFill, FSEND );
375 WriteGrabBagGradientFill(aGradientStops, aGradient);
376 mpFS->endElementNS( XML_a, XML_gradFill );
379 else
381 mpFS->startElementNS( XML_a, XML_gradFill, FSEND );
382 WriteGradientFill(aGradient);
383 mpFS->endElementNS( XML_a, XML_gradFill );
388 void DrawingML::WriteGrabBagGradientFill( const Sequence< PropertyValue >& aGradientStops, awt::Gradient rGradient )
390 // write back the original gradient
391 mpFS->startElementNS( XML_a, XML_gsLst, FSEND );
393 // get original stops and write them
394 for( sal_Int32 i=0; i < aGradientStops.getLength(); ++i )
396 Sequence< PropertyValue > aGradientStop;
397 aGradientStops[i].Value >>= aGradientStop;
399 // get values
400 OUString sSchemeClr;
401 double nPos = 0;
402 sal_Int16 nTransparency = 0;
403 sal_Int32 nRgbClr = 0;
404 Sequence< PropertyValue > aTransformations;
405 for( sal_Int32 j=0; j < aGradientStop.getLength(); ++j )
407 if( aGradientStop[j].Name == "SchemeClr" )
408 aGradientStop[j].Value >>= sSchemeClr;
409 else if( aGradientStop[j].Name == "RgbClr" )
410 aGradientStop[j].Value >>= nRgbClr;
411 else if( aGradientStop[j].Name == "Pos" )
412 aGradientStop[j].Value >>= nPos;
413 else if( aGradientStop[j].Name == "Transparency" )
414 aGradientStop[j].Value >>= nTransparency;
415 else if( aGradientStop[j].Name == "Transformations" )
416 aGradientStop[j].Value >>= aTransformations;
418 // write stop
419 mpFS->startElementNS( XML_a, XML_gs,
420 XML_pos, OString::number( nPos * 100000.0 ).getStr(),
421 FSEND );
422 if( sSchemeClr.isEmpty() )
424 // Calculate alpha value (see oox/source/drawingml/color.cxx : getTransparency())
425 sal_Int32 nAlpha = (MAX_PERCENT - ( PER_PERCENT * nTransparency ) );
426 WriteColor( nRgbClr, nAlpha );
428 else
430 WriteColor( sSchemeClr, aTransformations );
432 mpFS->endElementNS( XML_a, XML_gs );
434 mpFS->endElementNS( XML_a, XML_gsLst );
436 mpFS->singleElementNS( XML_a, XML_lin,
437 XML_ang, I32S( ( ( ( 3600 - rGradient.Angle + 900 ) * 6000 ) % 21600000 ) ),
438 FSEND );
441 void DrawingML::WriteGradientFill( awt::Gradient rGradient )
443 switch( rGradient.Style )
445 default:
446 case GradientStyle_LINEAR:
447 mpFS->startElementNS( XML_a, XML_gsLst, FSEND );
448 WriteGradientStop( 0, ColorWithIntensity( rGradient.StartColor, rGradient.StartIntensity ) );
449 WriteGradientStop( 100, ColorWithIntensity( rGradient.EndColor, rGradient.EndIntensity ) );
450 mpFS->endElementNS( XML_a, XML_gsLst );
451 mpFS->singleElementNS( XML_a, XML_lin,
452 XML_ang, I32S( ( ( ( 3600 - rGradient.Angle + 900 ) * 6000 ) % 21600000 ) ),
453 FSEND );
454 break;
456 case GradientStyle_AXIAL:
457 mpFS->startElementNS( XML_a, XML_gsLst, FSEND );
458 WriteGradientStop( 0, ColorWithIntensity( rGradient.EndColor, rGradient.EndIntensity ) );
459 WriteGradientStop( 50, ColorWithIntensity( rGradient.StartColor, rGradient.StartIntensity ) );
460 WriteGradientStop( 100, ColorWithIntensity( rGradient.EndColor, rGradient.EndIntensity ) );
461 mpFS->endElementNS( XML_a, XML_gsLst );
462 mpFS->singleElementNS( XML_a, XML_lin,
463 XML_ang, I32S( ( ( ( 3600 - rGradient.Angle + 900 ) * 6000 ) % 21600000 ) ),
464 FSEND );
465 break;
467 /* I don't see how to apply transformation to gradients, so
468 * elliptical will end as radial and square as
469 * rectangular. also position offsets are not applied */
470 case GradientStyle_RADIAL:
471 case GradientStyle_ELLIPTICAL:
472 case GradientStyle_RECT:
473 case GradientStyle_SQUARE:
474 mpFS->startElementNS( XML_a, XML_gsLst, FSEND );
475 WriteGradientStop( 0, ColorWithIntensity( rGradient.EndColor, rGradient.EndIntensity ) );
476 WriteGradientStop( 100, ColorWithIntensity( rGradient.StartColor, rGradient.StartIntensity ) );
477 mpFS->endElementNS( XML_a, XML_gsLst );
478 mpFS->singleElementNS( XML_a, XML_path,
479 XML_path, ( rGradient.Style == awt::GradientStyle_RADIAL || rGradient.Style == awt::GradientStyle_ELLIPTICAL ) ? "circle" : "rect",
480 FSEND );
481 break;
485 void DrawingML::WriteLineArrow( Reference< XPropertySet > rXPropSet, bool bLineStart )
487 ESCHER_LineEnd eLineEnd;
488 sal_Int32 nArrowLength;
489 sal_Int32 nArrowWidth;
491 if ( EscherPropertyContainer::GetLineArrow( bLineStart, rXPropSet, eLineEnd, nArrowLength, nArrowWidth ) )
493 const char* len;
494 const char* type;
495 const char* width;
497 switch( nArrowLength )
499 case ESCHER_LineShortArrow:
500 len = "sm";
501 break;
502 default:
503 case ESCHER_LineMediumLenArrow:
504 len = "med";
505 break;
506 case ESCHER_LineLongArrow:
507 len = "lg";
508 break;
511 switch( eLineEnd )
513 default:
514 case ESCHER_LineNoEnd:
515 type = "none";
516 break;
517 case ESCHER_LineArrowEnd:
518 type = "triangle";
519 break;
520 case ESCHER_LineArrowStealthEnd:
521 type = "stealth";
522 break;
523 case ESCHER_LineArrowDiamondEnd:
524 type = "diamond";
525 break;
526 case ESCHER_LineArrowOvalEnd:
527 type = "oval";
528 break;
529 case ESCHER_LineArrowOpenEnd:
530 type = "arrow";
531 break;
534 switch( nArrowWidth )
536 case ESCHER_LineNarrowArrow:
537 width = "sm";
538 break;
539 default:
540 case ESCHER_LineMediumWidthArrow:
541 width = "med";
542 break;
543 case ESCHER_LineWideArrow:
544 width = "lg";
545 break;
548 mpFS->singleElementNS( XML_a, bLineStart ? XML_headEnd : XML_tailEnd,
549 XML_len, len,
550 XML_type, type,
551 XML_w, width,
552 FSEND );
556 void DrawingML::WriteOutline( Reference<XPropertySet> rXPropSet )
558 drawing::LineStyle aLineStyle( drawing::LineStyle_NONE );
560 GET( aLineStyle, LineStyle );
562 sal_uInt32 nLineWidth = 0;
563 sal_uInt32 nColor = 0;
564 bool bColorSet = false;
565 const char* cap = NULL;
566 drawing::LineDash aLineDash;
567 bool bDashSet = false;
568 bool bNoFill = false;
570 // get InteropGrabBag and search the relevant attributes
571 OUString sColorFillScheme;
573 sal_uInt32 nOriginalColor = 0;
574 sal_uInt32 nStyleColor = 0;
575 sal_uInt32 nStyleLineWidth = 0;
577 Sequence<PropertyValue> aStyleProperties;
578 Sequence<PropertyValue> aTransformations;
580 drawing::LineStyle aStyleLineStyle(drawing::LineStyle_NONE);
581 drawing::LineJoint aStyleLineJoint(drawing::LineJoint_NONE);
583 if (GetProperty(rXPropSet, "InteropGrabBag"))
585 Sequence<PropertyValue> aGrabBag;
586 mAny >>= aGrabBag;
588 for (sal_Int32 i=0; i < aGrabBag.getLength(); ++i)
590 if( aGrabBag[i].Name == "SpPrLnSolidFillSchemeClr" )
591 aGrabBag[i].Value >>= sColorFillScheme;
592 else if( aGrabBag[i].Name == "OriginalLnSolidFillClr" )
593 aGrabBag[i].Value >>= nOriginalColor;
594 else if( aGrabBag[i].Name == "StyleLnRef" )
595 aGrabBag[i].Value >>= aStyleProperties;
596 else if( aGrabBag[i].Name == "SpPrLnSolidFillSchemeClrTransformations" )
597 aGrabBag[i].Value >>= aTransformations;
599 if (aStyleProperties.hasElements())
601 for (sal_Int32 i=0; i < aStyleProperties.getLength(); ++i)
603 if( aStyleProperties[i].Name == "Color" )
604 aStyleProperties[i].Value >>= nStyleColor;
605 else if( aStyleProperties[i].Name == "LineStyle" )
606 aStyleProperties[i].Value >>= aStyleLineStyle;
607 else if( aStyleProperties[i].Name == "LineJoint" )
608 aStyleProperties[i].Value >>= aStyleLineJoint;
609 else if( aStyleProperties[i].Name == "LineWidth" )
610 aStyleProperties[i].Value >>= nStyleLineWidth;
615 GET( nLineWidth, LineWidth );
617 switch (aLineStyle)
619 case drawing::LineStyle_NONE:
620 bNoFill = true;
621 break;
622 case drawing::LineStyle_DASH:
623 if (GetProperty(rXPropSet, "LineDash"))
625 aLineDash = mAny.get<drawing::LineDash>();
626 bDashSet = true;
627 if (aLineDash.Style == DashStyle_ROUND || aLineDash.Style == DashStyle_ROUNDRELATIVE)
629 cap = "rnd";
632 DBG(fprintf(stderr, "dash dots: %d dashes: %d dotlen: %d dashlen: %d distance: %d\n",
633 int( aLineDash.Dots ), int( aLineDash.Dashes ), int( aLineDash.DotLen ), int( aLineDash.DashLen ), int( aLineDash.Distance )));
635 /* fallthru intended */
636 case drawing::LineStyle_SOLID:
637 default:
638 if ( GETA( LineColor ) )
640 nColor = mAny.get<sal_uInt32>() & 0xffffff;
641 bColorSet = true;
643 break;
646 mpFS->startElementNS( XML_a, XML_ln,
647 XML_cap, cap,
648 XML_w, nLineWidth > 1 && nStyleLineWidth != nLineWidth ?
649 I64S( oox::drawingml::convertHmmToEmu( nLineWidth ) ) :NULL,
650 FSEND );
652 if( bColorSet )
654 if( nColor != nOriginalColor )
656 // the user has set a different color for the line
657 WriteSolidFill( nColor );
659 else if( !sColorFillScheme.isEmpty() )
661 // the line had a scheme color and the user didn't change it
662 WriteSolidFill( sColorFillScheme, aTransformations );
664 else if( aStyleProperties.hasElements() )
666 if( nColor != nStyleColor )
667 // the line style defines some color but it wasn't being used
668 WriteSolidFill( nColor );
669 // in case the shape used the style color and the user didn't change it,
670 // we must not write a <a: solidFill> tag.
672 else
674 WriteSolidFill( nColor );
678 if( bDashSet && aStyleLineStyle != drawing::LineStyle_DASH )
680 // line style is a dash and it was not set by the shape style
682 if (aLineDash.Dashes == 1 && aLineDash.DashLen == 564 && aLineDash.Distance == 423)
684 // That's exactly the predefined "dash" value.
685 mpFS->singleElementNS(XML_a, XML_prstDash,
686 XML_val, "dash",
687 FSEND);
689 else
691 mpFS->startElementNS( XML_a, XML_custDash, FSEND );
693 // Check that line-width is positive and distance between dashes\dots is positive
694 if ( nLineWidth > 0 && aLineDash.Distance > 0 )
696 // Write 'dashes' first, and then 'dots'
697 int i;
698 if ( aLineDash.Dashes > 0 )
700 for( i = 0; i < aLineDash.Dashes; i ++ )
702 mpFS->singleElementNS( XML_a , XML_ds,
703 XML_d , write1000thOfAPercent( aLineDash.DashLen > 0 ? aLineDash.DashLen / nLineWidth * 100 : 100 ),
704 XML_sp, write1000thOfAPercent( aLineDash.Distance > 0 ? aLineDash.Distance / nLineWidth * 100 : 100 ),
705 FSEND );
708 if ( aLineDash.Dots > 0 )
710 for( i = 0; i < aLineDash.Dots; i ++ )
712 mpFS->singleElementNS( XML_a, XML_ds,
713 XML_d , write1000thOfAPercent( aLineDash.DotLen > 0 ? aLineDash.DotLen / nLineWidth * 100 : 100 ),
714 XML_sp, write1000thOfAPercent( aLineDash.Distance > 0 ? aLineDash.Distance / nLineWidth * 100 : 100 ),
715 FSEND );
720 SAL_WARN_IF(nLineWidth <= 0,
721 "oox", "while writing outline - custom dash - line width was < 0 : " << nLineWidth);
722 SAL_WARN_IF(aLineDash.Dashes < 0,
723 "oox", "while writing outline - custom dash - number of dashes was < 0 : " << aLineDash.Dashes);
724 SAL_WARN_IF(aLineDash.Dashes > 0 && aLineDash.DashLen <= 0,
725 "oox", "while writing outline - custom dash - dash length was < 0 : " << aLineDash.DashLen);
726 SAL_WARN_IF(aLineDash.Dots < 0,
727 "oox", "while writing outline - custom dash - number of dots was < 0 : " << aLineDash.Dots);
728 SAL_WARN_IF(aLineDash.Dots > 0 && aLineDash.DotLen <= 0,
729 "oox", "while writing outline - custom dash - dot length was < 0 : " << aLineDash.DotLen);
730 SAL_WARN_IF(aLineDash.Distance <= 0,
731 "oox", "while writing outline - custom dash - distance was < 0 : " << aLineDash.Distance);
733 mpFS->endElementNS( XML_a, XML_custDash );
737 if( !bNoFill && nLineWidth > 1 && GETA( LineJoint ) )
739 LineJoint eLineJoint = mAny.get<LineJoint>();
741 if( aStyleLineJoint == LineJoint_NONE || aStyleLineJoint != eLineJoint )
743 // style-defined line joint does not exist, or is different from the shape's joint
744 switch( eLineJoint )
746 case LineJoint_NONE:
747 case LineJoint_MIDDLE:
748 case LineJoint_BEVEL:
749 mpFS->singleElementNS( XML_a, XML_bevel, FSEND );
750 break;
751 default:
752 case LineJoint_MITER:
753 mpFS->singleElementNS( XML_a, XML_miter, FSEND );
754 break;
755 case LineJoint_ROUND:
756 mpFS->singleElementNS( XML_a, XML_round, FSEND );
757 break;
762 if( !bNoFill )
764 WriteLineArrow( rXPropSet, true );
765 WriteLineArrow( rXPropSet, false );
767 else
769 mpFS->singleElementNS( XML_a, XML_noFill, FSEND );
772 mpFS->endElementNS( XML_a, XML_ln );
775 bool lcl_URLToGraphic(const OUString& rURL, Graphic& rGraphic)
777 OString aURLBS(OUStringToOString(rURL, RTL_TEXTENCODING_UTF8));
779 const char aURLBegin[] = "vnd.sun.star.GraphicObject:";
780 sal_Int32 index = aURLBS.indexOf(aURLBegin);
782 if ( index != -1 )
784 rGraphic = GraphicObject(aURLBS.copy(RTL_CONSTASCII_LENGTH(aURLBegin))).GetTransformedGraphic();
785 return true;
788 return false;
791 OUString DrawingML::WriteImage( const OUString& rURL, bool bRelPathToMedia )
793 Graphic aGraphic;
794 if (lcl_URLToGraphic(rURL, aGraphic))
796 return WriteImage( aGraphic , bRelPathToMedia );
798 else
800 // add link to relations
803 return OUString();
806 const char* DrawingML::GetComponentDir()
808 switch ( meDocumentType )
810 case DOCUMENT_DOCX: return "word";
811 case DOCUMENT_PPTX: return "ppt";
812 case DOCUMENT_XLSX: return "xl";
815 return "unknown";
818 const char* DrawingML::GetRelationCompPrefix()
820 switch ( meDocumentType )
822 case DOCUMENT_DOCX: return "";
823 case DOCUMENT_PPTX:
824 case DOCUMENT_XLSX: return "../";
827 return "unknown";
830 OUString DrawingML::WriteImage( const Graphic& rGraphic , bool bRelPathToMedia )
832 GfxLink aLink = rGraphic.GetLink ();
833 OUString sMediaType;
834 const char* pExtension = "";
835 OUString sRelId;
837 SvMemoryStream aStream;
838 const void* aData = aLink.GetData();
839 sal_Size nDataSize = aLink.GetDataSize();
841 switch ( aLink.GetType() )
843 case GFX_LINK_TYPE_NATIVE_GIF:
844 sMediaType = "image/gif";
845 pExtension = ".gif";
846 break;
848 // #i15508# added BMP type for better exports
849 // export not yet active, so adding for reference (not checked)
850 case GFX_LINK_TYPE_NATIVE_BMP:
851 sMediaType = "image/bmp";
852 pExtension = ".bmp";
853 break;
855 case GFX_LINK_TYPE_NATIVE_JPG:
856 sMediaType = "image/jpeg";
857 pExtension = ".jpeg";
858 break;
859 case GFX_LINK_TYPE_NATIVE_PNG:
860 sMediaType = "image/png";
861 pExtension = ".png";
862 break;
863 case GFX_LINK_TYPE_NATIVE_TIF:
864 sMediaType = "image/tiff";
865 pExtension = ".tif";
866 break;
867 case GFX_LINK_TYPE_NATIVE_WMF:
868 sMediaType = "image/x-wmf";
869 pExtension = ".wmf";
870 break;
871 case GFX_LINK_TYPE_NATIVE_MET:
872 sMediaType = "image/x-met";
873 pExtension = ".met";
874 break;
875 case GFX_LINK_TYPE_NATIVE_PCT:
876 sMediaType = "image/x-pict";
877 pExtension = ".pct";
878 break;
879 case GFX_LINK_TYPE_NATIVE_MOV:
880 sMediaType = "application/movie";
881 pExtension = ".MOV";
882 break;
883 default:
885 GraphicType aType = rGraphic.GetType();
886 if ( aType == GRAPHIC_BITMAP || aType == GRAPHIC_GDIMETAFILE)
888 if ( aType == GRAPHIC_BITMAP )
890 (void)GraphicConverter::Export( aStream, rGraphic, CVT_PNG );
891 sMediaType = "image/png";
892 pExtension = ".png";
894 else
896 (void)GraphicConverter::Export( aStream, rGraphic, CVT_EMF );
897 sMediaType = "image/x-emf";
898 pExtension = ".emf";
901 else
903 OSL_TRACE( "unhandled graphic type" );
904 /*Earlier, even in case of unhandled graphic types we were
905 proceeding to write the image, which would eventually
906 write an empty image with a zero size, and return a valid
907 relationID, which is incorrect.
909 return sRelId;
912 aData = aStream.GetData();
913 nDataSize = aStream.GetEndOfData();
914 break;
918 Reference< XOutputStream > xOutStream = mpFB->openFragmentStream( OUStringBuffer()
919 .appendAscii( GetComponentDir() )
920 .appendAscii( "/media/image" )
921 .append( (sal_Int32) mnImageCounter )
922 .appendAscii( pExtension )
923 .makeStringAndClear(),
924 sMediaType );
925 xOutStream->writeBytes( Sequence< sal_Int8 >( static_cast<const sal_Int8*>(aData), nDataSize ) );
926 xOutStream->closeOutput();
928 OString sRelPathToMedia = "media/image";
929 if ( bRelPathToMedia )
930 sRelPathToMedia = "../" + sRelPathToMedia;
931 sRelId = mpFB->addRelation( mpFS->getOutputStream(),
932 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
933 OUStringBuffer()
934 .appendAscii( GetRelationCompPrefix() )
935 .appendAscii( sRelPathToMedia.getStr() )
936 .append( (sal_Int32) mnImageCounter ++ )
937 .appendAscii( pExtension )
938 .makeStringAndClear() );
940 return sRelId;
943 OUString DrawingML::WriteBlip( Reference< XPropertySet > rXPropSet, const OUString& rURL, bool bRelPathToMedia, const Graphic *pGraphic )
945 OUString sRelId;
946 BitmapChecksum nChecksum = 0;
947 if (!rURL.isEmpty() && mpTextExport)
949 Graphic aGraphic;
950 if (lcl_URLToGraphic(rURL, aGraphic))
952 nChecksum = aGraphic.GetChecksum();
953 sRelId = mpTextExport->FindRelId(nChecksum);
956 if (sRelId.isEmpty())
958 sRelId = pGraphic ? WriteImage( *pGraphic, bRelPathToMedia ) : WriteImage( rURL, bRelPathToMedia );
959 if (!rURL.isEmpty() && mpTextExport)
960 mpTextExport->CacheRelId(nChecksum, sRelId);
962 sal_Int16 nBright = 0;
963 sal_Int32 nContrast = 0;
965 GET( nBright, AdjustLuminance );
966 GET( nContrast, AdjustContrast );
968 mpFS->startElementNS( XML_a, XML_blip,
969 FSNS( XML_r, XML_embed), sRelId.toUtf8().getStr(),
970 FSEND );
971 if( nBright || nContrast )
973 mpFS->singleElementNS( XML_a, XML_lum,
974 XML_bright, nBright ? I32S( nBright*1000 ) : NULL,
975 XML_contrast, nContrast ? I32S( nContrast*1000 ) : NULL,
976 FSEND );
978 WriteArtisticEffect( rXPropSet );
980 mpFS->endElementNS( XML_a, XML_blip );
982 return sRelId;
985 void DrawingML::WriteBlipMode( Reference< XPropertySet > rXPropSet, const OUString& rURL )
987 BitmapMode eBitmapMode( BitmapMode_NO_REPEAT );
988 if (GetProperty( rXPropSet, "FillBitmapMode" ) )
989 mAny >>= eBitmapMode;
991 DBG(fprintf(stderr, "fill bitmap mode: %d\n", eBitmapMode));
993 switch (eBitmapMode)
995 case BitmapMode_REPEAT:
996 mpFS->singleElementNS( XML_a, XML_tile, FSEND );
997 break;
998 case BitmapMode_STRETCH:
999 WriteStretch( rXPropSet, rURL );
1000 break;
1001 default:
1002 break;
1006 void DrawingML::WriteBlipOrNormalFill( Reference< XPropertySet > xPropSet, const OUString& rURLPropName )
1008 // check for blip and otherwise fall back to normal fill
1009 // we always store normal fill properties but OOXML
1010 // uses a choice between our fill props and BlipFill
1011 if (GetProperty ( xPropSet, rURLPropName ))
1012 WriteBlipFill( xPropSet, rURLPropName );
1013 else
1014 WriteFill(xPropSet);
1017 void DrawingML::WriteBlipFill( Reference< XPropertySet > rXPropSet, const OUString& sURLPropName )
1019 WriteBlipFill( rXPropSet, sURLPropName, XML_a );
1022 void DrawingML::WriteBlipFill( Reference< XPropertySet > rXPropSet, const OUString& sURLPropName, sal_Int32 nXmlNamespace )
1024 if ( GetProperty( rXPropSet, sURLPropName ) )
1026 OUString aURL;
1027 mAny >>= aURL;
1028 bool bWriteMode = false;
1029 if( sURLPropName == "FillBitmapURL" || sURLPropName == "BackGraphicURL")
1030 bWriteMode = true;
1031 WriteBlipFill( rXPropSet, aURL, nXmlNamespace, bWriteMode );
1035 void DrawingML::WriteBlipFill( Reference< XPropertySet > rXPropSet, const OUString& sBitmapURL, sal_Int32 nXmlNamespace, bool bWriteMode, bool bRelPathToMedia )
1037 if ( !sBitmapURL.isEmpty() )
1039 DBG(fprintf (stderr, "URL: %s\n", OUStringToOString( sBitmapURL, RTL_TEXTENCODING_UTF8 ).getStr() ));
1041 mpFS->startElementNS( nXmlNamespace , XML_blipFill, FSEND );
1043 WriteBlip( rXPropSet, sBitmapURL, bRelPathToMedia );
1045 if( bWriteMode )
1047 WriteBlipMode( rXPropSet, sBitmapURL );
1049 else if( GetProperty( rXPropSet, "FillBitmapStretch" ) )
1051 bool bStretch = false;
1052 mAny >>= bStretch;
1054 if( bStretch )
1055 WriteStretch( rXPropSet, sBitmapURL );
1057 mpFS->endElementNS( nXmlNamespace, XML_blipFill );
1061 void DrawingML::WritePattFill( Reference< XPropertySet > rXPropSet )
1063 if ( GetProperty( rXPropSet, "FillHatch" ) )
1065 drawing::Hatch aHatch;
1066 mAny >>= aHatch;
1068 mpFS->startElementNS( XML_a , XML_pattFill, XML_prst, GetHatchPattern(aHatch), FSEND );
1070 mpFS->startElementNS( XML_a , XML_fgClr, FSEND );
1071 WriteColor(aHatch.Color);
1072 mpFS->endElementNS( XML_a , XML_fgClr );
1074 // In Writer hatching has no background so use white as a default value.
1075 mpFS->startElementNS( XML_a , XML_bgClr, FSEND );
1076 WriteColor(COL_WHITE);
1077 mpFS->endElementNS( XML_a , XML_bgClr );
1079 mpFS->endElementNS( XML_a , XML_pattFill );
1083 void DrawingML::WriteSrcRect( Reference< XPropertySet > rXPropSet, const OUString& rURL )
1085 GraphicObject aGraphicObject = GraphicObject::CreateGraphicObjectFromURL(rURL);
1086 Size aOriginalSize = aGraphicObject.GetPrefSize();
1087 const MapMode& rMapMode = aGraphicObject.GetPrefMapMode();
1089 // GraphicCrop is in mm100, so in case the original size is in pixels, convert it over.
1090 if (rMapMode.GetMapUnit() == MAP_PIXEL)
1091 aOriginalSize = Application::GetDefaultDevice()->PixelToLogic(aOriginalSize, MapMode(MAP_100TH_MM));
1093 if ( GetProperty( rXPropSet, "GraphicCrop" ) )
1095 ::com::sun::star::text::GraphicCrop aGraphicCropStruct;
1096 mAny >>= aGraphicCropStruct;
1098 if ( (0 != aGraphicCropStruct.Left) || (0 != aGraphicCropStruct.Top) || (0 != aGraphicCropStruct.Right) || (0 != aGraphicCropStruct.Bottom) )
1100 mpFS->singleElementNS( XML_a, XML_srcRect,
1101 XML_l, I32S(rtl::math::round(static_cast<double>(aGraphicCropStruct.Left) * 100000 / aOriginalSize.Width())),
1102 XML_t, I32S(rtl::math::round(static_cast<double>(aGraphicCropStruct.Top) * 100000 / aOriginalSize.Height())),
1103 XML_r, I32S(rtl::math::round(static_cast<double>(aGraphicCropStruct.Right) * 100000 / aOriginalSize.Width())),
1104 XML_b, I32S(rtl::math::round(static_cast<double>(aGraphicCropStruct.Bottom) * 100000 / aOriginalSize.Height())),
1105 FSEND );
1110 void DrawingML::WriteStretch( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet, const OUString& rURL )
1112 mpFS->startElementNS( XML_a, XML_stretch, FSEND );
1114 bool bCrop = false;
1115 if ( GetProperty( rXPropSet, "GraphicCrop" ) )
1117 ::com::sun::star::text::GraphicCrop aGraphicCropStruct;
1118 mAny >>= aGraphicCropStruct;
1120 if ( (0 != aGraphicCropStruct.Left) || (0 != aGraphicCropStruct.Top) || (0 != aGraphicCropStruct.Right) || (0 != aGraphicCropStruct.Bottom) )
1122 Size aOriginalSize( GraphicObject::CreateGraphicObjectFromURL( rURL ).GetPrefSize() );
1123 mpFS->singleElementNS( XML_a, XML_fillRect,
1124 XML_l, I32S(((aGraphicCropStruct.Left) * 100000)/aOriginalSize.Width()),
1125 XML_t, I32S(((aGraphicCropStruct.Top) * 100000)/aOriginalSize.Height()),
1126 XML_r, I32S(((aGraphicCropStruct.Right) * 100000)/aOriginalSize.Width()),
1127 XML_b, I32S(((aGraphicCropStruct.Bottom) * 100000)/aOriginalSize.Height()),
1128 FSEND );
1129 bCrop = true;
1133 if( !bCrop )
1135 mpFS->singleElementNS( XML_a, XML_fillRect, FSEND );
1138 mpFS->endElementNS( XML_a, XML_stretch );
1141 void DrawingML::WriteTransformation( const Rectangle& rRect,
1142 sal_Int32 nXmlNamespace, bool bFlipH, bool bFlipV, sal_Int32 nRotation )
1144 mpFS->startElementNS( nXmlNamespace, XML_xfrm,
1145 XML_flipH, bFlipH ? "1" : NULL,
1146 XML_flipV, bFlipV ? "1" : NULL,
1147 XML_rot, (nRotation % 21600000) ? I32S( nRotation ) : NULL,
1148 FSEND );
1150 sal_Int32 nLeft = rRect.Left();
1151 sal_Int32 nTop = rRect.Top();
1152 if (GetDocumentType() == DOCUMENT_DOCX && !m_xParent.is())
1154 nLeft = 0;
1155 nTop = 0;
1158 mpFS->singleElementNS( XML_a, XML_off, XML_x, IS( oox::drawingml::convertHmmToEmu( nLeft ) ), XML_y, IS( oox::drawingml::convertHmmToEmu( nTop ) ), FSEND );
1159 mpFS->singleElementNS( XML_a, XML_ext, XML_cx, IS( oox::drawingml::convertHmmToEmu( rRect.GetWidth() ) ), XML_cy, IS( oox::drawingml::convertHmmToEmu( rRect.GetHeight() ) ), FSEND );
1161 mpFS->endElementNS( nXmlNamespace, XML_xfrm );
1164 void DrawingML::WriteShapeTransformation( Reference< XShape > rXShape, sal_Int32 nXmlNamespace, bool bFlipH, bool bFlipV, bool bSuppressRotation )
1166 DBG(fprintf(stderr, "write shape transformation\n" ));
1168 sal_Int32 nRotation=0;
1169 awt::Point aPos = rXShape->getPosition();
1170 awt::Size aSize = rXShape->getSize();
1172 if (m_xParent.is())
1174 awt::Point aParentPos = m_xParent->getPosition();
1175 aPos.X -= aParentPos.X;
1176 aPos.Y -= aParentPos.Y;
1179 if ( aSize.Width < 0 )
1180 aSize.Width = 1000;
1181 if ( aSize.Height < 0 )
1182 aSize.Height = 1000;
1183 if (!bSuppressRotation)
1185 SdrObject* pShape = GetSdrObjectFromXShape( rXShape );
1186 nRotation = pShape ? pShape->GetRotateAngle() : 0;
1187 if (nRotation != 0 && nRotation != 18000)
1189 int faccos=bFlipV ? -1 : 1;
1190 int facsin=bFlipH ? -1 : 1;
1191 aPos.X-=(1-faccos*cos(nRotation*F_PI18000))*aSize.Width/2-facsin*sin(nRotation*F_PI18000)*aSize.Height/2;
1192 aPos.Y-=(1-faccos*cos(nRotation*F_PI18000))*aSize.Height/2+facsin*sin(nRotation*F_PI18000)*aSize.Width/2;
1195 // The RotateAngle property's value is independent from any flipping, and that's exactly what we need here.
1196 uno::Reference<beans::XPropertySet> xPropertySet(rXShape, uno::UNO_QUERY);
1197 uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
1198 if (xPropertySetInfo->hasPropertyByName("RotateAngle"))
1199 xPropertySet->getPropertyValue("RotateAngle") >>= nRotation;
1201 WriteTransformation( Rectangle( Point( aPos.X, aPos.Y ), Size( aSize.Width, aSize.Height ) ), nXmlNamespace, bFlipH, bFlipV, OOX_DRAWINGML_EXPORT_ROTATE_CLOCKWISIFY(nRotation) );
1204 void DrawingML::WriteRunProperties( Reference< XPropertySet > rRun, bool bIsField, sal_Int32 nElement /*= XML_rPr*/ )
1206 Reference< XPropertySet > rXPropSet( rRun, UNO_QUERY );
1207 Reference< XPropertyState > rXPropState( rRun, UNO_QUERY );
1208 OUString usLanguage;
1209 PropertyState eState;
1210 SvtScriptType nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
1211 bool bComplex = ( nScriptType == SvtScriptType::COMPLEX );
1212 const char* bold = NULL;
1213 const char* italic = NULL;
1214 const char* underline = NULL;
1215 const char* strikeout = NULL;
1216 const char* cap = NULL;
1217 sal_Int32 nSize = 1800;
1218 sal_Int32 nCharEscapement = 0;
1219 sal_Int32 nCharKerning = 0;
1220 bool bCheckDirect = XML_endParaRPr != nElement ;
1221 if( GETA( CharHeight ) )
1222 nSize = (sal_Int32) (100*(*static_cast<float const *>(mAny.getValue())));
1224 if( GETA( CharKerning ) )
1225 nCharKerning = (sal_Int32)(*static_cast<short const *>(mAny.getValue()));
1226 /** While setting values in propertymap,
1227 * CharKerning converted using GetTextSpacingPoint
1228 * i.e set @ http://opengrok.libreoffice.org/xref/core/oox/source/drawingml/textcharacterproperties.cxx#129
1229 * therefore to get original value CharKerning need to be convert.
1230 * http://opengrok.libreoffice.org/xref/core/oox/source/drawingml/drawingmltypes.cxx#95
1232 nCharKerning = ((nCharKerning * 720)-360) / 254;
1234 if ( ( bComplex && GETA( CharWeightComplex ) ) || GETA( CharWeight ) )
1236 if ( *static_cast<float const *>(mAny.getValue()) >= awt::FontWeight::SEMIBOLD )
1237 bold = "1";
1240 if ( ( bComplex && GETA( CharPostureComplex ) ) || GETA( CharPosture ) )
1241 switch ( *static_cast<awt::FontSlant const *>(mAny.getValue()) )
1243 case awt::FontSlant_OBLIQUE :
1244 case awt::FontSlant_ITALIC :
1245 italic = "1";
1246 break;
1247 default:
1248 break;
1251 if ( CGETAD( CharUnderline ) )
1253 switch ( *static_cast<sal_Int16 const *>(mAny.getValue()) )
1255 case awt::FontUnderline::SINGLE :
1256 underline = "sng";
1257 break;
1258 case awt::FontUnderline::DOUBLE :
1259 underline = "dbl";
1260 break;
1261 case awt::FontUnderline::DOTTED :
1262 underline = "dotted";
1263 break;
1264 case awt::FontUnderline::DASH :
1265 underline = "dash";
1266 break;
1267 case awt::FontUnderline::LONGDASH :
1268 underline = "dashLong";
1269 break;
1270 case awt::FontUnderline::DASHDOT :
1271 underline = "dotDash";
1272 break;
1273 case awt::FontUnderline::DASHDOTDOT :
1274 underline = "dotDotDash";
1275 break;
1276 case awt::FontUnderline::WAVE :
1277 underline = "wavy";
1278 break;
1279 case awt::FontUnderline::DOUBLEWAVE :
1280 underline = "wavyDbl";
1281 break;
1282 case awt::FontUnderline::BOLD :
1283 underline = "heavy";
1284 break;
1285 case awt::FontUnderline::BOLDDOTTED :
1286 underline = "dottedHeavy";
1287 break;
1288 case awt::FontUnderline::BOLDDASH :
1289 underline = "dashHeavy";
1290 break;
1291 case awt::FontUnderline::BOLDLONGDASH :
1292 underline = "dashLongHeavy";
1293 break;
1294 case awt::FontUnderline::BOLDDASHDOT :
1295 underline = "dotDashHeavy";
1296 break;
1297 case awt::FontUnderline::BOLDDASHDOTDOT :
1298 underline = "dotDotDashHeavy";
1299 break;
1300 case awt::FontUnderline::BOLDWAVE :
1301 underline = "wavyHeavy";
1302 break;
1306 if ( CGETAD( CharStrikeout ) )
1308 switch ( *static_cast<sal_Int16 const *>(mAny.getValue()) )
1310 case awt::FontStrikeout::NONE :
1311 strikeout = "noStrike";
1312 break;
1313 case awt::FontStrikeout::SINGLE :
1314 // LibO supports further values of character
1315 // strikeout, OOXML standard (20.1.10.78,
1316 // ST_TextStrikeType) however specifies only
1317 // 3 - single, double and none. Approximate
1318 // the remaining ones by single strike (better
1319 // some strike than none at all).
1320 // TODO: figure out how to do this better
1321 case awt::FontStrikeout::BOLD :
1322 case awt::FontStrikeout::SLASH :
1323 case awt::FontStrikeout::X :
1324 strikeout = "sngStrike";
1325 break;
1326 case awt::FontStrikeout::DOUBLE :
1327 strikeout = "dblStrike";
1328 break;
1332 if( GETA( CharLocale ) )
1334 com::sun::star::lang::Locale aLocale;
1335 mAny >>= aLocale;
1336 LanguageTag aLanguageTag( aLocale);
1337 if (!aLanguageTag.isSystemLocale())
1338 usLanguage = aLanguageTag.getBcp47();
1341 if( GETAD( CharEscapement ) )
1342 mAny >>= nCharEscapement;
1344 if( nCharEscapement && GETAD( CharEscapementHeight ) )
1346 sal_uInt32 nCharEscapementHeight = 0;
1347 mAny >>= nCharEscapementHeight;
1348 nSize = (nSize * nCharEscapementHeight) / 100;
1349 // MSO uses default ~58% size
1350 nSize = (nSize / 0.58);
1353 if( GETA( CharCaseMap ) )
1355 switch ( *static_cast<sal_Int16 const *>(mAny.getValue()) )
1357 case CaseMap::UPPERCASE :
1358 cap = "all";
1359 break;
1360 case CaseMap::SMALLCAPS :
1361 cap = "small";
1362 break;
1366 mpFS->startElementNS( XML_a, nElement,
1367 XML_b, bold,
1368 XML_i, italic,
1369 XML_lang, usLanguage.isEmpty() ? NULL : USS( usLanguage ),
1370 XML_sz, IS( nSize ),
1371 // For Condensed character spacing spc value is negative.
1372 XML_spc, nCharKerning ? IS(nCharKerning) : NULL,
1373 XML_strike, strikeout,
1374 XML_u, underline,
1375 XML_baseline, nCharEscapement == 0 ? NULL : IS( nCharEscapement*1000 ),
1376 XML_cap, cap,
1377 FSEND );
1379 // mso doesn't like text color to be placed after typeface
1380 if( CGETAD( CharColor ) )
1382 sal_uInt32 color = *static_cast<sal_uInt32 const *>(mAny.getValue());
1383 DBG(fprintf(stderr, "run color: %x auto: %x\n", static_cast<unsigned int>( color ), static_cast<unsigned int>( COL_AUTO )));
1385 if( color == COL_AUTO ) // nCharColor depends to the background color
1387 color = mbIsBackgroundDark ? COL_WHITE : COL_BLACK ;
1389 color &= 0xffffff;
1391 // TODO: special handle embossed/engraved
1393 WriteSolidFill( color );
1396 if( CGETAD( CharUnderlineColor ) )
1398 sal_uInt32 color = *static_cast<sal_uInt32 const *>(mAny.getValue());
1400 mpFS->startElementNS( XML_a, XML_uFill,FSEND);
1401 WriteSolidFill( color );
1402 mpFS->endElementNS( XML_a, XML_uFill );
1405 if( GETA( CharFontName ) )
1407 const char* pitch = NULL;
1408 const char* charset = NULL;
1409 OUString usTypeface;
1411 mAny >>= usTypeface;
1412 OUString aSubstName( GetSubsFontName( usTypeface, SubsFontFlags::ONLYONE | SubsFontFlags::MS ) );
1414 mpFS->singleElementNS( XML_a, XML_latin,
1415 XML_typeface, USS(aSubstName.getLength() ? aSubstName : usTypeface),
1416 XML_pitchFamily, pitch,
1417 XML_charset, charset,
1418 FSEND );
1421 if( ( bComplex && GETAD( CharFontNameComplex ) ) || ( !bComplex && GETAD( CharFontNameAsian ) ) )
1423 const char* pitch = NULL;
1424 const char* charset = NULL;
1425 OUString usTypeface;
1427 mAny >>= usTypeface;
1428 OUString aSubstName( GetSubsFontName( usTypeface, SubsFontFlags::ONLYONE | SubsFontFlags::MS ) );
1430 mpFS->singleElementNS( XML_a, bComplex ? XML_cs : XML_ea,
1431 XML_typeface, USS(aSubstName.getLength() ? aSubstName : usTypeface),
1432 XML_pitchFamily, pitch,
1433 XML_charset, charset,
1434 FSEND );
1437 if( bIsField )
1439 Reference< XTextField > rXTextField;
1440 GET( rXTextField, TextField );
1441 if( rXTextField.is() )
1442 rXPropSet.set( rXTextField, UNO_QUERY );
1445 // field properties starts here
1446 if( GETA( URL ) )
1448 OUString sURL;
1450 mAny >>= sURL;
1451 if( !sURL.isEmpty() ) {
1452 OUString sRelId = mpFB->addRelation( mpFS->getOutputStream(),
1453 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
1454 sURL, true );
1456 mpFS->singleElementNS( XML_a, XML_hlinkClick,
1457 FSNS( XML_r,XML_id ), USS( sRelId ),
1458 FSEND );
1462 mpFS->endElementNS( XML_a, nElement );
1465 OUString DrawingML::GetFieldValue( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > rRun, bool& bIsURLField )
1467 Reference< XPropertySet > rXPropSet( rRun, UNO_QUERY );
1468 OUString aFieldType, aFieldValue;
1470 if( GETA( TextPortionType ) )
1472 aFieldType = OUString( *static_cast<OUString const *>(mAny.getValue()) );
1473 DBG(fprintf (stderr, "field type: %s\n", USS(aFieldType) ));
1476 if( aFieldType == "TextField" )
1478 Reference< XTextField > rXTextField;
1479 GET( rXTextField, TextField );
1480 if( rXTextField.is() )
1482 rXPropSet.set( rXTextField, UNO_QUERY );
1483 if( rXPropSet.is() )
1485 OUString aFieldKind( rXTextField->getPresentation( true ) );
1486 DBG(fprintf (stderr, "field kind: %s\n", USS(aFieldKind) ));
1487 if( aFieldKind == "Page" )
1489 aFieldValue = OUString("slidenum");
1491 else if( aFieldKind == "URL" )
1493 bIsURLField = true;
1494 GET( aFieldValue, Representation)
1501 return aFieldValue;
1504 void DrawingML::GetUUID( OStringBuffer& rBuffer )
1506 Sequence< sal_uInt8 > aSeq( 16 );
1507 static const char cDigits[17] = "0123456789ABCDEF";
1508 rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, true );
1509 int i;
1511 rBuffer.append( '{' );
1512 for( i = 0; i < 4; i++ )
1514 rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
1515 rBuffer.append( cDigits[ aSeq[i] & 0xf ] );
1517 rBuffer.append( '-' );
1518 for( ; i < 6; i++ )
1520 rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
1521 rBuffer.append( cDigits[ aSeq[i] & 0xf ] );
1523 rBuffer.append( '-' );
1524 for( ; i < 8; i++ )
1526 rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
1527 rBuffer.append( cDigits[ aSeq[i] & 0xf ] );
1529 rBuffer.append( '-' );
1530 for( ; i < 10; i++ )
1532 rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
1533 rBuffer.append( cDigits[ aSeq[i] & 0xf ] );
1535 rBuffer.append( '-' );
1536 for( ; i < 16; i++ )
1538 rBuffer.append( cDigits[ aSeq[i] >> 4 ] );
1539 rBuffer.append( cDigits[ aSeq[i] & 0xf ] );
1541 rBuffer.append( '}' );
1544 void DrawingML::WriteRun( Reference< XTextRange > rRun )
1546 Reference< XPropertySet > rXPropSet( rRun, UNO_QUERY );
1547 sal_Int16 nLevel = -1;
1548 GET( nLevel, NumberingLevel );
1550 bool bIsURLField = false;
1551 OUString sFieldValue = GetFieldValue( rRun, bIsURLField );
1552 bool bWriteField = !( sFieldValue.isEmpty() || bIsURLField );
1554 OUString sText = rRun->getString();
1556 //if there is no text following the bullet, add a space after the bullet
1557 if (nLevel !=-1 && sText.isEmpty() )
1558 sText=" ";
1560 if ( bIsURLField )
1561 sText = sFieldValue;
1563 if( sText.isEmpty())
1565 Reference< XPropertySet > xPropSet( rRun, UNO_QUERY );
1569 if( !xPropSet.is() || !( xPropSet->getPropertyValue( "PlaceholderText" ) >>= sText ) )
1570 return;
1571 if( sText.isEmpty() )
1572 return;
1574 catch (const Exception &)
1576 return;
1580 if( ( bWriteField ) )
1582 OStringBuffer sUUID(39);
1584 GetUUID( sUUID );
1585 mpFS->startElementNS( XML_a, XML_fld,
1586 XML_id, sUUID.getStr(),
1587 XML_type, OUStringToOString( sFieldValue, RTL_TEXTENCODING_UTF8 ).getStr(),
1588 FSEND );
1590 else
1592 mpFS->startElementNS( XML_a, XML_r, FSEND );
1595 Reference< XPropertySet > xPropSet( rRun, uno::UNO_QUERY );
1596 WriteRunProperties( xPropSet, bIsURLField );
1598 mpFS->startElementNS( XML_a, XML_t, FSEND );
1599 mpFS->writeEscaped( sText );
1600 mpFS->endElementNS( XML_a, XML_t );
1602 if( bWriteField )
1603 mpFS->endElementNS( XML_a, XML_fld );
1604 else
1605 mpFS->endElementNS( XML_a, XML_r );
1608 OUString GetAutoNumType(sal_Int16 nNumberingType, bool bSDot, bool bPBehind, bool bPBoth)
1610 OUString sPrefixSuffix;
1612 if (bPBoth)
1613 sPrefixSuffix = "ParenBoth";
1614 else if (bPBehind)
1615 sPrefixSuffix = "ParenR";
1616 else if (bSDot)
1617 sPrefixSuffix = "Period";
1619 switch( (SvxExtNumType)nNumberingType )
1621 case SVX_NUM_CHARS_UPPER_LETTER_N :
1622 case SVX_NUM_CHARS_UPPER_LETTER :
1623 return "alphaUc" + sPrefixSuffix;
1625 case SVX_NUM_CHARS_LOWER_LETTER_N :
1626 case SVX_NUM_CHARS_LOWER_LETTER :
1627 return "alphaLc" + sPrefixSuffix;
1629 case SVX_NUM_ROMAN_UPPER :
1630 return "romanUc" + sPrefixSuffix;
1632 case SVX_NUM_ROMAN_LOWER :
1633 return "romanLc" + sPrefixSuffix;
1635 case SVX_NUM_ARABIC :
1637 if (sPrefixSuffix.isEmpty())
1638 return OUString("arabicPlain");
1639 else
1640 return "arabic" + sPrefixSuffix;
1642 default:
1643 break;
1646 return OUString();
1649 void DrawingML::WriteParagraphNumbering( Reference< XPropertySet > rXPropSet, sal_Int16 nLevel )
1651 if( nLevel < 0 || !GETA( NumberingRules ) )
1652 return;
1654 Reference< XIndexAccess > rXIndexAccess;
1656 if (!(mAny >>= rXIndexAccess) || nLevel >= rXIndexAccess->getCount())
1657 return;
1659 DBG(fprintf (stderr, "numbering rules\n"));
1661 Sequence<PropertyValue> aPropertySequence;
1662 rXIndexAccess->getByIndex(nLevel) >>= aPropertySequence;
1664 if (!aPropertySequence.hasElements())
1665 return;
1667 sal_Int32 nPropertyCount = aPropertySequence.getLength();
1669 const PropertyValue* pPropValue = aPropertySequence.getArray();
1671 sal_Int16 nNumberingType = SVX_NUM_NUMBER_NONE;
1672 bool bSDot = false;
1673 bool bPBehind = false;
1674 bool bPBoth = false;
1675 sal_Unicode aBulletChar = 0x2022; // a bullet
1676 awt::FontDescriptor aFontDesc;
1677 bool bHasFontDesc = false;
1678 OUString aGraphicURL;
1679 sal_Int16 nBulletRelSize = 0;
1680 sal_Int16 nStartWith = 1;
1681 sal_uInt32 nBulletColor = 0;
1682 bool bHasBulletColor = false;
1684 for ( sal_Int32 i = 0; i < nPropertyCount; i++ )
1686 const void* pValue = pPropValue[ i ].Value.getValue();
1687 if ( pValue )
1689 OUString aPropName( pPropValue[ i ].Name );
1690 DBG(fprintf (stderr, "pro name: %s\n", OUStringToOString( aPropName, RTL_TEXTENCODING_UTF8 ).getStr()));
1691 if ( aPropName == "NumberingType" )
1693 nNumberingType = *( static_cast<sal_Int16 const *>(pValue) );
1695 else if ( aPropName == "Prefix" )
1697 if( *static_cast<OUString const *>(pValue) == ")")
1698 bPBoth = true;
1700 else if ( aPropName == "Suffix" )
1702 if( *static_cast<OUString const *>(pValue) == ".")
1703 bSDot = true;
1704 else if( *static_cast<OUString const *>(pValue) == ")")
1705 bPBehind = true;
1707 else if(aPropName == "BulletColor")
1709 nBulletColor = *static_cast<sal_uInt32 const *>(pValue);
1710 bHasBulletColor = true;
1712 else if ( aPropName == "BulletChar" )
1714 aBulletChar = OUString ( *( static_cast<OUString const *>(pValue) ) )[ 0 ];
1716 else if ( aPropName == "BulletFont" )
1718 aFontDesc = *static_cast<awt::FontDescriptor const *>(pValue);
1719 bHasFontDesc = true;
1721 // Our numbullet dialog has set the wrong textencoding for our "StarSymbol" font,
1722 // instead of a Unicode encoding the encoding RTL_TEXTENCODING_SYMBOL was used.
1723 // Because there might exist a lot of damaged documemts I added this two lines
1724 // which fixes the bullet problem for the export.
1725 if ( aFontDesc.Name.equalsIgnoreAsciiCase("StarSymbol") )
1726 aFontDesc.CharSet = RTL_TEXTENCODING_MS_1252;
1729 else if ( aPropName == "BulletRelSize" )
1731 nBulletRelSize = *static_cast<sal_Int16 const *>(pValue);
1733 else if ( aPropName == "StartWith" )
1735 nStartWith = *static_cast<sal_Int16 const *>(pValue);
1737 else if ( aPropName == "GraphicURL" )
1739 aGraphicURL = *static_cast<OUString const *>(pValue);
1740 DBG(fprintf (stderr, "graphic url: %s\n", OUStringToOString( aGraphicURL, RTL_TEXTENCODING_UTF8 ).getStr()));
1742 else if ( aPropName == "GraphicSize" )
1744 if ( pPropValue[ i ].Value.getValueType() == cppu::UnoType<awt::Size>::get())
1746 // don't cast awt::Size to Size as on 64-bits they are not the same.
1747 css::awt::Size aSize;
1748 pPropValue[ i ].Value >>= aSize;
1749 //aBuGraSize.nA = aSize.Width;
1750 //aBuGraSize.nB = aSize.Height;
1751 DBG(fprintf(stderr, "graphic size: %dx%d\n", int( aSize.Width ), int( aSize.Height )));
1757 if (nNumberingType == SVX_NUM_NUMBER_NONE)
1758 return;
1760 if( !aGraphicURL.isEmpty() )
1762 OUString sRelId = WriteImage( aGraphicURL );
1764 mpFS->startElementNS( XML_a, XML_buBlip, FSEND );
1765 mpFS->singleElementNS( XML_a, XML_blip, FSNS( XML_r, XML_embed ), USS( sRelId ), FSEND );
1766 mpFS->endElementNS( XML_a, XML_buBlip );
1768 else
1770 if(bHasBulletColor)
1772 if (nBulletColor == COL_AUTO )
1774 nBulletColor = mbIsBackgroundDark ? COL_WHITE : COL_BLACK ;
1776 mpFS->startElementNS( XML_a, XML_buClr, FSEND );
1777 WriteColor( nBulletColor );
1778 mpFS->endElementNS( XML_a, XML_buClr );
1781 if( nBulletRelSize && nBulletRelSize != 100 )
1782 mpFS->singleElementNS( XML_a, XML_buSzPct,
1783 XML_val, IS( std::max( (sal_Int32)25000, std::min( (sal_Int32)400000, 1000*( (sal_Int32)nBulletRelSize ) ) ) ), FSEND );
1784 if( bHasFontDesc )
1786 if ( SVX_NUM_CHAR_SPECIAL == nNumberingType )
1787 aBulletChar = SubstituteBullet( aBulletChar, aFontDesc );
1788 mpFS->singleElementNS( XML_a, XML_buFont,
1789 XML_typeface, aFontDesc.Name.toUtf8().getStr(),
1790 XML_charset, (aFontDesc.CharSet == awt::CharSet::SYMBOL) ? "2" : NULL,
1791 FSEND );
1794 OUString pAutoNumType = GetAutoNumType( nNumberingType, bSDot, bPBehind, bPBoth );
1796 if (!pAutoNumType.isEmpty())
1798 mpFS->singleElementNS(XML_a, XML_buAutoNum,
1799 XML_type, OUStringToOString(pAutoNumType, RTL_TEXTENCODING_UTF8).getStr(),
1800 XML_startAt, nStartWith > 1 ? IS(nStartWith) : NULL,
1801 FSEND);
1803 else
1805 mpFS->singleElementNS(XML_a, XML_buChar, XML_char, USS( OUString( aBulletChar ) ), FSEND);
1810 sal_Int32 DrawingML::getBulletMarginIndentation (Reference< XPropertySet > rXPropSet,sal_Int16 nLevel, const OUString& propName)
1812 if( nLevel < 0 || !GETA( NumberingRules ) )
1813 return 0;
1815 Reference< XIndexAccess > rXIndexAccess;
1817 if (!(mAny >>= rXIndexAccess) || nLevel >= rXIndexAccess->getCount())
1818 return 0;
1820 DBG(fprintf (stderr, "numbering rules\n"));
1822 Sequence<PropertyValue> aPropertySequence;
1823 rXIndexAccess->getByIndex(nLevel) >>= aPropertySequence;
1825 if (!aPropertySequence.hasElements())
1826 return 0;
1828 sal_Int32 nPropertyCount = aPropertySequence.getLength();
1830 const PropertyValue* pPropValue = aPropertySequence.getArray();
1832 for ( sal_Int32 i = 0; i < nPropertyCount; i++ )
1834 const void* pValue = pPropValue[ i ].Value.getValue();
1835 if ( pValue )
1837 OUString aPropName( pPropValue[ i ].Name );
1838 DBG(fprintf (stderr, "pro name: %s\n", OUStringToOString( aPropName, RTL_TEXTENCODING_UTF8 ).getStr()));
1839 if ( aPropName == propName )
1840 return *( static_cast<sal_Int32 const *>(pValue) );
1844 return 0;
1847 const char* DrawingML::GetAlignment( sal_Int32 nAlignment )
1849 const char* sAlignment = NULL;
1851 switch( nAlignment )
1853 case style::ParagraphAdjust_CENTER:
1854 sAlignment = "ctr";
1855 break;
1856 case style::ParagraphAdjust_RIGHT:
1857 sAlignment = "r";
1858 break;
1859 case style::ParagraphAdjust_BLOCK:
1860 sAlignment = "just";
1861 break;
1862 default:
1866 return sAlignment;
1869 void DrawingML::WriteLinespacing( LineSpacing& rSpacing )
1871 if( rSpacing.Mode == LineSpacingMode::PROP )
1873 mpFS->singleElementNS( XML_a, XML_spcPct,
1874 XML_val, I32S( ((sal_Int32)rSpacing.Height)*1000 ),
1875 FSEND );
1877 else
1879 mpFS->singleElementNS( XML_a, XML_spcPts,
1880 XML_val, I32S( rSpacing.Height ),
1881 FSEND );
1885 void DrawingML::WriteParagraphProperties( Reference< XTextContent > rParagraph )
1887 Reference< XPropertySet > rXPropSet( rParagraph, UNO_QUERY );
1888 Reference< XPropertyState > rXPropState( rParagraph, UNO_QUERY );
1889 PropertyState eState;
1891 if( !rXPropSet.is() || !rXPropState.is() )
1892 return;
1894 sal_Int16 nLevel = -1;
1895 GET( nLevel, NumberingLevel );
1897 sal_Int16 nAlignment( style::ParagraphAdjust_LEFT );
1898 GET( nAlignment, ParaAdjust );
1900 bool bHasLinespacing = false;
1901 LineSpacing aLineSpacing;
1902 if( GETAD( ParaLineSpacing ) )
1903 bHasLinespacing = ( mAny >>= aLineSpacing );
1905 bool bRtl = false;
1906 if( GETA( WritingMode ) )
1908 sal_Int16 nWritingMode;
1909 if( ( mAny >>= nWritingMode ) && nWritingMode == text::WritingMode2::RL_TB )
1911 bRtl = true;
1915 sal_Int32 nParaLeftMargin = 0;
1916 sal_Int32 nParaFirstLineIndent = 0;
1918 GET( nParaLeftMargin, ParaLeftMargin );
1919 GET( nParaFirstLineIndent,ParaFirstLineIndent);
1921 sal_Int32 nLeftMargin = getBulletMarginIndentation ( rXPropSet, nLevel,"LeftMargin");
1922 sal_Int32 nLineIndentation = getBulletMarginIndentation ( rXPropSet, nLevel,"FirstLineOffset");
1924 if( nLevel != -1
1925 || nAlignment != style::ParagraphAdjust_LEFT
1926 || bHasLinespacing )
1928 if (nParaLeftMargin) // For Paraghraph
1929 mpFS->startElementNS( XML_a, XML_pPr,
1930 XML_lvl, nLevel > 0 ? I32S( nLevel ) : NULL,
1931 XML_marL, nParaLeftMargin > 0 ? I32S( oox::drawingml::convertHmmToEmu( nParaLeftMargin ) ) : NULL,
1932 XML_indent, nParaFirstLineIndent ? I32S( oox::drawingml::convertHmmToEmu( nParaFirstLineIndent ) ) : NULL,
1933 XML_algn, GetAlignment( nAlignment ),
1934 XML_rtl, bRtl ? BS(bRtl) : NULL,
1935 FSEND );
1936 else
1937 mpFS->startElementNS( XML_a, XML_pPr,
1938 XML_lvl, nLevel > 0 ? I32S( nLevel ) : NULL,
1939 XML_marL, nLeftMargin > 0 ? I32S( oox::drawingml::convertHmmToEmu( nLeftMargin ) ) : NULL,
1940 XML_indent, nLineIndentation ? I32S( oox::drawingml::convertHmmToEmu( nLineIndentation ) ) : NULL,
1941 XML_algn, GetAlignment( nAlignment ),
1942 XML_rtl, bRtl ? BS(bRtl) : NULL,
1943 FSEND );
1947 if( bHasLinespacing )
1949 mpFS->startElementNS( XML_a, XML_lnSpc, FSEND );
1950 WriteLinespacing( aLineSpacing );
1951 mpFS->endElementNS( XML_a, XML_lnSpc );
1954 WriteParagraphNumbering( rXPropSet, nLevel );
1956 mpFS->endElementNS( XML_a, XML_pPr );
1960 void DrawingML::WriteParagraph( Reference< XTextContent > rParagraph )
1962 Reference< XEnumerationAccess > access( rParagraph, UNO_QUERY );
1963 if( !access.is() )
1964 return;
1966 Reference< XEnumeration > enumeration( access->createEnumeration() );
1967 if( !enumeration.is() )
1968 return;
1970 mpFS->startElementNS( XML_a, XML_p, FSEND );
1973 bool bPropertiesWritten = false;
1974 while( enumeration->hasMoreElements() )
1976 Reference< XTextRange > run;
1977 Any any ( enumeration->nextElement() );
1979 if (any >>= run)
1981 if( !bPropertiesWritten )
1983 WriteParagraphProperties( rParagraph );
1984 bPropertiesWritten = true;
1986 WriteRun( run );
1989 Reference< XPropertySet > rXPropSet( rParagraph, UNO_QUERY );
1990 WriteRunProperties( rXPropSet , false, XML_endParaRPr );
1992 mpFS->endElementNS( XML_a, XML_p );
1995 void DrawingML::WriteText( Reference< XInterface > rXIface, const OUString& presetWarp, bool bBodyPr, bool bText, sal_Int32 nXmlNamespace )
1997 Reference< XText > xXText( rXIface, UNO_QUERY );
1998 Reference< XPropertySet > rXPropSet( rXIface, UNO_QUERY );
2000 if( !xXText.is() )
2001 return;
2003 #define DEFLRINS 254
2004 #define DEFTBINS 127
2005 sal_Int32 nLeft, nRight, nTop, nBottom;
2006 nLeft = nRight = DEFLRINS;
2007 nTop = nBottom = DEFTBINS;
2009 // top inset looks a bit different compared to ppt export
2010 // check if something related doesn't work as expected
2011 GET( nLeft, TextLeftDistance );
2012 GET( nRight, TextRightDistance );
2013 GET( nTop, TextUpperDistance );
2014 GET( nBottom, TextLowerDistance );
2016 TextVerticalAdjust eVerticalAlignment( TextVerticalAdjust_TOP );
2017 const char* sVerticalAlignment = NULL;
2018 GET( eVerticalAlignment, TextVerticalAdjust );
2019 if( eVerticalAlignment != TextVerticalAdjust_TOP )
2020 sVerticalAlignment = GetTextVerticalAdjust(eVerticalAlignment);
2022 const char* sWritingMode = NULL;
2023 bool bVertical = false;
2024 if( GETA( TextWritingMode ) )
2026 WritingMode eMode;
2028 if( ( mAny >>= eMode ) && eMode == WritingMode_TB_RL )
2030 sWritingMode = "vert";
2031 bVertical = true;
2035 if ( GETA( CustomShapeGeometry ) )
2037 Sequence< PropertyValue > aProps;
2038 if ( mAny >>= aProps )
2040 for ( sal_Int32 i = 0, nElems = aProps.getLength(); i < nElems; ++i )
2042 sal_Int32 nTextRotateAngle = 0;
2043 if ( aProps[ i ].Name == "TextPreRotateAngle" && ( aProps[ i ].Value >>= nTextRotateAngle ) )
2045 if ( nTextRotateAngle == -90 )
2047 sWritingMode = "vert";
2048 bVertical = true;
2050 else if ( nTextRotateAngle == -270 )
2052 sWritingMode = "vert270";
2053 bVertical = true;
2055 break;
2061 TextHorizontalAdjust eHorizontalAlignment( TextHorizontalAdjust_CENTER );
2062 bool bHorizontalCenter = false;
2063 GET( eHorizontalAlignment, TextHorizontalAdjust );
2064 if( eHorizontalAlignment == TextHorizontalAdjust_CENTER )
2065 bHorizontalCenter = true;
2066 else if( bVertical && eHorizontalAlignment == TextHorizontalAdjust_LEFT )
2067 sVerticalAlignment = "b";
2069 bool bHasWrap = false;
2070 bool bWrap = false;
2071 // Only custom shapes obey the TextWordWrap option, normal text always wraps.
2072 if( dynamic_cast<SvxCustomShape*>(rXIface.get()) && GETA( TextWordWrap ) )
2074 mAny >>= bWrap;
2075 bHasWrap = true;
2078 if (bBodyPr)
2080 const char* pWrap = bHasWrap && !bWrap ? "none" : NULL;
2081 if (GetDocumentType() == DOCUMENT_DOCX)
2083 // In case of DOCX, if we want to have the same effect as
2084 // TextShape's automatic word wrapping, then we need to set
2085 // wrapping to square.
2086 uno::Reference<lang::XServiceInfo> xServiceInfo(rXIface, uno::UNO_QUERY);
2087 if (xServiceInfo.is() && xServiceInfo->supportsService("com.sun.star.drawing.TextShape"))
2088 pWrap = "square";
2090 mpFS->startElementNS( (nXmlNamespace ? nXmlNamespace : XML_a), XML_bodyPr,
2091 XML_wrap, pWrap,
2092 XML_lIns, (nLeft != DEFLRINS) ? IS( oox::drawingml::convertHmmToEmu( nLeft ) ) : NULL,
2093 XML_rIns, (nRight != DEFLRINS) ? IS( oox::drawingml::convertHmmToEmu( nRight ) ) : NULL,
2094 XML_tIns, (nTop != DEFTBINS) ? IS( oox::drawingml::convertHmmToEmu( nTop ) ) : NULL,
2095 XML_bIns, (nBottom != DEFTBINS) ? IS( oox::drawingml::convertHmmToEmu( nBottom ) ) : NULL,
2096 XML_anchor, sVerticalAlignment,
2097 XML_anchorCtr, bHorizontalCenter ? "1" : NULL,
2098 XML_vert, sWritingMode,
2099 FSEND );
2100 if( presetWarp != NULL && !presetWarp.isEmpty())
2102 mpFS->singleElementNS(XML_a, XML_prstTxWarp, XML_prst, presetWarp.toUtf8().getStr(),
2103 FSEND );
2105 if (GetDocumentType() == DOCUMENT_DOCX)
2107 sal_Bool bTextAutoGrowHeight = sal_False;
2108 GET(bTextAutoGrowHeight, TextAutoGrowHeight);
2109 mpFS->singleElementNS(XML_a, (bTextAutoGrowHeight ? XML_spAutoFit : XML_noAutofit), FSEND);
2111 mpFS->endElementNS((nXmlNamespace ? nXmlNamespace : XML_a), XML_bodyPr);
2114 Reference< XEnumerationAccess > access( xXText, UNO_QUERY );
2115 if( !access.is() || !bText )
2116 return;
2118 Reference< XEnumeration > enumeration( access->createEnumeration() );
2119 if( !enumeration.is() )
2120 return;
2122 uno::Reference<drawing::XShape> xShape(rXIface, uno::UNO_QUERY);
2123 SdrObject* pSdrObject = xShape.is() ? GetSdrObjectFromXShape(xShape) : 0;
2124 const SdrTextObj* pTxtObj = PTR_CAST(SdrTextObj, pSdrObject);
2125 if (pTxtObj && mpTextExport)
2127 const OutlinerParaObject* pParaObj = 0;
2128 bool bOwnParaObj = false;
2131 #i13885#
2132 When the object is actively being edited, that text is not set into
2133 the objects normal text object, but lives in a separate object.
2135 if (pTxtObj->IsTextEditActive())
2137 pParaObj = pTxtObj->GetEditOutlinerParaObject();
2138 bOwnParaObj = true;
2140 else
2141 pParaObj = pTxtObj->GetOutlinerParaObject();
2143 if (pParaObj)
2145 // this is reached only in case some text is attached to the shape
2146 mpTextExport->WriteOutliner(*pParaObj);
2147 if (bOwnParaObj)
2148 delete pParaObj;
2150 return;
2153 while( enumeration->hasMoreElements() )
2155 Reference< XTextContent > paragraph;
2156 Any any ( enumeration->nextElement() );
2158 if( any >>= paragraph)
2159 WriteParagraph( paragraph );
2164 void DrawingML::WritePresetShape( const char* pShape )
2166 mpFS->startElementNS( XML_a, XML_prstGeom,
2167 XML_prst, pShape,
2168 FSEND );
2169 mpFS->singleElementNS( XML_a, XML_avLst, FSEND );
2170 mpFS->endElementNS( XML_a, XML_prstGeom );
2173 std::map< OString, std::vector<OString> > lcl_getAdjNames()
2175 std::map< OString, std::vector<OString> > aRet;
2177 OUString aPath("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/filter/oox-drawingml-adj-names");
2178 rtl::Bootstrap::expandMacros(aPath);
2179 SvFileStream aStream(aPath, StreamMode::READ);
2180 if (aStream.GetError() != ERRCODE_NONE)
2181 SAL_WARN("oox", "failed to open oox-drawingml-adj-names");
2182 OString aLine;
2183 bool bNotDone = aStream.ReadLine(aLine);
2184 while (bNotDone)
2186 sal_Int32 nIndex = 0;
2187 // Each line is in a "key\tvalue" format: read the key, the rest is the value.
2188 OString aKey = aLine.getToken(0, '\t', nIndex);
2189 OString aValue = aLine.copy(nIndex);
2190 aRet[aKey].push_back(aValue);
2191 bNotDone = aStream.ReadLine(aLine);
2193 return aRet;
2196 void DrawingML::WritePresetShape( const char* pShape, MSO_SPT eShapeType, bool bPredefinedHandlesUsed, sal_Int32 nAdjustmentsWhichNeedsToBeConverted, const PropertyValue& rProp )
2198 static std::map< OString, std::vector<OString> > aAdjMap = lcl_getAdjNames();
2199 // If there are predefined adj names for this shape type, look them up now.
2200 std::vector<OString> aAdjustments;
2201 if (aAdjMap.find(OString(pShape)) != aAdjMap.end())
2202 aAdjustments = aAdjMap[OString(pShape)];
2204 mpFS->startElementNS( XML_a, XML_prstGeom,
2205 XML_prst, pShape,
2206 FSEND );
2207 mpFS->startElementNS( XML_a, XML_avLst, FSEND );
2209 Sequence< drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentSeq;
2210 if ( ( rProp.Value >>= aAdjustmentSeq )
2211 && eShapeType != mso_sptActionButtonForwardNext // we have adjustments values for these type of shape, but MSO doesn't like them
2212 && eShapeType != mso_sptActionButtonBackPrevious // so they are now disabled
2213 && OString(pShape) != "rect" //some shape types are commented out in pCustomShapeTypeTranslationTable[] & are being defaulted to rect & rect does not have adjustment values/name.
2216 DBG(fprintf(stderr, "adj seq len: %d\n", int( aAdjustmentSeq.getLength() )));
2217 if ( bPredefinedHandlesUsed )
2218 EscherPropertyContainer::LookForPolarHandles( eShapeType, nAdjustmentsWhichNeedsToBeConverted );
2220 sal_Int32 nValue, nLength = aAdjustmentSeq.getLength();
2221 //aAdjustments will give info about the number of adj values for a particular geometry. For example for hexagon aAdjustments.size() will be 2 and for circular arrow it will be 5 as per lcl_getAdjNames.
2222 if(aAdjustments.size() == static_cast<sal_uInt32>(nLength))// In case there is a mismatch do not write the XML_gd tag.
2224 for( sal_Int32 i=0; i < nLength; i++ )
2226 if( EscherPropertyContainer::GetAdjustmentValue( aAdjustmentSeq[ i ], i, nAdjustmentsWhichNeedsToBeConverted, nValue ) )
2228 // If the document model doesn't have an adjustment name (e.g. shape was created from VML), then take it from the predefined list.
2229 OString aAdjName;
2230 if (aAdjustmentSeq[i].Name.isEmpty() && static_cast<sal_uInt32>(i) < aAdjustments.size())
2231 aAdjName = aAdjustments[i];
2233 mpFS->singleElementNS( XML_a, XML_gd,
2234 XML_name, aAdjustmentSeq[ i ].Name.getLength() > 0 ? USS(aAdjustmentSeq[ i ].Name) : aAdjName.getStr(),
2235 XML_fmla, OString("val " + OString::number( nValue )).getStr(),
2236 FSEND );
2242 mpFS->endElementNS( XML_a, XML_avLst );
2243 mpFS->endElementNS( XML_a, XML_prstGeom );
2246 void DrawingML::WriteCustomGeometry( Reference< XShape > rXShape )
2248 uno::Reference< beans::XPropertySet > aXPropSet;
2249 uno::Any aAny( rXShape->queryInterface(cppu::UnoType<beans::XPropertySet>::get()));
2251 if ( ! (aAny >>= aXPropSet) )
2252 return;
2256 aAny = aXPropSet->getPropertyValue( "CustomShapeGeometry" );
2257 if ( !aAny.hasValue() )
2258 return;
2260 catch( const ::uno::Exception& )
2262 return;
2267 uno::Sequence< beans::PropertyValue > const * pGeometrySeq =
2268 static_cast<uno::Sequence< beans::PropertyValue > const *>(aAny.getValue());
2270 if ( pGeometrySeq )
2272 for( int i = 0; i < pGeometrySeq->getLength(); ++i )
2274 const beans::PropertyValue& rProp = (*pGeometrySeq)[ i ];
2275 if ( rProp.Name == "Path" )
2277 uno::Sequence<beans::PropertyValue> aPathProp;
2278 rProp.Value >>= aPathProp;
2280 uno::Sequence<drawing::EnhancedCustomShapeParameterPair> aPairs;
2281 uno::Sequence<drawing::EnhancedCustomShapeSegment> aSegments;
2282 uno::Sequence<awt::Size> aPathSize;
2283 for (int j = 0; j < aPathProp.getLength(); ++j )
2285 const beans::PropertyValue& rPathProp = aPathProp[j];
2286 if (rPathProp.Name == "Coordinates")
2287 rPathProp.Value >>= aPairs;
2288 else if (rPathProp.Name == "Segments")
2289 rPathProp.Value >>= aSegments;
2290 else if (rPathProp.Name == "SubViewSize")
2291 rPathProp.Value >>= aPathSize;
2294 if ( !aPairs.hasElements() )
2295 return;
2297 if ( !aSegments.hasElements() )
2299 aSegments = uno::Sequence<drawing::EnhancedCustomShapeSegment>(4);
2300 aSegments[0].Count = 1;
2301 aSegments[0].Command = drawing::EnhancedCustomShapeSegmentCommand::MOVETO;
2302 aSegments[1].Count = (sal_Int16)std::min( aPairs.getLength() - 1, (sal_Int32)32767 );
2303 aSegments[1].Command = drawing::EnhancedCustomShapeSegmentCommand::LINETO;
2304 aSegments[2].Count = 0;
2305 aSegments[2].Command = drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
2306 aSegments[3].Count = 0;
2307 aSegments[3].Command = drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
2310 int nExpectedPairCount = 0;
2311 for( int j = 0; j < aSegments.getLength(); ++j )
2313 nExpectedPairCount += aSegments[j].Count;
2316 if ( nExpectedPairCount > aPairs.getLength() )
2318 SAL_WARN("oox", "Segments need " << nExpectedPairCount << " coordinates, but Coordinates have only " << aPairs.getLength() << " pairs.");
2319 return;
2322 mpFS->startElementNS( XML_a, XML_custGeom, FSEND );
2323 mpFS->singleElementNS( XML_a, XML_avLst, FSEND );
2324 mpFS->singleElementNS( XML_a, XML_gdLst, FSEND );
2325 mpFS->singleElementNS( XML_a, XML_ahLst, FSEND );
2326 mpFS->singleElementNS( XML_a, XML_rect, XML_l, "l", XML_t, "t",
2327 XML_r, "r", XML_b, "b", FSEND );
2328 mpFS->startElementNS( XML_a, XML_pathLst, FSEND );
2330 if ( aPathSize.hasElements() )
2332 mpFS->startElementNS( XML_a, XML_path,
2333 XML_w, I64S( aPathSize[0].Width ),
2334 XML_h, I64S( aPathSize[0].Height ),
2335 FSEND );
2337 else
2339 sal_Int32 nXMin(0);
2340 aPairs[0].First.Value >>= nXMin;
2341 sal_Int32 nXMax = nXMin;
2342 sal_Int32 nYMin(0);
2343 aPairs[0].Second.Value >>= nYMin;
2344 sal_Int32 nYMax = nYMin;
2346 for ( int j = 0; j < aPairs.getLength(); ++j )
2348 sal_Int32 nCandidate(0);
2349 if ((aPairs[j].First.Value >>= nCandidate) && nCandidate < nXMin)
2350 nXMin = nCandidate;
2351 if ((aPairs[j].Second.Value >>= nCandidate) && nCandidate < nYMin)
2352 nYMin = nCandidate;
2353 if ((aPairs[j].First.Value >>= nCandidate) && nCandidate > nXMax)
2354 nXMax = nCandidate;
2355 if ((aPairs[j].Second.Value >>= nCandidate) && nCandidate > nYMax)
2356 nYMax = nCandidate;
2358 mpFS->startElementNS( XML_a, XML_path,
2359 XML_w, I64S( nXMax - nXMin ),
2360 XML_h, I64S( nYMax - nYMin ),
2361 FSEND );
2365 int nPairIndex = 0;
2366 for( int j = 0; j < aSegments.getLength(); ++j )
2368 if ( aSegments[ j ].Command == drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH )
2370 mpFS->singleElementNS( XML_a, XML_close, FSEND );
2372 for ( int k = 0; k < aSegments[j].Count; ++k )
2374 switch( aSegments[ j ].Command )
2376 case drawing::EnhancedCustomShapeSegmentCommand::MOVETO :
2378 mpFS->startElementNS( XML_a, XML_moveTo, FSEND );
2380 sal_Int32 nX(0), nY(0);
2381 aPairs[nPairIndex].First.Value >>= nX;
2382 aPairs[nPairIndex].Second.Value >>= nY;
2384 mpFS->singleElementNS( XML_a, XML_pt,
2385 XML_x, I64S(nX),
2386 XML_y, I64S(nY),
2387 FSEND );
2389 mpFS->endElementNS( XML_a, XML_moveTo );
2390 nPairIndex++;
2391 break;
2393 case drawing::EnhancedCustomShapeSegmentCommand::LINETO :
2395 mpFS->startElementNS( XML_a, XML_lnTo, FSEND );
2397 sal_Int32 nX(0), nY(0);
2398 aPairs[nPairIndex].First.Value >>= nX;
2399 aPairs[nPairIndex].Second.Value >>= nY;
2401 mpFS->singleElementNS( XML_a, XML_pt,
2402 XML_x, I64S(nX),
2403 XML_y, I64S(nY),
2404 FSEND );
2405 mpFS->endElementNS( XML_a, XML_lnTo );
2406 nPairIndex++;
2407 break;
2409 case drawing::EnhancedCustomShapeSegmentCommand::CURVETO :
2411 mpFS->startElementNS( XML_a, XML_cubicBezTo, FSEND );
2412 for( sal_uInt8 l = 0; l <= 2; ++l )
2414 sal_Int32 nX(0), nY(0);
2415 aPairs[nPairIndex+l].First.Value >>= nX;
2416 aPairs[nPairIndex+l].Second.Value >>= nY;
2418 mpFS->singleElementNS( XML_a, XML_pt,
2419 XML_x, I64S( nX ),
2420 XML_y, I64S( nY ),
2421 FSEND );
2424 mpFS->endElementNS( XML_a, XML_cubicBezTo );
2425 nPairIndex += 3;
2426 break;
2428 case drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
2429 case drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
2431 nPairIndex += 3;
2432 break;
2434 case drawing::EnhancedCustomShapeSegmentCommand::ARCTO :
2435 case drawing::EnhancedCustomShapeSegmentCommand::ARC :
2436 case drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
2437 case drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
2439 nPairIndex += 4;
2440 break;
2442 case drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
2443 case drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
2445 nPairIndex++;
2446 break;
2448 case drawing::EnhancedCustomShapeSegmentCommand::QUADRATICCURVETO :
2450 mpFS->startElementNS( XML_a, XML_quadBezTo, FSEND );
2451 for( sal_uInt8 l = 0; l < 2; ++l )
2453 sal_Int32 nX(0), nY(0);
2454 aPairs[nPairIndex+l].First.Value >>= nX;
2455 aPairs[nPairIndex+l].Second.Value >>= nY;
2457 mpFS->singleElementNS( XML_a, XML_pt,
2458 XML_x, I64S( nX ),
2459 XML_y, I64S( nY ),
2460 FSEND );
2463 mpFS->endElementNS( XML_a, XML_quadBezTo );
2464 nPairIndex += 2;
2465 break;
2467 case drawing::EnhancedCustomShapeSegmentCommand::ARCANGLETO :
2469 nPairIndex += 2;
2470 break;
2472 default:
2473 // do nothing
2474 break;
2478 mpFS->endElementNS( XML_a, XML_path );
2479 mpFS->endElementNS( XML_a, XML_pathLst );
2480 mpFS->endElementNS( XML_a, XML_custGeom );
2487 void DrawingML::WritePolyPolygon( const tools::PolyPolygon& rPolyPolygon )
2489 if( rPolyPolygon.Count() < 1 )
2490 return;
2492 mpFS->startElementNS( XML_a, XML_custGeom, FSEND );
2493 mpFS->singleElementNS( XML_a, XML_avLst, FSEND );
2494 mpFS->singleElementNS( XML_a, XML_gdLst, FSEND );
2495 mpFS->singleElementNS( XML_a, XML_ahLst, FSEND );
2496 mpFS->singleElementNS( XML_a, XML_rect,
2497 XML_l, "0",
2498 XML_t, "0",
2499 XML_r, "r",
2500 XML_b, "b",
2501 FSEND );
2503 mpFS->startElementNS( XML_a, XML_pathLst, FSEND );
2505 for( sal_uInt16 i = 0; i < rPolyPolygon.Count(); i ++ )
2508 const Polygon& rPoly = rPolyPolygon[ i ];
2509 Rectangle aRect( rPoly.GetBoundRect() );
2511 mpFS->startElementNS( XML_a, XML_path,
2512 XML_w, I64S( aRect.GetWidth() ),
2513 XML_h, I64S( aRect.GetHeight() ),
2514 FSEND );
2516 if( rPoly.GetSize() > 0 )
2518 mpFS->startElementNS( XML_a, XML_moveTo, FSEND );
2520 mpFS->singleElementNS( XML_a, XML_pt,
2521 XML_x, I64S( rPoly[ 0 ].X() - aRect.Left() ),
2522 XML_y, I64S( rPoly[ 0 ].Y() - aRect.Top() ),
2523 FSEND );
2525 mpFS->endElementNS( XML_a, XML_moveTo );
2528 for( sal_uInt16 j = 1; j < rPoly.GetSize(); j ++ )
2530 enum PolyFlags flags = rPoly.GetFlags(j);
2531 if( flags == POLY_CONTROL )
2533 // a:cubicBezTo can only contain 3 a:pt elements, so we need to make sure of this
2534 if( j+2 < rPoly.GetSize() && rPoly.GetFlags(j+1) == POLY_CONTROL && rPoly.GetFlags(j+2) != POLY_CONTROL )
2537 mpFS->startElementNS( XML_a, XML_cubicBezTo, FSEND );
2538 for( sal_uInt8 k = 0; k <= 2; ++k )
2540 mpFS->singleElementNS( XML_a, XML_pt,
2541 XML_x, I64S( rPoly[j+k].X() - aRect.Left() ),
2542 XML_y, I64S( rPoly[j+k].Y() - aRect.Top() ),
2543 FSEND );
2546 mpFS->endElementNS( XML_a, XML_cubicBezTo );
2547 j += 2;
2550 else if( flags == POLY_NORMAL )
2552 mpFS->startElementNS( XML_a, XML_lnTo, FSEND );
2553 mpFS->singleElementNS( XML_a, XML_pt,
2554 XML_x, I64S( rPoly[j].X() - aRect.Left() ),
2555 XML_y, I64S( rPoly[j].Y() - aRect.Top() ),
2556 FSEND );
2557 mpFS->endElementNS( XML_a, XML_lnTo );
2561 mpFS->endElementNS( XML_a, XML_path );
2564 mpFS->endElementNS( XML_a, XML_pathLst );
2566 mpFS->endElementNS( XML_a, XML_custGeom );
2569 void DrawingML::WriteConnectorConnections( EscherConnectorListEntry& rConnectorEntry, sal_Int32 nStartID, sal_Int32 nEndID )
2571 if( nStartID != -1 )
2573 mpFS->singleElementNS( XML_a, XML_stCxn,
2574 XML_id, I32S( nStartID ),
2575 XML_idx, I64S( rConnectorEntry.GetConnectorRule( true ) ),
2576 FSEND );
2578 if( nEndID != -1 )
2580 mpFS->singleElementNS( XML_a, XML_endCxn,
2581 XML_id, I32S( nEndID ),
2582 XML_idx, I64S( rConnectorEntry.GetConnectorRule( false ) ),
2583 FSEND );
2587 sal_Unicode DrawingML::SubstituteBullet( sal_Unicode cBulletId, ::com::sun::star::awt::FontDescriptor& rFontDesc )
2589 if ( IsStarSymbol(rFontDesc.Name) )
2591 rtl_TextEncoding eCharSet = rFontDesc.CharSet;
2592 cBulletId = msfilter::util::bestFitOpenSymbolToMSFont(cBulletId, eCharSet, rFontDesc.Name);
2593 rFontDesc.CharSet = eCharSet;
2596 return cBulletId;
2599 sax_fastparser::FSHelperPtr DrawingML::CreateOutputStream (
2600 const OUString& sFullStream,
2601 const OUString& sRelativeStream,
2602 const Reference< XOutputStream >& xParentRelation,
2603 const char* sContentType,
2604 const char* sRelationshipType,
2605 OUString* pRelationshipId )
2607 OUString sRelationshipId;
2608 if (xParentRelation.is())
2609 sRelationshipId = GetFB()->addRelation( xParentRelation, OUString::createFromAscii( sRelationshipType), sRelativeStream );
2610 else
2611 sRelationshipId = GetFB()->addRelation( OUString::createFromAscii( sRelationshipType ), sRelativeStream );
2613 if( pRelationshipId )
2614 *pRelationshipId = sRelationshipId;
2616 sax_fastparser::FSHelperPtr p = GetFB()->openFragmentStreamWithSerializer( sFullStream, OUString::createFromAscii( sContentType ) );
2618 return p;
2621 void DrawingML::WriteFill( Reference< XPropertySet > xPropSet )
2623 if ( !GetProperty( xPropSet, "FillStyle" ) )
2624 return;
2625 FillStyle aFillStyle( FillStyle_NONE );
2626 xPropSet->getPropertyValue( "FillStyle" ) >>= aFillStyle;
2628 if ( aFillStyle == FillStyle_SOLID && GetProperty( xPropSet, "FillTransparence" ) )
2630 // map full transparent background to no fill
2631 sal_Int16 nVal = 0;
2632 xPropSet->getPropertyValue( "FillTransparence" ) >>= nVal;
2633 if ( nVal == 100 )
2634 aFillStyle = FillStyle_NONE;
2637 switch( aFillStyle )
2639 case FillStyle_SOLID :
2640 WriteSolidFill( xPropSet );
2641 break;
2642 case FillStyle_GRADIENT :
2643 WriteGradientFill( xPropSet );
2644 break;
2645 case FillStyle_BITMAP :
2646 WriteBlipFill( xPropSet, "FillBitmapURL" );
2647 break;
2648 case FillStyle_HATCH :
2649 WritePattFill( xPropSet );
2650 break;
2651 case FillStyle_NONE:
2652 mpFS->singleElementNS( XML_a, XML_noFill, FSEND );
2653 break;
2654 default:
2658 return;
2661 void DrawingML::WriteStyleProperties( sal_Int32 nTokenId, const Sequence< PropertyValue >& aProperties )
2663 if( aProperties.getLength() > 0 )
2665 OUString sSchemeClr;
2666 sal_uInt32 nIdx = 0;
2667 Sequence< PropertyValue > aTransformations;
2668 for( sal_Int32 i=0; i < aProperties.getLength(); ++i)
2670 if( aProperties[i].Name == "SchemeClr" )
2671 aProperties[i].Value >>= sSchemeClr;
2672 else if( aProperties[i].Name == "Idx" )
2673 aProperties[i].Value >>= nIdx;
2674 else if( aProperties[i].Name == "Transformations" )
2675 aProperties[i].Value >>= aTransformations;
2677 mpFS->startElementNS( XML_a, nTokenId, XML_idx, I32S( nIdx ), FSEND );
2678 WriteColor( sSchemeClr, aTransformations );
2679 mpFS->endElementNS( XML_a, nTokenId );
2681 else
2683 // write mock <a:*Ref> tag
2684 mpFS->singleElementNS( XML_a, nTokenId, XML_idx, I32S( 0 ), FSEND );
2688 void DrawingML::WriteShapeStyle( Reference< XPropertySet > xPropSet )
2690 // check existence of the grab bag
2691 if ( !GetProperty( xPropSet, "InteropGrabBag" ) )
2692 return;
2694 // extract the relevant properties from the grab bag
2695 Sequence< PropertyValue > aGrabBag;
2696 Sequence< PropertyValue > aFillRefProperties, aLnRefProperties, aEffectRefProperties;
2697 mAny >>= aGrabBag;
2698 for( sal_Int32 i=0; i < aGrabBag.getLength(); ++i)
2700 if( aGrabBag[i].Name == "StyleFillRef" )
2701 aGrabBag[i].Value >>= aFillRefProperties;
2702 else if( aGrabBag[i].Name == "StyleLnRef" )
2703 aGrabBag[i].Value >>= aLnRefProperties;
2704 else if( aGrabBag[i].Name == "StyleEffectRef" )
2705 aGrabBag[i].Value >>= aEffectRefProperties;
2708 WriteStyleProperties( XML_lnRef, aLnRefProperties );
2709 WriteStyleProperties( XML_fillRef, aFillRefProperties );
2710 WriteStyleProperties( XML_effectRef, aEffectRefProperties );
2712 // write mock <a:fontRef>
2713 mpFS->singleElementNS( XML_a, XML_fontRef, XML_idx, "minor", FSEND );
2716 void DrawingML::WriteShapeEffect( const OUString& sName, const Sequence< PropertyValue >& aEffectProps )
2718 if( aEffectProps.getLength() == 0 )
2719 return;
2721 // assign the proper tag and enable bContainsColor if necessary
2722 sal_Int32 nEffectToken = 0;
2723 bool bContainsColor = false;
2724 if( sName == "outerShdw" )
2726 nEffectToken = FSNS( XML_a, XML_outerShdw );
2727 bContainsColor = true;
2729 else if( sName == "innerShdw" )
2731 nEffectToken = FSNS( XML_a, XML_innerShdw );
2732 bContainsColor = true;
2734 else if( sName == "glow" )
2736 nEffectToken = FSNS( XML_a, XML_glow );
2737 bContainsColor = true;
2739 else if( sName == "softEdge" )
2740 nEffectToken = FSNS( XML_a, XML_softEdge );
2741 else if( sName == "reflection" )
2742 nEffectToken = FSNS( XML_a, XML_reflection );
2743 else if( sName == "blur" )
2744 nEffectToken = FSNS( XML_a, XML_blur );
2746 OUString sSchemeClr;
2747 sal_uInt32 nRgbClr = 0;
2748 sal_Int32 nAlpha = MAX_PERCENT;
2749 Sequence< PropertyValue > aTransformations;
2750 sax_fastparser::FastAttributeList *aOuterShdwAttrList = FastSerializerHelper::createAttrList();
2751 sax_fastparser::XFastAttributeListRef xOuterShdwAttrList( aOuterShdwAttrList );
2752 for( sal_Int32 i=0; i < aEffectProps.getLength(); ++i )
2754 if( aEffectProps[i].Name == "Attribs" )
2756 // read tag attributes
2757 uno::Sequence< beans::PropertyValue > aOuterShdwProps;
2758 aEffectProps[i].Value >>= aOuterShdwProps;
2759 for( sal_Int32 j=0; j < aOuterShdwProps.getLength(); ++j )
2761 if( aOuterShdwProps[j].Name == "algn" )
2763 OUString sVal;
2764 aOuterShdwProps[j].Value >>= sVal;
2765 aOuterShdwAttrList->add( XML_algn, OUStringToOString( sVal, RTL_TEXTENCODING_UTF8 ).getStr() );
2767 else if( aOuterShdwProps[j].Name == "blurRad" )
2769 sal_Int32 nVal = 0;
2770 aOuterShdwProps[j].Value >>= nVal;
2771 aOuterShdwAttrList->add( XML_blurRad, OString::number( nVal ).getStr() );
2773 else if( aOuterShdwProps[j].Name == "dir" )
2775 sal_Int32 nVal = 0;
2776 aOuterShdwProps[j].Value >>= nVal;
2777 aOuterShdwAttrList->add( XML_dir, OString::number( nVal ).getStr() );
2779 else if( aOuterShdwProps[j].Name == "dist" )
2781 sal_Int32 nVal = 0;
2782 aOuterShdwProps[j].Value >>= nVal;
2783 aOuterShdwAttrList->add( XML_dist, OString::number( nVal ).getStr() );
2785 else if( aOuterShdwProps[j].Name == "kx" )
2787 sal_Int32 nVal = 0;
2788 aOuterShdwProps[j].Value >>= nVal;
2789 aOuterShdwAttrList->add( XML_kx, OString::number( nVal ).getStr() );
2791 else if( aOuterShdwProps[j].Name == "ky" )
2793 sal_Int32 nVal = 0;
2794 aOuterShdwProps[j].Value >>= nVal;
2795 aOuterShdwAttrList->add( XML_ky, OString::number( nVal ).getStr() );
2797 else if( aOuterShdwProps[j].Name == "rotWithShape" )
2799 sal_Int32 nVal = 0;
2800 aOuterShdwProps[j].Value >>= nVal;
2801 aOuterShdwAttrList->add( XML_rotWithShape, OString::number( nVal ).getStr() );
2803 else if( aOuterShdwProps[j].Name == "sx" )
2805 sal_Int32 nVal = 0;
2806 aOuterShdwProps[j].Value >>= nVal;
2807 aOuterShdwAttrList->add( XML_sx, OString::number( nVal ).getStr() );
2809 else if( aOuterShdwProps[j].Name == "sy" )
2811 sal_Int32 nVal = 0;
2812 aOuterShdwProps[j].Value >>= nVal;
2813 aOuterShdwAttrList->add( XML_sy, OString::number( nVal ).getStr() );
2815 else if( aOuterShdwProps[j].Name == "rad" )
2817 sal_Int32 nVal = 0;
2818 aOuterShdwProps[j].Value >>= nVal;
2819 aOuterShdwAttrList->add( XML_rad, OString::number( nVal ).getStr() );
2821 else if( aOuterShdwProps[j].Name == "endA" )
2823 sal_Int32 nVal = 0;
2824 aOuterShdwProps[j].Value >>= nVal;
2825 aOuterShdwAttrList->add( XML_endA, OString::number( nVal ).getStr() );
2827 else if( aOuterShdwProps[j].Name == "endPos" )
2829 sal_Int32 nVal = 0;
2830 aOuterShdwProps[j].Value >>= nVal;
2831 aOuterShdwAttrList->add( XML_endPos, OString::number( nVal ).getStr() );
2833 else if( aOuterShdwProps[j].Name == "fadeDir" )
2835 sal_Int32 nVal = 0;
2836 aOuterShdwProps[j].Value >>= nVal;
2837 aOuterShdwAttrList->add( XML_fadeDir, OString::number( nVal ).getStr() );
2839 else if( aOuterShdwProps[j].Name == "stA" )
2841 sal_Int32 nVal = 0;
2842 aOuterShdwProps[j].Value >>= nVal;
2843 aOuterShdwAttrList->add( XML_stA, OString::number( nVal ).getStr() );
2845 else if( aOuterShdwProps[j].Name == "stPos" )
2847 sal_Int32 nVal = 0;
2848 aOuterShdwProps[j].Value >>= nVal;
2849 aOuterShdwAttrList->add( XML_stPos, OString::number( nVal ).getStr() );
2851 else if( aOuterShdwProps[j].Name == "grow" )
2853 sal_Int32 nVal = 0;
2854 aOuterShdwProps[j].Value >>= nVal;
2855 aOuterShdwAttrList->add( XML_grow, OString::number( nVal ).getStr() );
2859 else if(aEffectProps[i].Name == "RgbClr")
2861 aEffectProps[i].Value >>= nRgbClr;
2863 else if(aEffectProps[i].Name == "RgbClrTransparency")
2865 sal_Int32 nTransparency;
2866 if (aEffectProps[i].Value >>= nTransparency)
2867 // Calculate alpha value (see oox/source/drawingml/color.cxx : getTransparency())
2868 nAlpha = MAX_PERCENT - ( PER_PERCENT * nTransparency );
2870 else if(aEffectProps[i].Name == "SchemeClr")
2872 aEffectProps[i].Value >>= sSchemeClr;
2874 else if(aEffectProps[i].Name == "SchemeClrTransformations")
2876 aEffectProps[i].Value >>= aTransformations;
2880 if( nEffectToken > 0 )
2882 mpFS->startElement( nEffectToken, xOuterShdwAttrList );
2884 if( bContainsColor )
2886 if( sSchemeClr.isEmpty() )
2887 WriteColor( nRgbClr, nAlpha );
2888 else
2889 WriteColor( sSchemeClr, aTransformations );
2892 mpFS->endElement( nEffectToken );
2896 void DrawingML::WriteShapeEffects( Reference< XPropertySet > rXPropSet )
2898 if( !GetProperty( rXPropSet, "InteropGrabBag" ) )
2899 return;
2901 Sequence< PropertyValue > aGrabBag, aEffects;
2902 mAny >>= aGrabBag;
2903 for( sal_Int32 i=0; i < aGrabBag.getLength(); ++i )
2905 if( aGrabBag[i].Name == "EffectProperties" )
2907 aGrabBag[i].Value >>= aEffects;
2908 break;
2911 if( aEffects.getLength() == 0 )
2913 bool bHasShadow = false;
2914 rXPropSet->getPropertyValue( "Shadow" ) >>= bHasShadow;
2915 if( bHasShadow )
2917 Sequence< PropertyValue > aShadowGrabBag( 3 );
2918 Sequence< PropertyValue > aShadowAttribsGrabBag( 2 );
2920 double dX = +0.0, dY = +0.0;
2921 rXPropSet->getPropertyValue( "ShadowXDistance" ) >>= dX;
2922 rXPropSet->getPropertyValue( "ShadowYDistance" ) >>= dY;
2924 aShadowAttribsGrabBag[0].Name = "dist";
2925 aShadowAttribsGrabBag[0].Value = Any(static_cast< sal_Int32 >(sqrt(dX*dX + dY*dY) * 360));
2926 aShadowAttribsGrabBag[1].Name = "dir";
2927 aShadowAttribsGrabBag[1].Value = Any(static_cast< sal_Int32 >(atan2(dY,dX) * 180 * 60000 / M_PI));
2929 aShadowGrabBag[0].Name = "Attribs";
2930 aShadowGrabBag[0].Value = Any(aShadowAttribsGrabBag);
2931 aShadowGrabBag[1].Name = "RgbClr";
2932 aShadowGrabBag[1].Value = rXPropSet->getPropertyValue( "ShadowColor" );
2933 aShadowGrabBag[2].Name = "RgbClrTransparency";
2934 aShadowGrabBag[2].Value = rXPropSet->getPropertyValue( "ShadowTransparence" );
2936 mpFS->startElementNS(XML_a, XML_effectLst, FSEND);
2937 WriteShapeEffect( "outerShdw", aShadowGrabBag );
2938 mpFS->endElementNS(XML_a, XML_effectLst);
2940 return;
2943 mpFS->startElementNS(XML_a, XML_effectLst, FSEND);
2945 for( sal_Int32 i=0; i < aEffects.getLength(); ++i )
2947 Sequence< PropertyValue > aEffectProps;
2948 aEffects[i].Value >>= aEffectProps;
2949 WriteShapeEffect( aEffects[i].Name, aEffectProps );
2952 mpFS->endElementNS(XML_a, XML_effectLst);
2955 void DrawingML::WriteShape3DEffects( Reference< XPropertySet > xPropSet )
2957 // check existence of the grab bag
2958 if( !GetProperty( xPropSet, "InteropGrabBag" ) )
2959 return;
2961 // extract the relevant properties from the grab bag
2962 Sequence< PropertyValue > aGrabBag, aEffectProps, aLightRigProps, aShape3DProps;
2963 mAny >>= aGrabBag;
2964 for( sal_Int32 i=0; i < aGrabBag.getLength(); ++i )
2966 if( aGrabBag[i].Name == "3DEffectProperties" )
2968 Sequence< PropertyValue > a3DEffectProps;
2969 aGrabBag[i].Value >>= a3DEffectProps;
2970 for( sal_Int32 j=0; j < a3DEffectProps.getLength(); ++j )
2972 if( a3DEffectProps[j].Name == "Camera" )
2973 a3DEffectProps[j].Value >>= aEffectProps;
2974 else if( a3DEffectProps[j].Name == "LightRig" )
2975 a3DEffectProps[j].Value >>= aLightRigProps;
2976 else if( a3DEffectProps[j].Name == "Shape3D" )
2977 a3DEffectProps[j].Value >>= aShape3DProps;
2979 break;
2982 if( aEffectProps.getLength() == 0 && aLightRigProps.getLength() == 0 && aShape3DProps.getLength() == 0 )
2983 return;
2985 bool bCameraRotationPresent = false;
2986 sax_fastparser::FastAttributeList *aCameraAttrList = FastSerializerHelper::createAttrList();
2987 sax_fastparser::XFastAttributeListRef xCameraAttrList( aCameraAttrList );
2988 sax_fastparser::FastAttributeList *aCameraRotationAttrList = FastSerializerHelper::createAttrList();
2989 sax_fastparser::XFastAttributeListRef xRotAttrList( aCameraRotationAttrList );
2990 for( sal_Int32 i=0; i < aEffectProps.getLength(); ++i )
2992 if( aEffectProps[i].Name == "prst" )
2994 OUString sVal;
2995 aEffectProps[i].Value >>= sVal;
2996 aCameraAttrList->add( XML_prst, OUStringToOString( sVal, RTL_TEXTENCODING_UTF8 ).getStr() );
2998 else if( aEffectProps[i].Name == "fov" )
3000 float fVal = 0;
3001 aEffectProps[i].Value >>= fVal;
3002 aCameraAttrList->add( XML_fov, OString::number( fVal * 60000 ).getStr() );
3004 else if( aEffectProps[i].Name == "zoom" )
3006 float fVal = 1;
3007 aEffectProps[i].Value >>= fVal;
3008 aCameraAttrList->add( XML_zoom, OString::number( fVal * 100000 ).getStr() );
3010 else if( aEffectProps[i].Name == "rotLat" ||
3011 aEffectProps[i].Name == "rotLon" ||
3012 aEffectProps[i].Name == "rotRev" )
3014 sal_Int32 nVal = 0, nToken = XML_none;
3015 aEffectProps[i].Value >>= nVal;
3016 if( aEffectProps[i].Name == "rotLat" )
3017 nToken = XML_lat;
3018 else if( aEffectProps[i].Name == "rotLon" )
3019 nToken = XML_lon;
3020 else if( aEffectProps[i].Name == "rotRev" )
3021 nToken = XML_rev;
3022 aCameraRotationAttrList->add( nToken, OString::number( nVal ).getStr() );
3023 bCameraRotationPresent = true;
3027 bool bLightRigRotationPresent = false;
3028 sax_fastparser::FastAttributeList *aLightRigAttrList = FastSerializerHelper::createAttrList();
3029 sax_fastparser::XFastAttributeListRef xLightAttrList( aLightRigAttrList );
3030 sax_fastparser::FastAttributeList *aLightRigRotationAttrList = FastSerializerHelper::createAttrList();
3031 sax_fastparser::XFastAttributeListRef xLightRotAttrList( aLightRigRotationAttrList );
3032 for( sal_Int32 i=0; i < aLightRigProps.getLength(); ++i )
3034 if( aLightRigProps[i].Name == "rig" || aLightRigProps[i].Name == "dir" )
3036 OUString sVal;
3037 sal_Int32 nToken = XML_none;
3038 aLightRigProps[i].Value >>= sVal;
3039 if( aLightRigProps[i].Name == "rig" )
3040 nToken = XML_rig;
3041 else if( aLightRigProps[i].Name == "dir" )
3042 nToken = XML_dir;
3043 aLightRigAttrList->add( nToken, OUStringToOString( sVal, RTL_TEXTENCODING_UTF8 ).getStr() );
3045 else if( aLightRigProps[i].Name == "rotLat" ||
3046 aLightRigProps[i].Name == "rotLon" ||
3047 aLightRigProps[i].Name == "rotRev" )
3049 sal_Int32 nVal = 0, nToken = XML_none;
3050 aLightRigProps[i].Value >>= nVal;
3051 if( aLightRigProps[i].Name == "rotLat" )
3052 nToken = XML_lat;
3053 else if( aLightRigProps[i].Name == "rotLon" )
3054 nToken = XML_lon;
3055 else if( aLightRigProps[i].Name == "rotRev" )
3056 nToken = XML_rev;
3057 aLightRigRotationAttrList->add( nToken, OString::number( nVal ).getStr() );
3058 bLightRigRotationPresent = true;
3062 mpFS->startElementNS( XML_a, XML_scene3d, FSEND );
3064 if( aEffectProps.getLength() > 0 )
3066 mpFS->startElementNS( XML_a, XML_camera, xCameraAttrList );
3067 if( bCameraRotationPresent )
3069 mpFS->singleElementNS( XML_a, XML_rot, xRotAttrList );
3071 mpFS->endElementNS( XML_a, XML_camera );
3073 else
3075 // a:camera with Word default values - Word won't open the document if this is not present
3076 mpFS->singleElementNS( XML_a, XML_camera, XML_prst, "orthographicFront", FSEND );
3079 if( aEffectProps.getLength() > 0 )
3081 mpFS->startElementNS( XML_a, XML_lightRig, xLightAttrList );
3082 if( bLightRigRotationPresent )
3084 mpFS->singleElementNS( XML_a, XML_rot, xLightRotAttrList );
3086 mpFS->endElementNS( XML_a, XML_lightRig );
3088 else
3090 // a:lightRig with Word default values - Word won't open the document if this is not present
3091 mpFS->singleElementNS( XML_a, XML_lightRig, XML_rig, "threePt", XML_dir, "t", FSEND );
3094 mpFS->endElementNS( XML_a, XML_scene3d );
3096 if( aShape3DProps.getLength() == 0 )
3097 return;
3099 bool bBevelTPresent = false, bBevelBPresent = false;
3100 Sequence< PropertyValue > aExtrusionColorProps, aContourColorProps;
3101 sax_fastparser::FastAttributeList *aBevelTAttrList = FastSerializerHelper::createAttrList();
3102 sax_fastparser::XFastAttributeListRef xBevelTAttrList( aBevelTAttrList );
3103 sax_fastparser::FastAttributeList *aBevelBAttrList = FastSerializerHelper::createAttrList();
3104 sax_fastparser::XFastAttributeListRef xBevelBAttrList( aBevelBAttrList );
3105 sax_fastparser::FastAttributeList *aShape3DAttrList = FastSerializerHelper::createAttrList();
3106 for( sal_Int32 i=0; i < aShape3DProps.getLength(); ++i )
3108 if( aShape3DProps[i].Name == "extrusionH" || aShape3DProps[i].Name == "contourW" || aShape3DProps[i].Name == "z" )
3110 sal_Int32 nVal = 0, nToken = XML_none;
3111 aShape3DProps[i].Value >>= nVal;
3112 if( aShape3DProps[i].Name == "extrusionH" )
3113 nToken = XML_extrusionH;
3114 else if( aShape3DProps[i].Name == "contourW" )
3115 nToken = XML_contourW;
3116 else if( aShape3DProps[i].Name == "z" )
3117 nToken = XML_z;
3118 aShape3DAttrList->add( nToken, OString::number( nVal ).getStr() );
3120 else if( aShape3DProps[i].Name == "prstMaterial" )
3122 OUString sVal;
3123 aShape3DProps[i].Value >>= sVal;
3124 aShape3DAttrList->add( XML_prstMaterial, OUStringToOString( sVal, RTL_TEXTENCODING_UTF8 ).getStr() );
3126 else if( aShape3DProps[i].Name == "extrusionClr" )
3128 aShape3DProps[i].Value >>= aExtrusionColorProps;
3130 else if( aShape3DProps[i].Name == "contourClr" )
3132 aShape3DProps[i].Value >>= aContourColorProps;
3134 else if( aShape3DProps[i].Name == "bevelT" || aShape3DProps[i].Name == "bevelB" )
3136 Sequence< PropertyValue > aBevelProps;
3137 aShape3DProps[i].Value >>= aBevelProps;
3138 if ( aBevelProps.getLength() == 0 )
3139 continue;
3141 sax_fastparser::FastAttributeList *aBevelAttrList = NULL;
3142 if( aShape3DProps[i].Name == "bevelT" )
3144 bBevelTPresent = true;
3145 aBevelAttrList = aBevelTAttrList;
3147 else
3149 bBevelBPresent = true;
3150 aBevelAttrList = aBevelBAttrList;
3152 for( sal_Int32 j=0; j < aBevelProps.getLength(); ++j )
3154 if( aBevelProps[j].Name == "w" || aBevelProps[j].Name == "h" )
3156 sal_Int32 nVal = 0, nToken = XML_none;
3157 aBevelProps[j].Value >>= nVal;
3158 if( aBevelProps[j].Name == "w" )
3159 nToken = XML_w;
3160 else if( aBevelProps[j].Name == "h" )
3161 nToken = XML_h;
3162 aBevelAttrList->add( nToken, OString::number( nVal ).getStr() );
3164 else if( aBevelProps[j].Name == "prst" )
3166 OUString sVal;
3167 aBevelProps[j].Value >>= sVal;
3168 aBevelAttrList->add( XML_prst, OUStringToOString( sVal, RTL_TEXTENCODING_UTF8 ).getStr() );
3175 sax_fastparser::XFastAttributeListRef xAttrList( aShape3DAttrList );
3176 mpFS->startElementNS( XML_a, XML_sp3d, xAttrList );
3177 if( bBevelTPresent )
3179 mpFS->singleElementNS( XML_a, XML_bevelT, xBevelTAttrList );
3181 if( bBevelBPresent )
3183 mpFS->singleElementNS( XML_a, XML_bevelB, xBevelBAttrList );
3185 if( aExtrusionColorProps.getLength() > 0 )
3187 OUString sSchemeClr;
3188 sal_Int32 nColor(0);
3189 sal_Int32 nTransparency(0);
3190 Sequence< PropertyValue > aColorTransformations;
3191 for( sal_Int32 i=0; i < aExtrusionColorProps.getLength(); ++i )
3193 if( aExtrusionColorProps[i].Name == "schemeClr" )
3194 aExtrusionColorProps[i].Value >>= sSchemeClr;
3195 else if( aExtrusionColorProps[i].Name == "schemeClrTransformations" )
3196 aExtrusionColorProps[i].Value >>= aColorTransformations;
3197 else if( aExtrusionColorProps[i].Name == "rgbClr" )
3198 aExtrusionColorProps[i].Value >>= nColor;
3199 else if( aExtrusionColorProps[i].Name == "rgbClrTransparency" )
3200 aExtrusionColorProps[i].Value >>= nTransparency;
3202 mpFS->startElementNS( XML_a, XML_extrusionClr, FSEND );
3204 if( sSchemeClr.isEmpty() )
3205 WriteColor( nColor, MAX_PERCENT - ( PER_PERCENT * nTransparency ) );
3206 else
3207 WriteColor( sSchemeClr, aColorTransformations );
3209 mpFS->endElementNS( XML_a, XML_extrusionClr );
3211 if( aContourColorProps.getLength() > 0 )
3213 OUString sSchemeClr;
3214 sal_Int32 nColor(0);
3215 sal_Int32 nTransparency(0);
3216 Sequence< PropertyValue > aColorTransformations;
3217 for( sal_Int32 i=0; i < aContourColorProps.getLength(); ++i )
3219 if( aContourColorProps[i].Name == "schemeClr" )
3220 aContourColorProps[i].Value >>= sSchemeClr;
3221 else if( aContourColorProps[i].Name == "schemeClrTransformations" )
3222 aContourColorProps[i].Value >>= aColorTransformations;
3223 else if( aContourColorProps[i].Name == "rgbClr" )
3224 aContourColorProps[i].Value >>= nColor;
3225 else if( aContourColorProps[i].Name == "rgbClrTransparency" )
3226 aContourColorProps[i].Value >>= nTransparency;
3228 mpFS->startElementNS( XML_a, XML_contourClr, FSEND );
3230 if( sSchemeClr.isEmpty() )
3231 WriteColor( nColor, MAX_PERCENT - ( PER_PERCENT * nTransparency ) );
3232 else
3233 WriteColor( sSchemeClr, aContourColorProps );
3235 mpFS->endElementNS( XML_a, XML_contourClr );
3237 mpFS->endElementNS( XML_a, XML_sp3d );
3240 void DrawingML::WriteArtisticEffect( Reference< XPropertySet > rXPropSet )
3242 if( !GetProperty( rXPropSet, "InteropGrabBag" ) )
3243 return;
3245 PropertyValue aEffect;
3246 Sequence< PropertyValue > aGrabBag;
3247 mAny >>= aGrabBag;
3248 for( sal_Int32 i=0; i < aGrabBag.getLength(); ++i )
3250 if( aGrabBag[i].Name == "ArtisticEffectProperties" )
3252 aGrabBag[i].Value >>= aEffect;
3253 break;
3256 sal_Int32 nEffectToken = ArtisticEffectProperties::getEffectToken( aEffect.Name );
3257 if( nEffectToken == XML_none )
3258 return;
3260 Sequence< PropertyValue > aAttrs;
3261 aEffect.Value >>= aAttrs;
3262 sax_fastparser::FastAttributeList *aAttrList = FastSerializerHelper::createAttrList();
3263 OString sRelId;
3264 for( sal_Int32 i=0; i < aAttrs.getLength(); ++i )
3266 sal_Int32 nToken = ArtisticEffectProperties::getEffectToken( aAttrs[i].Name );
3267 if( nToken != XML_none )
3269 sal_Int32 nVal = 0;
3270 aAttrs[i].Value >>= nVal;
3271 aAttrList->add( nToken, OString::number( nVal ).getStr() );
3273 else if( aAttrs[i].Name == "OriginalGraphic" )
3275 Sequence< PropertyValue > aGraphic;
3276 aAttrs[i].Value >>= aGraphic;
3277 Sequence< sal_Int8 > aGraphicData;
3278 OUString sGraphicId;
3279 for( sal_Int32 j=0; j < aGraphic.getLength(); ++j )
3281 if( aGraphic[j].Name == "Id" )
3282 aGraphic[j].Value >>= sGraphicId;
3283 else if( aGraphic[j].Name == "Data" )
3284 aGraphic[j].Value >>= aGraphicData;
3286 sRelId = WriteWdpPicture( sGraphicId, aGraphicData );
3290 mpFS->startElementNS( XML_a, XML_extLst, FSEND );
3291 mpFS->startElementNS( XML_a, XML_ext,
3292 XML_uri, "{BEBA8EAE-BF5A-486C-A8C5-ECC9F3942E4B}",
3293 FSEND );
3294 mpFS->startElementNS( XML_a14, XML_imgProps,
3295 FSNS( XML_xmlns, XML_a14 ), "http://schemas.microsoft.com/office/drawing/2010/main",
3296 FSEND );
3297 mpFS->startElementNS( XML_a14, XML_imgLayer,
3298 FSNS( XML_r, XML_embed), sRelId.getStr(),
3299 FSEND );
3300 mpFS->startElementNS( XML_a14, XML_imgEffect, FSEND );
3302 sax_fastparser::XFastAttributeListRef xAttrList( aAttrList );
3303 mpFS->singleElementNS( XML_a14, nEffectToken, xAttrList );
3305 mpFS->endElementNS( XML_a14, XML_imgEffect );
3306 mpFS->endElementNS( XML_a14, XML_imgLayer );
3307 mpFS->endElementNS( XML_a14, XML_imgProps );
3308 mpFS->endElementNS( XML_a, XML_ext );
3309 mpFS->endElementNS( XML_a, XML_extLst );
3312 OString DrawingML::WriteWdpPicture( const OUString& rFileId, const Sequence< sal_Int8 >& rPictureData )
3314 std::map<OUString, OUString>::iterator aCachedItem = maWdpCache.find( rFileId );
3315 if( aCachedItem != maWdpCache.end() )
3316 return OUStringToOString( aCachedItem->second, RTL_TEXTENCODING_UTF8 );
3318 OUString sFileName = "media/hdphoto" + OUString::number( mnWdpImageCounter++ ) + ".wdp";
3319 uno::Reference< io::XOutputStream > xOutStream =
3320 mpFB->openFragmentStream( "word/" + sFileName,
3321 "image/vnd.ms-photo" );
3322 OUString sId;
3323 xOutStream->writeBytes( rPictureData );
3324 xOutStream->closeOutput();
3326 sId = mpFB->addRelation( mpFS->getOutputStream(),
3327 "http://schemas.microsoft.com/office/2007/relationships/hdphoto",
3328 sFileName, false );
3330 maWdpCache[rFileId] = sId;
3331 return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
3337 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */