1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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_features.h>
22 #include <config_folders.h>
23 #include <rtl/bootstrap.hxx>
24 #include <sal/log.hxx>
25 #include <oox/core/xmlfilterbase.hxx>
26 #include <oox/export/drawingml.hxx>
27 #include <oox/export/utils.hxx>
28 #include <oox/helper/propertyset.hxx>
29 #include <oox/drawingml/color.hxx>
30 #include <drawingml/fillproperties.hxx>
31 #include <drawingml/textparagraph.hxx>
32 #include <oox/token/namespaces.hxx>
33 #include <oox/token/properties.hxx>
34 #include <oox/token/relationship.hxx>
35 #include <oox/token/tokens.hxx>
36 #include <oox/drawingml/drawingmltypes.hxx>
37 #include <svtools/unitconv.hxx>
38 #include <sax/fastattribs.hxx>
39 #include <i18nlangtag/languagetag.hxx>
42 #include <com/sun/star/awt/CharSet.hpp>
43 #include <com/sun/star/awt/FontDescriptor.hpp>
44 #include <com/sun/star/awt/FontSlant.hpp>
45 #include <com/sun/star/awt/FontStrikeout.hpp>
46 #include <com/sun/star/awt/FontWeight.hpp>
47 #include <com/sun/star/awt/FontUnderline.hpp>
48 #include <com/sun/star/awt/Gradient.hpp>
49 #include <com/sun/star/beans/XPropertySet.hpp>
50 #include <com/sun/star/beans/XPropertyState.hpp>
51 #include <com/sun/star/beans/Property.hpp>
52 #include <com/sun/star/beans/XPropertySetInfo.hpp>
53 #include <com/sun/star/container/XEnumerationAccess.hpp>
54 #include <com/sun/star/container/XIndexAccess.hpp>
55 #include <com/sun/star/document/XStorageBasedDocument.hpp>
56 #include <com/sun/star/drawing/BitmapMode.hpp>
57 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
58 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
59 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
60 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
61 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
62 #include <com/sun/star/drawing/Hatch.hpp>
63 #include <com/sun/star/drawing/LineDash.hpp>
64 #include <com/sun/star/drawing/LineJoint.hpp>
65 #include <com/sun/star/drawing/LineStyle.hpp>
66 #include <com/sun/star/drawing/TextFitToSizeType.hpp>
67 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
68 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
69 #include <com/sun/star/drawing/XShape.hpp>
70 #include <com/sun/star/drawing/FillStyle.hpp>
71 #include <com/sun/star/embed/ElementModes.hpp>
72 #include <com/sun/star/graphic/XGraphic.hpp>
73 #include <com/sun/star/i18n/ScriptType.hpp>
74 #include <com/sun/star/io/XOutputStream.hpp>
75 #include <com/sun/star/style/LineSpacing.hpp>
76 #include <com/sun/star/style/LineSpacingMode.hpp>
77 #include <com/sun/star/text/WritingMode.hpp>
78 #include <com/sun/star/text/WritingMode2.hpp>
79 #include <com/sun/star/text/GraphicCrop.hpp>
80 #include <com/sun/star/text/XText.hpp>
81 #include <com/sun/star/text/XTextContent.hpp>
82 #include <com/sun/star/text/XTextField.hpp>
83 #include <com/sun/star/text/XTextRange.hpp>
84 #include <com/sun/star/style/CaseMap.hpp>
85 #include <com/sun/star/xml/dom/XNodeList.hpp>
86 #include <com/sun/star/xml/sax/Writer.hpp>
87 #include <com/sun/star/xml/sax/XSAXSerializable.hpp>
89 #include <comphelper/processfactory.hxx>
90 #include <comphelper/random.hxx>
91 #include <comphelper/seqstream.hxx>
92 #include <comphelper/storagehelper.hxx>
93 #include <comphelper/xmltools.hxx>
94 #include <o3tl/any.hxx>
95 #include <tools/stream.hxx>
96 #include <unotools/fontdefs.hxx>
97 #include <vcl/cvtgrf.hxx>
98 #include <vcl/graph.hxx>
99 #include <vcl/settings.hxx>
100 #include <vcl/GraphicObject.hxx>
101 #include <vcl/svapp.hxx>
102 #include <rtl/strbuf.hxx>
103 #include <sfx2/app.hxx>
104 #include <svl/languageoptions.hxx>
105 #include <filter/msfilter/escherex.hxx>
106 #include <filter/msfilter/util.hxx>
107 #include <editeng/outlobj.hxx>
108 #include <editeng/svxenum.hxx>
109 #include <editeng/unonames.hxx>
110 #include <editeng/unoprnms.hxx>
111 #include <editeng/flditem.hxx>
112 #include <svx/sdtfsitm.hxx>
113 #include <svx/svdoashp.hxx>
114 #include <svx/svdomedia.hxx>
115 #include <svx/unoapi.hxx>
116 #include <svx/unoshape.hxx>
117 #include <svx/EnhancedCustomShape2d.hxx>
119 using namespace ::css
;
120 using namespace ::css::beans
;
121 using namespace ::css::drawing
;
122 using namespace ::css::i18n
;
123 using namespace ::css::style
;
124 using namespace ::css::text
;
125 using namespace ::css::uno
;
126 using namespace ::css::container
;
128 using ::css::io::XOutputStream
;
129 using ::sax_fastparser::FSHelperPtr
;
130 using ::sax_fastparser::FastSerializerHelper
;
134 namespace drawingml
{
136 URLTransformer::~URLTransformer()
140 OUString
URLTransformer::getTransformedString(const OUString
& rString
) const
145 bool URLTransformer::isExternalURL(const OUString
& /*rURL*/) const
150 static css::uno::Any
getLineDash( const css::uno::Reference
<css::frame::XModel
>& xModel
, const OUString
& rDashName
)
152 css::uno::Reference
<css::lang::XMultiServiceFactory
> xFact(xModel
, css::uno::UNO_QUERY
);
153 css::uno::Reference
<css::container::XNameAccess
> xNameAccess(
154 xFact
->createInstance("com.sun.star.drawing.DashTable"),
155 css::uno::UNO_QUERY
);
158 if (!xNameAccess
->hasByName(rDashName
))
159 return css::uno::Any();
161 return xNameAccess
->getByName(rDashName
);
164 return css::uno::Any();
169 void WriteRadialGradientPath(const awt::Gradient
& rGradient
, const FSHelperPtr
& pFS
)
171 pFS
->startElementNS(XML_a
, XML_path
, XML_path
, "circle");
173 // Write the focus rectangle. Work with the focus point, and assume
174 // that it extends 50% in all directions. The below
175 // left/top/right/bottom values are percentages, where 0 means the
176 // edge of the tile rectangle and 100% means the center of it.
177 rtl::Reference
<sax_fastparser::FastAttributeList
> pAttributeList(
178 sax_fastparser::FastSerializerHelper::createAttrList());
179 sal_Int32 nLeftPercent
= rGradient
.XOffset
* 2 - 50;
180 pAttributeList
->add(XML_l
, OString::number(nLeftPercent
* PER_PERCENT
));
181 sal_Int32 nTopPercent
= rGradient
.YOffset
* 2 - 50;
182 pAttributeList
->add(XML_t
, OString::number(nTopPercent
* PER_PERCENT
));
183 sal_Int32 nRightPercent
= (100 - rGradient
.XOffset
) * 2 - 50;
184 pAttributeList
->add(XML_r
, OString::number(nRightPercent
* PER_PERCENT
));
185 sal_Int32 nBottomPercent
= (100 - rGradient
.YOffset
) * 2 - 50;
186 pAttributeList
->add(XML_b
, OString::number(nBottomPercent
* PER_PERCENT
));
187 sax_fastparser::XFastAttributeListRef
xAttributeList(pAttributeList
.get());
188 pFS
->singleElementNS(XML_a
, XML_fillToRect
, xAttributeList
);
190 pFS
->endElementNS(XML_a
, XML_path
);
195 int DrawingML::mnImageCounter
= 1;
196 int DrawingML::mnWdpImageCounter
= 1;
197 std::map
<OUString
, OUString
> DrawingML::maWdpCache
;
199 void DrawingML::ResetCounters()
202 mnWdpImageCounter
= 1;
206 bool DrawingML::GetProperty( const Reference
< XPropertySet
>& rXPropertySet
, const OUString
& aName
)
210 mAny
= rXPropertySet
->getPropertyValue(aName
);
214 catch( const Exception
& )
216 /* printf ("exception when trying to get value of property: %s\n", aName.toUtf8()); */
221 bool DrawingML::GetPropertyAndState( const Reference
< XPropertySet
>& rXPropertySet
, const Reference
< XPropertyState
>& rXPropertyState
, const OUString
& aName
, PropertyState
& eState
)
225 mAny
= rXPropertySet
->getPropertyValue(aName
);
228 eState
= rXPropertyState
->getPropertyState(aName
);
232 catch( const Exception
& )
234 /* printf ("exception when trying to get value of property: %s\n", aName.toUtf8()); */
239 void DrawingML::WriteColor( ::Color nColor
, sal_Int32 nAlpha
)
241 // Transparency is a separate element.
242 OString sColor
= OString::number( sal_uInt32(nColor
) & 0x00FFFFFF, 16 );
243 if( sColor
.getLength() < 6 )
245 OStringBuffer
sBuf( "0" );
246 int remains
= 5 - sColor
.getLength();
254 sBuf
.append( sColor
);
256 sColor
= sBuf
.getStr();
258 if( nAlpha
< MAX_PERCENT
)
260 mpFS
->startElementNS(XML_a
, XML_srgbClr
, XML_val
, sColor
);
261 mpFS
->singleElementNS(XML_a
, XML_alpha
, XML_val
, OString::number(nAlpha
));
262 mpFS
->endElementNS( XML_a
, XML_srgbClr
);
267 mpFS
->singleElementNS(XML_a
, XML_srgbClr
, XML_val
, sColor
);
271 void DrawingML::WriteColor( const OUString
& sColorSchemeName
, const Sequence
< PropertyValue
>& aTransformations
, sal_Int32 nAlpha
)
273 // prevent writing a tag with empty val attribute
274 if( sColorSchemeName
.isEmpty() )
277 if( aTransformations
.hasElements() )
279 mpFS
->startElementNS(XML_a
, XML_schemeClr
, XML_val
, sColorSchemeName
.toUtf8());
280 WriteColorTransformations( aTransformations
, nAlpha
);
281 mpFS
->endElementNS( XML_a
, XML_schemeClr
);
283 else if(nAlpha
< MAX_PERCENT
)
285 mpFS
->startElementNS(XML_a
, XML_schemeClr
, XML_val
, sColorSchemeName
.toUtf8());
286 mpFS
->singleElementNS(XML_a
, XML_alpha
, XML_val
, OString::number(nAlpha
));
287 mpFS
->endElementNS( XML_a
, XML_schemeClr
);
291 mpFS
->singleElementNS(XML_a
, XML_schemeClr
, XML_val
, sColorSchemeName
.toUtf8());
295 void DrawingML::WriteColorTransformations( const Sequence
< PropertyValue
>& aTransformations
, sal_Int32 nAlpha
)
297 for( sal_Int32 i
= 0; i
< aTransformations
.getLength(); i
++ )
299 sal_Int32 nToken
= Color::getColorTransformationToken( aTransformations
[i
].Name
);
300 if( nToken
!= XML_TOKEN_INVALID
&& aTransformations
[i
].Value
.hasValue() )
302 if(nToken
== XML_alpha
&& nAlpha
< MAX_PERCENT
)
304 mpFS
->singleElementNS(XML_a
, nToken
, XML_val
, OString::number(nAlpha
));
308 sal_Int32 nValue
= aTransformations
[i
].Value
.get
<sal_Int32
>();
309 mpFS
->singleElementNS(XML_a
, nToken
, XML_val
, OString::number(nValue
));
315 void DrawingML::WriteSolidFill( ::Color nColor
, sal_Int32 nAlpha
)
317 mpFS
->startElementNS(XML_a
, XML_solidFill
);
318 WriteColor( nColor
, nAlpha
);
319 mpFS
->endElementNS( XML_a
, XML_solidFill
);
322 void DrawingML::WriteSolidFill( const OUString
& sSchemeName
, const Sequence
< PropertyValue
>& aTransformations
, sal_Int32 nAlpha
)
324 mpFS
->startElementNS(XML_a
, XML_solidFill
);
325 WriteColor( sSchemeName
, aTransformations
, nAlpha
);
326 mpFS
->endElementNS( XML_a
, XML_solidFill
);
329 void DrawingML::WriteSolidFill( const Reference
< XPropertySet
>& rXPropSet
)
332 if ( !GetProperty( rXPropSet
, "FillColor" ) )
334 sal_uInt32 nFillColor
= mAny
.get
<sal_uInt32
>();
336 // get InteropGrabBag and search the relevant attributes
337 OUString sColorFillScheme
;
338 sal_uInt32 nOriginalColor
= 0;
339 Sequence
< PropertyValue
> aStyleProperties
, aTransformations
;
340 if ( GetProperty( rXPropSet
, "InteropGrabBag" ) )
342 Sequence
< PropertyValue
> aGrabBag
;
344 for( sal_Int32 i
=0; i
< aGrabBag
.getLength(); ++i
)
346 if( aGrabBag
[i
].Name
== "SpPrSolidFillSchemeClr" )
347 aGrabBag
[i
].Value
>>= sColorFillScheme
;
348 else if( aGrabBag
[i
].Name
== "OriginalSolidFillClr" )
349 aGrabBag
[i
].Value
>>= nOriginalColor
;
350 else if( aGrabBag
[i
].Name
== "StyleFillRef" )
351 aGrabBag
[i
].Value
>>= aStyleProperties
;
352 else if( aGrabBag
[i
].Name
== "SpPrSolidFillSchemeClrTransformations" )
353 aGrabBag
[i
].Value
>>= aTransformations
;
357 sal_Int32 nAlpha
= MAX_PERCENT
;
358 if( GetProperty( rXPropSet
, "FillTransparence" ) )
360 sal_Int32 nTransparency
= 0;
361 mAny
>>= nTransparency
;
362 // Calculate alpha value (see oox/source/drawingml/color.cxx : getTransparency())
363 nAlpha
= (MAX_PERCENT
- ( PER_PERCENT
* nTransparency
) );
367 if ( nFillColor
!= nOriginalColor
)
369 // the user has set a different color for the shape
370 WriteSolidFill( ::Color(nFillColor
& 0xffffff), nAlpha
);
372 else if ( !sColorFillScheme
.isEmpty() )
374 // the shape had a scheme color and the user didn't change it
375 WriteSolidFill( sColorFillScheme
, aTransformations
, nAlpha
);
377 else if ( aStyleProperties
.hasElements() )
379 sal_uInt32 nThemeColor
= 0;
380 sal_Int32 nThemeAlpha
= MAX_PERCENT
;
381 for( sal_Int32 i
=0; i
< aStyleProperties
.getLength(); ++i
)
383 if( aStyleProperties
[i
].Name
== "Color" )
385 aStyleProperties
[i
].Value
>>= nThemeColor
;
387 else if(aStyleProperties
[i
].Name
== "Transformations" )
389 Sequence
< PropertyValue
> aStyleTransformations
;
390 aStyleProperties
[i
].Value
>>= aStyleTransformations
;
391 for( sal_Int32 j
= 0; j
< aStyleTransformations
.getLength(); j
++ )
393 if (aStyleTransformations
[j
].Name
== "alpha" )
395 aStyleTransformations
[j
].Value
>>= nThemeAlpha
;
401 if ( nFillColor
!= nThemeColor
|| nAlpha
!= nThemeAlpha
)
402 // the shape contains a theme but it wasn't being used
403 WriteSolidFill( ::Color(nFillColor
& 0xffffff), nAlpha
);
405 // in case the shape used the style color and the user didn't change it,
406 // we must not write a <a: solidFill> tag.
410 // the shape had a custom color and the user didn't change it
411 WriteSolidFill( ::Color(nFillColor
& 0xffffff), nAlpha
);
415 void DrawingML::WriteGradientStop( sal_uInt16 nStop
, ::Color nColor
)
417 mpFS
->startElementNS(XML_a
, XML_gs
, XML_pos
, OString::number(nStop
* 1000));
418 WriteColor( nColor
);
419 mpFS
->endElementNS( XML_a
, XML_gs
);
422 ::Color
DrawingML::ColorWithIntensity( sal_uInt32 nColor
, sal_uInt32 nIntensity
)
424 return ::Color(( ( ( nColor
& 0xff ) * nIntensity
) / 100 )
425 | ( ( ( ( ( nColor
& 0xff00 ) >> 8 ) * nIntensity
) / 100 ) << 8 )
426 | ( ( ( ( ( nColor
& 0xff0000 ) >> 8 ) * nIntensity
) / 100 ) << 8 ));
429 bool DrawingML::EqualGradients( awt::Gradient aGradient1
, awt::Gradient aGradient2
)
431 return aGradient1
.Style
== aGradient2
.Style
&&
432 aGradient1
.StartColor
== aGradient2
.StartColor
&&
433 aGradient1
.EndColor
== aGradient2
.EndColor
&&
434 aGradient1
.Angle
== aGradient2
.Angle
&&
435 aGradient1
.Border
== aGradient2
.Border
&&
436 aGradient1
.XOffset
== aGradient2
.XOffset
&&
437 aGradient1
.YOffset
== aGradient2
.YOffset
&&
438 aGradient1
.StartIntensity
== aGradient2
.StartIntensity
&&
439 aGradient1
.EndIntensity
== aGradient2
.EndIntensity
&&
440 aGradient1
.StepCount
== aGradient2
.StepCount
;
443 void DrawingML::WriteGradientFill( const Reference
< XPropertySet
>& rXPropSet
)
445 awt::Gradient aGradient
;
446 if (GetProperty(rXPropSet
, "FillGradient"))
448 aGradient
= *o3tl::doAccess
<awt::Gradient
>(mAny
);
450 // get InteropGrabBag and search the relevant attributes
451 awt::Gradient aOriginalGradient
;
452 Sequence
< PropertyValue
> aGradientStops
;
453 if ( GetProperty( rXPropSet
, "InteropGrabBag" ) )
455 Sequence
< PropertyValue
> aGrabBag
;
457 for( sal_Int32 i
=0; i
< aGrabBag
.getLength(); ++i
)
458 if( aGrabBag
[i
].Name
== "GradFillDefinition" )
459 aGrabBag
[i
].Value
>>= aGradientStops
;
460 else if( aGrabBag
[i
].Name
== "OriginalGradFill" )
461 aGrabBag
[i
].Value
>>= aOriginalGradient
;
464 // check if an ooxml gradient had been imported and if the user has modified it
465 // Gradient grab-bag depends on theme grab-bag, which is implemented
467 if( EqualGradients( aOriginalGradient
, aGradient
) && GetDocumentType() == DOCUMENT_DOCX
)
469 // If we have no gradient stops that means original gradient were defined by a theme.
470 if( aGradientStops
.hasElements() )
472 mpFS
->startElementNS(XML_a
, XML_gradFill
, XML_rotWithShape
, "0");
473 WriteGrabBagGradientFill(aGradientStops
, aGradient
);
474 mpFS
->endElementNS( XML_a
, XML_gradFill
);
479 mpFS
->startElementNS(XML_a
, XML_gradFill
, XML_rotWithShape
, "0");
480 WriteGradientFill(aGradient
);
481 mpFS
->endElementNS( XML_a
, XML_gradFill
);
486 void DrawingML::WriteGrabBagGradientFill( const Sequence
< PropertyValue
>& aGradientStops
, awt::Gradient rGradient
)
488 // write back the original gradient
489 mpFS
->startElementNS(XML_a
, XML_gsLst
);
491 // get original stops and write them
492 for( sal_Int32 i
=0; i
< aGradientStops
.getLength(); ++i
)
494 Sequence
< PropertyValue
> aGradientStop
;
495 aGradientStops
[i
].Value
>>= aGradientStop
;
500 sal_Int16 nTransparency
= 0;
502 Sequence
< PropertyValue
> aTransformations
;
503 for( sal_Int32 j
=0; j
< aGradientStop
.getLength(); ++j
)
505 if( aGradientStop
[j
].Name
== "SchemeClr" )
506 aGradientStop
[j
].Value
>>= sSchemeClr
;
507 else if( aGradientStop
[j
].Name
== "RgbClr" )
508 aGradientStop
[j
].Value
>>= nRgbClr
;
509 else if( aGradientStop
[j
].Name
== "Pos" )
510 aGradientStop
[j
].Value
>>= nPos
;
511 else if( aGradientStop
[j
].Name
== "Transparency" )
512 aGradientStop
[j
].Value
>>= nTransparency
;
513 else if( aGradientStop
[j
].Name
== "Transformations" )
514 aGradientStop
[j
].Value
>>= aTransformations
;
517 mpFS
->startElementNS(XML_a
, XML_gs
, XML_pos
, OString::number(nPos
* 100000.0).getStr());
518 if( sSchemeClr
.isEmpty() )
520 // Calculate alpha value (see oox/source/drawingml/color.cxx : getTransparency())
521 sal_Int32 nAlpha
= MAX_PERCENT
- ( PER_PERCENT
* nTransparency
);
522 WriteColor( nRgbClr
, nAlpha
);
526 WriteColor( sSchemeClr
, aTransformations
);
528 mpFS
->endElementNS( XML_a
, XML_gs
);
530 mpFS
->endElementNS( XML_a
, XML_gsLst
);
532 switch (rGradient
.Style
)
535 mpFS
->singleElementNS(
536 XML_a
, XML_lin
, XML_ang
,
537 OString::number((((3600 - rGradient
.Angle
+ 900) * 6000) % 21600000)));
539 case awt::GradientStyle_RADIAL
:
540 WriteRadialGradientPath(rGradient
, mpFS
);
545 void DrawingML::WriteGradientFill( awt::Gradient rGradient
)
547 switch( rGradient
.Style
)
550 case awt::GradientStyle_LINEAR
:
551 mpFS
->startElementNS(XML_a
, XML_gsLst
);
552 WriteGradientStop( 0, ColorWithIntensity( rGradient
.StartColor
, rGradient
.StartIntensity
) );
553 WriteGradientStop( 100, ColorWithIntensity( rGradient
.EndColor
, rGradient
.EndIntensity
) );
554 mpFS
->endElementNS( XML_a
, XML_gsLst
);
555 mpFS
->singleElementNS(
556 XML_a
, XML_lin
, XML_ang
,
557 OString::number((((3600 - rGradient
.Angle
+ 900) * 6000) % 21600000)));
560 case awt::GradientStyle_AXIAL
:
561 mpFS
->startElementNS(XML_a
, XML_gsLst
);
562 WriteGradientStop( 0, ColorWithIntensity( rGradient
.EndColor
, rGradient
.EndIntensity
) );
563 WriteGradientStop( 50, ColorWithIntensity( rGradient
.StartColor
, rGradient
.StartIntensity
) );
564 WriteGradientStop( 100, ColorWithIntensity( rGradient
.EndColor
, rGradient
.EndIntensity
) );
565 mpFS
->endElementNS( XML_a
, XML_gsLst
);
566 mpFS
->singleElementNS(
567 XML_a
, XML_lin
, XML_ang
,
568 OString::number((((3600 - rGradient
.Angle
+ 900) * 6000) % 21600000)));
571 case awt::GradientStyle_RADIAL
:
573 mpFS
->startElementNS(XML_a
, XML_gsLst
);
574 WriteGradientStop(0, ColorWithIntensity(rGradient
.EndColor
, rGradient
.EndIntensity
));
575 if (rGradient
.Border
> 0 && rGradient
.Border
< 100)
576 // Map border to an additional gradient stop, which has the
577 // same color as the final stop.
579 100 - rGradient
.Border
,
580 ColorWithIntensity(rGradient
.StartColor
, rGradient
.StartIntensity
));
581 WriteGradientStop(100,
582 ColorWithIntensity(rGradient
.StartColor
, rGradient
.StartIntensity
));
583 mpFS
->endElementNS(XML_a
, XML_gsLst
);
585 WriteRadialGradientPath(rGradient
, mpFS
);
588 /* I don't see how to apply transformation to gradients, so
589 * elliptical will end as radial and square as
590 * rectangular. also position offsets are not applied */
591 case awt::GradientStyle_ELLIPTICAL
:
592 case awt::GradientStyle_RECT
:
593 case awt::GradientStyle_SQUARE
:
594 mpFS
->startElementNS(XML_a
, XML_gsLst
);
595 WriteGradientStop( 0, ColorWithIntensity( rGradient
.EndColor
, rGradient
.EndIntensity
) );
596 WriteGradientStop( 100, ColorWithIntensity( rGradient
.StartColor
, rGradient
.StartIntensity
) );
597 mpFS
->endElementNS( XML_a
, XML_gsLst
);
598 mpFS
->singleElementNS( XML_a
, XML_path
,
599 XML_path
, ( rGradient
.Style
== awt::GradientStyle_RADIAL
|| rGradient
.Style
== awt::GradientStyle_ELLIPTICAL
) ? "circle" : "rect" );
604 void DrawingML::WriteLineArrow( const Reference
< XPropertySet
>& rXPropSet
, bool bLineStart
)
606 ESCHER_LineEnd eLineEnd
;
607 sal_Int32 nArrowLength
;
608 sal_Int32 nArrowWidth
;
610 if ( EscherPropertyContainer::GetLineArrow( bLineStart
, rXPropSet
, eLineEnd
, nArrowLength
, nArrowWidth
) )
616 switch( nArrowLength
)
618 case ESCHER_LineShortArrow
:
622 case ESCHER_LineMediumLenArrow
:
625 case ESCHER_LineLongArrow
:
633 case ESCHER_LineNoEnd
:
636 case ESCHER_LineArrowEnd
:
639 case ESCHER_LineArrowStealthEnd
:
642 case ESCHER_LineArrowDiamondEnd
:
645 case ESCHER_LineArrowOvalEnd
:
648 case ESCHER_LineArrowOpenEnd
:
653 switch( nArrowWidth
)
655 case ESCHER_LineNarrowArrow
:
659 case ESCHER_LineMediumWidthArrow
:
662 case ESCHER_LineWideArrow
:
667 mpFS
->singleElementNS( XML_a
, bLineStart
? XML_headEnd
: XML_tailEnd
,
674 void DrawingML::WriteOutline( const Reference
<XPropertySet
>& rXPropSet
, Reference
< frame::XModel
> const & xModel
)
676 drawing::LineStyle
aLineStyle( drawing::LineStyle_NONE
);
678 if (GetProperty(rXPropSet
, "LineStyle"))
681 sal_uInt32 nLineWidth
= 0;
683 sal_Int32 nColorAlpha
= MAX_PERCENT
;
684 bool bColorSet
= false;
685 const char* cap
= nullptr;
686 drawing::LineDash aLineDash
;
687 bool bDashSet
= false;
688 bool bNoFill
= false;
690 // get InteropGrabBag and search the relevant attributes
691 OUString sColorFillScheme
;
693 ::Color nOriginalColor
;
695 sal_uInt32 nStyleLineWidth
= 0;
697 Sequence
<PropertyValue
> aStyleProperties
;
698 Sequence
<PropertyValue
> aTransformations
;
700 drawing::LineStyle
aStyleLineStyle(drawing::LineStyle_NONE
);
701 drawing::LineJoint
aStyleLineJoint(drawing::LineJoint_NONE
);
703 if (GetProperty(rXPropSet
, "InteropGrabBag"))
705 Sequence
<PropertyValue
> aGrabBag
;
708 for (sal_Int32 i
=0; i
< aGrabBag
.getLength(); ++i
)
710 if( aGrabBag
[i
].Name
== "SpPrLnSolidFillSchemeClr" )
711 aGrabBag
[i
].Value
>>= sColorFillScheme
;
712 else if( aGrabBag
[i
].Name
== "OriginalLnSolidFillClr" )
713 aGrabBag
[i
].Value
>>= nOriginalColor
;
714 else if( aGrabBag
[i
].Name
== "StyleLnRef" )
715 aGrabBag
[i
].Value
>>= aStyleProperties
;
716 else if( aGrabBag
[i
].Name
== "SpPrLnSolidFillSchemeClrTransformations" )
717 aGrabBag
[i
].Value
>>= aTransformations
;
719 if (aStyleProperties
.hasElements())
721 for (sal_Int32 i
=0; i
< aStyleProperties
.getLength(); ++i
)
723 if( aStyleProperties
[i
].Name
== "Color" )
724 aStyleProperties
[i
].Value
>>= nStyleColor
;
725 else if( aStyleProperties
[i
].Name
== "LineStyle" )
726 aStyleProperties
[i
].Value
>>= aStyleLineStyle
;
727 else if( aStyleProperties
[i
].Name
== "LineJoint" )
728 aStyleProperties
[i
].Value
>>= aStyleLineJoint
;
729 else if( aStyleProperties
[i
].Name
== "LineWidth" )
730 aStyleProperties
[i
].Value
>>= nStyleLineWidth
;
735 if (GetProperty(rXPropSet
, "LineWidth"))
740 case drawing::LineStyle_NONE
:
743 case drawing::LineStyle_DASH
:
744 if (GetProperty(rXPropSet
, "LineDash"))
746 aLineDash
= mAny
.get
<drawing::LineDash
>();
747 //this query is good for shapes, but in the case of charts it returns 0 values
748 if (aLineDash
.Dots
== 0 && aLineDash
.DotLen
== 0 && aLineDash
.Dashes
== 0 && aLineDash
.DashLen
== 0 && aLineDash
.Distance
== 0) {
749 OUString aLineDashName
;
750 if (GetProperty(rXPropSet
, "LineDashName"))
751 mAny
>>= aLineDashName
;
752 if (!aLineDashName
.isEmpty() && xModel
) {
753 css::uno::Any aAny
= getLineDash(xModel
, aLineDashName
);
760 //export the linestyle of chart wall (plot area) and chart page
761 OUString aLineDashName
;
762 if (GetProperty(rXPropSet
, "LineDashName"))
763 mAny
>>= aLineDashName
;
764 if (!aLineDashName
.isEmpty() && xModel
) {
765 css::uno::Any aAny
= getLineDash(xModel
, aLineDashName
);
770 if (aLineDash
.Style
== DashStyle_ROUND
|| aLineDash
.Style
== DashStyle_ROUNDRELATIVE
)
775 SAL_INFO("oox.shape", "dash dots: " << aLineDash
.Dots
<< " dashes: " << aLineDash
.Dashes
776 << " dotlen: " << aLineDash
.DotLen
<< " dashlen: " << aLineDash
.DashLen
<< " distance: " << aLineDash
.Distance
);
779 case drawing::LineStyle_SOLID
:
781 if (GetProperty(rXPropSet
, "LineColor"))
783 nColor
= ::Color(mAny
.get
<sal_uInt32
>() & 0xffffff);
786 if (GetProperty(rXPropSet
, "LineTransparence"))
788 nColorAlpha
= MAX_PERCENT
- (mAny
.get
<sal_Int16
>() * PER_PERCENT
);
793 mpFS
->startElementNS( XML_a
, XML_ln
,
795 XML_w
, nLineWidth
> 1 && nStyleLineWidth
!= nLineWidth
?
796 OString::number(oox::drawingml::convertHmmToEmu(nLineWidth
)).getStr() : nullptr );
800 if( nColor
!= nOriginalColor
)
802 // the user has set a different color for the line
803 WriteSolidFill( nColor
, nColorAlpha
);
805 else if( !sColorFillScheme
.isEmpty() )
807 // the line had a scheme color and the user didn't change it
808 WriteSolidFill( sColorFillScheme
, aTransformations
);
810 else if( aStyleProperties
.hasElements() )
812 if( nColor
!= nStyleColor
)
813 // the line style defines some color but it wasn't being used
814 WriteSolidFill( nColor
);
815 // in case the shape used the style color and the user didn't change it,
816 // we must not write a <a: solidFill> tag.
820 WriteSolidFill( nColor
, nColorAlpha
);
824 if( bDashSet
&& aStyleLineStyle
!= drawing::LineStyle_DASH
)
826 // convert absolute dash/dot length to relative length
827 int relDotLen
= nLineWidth
? aLineDash
.DotLen
/ nLineWidth
: 0;
828 int relDashLen
= nLineWidth
? aLineDash
.DashLen
/ nLineWidth
: 0;
829 int relDistance
= nLineWidth
? aLineDash
.Distance
/ nLineWidth
: 0;
830 // fixing relative values in the case of linewidths smaller than 1 pt
831 if (0 < nLineWidth
&& nLineWidth
< 35) //35 HMM == 1 pt
833 relDotLen
= relDotLen
? (relDotLen
+ 1) * (nLineWidth
* 360.0 / 12700) : 0;
834 relDashLen
= relDashLen
? (relDashLen
+ 1) * (nLineWidth
* 360.0 / 12700) : 0;
835 relDistance
= relDistance
? (relDistance
+ 1) * (nLineWidth
* 360.0 / 12700) : 0;
837 // keep default mso preset linestyles (instead of custdash)
838 if (aLineDash
.Dots
== 1 && relDotLen
== 1 && aLineDash
.Dashes
== 0 && relDashLen
== 0 && relDistance
== 3)
840 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "dot");
842 else if (aLineDash
.Dots
== 0 && relDotLen
== 0 && aLineDash
.Dashes
== 1 && relDashLen
== 4 && relDistance
== 3)
844 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "dash");
846 else if (aLineDash
.Dots
== 1 && relDotLen
== 1 && aLineDash
.Dashes
== 1 && relDashLen
== 4 && relDistance
== 3)
848 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "dashDot");
850 else if (aLineDash
.Dots
== 0 && relDotLen
== 0 && aLineDash
.Dashes
== 1 && relDashLen
== 8 && relDistance
== 3)
852 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "lgDash");
854 else if (aLineDash
.Dots
== 1 && relDotLen
== 1 && aLineDash
.Dashes
== 1 && relDashLen
== 8 && relDistance
== 3)
856 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "lgDashDot");
858 else if (aLineDash
.Dots
== 2 && relDotLen
== 1 && aLineDash
.Dashes
== 1 && relDashLen
== 8 && relDistance
== 3)
860 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "lgDashDotDot");
862 else if (aLineDash
.Dots
== 1 && relDotLen
== 1 && aLineDash
.Dashes
== 0 && relDashLen
== 0 && relDistance
== 1)
864 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "sysDot");
866 else if (aLineDash
.Dots
== 0 && relDotLen
== 0 && aLineDash
.Dashes
== 1 && relDashLen
== 3 && relDistance
== 1)
868 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "sysDash");
870 else if (aLineDash
.Dots
== 1 && relDotLen
== 1 && aLineDash
.Dashes
== 1 && relDashLen
== 3 && relDistance
== 1)
872 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "sysDashDot");
874 else if (aLineDash
.Dots
== 2 && relDotLen
== 1 && aLineDash
.Dashes
== 1 && relDashLen
== 3 && relDistance
== 1)
876 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "sysDashDotDot");
878 /*convert some LO preset dashes to MSO preset dashes for oox interoperability
879 LO preset dashes which don't have equivalent in MSO preset dashes: 2 Dots 3 Dashes, Line with Fine Dots, 3 Dashes 3 Dots*/
880 //ultrafine Dashed, Ultrafine Dotted -> sysDot
881 else if ((aLineDash
.Dots
== 1 && aLineDash
.DotLen
== 51 && aLineDash
.Dashes
== 1 && aLineDash
.DashLen
== 51 && aLineDash
.Distance
== 51) ||
882 (aLineDash
.Dots
== 1 && aLineDash
.DotLen
== 0 && aLineDash
.Dashes
== 0 && aLineDash
.DashLen
== 0 && aLineDash
.Distance
== 50))
884 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "sysDot");
886 //Fine Dashed -> dash
887 else if (aLineDash
.Dots
== 1 && aLineDash
.DotLen
== 197 && aLineDash
.Dashes
== 0 && aLineDash
.DashLen
== 0 && aLineDash
.Distance
== 197)
889 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "dash");
892 else if (aLineDash
.Dots
== 1 && aLineDash
.DotLen
== 0 && aLineDash
.Dashes
== 0 && aLineDash
.DashLen
== 0 && aLineDash
.Distance
== 457)
894 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "dot");
896 //Line Style 9, Dashed -> sysDash
897 else if ((aLineDash
.Dots
== 1 && aLineDash
.DotLen
== 197 && aLineDash
.Dashes
== 0 && aLineDash
.DashLen
== 0 && aLineDash
.Distance
== 120) ||
898 (aLineDash
.Dots
== 1 && aLineDash
.DotLen
== 197 && aLineDash
.Dashes
== 0 && aLineDash
.DashLen
== 0 && aLineDash
.Distance
== 127))
900 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "sysDash");
902 //2 Dots 1 Dash -> sysDashDotDot
903 else if (aLineDash
.Dots
== 2 && aLineDash
.DotLen
== 0 && aLineDash
.Dashes
== 1 && aLineDash
.DashLen
== 203 && aLineDash
.Distance
== 203)
905 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, "sysDashDotDot");
909 mpFS
->startElementNS(XML_a
, XML_custDash
);
911 // Check that line-width is positive and distance between dashes\dots is positive
912 if ( nLineWidth
> 0 && aLineDash
.Distance
> 0 )
914 // Write 'dashes' first, and then 'dots'
916 sal_Int32 nSp
= aLineDash
.Distance
* 100 / nLineWidth
;
917 if ( aLineDash
.Dashes
> 0 )
919 sal_Int32 nD
= aLineDash
.DashLen
* 100 / nLineWidth
;
920 for( i
= 0; i
< aLineDash
.Dashes
; i
++ )
922 mpFS
->singleElementNS( XML_a
, XML_ds
,
923 XML_d
, write1000thOfAPercent(nD
),
924 XML_sp
, write1000thOfAPercent(nSp
) );
927 if ( aLineDash
.Dots
> 0 )
929 sal_Int32 nD
= aLineDash
.DotLen
* 100 / nLineWidth
;
930 for( i
= 0; i
< aLineDash
.Dots
; i
++ )
932 mpFS
->singleElementNS( XML_a
, XML_ds
,
933 XML_d
, write1000thOfAPercent(nD
),
934 XML_sp
, write1000thOfAPercent(nSp
) );
939 SAL_WARN_IF(nLineWidth
<= 0,
940 "oox.shape", "while writing outline - custom dash - line width was < 0 : " << nLineWidth
);
941 SAL_WARN_IF(aLineDash
.Dashes
< 0,
942 "oox.shape", "while writing outline - custom dash - number of dashes was < 0 : " << aLineDash
.Dashes
);
943 SAL_WARN_IF(aLineDash
.Dashes
> 0 && aLineDash
.DashLen
<= 0,
944 "oox.shape", "while writing outline - custom dash - dash length was < 0 : " << aLineDash
.DashLen
);
945 SAL_WARN_IF(aLineDash
.Dots
< 0,
946 "oox.shape", "while writing outline - custom dash - number of dots was < 0 : " << aLineDash
.Dots
);
947 SAL_WARN_IF(aLineDash
.Dots
> 0 && aLineDash
.DotLen
<= 0,
948 "oox.shape", "while writing outline - custom dash - dot length was < 0 : " << aLineDash
.DotLen
);
949 SAL_WARN_IF(aLineDash
.Distance
<= 0,
950 "oox.shape", "while writing outline - custom dash - distance was < 0 : " << aLineDash
.Distance
);
952 mpFS
->endElementNS( XML_a
, XML_custDash
);
956 if (!bNoFill
&& nLineWidth
> 1 && GetProperty(rXPropSet
, "LineJoint"))
958 LineJoint eLineJoint
= mAny
.get
<LineJoint
>();
960 if( aStyleLineJoint
== LineJoint_NONE
|| aStyleLineJoint
!= eLineJoint
)
962 // style-defined line joint does not exist, or is different from the shape's joint
966 case LineJoint_BEVEL
:
967 mpFS
->singleElementNS(XML_a
, XML_bevel
);
970 case LineJoint_MIDDLE
:
971 case LineJoint_MITER
:
972 mpFS
->singleElementNS(XML_a
, XML_miter
);
974 case LineJoint_ROUND
:
975 mpFS
->singleElementNS(XML_a
, XML_round
);
983 WriteLineArrow( rXPropSet
, true );
984 WriteLineArrow( rXPropSet
, false );
988 mpFS
->singleElementNS(XML_a
, XML_noFill
);
991 mpFS
->endElementNS( XML_a
, XML_ln
);
994 const char* DrawingML::GetComponentDir()
996 switch ( meDocumentType
)
998 case DOCUMENT_DOCX
: return "word";
999 case DOCUMENT_PPTX
: return "ppt";
1000 case DOCUMENT_XLSX
: return "xl";
1006 const char* DrawingML::GetRelationCompPrefix()
1008 switch ( meDocumentType
)
1010 case DOCUMENT_DOCX
: return "";
1012 case DOCUMENT_XLSX
: return "../";
1018 OUString
DrawingML::WriteImage( const Graphic
& rGraphic
, bool bRelPathToMedia
)
1020 GfxLink aLink
= rGraphic
.GetGfxLink ();
1021 OUString sMediaType
;
1022 const char* pExtension
= "";
1025 SvMemoryStream aStream
;
1026 const void* aData
= aLink
.GetData();
1027 std::size_t nDataSize
= aLink
.GetDataSize();
1029 switch ( aLink
.GetType() )
1031 case GfxLinkType::NativeGif
:
1032 sMediaType
= "image/gif";
1033 pExtension
= ".gif";
1036 // #i15508# added BMP type for better exports
1037 // export not yet active, so adding for reference (not checked)
1038 case GfxLinkType::NativeBmp
:
1039 sMediaType
= "image/bmp";
1040 pExtension
= ".bmp";
1043 case GfxLinkType::NativeJpg
:
1044 sMediaType
= "image/jpeg";
1045 pExtension
= ".jpeg";
1047 case GfxLinkType::NativePng
:
1048 sMediaType
= "image/png";
1049 pExtension
= ".png";
1051 case GfxLinkType::NativeTif
:
1052 sMediaType
= "image/tiff";
1053 pExtension
= ".tif";
1055 case GfxLinkType::NativeWmf
:
1056 sMediaType
= "image/x-wmf";
1057 pExtension
= ".wmf";
1059 case GfxLinkType::NativeMet
:
1060 sMediaType
= "image/x-met";
1061 pExtension
= ".met";
1063 case GfxLinkType::NativePct
:
1064 sMediaType
= "image/x-pict";
1065 pExtension
= ".pct";
1067 case GfxLinkType::NativeMov
:
1068 sMediaType
= "application/movie";
1069 pExtension
= ".MOV";
1073 GraphicType aType
= rGraphic
.GetType();
1074 if ( aType
== GraphicType::Bitmap
|| aType
== GraphicType::GdiMetafile
)
1076 if ( aType
== GraphicType::Bitmap
)
1078 (void)GraphicConverter::Export( aStream
, rGraphic
, ConvertDataFormat::PNG
);
1079 sMediaType
= "image/png";
1080 pExtension
= ".png";
1084 (void)GraphicConverter::Export( aStream
, rGraphic
, ConvertDataFormat::EMF
);
1085 sMediaType
= "image/x-emf";
1086 pExtension
= ".emf";
1091 SAL_WARN("oox.shape", "unhandled graphic type " << static_cast<int>(aType
) );
1092 /*Earlier, even in case of unhandled graphic types we were
1093 proceeding to write the image, which would eventually
1094 write an empty image with a zero size, and return a valid
1095 relationID, which is incorrect.
1100 aData
= aStream
.GetData();
1101 nDataSize
= aStream
.GetEndOfData();
1106 Reference
< XOutputStream
> xOutStream
= mpFB
->openFragmentStream( OUStringBuffer()
1107 .appendAscii( GetComponentDir() )
1108 .append( "/media/image" )
1109 .append( static_cast<sal_Int32
>(mnImageCounter
) )
1110 .appendAscii( pExtension
)
1111 .makeStringAndClear(),
1113 xOutStream
->writeBytes( Sequence
< sal_Int8
>( static_cast<const sal_Int8
*>(aData
), nDataSize
) );
1114 xOutStream
->closeOutput();
1116 const OString sRelPathToMedia
= "media/image";
1117 OString sRelationCompPrefix
;
1118 if ( bRelPathToMedia
)
1119 sRelationCompPrefix
= "../";
1121 sRelationCompPrefix
= GetRelationCompPrefix();
1122 sRelId
= mpFB
->addRelation( mpFS
->getOutputStream(),
1123 oox::getRelationship(Relationship::IMAGE
),
1125 .appendAscii( sRelationCompPrefix
.getStr() )
1126 .appendAscii( sRelPathToMedia
.getStr() )
1127 .append( static_cast<sal_Int32
>(mnImageCounter
++) )
1128 .appendAscii( pExtension
)
1129 .makeStringAndClear() );
1134 void DrawingML::WriteMediaNonVisualProperties(const css::uno::Reference
<css::drawing::XShape
>& xShape
)
1136 SdrMediaObj
* pMediaObj
= dynamic_cast<SdrMediaObj
*>(GetSdrObjectFromXShape(xShape
));
1141 OUString aExtension
;
1142 const OUString
& rURL(pMediaObj
->getURL());
1143 int nLastDot
= rURL
.lastIndexOf('.');
1145 aExtension
= rURL
.copy(nLastDot
);
1147 bool bEmbed
= rURL
.startsWith("vnd.sun.star.Package:");
1148 Relationship eMediaType
= Relationship::VIDEO
;
1151 #if HAVE_FEATURE_AVMEDIA
1152 OUString
aMimeType(pMediaObj
->getMediaProperties().getMimeType());
1154 OUString
aMimeType("none");
1156 if (aMimeType
== "application/vnd.sun.star.media")
1158 // try to set something better
1159 // TODO fix the importer to actually set the mimetype on import
1160 if (aExtension
.equalsIgnoreAsciiCase(".avi"))
1161 aMimeType
= "video/x-msvideo";
1162 else if (aExtension
.equalsIgnoreAsciiCase(".flv"))
1163 aMimeType
= "video/x-flv";
1164 else if (aExtension
.equalsIgnoreAsciiCase(".mp4"))
1165 aMimeType
= "video/mp4";
1166 else if (aExtension
.equalsIgnoreAsciiCase(".mov"))
1167 aMimeType
= "video/quicktime";
1168 else if (aExtension
.equalsIgnoreAsciiCase(".ogv"))
1169 aMimeType
= "video/ogg";
1170 else if (aExtension
.equalsIgnoreAsciiCase(".wmv"))
1171 aMimeType
= "video/x-ms-wmv";
1172 else if (aExtension
.equalsIgnoreAsciiCase(".wav"))
1174 aMimeType
= "audio/x-wav";
1175 eMediaType
= Relationship::AUDIO
;
1179 OUString aVideoFileRelId
;
1180 OUString aMediaRelId
;
1184 // copy the video stream
1185 Reference
<XOutputStream
> xOutStream
= mpFB
->openFragmentStream(OUStringBuffer()
1186 .appendAscii(GetComponentDir())
1187 .append("/media/media")
1188 .append(static_cast<sal_Int32
>(mnImageCounter
))
1190 .makeStringAndClear(),
1193 uno::Reference
<io::XInputStream
> xInputStream(pMediaObj
->GetInputStream());
1194 comphelper::OStorageHelper::CopyInputToOutput(xInputStream
, xOutStream
);
1196 xOutStream
->closeOutput();
1198 // create the relation
1199 OUString aPath
= OUStringBuffer().appendAscii(GetRelationCompPrefix())
1200 .append("media/media")
1201 .append(static_cast<sal_Int32
>(mnImageCounter
++))
1203 .makeStringAndClear();
1204 aVideoFileRelId
= mpFB
->addRelation(mpFS
->getOutputStream(), oox::getRelationship(eMediaType
), aPath
);
1205 aMediaRelId
= mpFB
->addRelation(mpFS
->getOutputStream(), oox::getRelationship(Relationship::MEDIA
), aPath
);
1209 aVideoFileRelId
= mpFB
->addRelation(mpFS
->getOutputStream(), oox::getRelationship(eMediaType
), rURL
);
1210 aMediaRelId
= mpFB
->addRelation(mpFS
->getOutputStream(), oox::getRelationship(Relationship::MEDIA
), rURL
);
1213 GetFS()->startElementNS(XML_p
, XML_nvPr
);
1215 GetFS()->singleElementNS(XML_a
, eMediaType
== Relationship::VIDEO
? XML_videoFile
: XML_audioFile
,
1216 FSNS(XML_r
, XML_link
), aVideoFileRelId
.toUtf8());
1218 GetFS()->startElementNS(XML_p
, XML_extLst
);
1219 // media extensions; google this ID for details
1220 GetFS()->startElementNS(XML_p
, XML_ext
, XML_uri
, "{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}");
1222 GetFS()->singleElementNS(XML_p14
, XML_media
,
1223 bEmbed
? FSNS(XML_r
, XML_embed
): FSNS(XML_r
, XML_link
), aMediaRelId
.toUtf8());
1225 GetFS()->endElementNS(XML_p
, XML_ext
);
1226 GetFS()->endElementNS(XML_p
, XML_extLst
);
1228 GetFS()->endElementNS(XML_p
, XML_nvPr
);
1231 void DrawingML::WriteImageBrightnessContrastTransparence(uno::Reference
<beans::XPropertySet
> const & rXPropSet
)
1233 sal_Int16 nBright
= 0;
1234 sal_Int32 nContrast
= 0;
1235 sal_Int16 nTransparence
= 0;
1237 if (GetProperty(rXPropSet
, "AdjustLuminance"))
1238 nBright
= mAny
.get
<sal_Int16
>();
1239 if (GetProperty(rXPropSet
, "AdjustContrast"))
1240 nContrast
= mAny
.get
<sal_Int32
>();
1241 if (GetProperty(rXPropSet
, "Transparency"))
1242 nTransparence
= mAny
.get
<sal_Int16
>();
1245 if (nBright
|| nContrast
)
1247 mpFS
->singleElementNS(XML_a
, XML_lum
,
1248 XML_bright
, nBright
? OString::number(nBright
* 1000).getStr() : nullptr,
1249 XML_contrast
, nContrast
? OString::number(nContrast
* 1000).getStr() : nullptr);
1254 sal_Int32 nAlphaMod
= (100 - nTransparence
) * PER_PERCENT
;
1255 mpFS
->singleElementNS(XML_a
, XML_alphaModFix
, XML_amt
, OString::number(nAlphaMod
));
1259 OUString
DrawingML::WriteXGraphicBlip(uno::Reference
<beans::XPropertySet
> const & rXPropSet
,
1260 uno::Reference
<graphic::XGraphic
> const & rxGraphic
,
1261 bool bRelPathToMedia
)
1265 if (!rxGraphic
.is())
1268 Graphic
aGraphic(rxGraphic
);
1271 BitmapChecksum nChecksum
= aGraphic
.GetChecksum();
1272 sRelId
= mpTextExport
->FindRelId(nChecksum
);
1274 if (sRelId
.isEmpty())
1276 sRelId
= WriteImage(aGraphic
, bRelPathToMedia
);
1279 BitmapChecksum nChecksum
= aGraphic
.GetChecksum();
1280 mpTextExport
->CacheRelId(nChecksum
, sRelId
);
1284 mpFS
->startElementNS(XML_a
, XML_blip
, FSNS(XML_r
, XML_embed
), sRelId
.toUtf8());
1286 WriteImageBrightnessContrastTransparence(rXPropSet
);
1288 WriteArtisticEffect(rXPropSet
);
1290 mpFS
->endElementNS(XML_a
, XML_blip
);
1295 void DrawingML::WriteXGraphicBlipMode(uno::Reference
<beans::XPropertySet
> const & rXPropSet
,
1296 uno::Reference
<graphic::XGraphic
> const & rxGraphic
)
1298 BitmapMode
eBitmapMode(BitmapMode_NO_REPEAT
);
1299 if (GetProperty(rXPropSet
, "FillBitmapMode"))
1300 mAny
>>= eBitmapMode
;
1302 SAL_INFO("oox.shape", "fill bitmap mode: " << int(eBitmapMode
));
1304 switch (eBitmapMode
)
1306 case BitmapMode_REPEAT
:
1307 mpFS
->singleElementNS(XML_a
, XML_tile
);
1309 case BitmapMode_STRETCH
:
1310 WriteXGraphicStretch(rXPropSet
, rxGraphic
);
1317 void DrawingML::WriteBlipOrNormalFill( const Reference
< XPropertySet
>& xPropSet
, const OUString
& rURLPropName
)
1319 // check for blip and otherwise fall back to normal fill
1320 // we always store normal fill properties but OOXML
1321 // uses a choice between our fill props and BlipFill
1322 if (GetProperty ( xPropSet
, rURLPropName
))
1323 WriteBlipFill( xPropSet
, rURLPropName
);
1325 WriteFill(xPropSet
);
1328 void DrawingML::WriteBlipFill( const Reference
< XPropertySet
>& rXPropSet
, const OUString
& sURLPropName
)
1330 WriteBlipFill( rXPropSet
, sURLPropName
, XML_a
);
1333 void DrawingML::WriteBlipFill( const Reference
< XPropertySet
>& rXPropSet
, const OUString
& sURLPropName
, sal_Int32 nXmlNamespace
)
1335 if ( GetProperty( rXPropSet
, sURLPropName
) )
1337 uno::Reference
<graphic::XGraphic
> xGraphic
;
1338 if (mAny
.has
<uno::Reference
<awt::XBitmap
>>())
1340 uno::Reference
<awt::XBitmap
> xBitmap
= mAny
.get
<uno::Reference
<awt::XBitmap
>>();
1342 xGraphic
.set(xBitmap
, uno::UNO_QUERY
);
1344 else if (mAny
.has
<uno::Reference
<graphic::XGraphic
>>())
1346 xGraphic
= mAny
.get
<uno::Reference
<graphic::XGraphic
>>();
1351 bool bWriteMode
= false;
1352 if (sURLPropName
== "FillBitmap" || sURLPropName
== "BackGraphic")
1354 WriteXGraphicBlipFill(rXPropSet
, xGraphic
, nXmlNamespace
, bWriteMode
);
1359 void DrawingML::WriteXGraphicBlipFill(uno::Reference
<beans::XPropertySet
> const & rXPropSet
,
1360 uno::Reference
<graphic::XGraphic
> const & rxGraphic
,
1361 sal_Int32 nXmlNamespace
, bool bWriteMode
, bool bRelPathToMedia
)
1363 if (!rxGraphic
.is() )
1366 mpFS
->startElementNS(nXmlNamespace
, XML_blipFill
, XML_rotWithShape
, "0");
1368 WriteXGraphicBlip(rXPropSet
, rxGraphic
, bRelPathToMedia
);
1372 WriteXGraphicBlipMode(rXPropSet
, rxGraphic
);
1374 else if(GetProperty(rXPropSet
, "FillBitmapStretch"))
1376 bool bStretch
= mAny
.get
<bool>();
1380 WriteXGraphicStretch(rXPropSet
, rxGraphic
);
1383 mpFS
->endElementNS(nXmlNamespace
, XML_blipFill
);
1386 void DrawingML::WritePattFill( const Reference
< XPropertySet
>& rXPropSet
)
1388 if ( GetProperty( rXPropSet
, "FillHatch" ) )
1390 drawing::Hatch aHatch
;
1392 WritePattFill(rXPropSet
, aHatch
);
1396 void DrawingML::WritePattFill(const Reference
<XPropertySet
>& rXPropSet
, const css::drawing::Hatch
& rHatch
)
1398 mpFS
->startElementNS(XML_a
, XML_pattFill
, XML_prst
, GetHatchPattern(rHatch
));
1400 mpFS
->startElementNS(XML_a
, XML_fgClr
);
1401 WriteColor(::Color(rHatch
.Color
));
1402 mpFS
->endElementNS( XML_a
, XML_fgClr
);
1404 ::Color nColor
= COL_WHITE
;
1405 sal_Int32 nAlpha
= 0;
1407 if ( GetProperty( rXPropSet
, "FillBackground" ) )
1409 bool isBackgroundFilled
= false;
1410 mAny
>>= isBackgroundFilled
;
1411 if( isBackgroundFilled
)
1413 nAlpha
= MAX_PERCENT
;
1415 if( GetProperty( rXPropSet
, "FillColor" ) )
1422 mpFS
->startElementNS(XML_a
, XML_bgClr
);
1423 WriteColor(nColor
, nAlpha
);
1424 mpFS
->endElementNS( XML_a
, XML_bgClr
);
1426 mpFS
->endElementNS( XML_a
, XML_pattFill
);
1429 void DrawingML::WriteGraphicCropProperties(uno::Reference
<beans::XPropertySet
> const & rXPropSet
, Size
const & rOriginalSize
, MapMode
const & rMapMode
)
1431 if (GetProperty(rXPropSet
, "GraphicCrop"))
1433 Size
aOriginalSize(rOriginalSize
);
1435 // GraphicCrop is in mm100, so in case the original size is in pixels, convert it over.
1436 if (rMapMode
.GetMapUnit() == MapUnit::MapPixel
)
1437 aOriginalSize
= Application::GetDefaultDevice()->PixelToLogic(aOriginalSize
, MapMode(MapUnit::Map100thMM
));
1439 css::text::GraphicCrop aGraphicCropStruct
;
1440 mAny
>>= aGraphicCropStruct
;
1442 if ( (0 != aGraphicCropStruct
.Left
) || (0 != aGraphicCropStruct
.Top
) || (0 != aGraphicCropStruct
.Right
) || (0 != aGraphicCropStruct
.Bottom
) )
1444 mpFS
->singleElementNS( XML_a
, XML_srcRect
,
1445 XML_l
, OString::number(rtl::math::round(aGraphicCropStruct
.Left
* 100000.0 / aOriginalSize
.Width())),
1446 XML_t
, OString::number(rtl::math::round(aGraphicCropStruct
.Top
* 100000.0 / aOriginalSize
.Height())),
1447 XML_r
, OString::number(rtl::math::round(aGraphicCropStruct
.Right
* 100000.0 / aOriginalSize
.Width())),
1448 XML_b
, OString::number(rtl::math::round(aGraphicCropStruct
.Bottom
* 100000.0 / aOriginalSize
.Height())) );
1453 void DrawingML::WriteSrcRectXGraphic(uno::Reference
<beans::XPropertySet
> const & rxPropertySet
,
1454 uno::Reference
<graphic::XGraphic
> const & rxGraphic
)
1456 Graphic
aGraphic(rxGraphic
);
1457 Size aOriginalSize
= aGraphic
.GetPrefSize();
1458 const MapMode
& rMapMode
= aGraphic
.GetPrefMapMode();
1459 WriteGraphicCropProperties(rxPropertySet
, aOriginalSize
, rMapMode
);
1462 void DrawingML::WriteXGraphicStretch(uno::Reference
<beans::XPropertySet
> const & rXPropSet
,
1463 uno::Reference
<graphic::XGraphic
> const & rxGraphic
)
1465 mpFS
->startElementNS(XML_a
, XML_stretch
);
1468 if (GetProperty(rXPropSet
, "GraphicCrop"))
1470 css::text::GraphicCrop aGraphicCropStruct
;
1471 mAny
>>= aGraphicCropStruct
;
1473 if ((0 != aGraphicCropStruct
.Left
)
1474 || (0 != aGraphicCropStruct
.Top
)
1475 || (0 != aGraphicCropStruct
.Right
)
1476 || (0 != aGraphicCropStruct
.Bottom
))
1478 Graphic
aGraphic(rxGraphic
);
1479 Size
aOriginalSize(aGraphic
.GetPrefSize());
1480 mpFS
->singleElementNS(XML_a
, XML_fillRect
,
1481 XML_l
, OString::number(((aGraphicCropStruct
.Left
) * 100000) / aOriginalSize
.Width()),
1482 XML_t
, OString::number(((aGraphicCropStruct
.Top
) * 100000) / aOriginalSize
.Height()),
1483 XML_r
, OString::number(((aGraphicCropStruct
.Right
) * 100000) / aOriginalSize
.Width()),
1484 XML_b
, OString::number(((aGraphicCropStruct
.Bottom
) * 100000) / aOriginalSize
.Height()));
1491 mpFS
->singleElementNS(XML_a
, XML_fillRect
);
1494 mpFS
->endElementNS(XML_a
, XML_stretch
);
1497 void DrawingML::WriteTransformation(const tools::Rectangle
& rRect
,
1498 sal_Int32 nXmlNamespace
, bool bFlipH
, bool bFlipV
, sal_Int32 nRotation
, bool bIsGroupShape
)
1501 mpFS
->startElementNS( nXmlNamespace
, XML_xfrm
,
1502 XML_flipH
, bFlipH
? "1" : nullptr,
1503 XML_flipV
, bFlipV
? "1" : nullptr,
1504 XML_rot
, (nRotation
% 21600000) ? OString::number(nRotation
).getStr() : nullptr );
1506 sal_Int32 nLeft
= rRect
.Left();
1507 sal_Int32 nTop
= rRect
.Top();
1508 if (GetDocumentType() == DOCUMENT_DOCX
&& !m_xParent
.is())
1514 mpFS
->singleElementNS(XML_a
, XML_off
,
1515 XML_x
, OString::number(oox::drawingml::convertHmmToEmu(nLeft
)),
1516 XML_y
, OString::number(oox::drawingml::convertHmmToEmu(nTop
)));
1517 mpFS
->singleElementNS(XML_a
, XML_ext
,
1518 XML_cx
, OString::number(oox::drawingml::convertHmmToEmu(rRect
.GetWidth())),
1519 XML_cy
, OString::number(oox::drawingml::convertHmmToEmu(rRect
.GetHeight())));
1521 if (GetDocumentType() != DOCUMENT_DOCX
&& bIsGroupShape
)
1523 mpFS
->singleElementNS(XML_a
, XML_chOff
,
1524 XML_x
, OString::number(oox::drawingml::convertHmmToEmu(nLeft
)),
1525 XML_y
, OString::number(oox::drawingml::convertHmmToEmu(nTop
)));
1526 mpFS
->singleElementNS(XML_a
, XML_chExt
,
1527 XML_cx
, OString::number(oox::drawingml::convertHmmToEmu(rRect
.GetWidth())),
1528 XML_cy
, OString::number(oox::drawingml::convertHmmToEmu(rRect
.GetHeight())));
1531 mpFS
->endElementNS( nXmlNamespace
, XML_xfrm
);
1534 void DrawingML::WriteShapeTransformation( const Reference
< XShape
>& rXShape
, sal_Int32 nXmlNamespace
, bool bFlipH
, bool bFlipV
, bool bSuppressRotation
, bool bSuppressFlipping
, bool bFlippedBeforeRotation
)
1536 SAL_INFO("oox.shape", "write shape transformation");
1538 sal_Int32 nRotation
=0;
1539 awt::Point aPos
= rXShape
->getPosition();
1540 awt::Size aSize
= rXShape
->getSize();
1542 bool bFlipHWrite
= bFlipH
&& !bSuppressFlipping
;
1543 bool bFlipVWrite
= bFlipV
&& !bSuppressFlipping
;
1544 bFlipH
= bFlipH
&& !bFlippedBeforeRotation
;
1545 bFlipV
= bFlipV
&& !bFlippedBeforeRotation
;
1547 if (GetDocumentType() == DOCUMENT_DOCX
&& m_xParent
.is())
1549 awt::Point aParentPos
= m_xParent
->getPosition();
1550 aPos
.X
-= aParentPos
.X
;
1551 aPos
.Y
-= aParentPos
.Y
;
1554 if ( aSize
.Width
< 0 )
1556 if ( aSize
.Height
< 0 )
1557 aSize
.Height
= 1000;
1558 if (!bSuppressRotation
)
1560 SdrObject
* pShape
= GetSdrObjectFromXShape( rXShape
);
1561 nRotation
= pShape
? pShape
->GetRotateAngle() : 0;
1562 if ( nRotation
!= 0 && GetDocumentType() != DOCUMENT_DOCX
)
1564 int faccos
=bFlipV
? -1 : 1;
1565 int facsin
=bFlipH
? -1 : 1;
1566 aPos
.X
-=(1-faccos
*cos(nRotation
*F_PI18000
))*aSize
.Width
/2-facsin
*sin(nRotation
*F_PI18000
)*aSize
.Height
/2;
1567 aPos
.Y
-=(1-faccos
*cos(nRotation
*F_PI18000
))*aSize
.Height
/2+facsin
*sin(nRotation
*F_PI18000
)*aSize
.Width
/2;
1570 // The RotateAngle property's value is independent from any flipping, and that's exactly what we need here.
1571 uno::Reference
<beans::XPropertySet
> xPropertySet(rXShape
, uno::UNO_QUERY
);
1572 uno::Reference
<beans::XPropertySetInfo
> xPropertySetInfo
= xPropertySet
->getPropertySetInfo();
1573 if (xPropertySetInfo
->hasPropertyByName("RotateAngle"))
1574 xPropertySet
->getPropertyValue("RotateAngle") >>= nRotation
;
1577 // OOXML flips shapes before rotating them.
1578 if(bFlipH
!= bFlipV
)
1579 nRotation
= nRotation
* -1 + 36000;
1581 WriteTransformation(tools::Rectangle(Point(aPos
.X
, aPos
.Y
), Size(aSize
.Width
, aSize
.Height
)), nXmlNamespace
,
1582 bFlipHWrite
, bFlipVWrite
, ExportRotateClockwisify(nRotation
), IsGroupShape( rXShape
));
1585 void DrawingML::WriteRunProperties( const Reference
< XPropertySet
>& rRun
, bool bIsField
, sal_Int32 nElement
, bool bCheckDirect
,
1586 bool& rbOverridingCharHeight
, sal_Int32
& rnCharHeight
)
1588 Reference
< XPropertySet
> rXPropSet( rRun
, UNO_QUERY
);
1589 Reference
< XPropertyState
> rXPropState( rRun
, UNO_QUERY
);
1590 OUString usLanguage
;
1591 PropertyState eState
;
1592 SvtScriptType nScriptType
= SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
1593 bool bComplex
= ( nScriptType
== SvtScriptType::COMPLEX
);
1594 const char* bold
= "0";
1595 const char* italic
= nullptr;
1596 const char* underline
= nullptr;
1597 const char* strikeout
= nullptr;
1598 const char* cap
= nullptr;
1599 sal_Int32 nSize
= 1800;
1600 sal_Int32 nCharEscapement
= 0;
1601 sal_Int32 nCharKerning
= 0;
1603 if ( nElement
== XML_endParaRPr
&& rbOverridingCharHeight
)
1605 nSize
= rnCharHeight
;
1607 else if (GetProperty(rXPropSet
, "CharHeight"))
1609 nSize
= static_cast<sal_Int32
>(100*(*o3tl::doAccess
<float>(mAny
)));
1610 if ( nElement
== XML_rPr
)
1612 rbOverridingCharHeight
= true;
1613 rnCharHeight
= nSize
;
1617 if (GetProperty(rXPropSet
, "CharKerning"))
1618 nCharKerning
= static_cast<sal_Int32
>(*o3tl::doAccess
<sal_Int16
>(mAny
));
1619 /** While setting values in propertymap,
1620 * CharKerning converted using GetTextSpacingPoint
1621 * i.e set @ https://opengrok.libreoffice.org/xref/core/oox/source/drawingml/textcharacterproperties.cxx#129
1622 * therefore to get original value CharKerning need to be convert.
1623 * https://opengrok.libreoffice.org/xref/core/oox/source/drawingml/drawingmltypes.cxx#95
1625 nCharKerning
= ((nCharKerning
* 720)-360) / 254;
1627 if ((bComplex
&& GetProperty(rXPropSet
, "CharWeightComplex"))
1628 || GetProperty(rXPropSet
, "CharWeight"))
1630 if ( *o3tl::doAccess
<float>(mAny
) >= awt::FontWeight::SEMIBOLD
)
1634 if ((bComplex
&& GetProperty(rXPropSet
, "CharPostureComplex"))
1635 || GetProperty(rXPropSet
, "CharPosture"))
1636 switch ( *o3tl::doAccess
<awt::FontSlant
>(mAny
) )
1638 case awt::FontSlant_OBLIQUE
:
1639 case awt::FontSlant_ITALIC
:
1646 if ((bCheckDirect
&& GetPropertyAndState(rXPropSet
, rXPropState
, "CharUnderline", eState
)
1647 && eState
== beans::PropertyState_DIRECT_VALUE
)
1648 || GetProperty(rXPropSet
, "CharUnderline"))
1650 switch ( *o3tl::doAccess
<sal_Int16
>(mAny
) )
1652 case awt::FontUnderline::SINGLE
:
1655 case awt::FontUnderline::DOUBLE
:
1658 case awt::FontUnderline::DOTTED
:
1659 underline
= "dotted";
1661 case awt::FontUnderline::DASH
:
1664 case awt::FontUnderline::LONGDASH
:
1665 underline
= "dashLong";
1667 case awt::FontUnderline::DASHDOT
:
1668 underline
= "dotDash";
1670 case awt::FontUnderline::DASHDOTDOT
:
1671 underline
= "dotDotDash";
1673 case awt::FontUnderline::WAVE
:
1676 case awt::FontUnderline::DOUBLEWAVE
:
1677 underline
= "wavyDbl";
1679 case awt::FontUnderline::BOLD
:
1680 underline
= "heavy";
1682 case awt::FontUnderline::BOLDDOTTED
:
1683 underline
= "dottedHeavy";
1685 case awt::FontUnderline::BOLDDASH
:
1686 underline
= "dashHeavy";
1688 case awt::FontUnderline::BOLDLONGDASH
:
1689 underline
= "dashLongHeavy";
1691 case awt::FontUnderline::BOLDDASHDOT
:
1692 underline
= "dotDashHeavy";
1694 case awt::FontUnderline::BOLDDASHDOTDOT
:
1695 underline
= "dotDotDashHeavy";
1697 case awt::FontUnderline::BOLDWAVE
:
1698 underline
= "wavyHeavy";
1703 if ((bCheckDirect
&& GetPropertyAndState(rXPropSet
, rXPropState
, "CharStrikeout", eState
)
1704 && eState
== beans::PropertyState_DIRECT_VALUE
)
1705 || GetProperty(rXPropSet
, "CharStrikeout"))
1707 switch ( *o3tl::doAccess
<sal_Int16
>(mAny
) )
1709 case awt::FontStrikeout::NONE
:
1710 strikeout
= "noStrike";
1712 case awt::FontStrikeout::SINGLE
:
1713 // LibO supports further values of character
1714 // strikeout, OOXML standard (20.1.10.78,
1715 // ST_TextStrikeType) however specifies only
1716 // 3 - single, double and none. Approximate
1717 // the remaining ones by single strike (better
1718 // some strike than none at all).
1719 // TODO: figure out how to do this better
1720 case awt::FontStrikeout::BOLD
:
1721 case awt::FontStrikeout::SLASH
:
1722 case awt::FontStrikeout::X
:
1723 strikeout
= "sngStrike";
1725 case awt::FontStrikeout::DOUBLE
:
1726 strikeout
= "dblStrike";
1731 if (GetProperty(rXPropSet
, "CharLocale"))
1733 css::lang::Locale aLocale
;
1735 LanguageTag
aLanguageTag( aLocale
);
1736 if (!aLanguageTag
.isSystemLocale())
1737 usLanguage
= aLanguageTag
.getBcp47MS();
1740 if (GetPropertyAndState(rXPropSet
, rXPropState
, "CharEscapement", eState
)
1741 && eState
== beans::PropertyState_DIRECT_VALUE
)
1742 mAny
>>= nCharEscapement
;
1745 && (GetPropertyAndState(rXPropSet
, rXPropState
, "CharEscapementHeight", eState
)
1746 && eState
== beans::PropertyState_DIRECT_VALUE
))
1748 sal_uInt32 nCharEscapementHeight
= 0;
1749 mAny
>>= nCharEscapementHeight
;
1750 nSize
= (nSize
* nCharEscapementHeight
) / 100;
1751 // MSO uses default ~58% size
1752 nSize
= (nSize
/ 0.58);
1755 if (GetProperty(rXPropSet
, "CharCaseMap"))
1757 switch ( *o3tl::doAccess
<sal_Int16
>(mAny
) )
1759 case CaseMap::UPPERCASE
:
1762 case CaseMap::SMALLCAPS
:
1768 mpFS
->startElementNS( XML_a
, nElement
,
1771 XML_lang
, usLanguage
.isEmpty() ? nullptr : usLanguage
.toUtf8().getStr(),
1772 XML_sz
, OString::number(nSize
),
1773 // For Condensed character spacing spc value is negative.
1774 XML_spc
, nCharKerning
? OString::number(nCharKerning
).getStr() : nullptr,
1775 XML_strike
, strikeout
,
1777 XML_baseline
, nCharEscapement
== 0 ? nullptr : OString::number(nCharEscapement
*1000).getStr(),
1780 // mso doesn't like text color to be placed after typeface
1781 if ((bCheckDirect
&& GetPropertyAndState(rXPropSet
, rXPropState
, "CharColor", eState
)
1782 && eState
== beans::PropertyState_DIRECT_VALUE
)
1783 || GetProperty(rXPropSet
, "CharColor"))
1785 ::Color
color( *o3tl::doAccess
<sal_uInt32
>(mAny
) );
1786 SAL_INFO("oox.shape", "run color: " << sal_uInt32(color
) << " auto: " << sal_uInt32(COL_AUTO
));
1788 // tdf#104219 In LibreOffice and MS Office, there are two types of colors:
1789 // Automatic and Fixed. OOXML is setting automatic color, by not providing color.
1790 if( color
!= COL_AUTO
)
1792 color
.SetTransparency(0);
1793 // TODO: special handle embossed/engraved
1794 WriteSolidFill( color
);
1800 && GetPropertyAndState(rXPropSet
, rXPropState
, "CharUnderlineColor", eState
)
1801 && eState
== beans::PropertyState_DIRECT_VALUE
)
1802 || GetProperty(rXPropSet
, "CharUnderlineColor")))
1804 ::Color
color(*o3tl::doAccess
<sal_uInt32
>(mAny
));
1805 // if color is automatic, then we shouldn't write information about color but to take color from character
1806 if( color
!= COL_AUTO
)
1808 mpFS
->startElementNS(XML_a
, XML_uFill
);
1809 WriteSolidFill( color
);
1810 mpFS
->endElementNS( XML_a
, XML_uFill
);
1814 mpFS
->singleElementNS(XML_a
, XML_uFillTx
);
1818 if (GetProperty(rXPropSet
, "CharFontName"))
1820 const char* const pitch
= nullptr;
1821 const char* const charset
= nullptr;
1822 OUString usTypeface
;
1824 mAny
>>= usTypeface
;
1825 OUString
aSubstName( GetSubsFontName( usTypeface
, SubsFontFlags::ONLYONE
| SubsFontFlags::MS
) );
1826 if (!aSubstName
.isEmpty())
1827 usTypeface
= aSubstName
;
1829 mpFS
->singleElementNS( XML_a
, XML_latin
,
1830 XML_typeface
, usTypeface
.toUtf8(),
1831 XML_pitchFamily
, pitch
,
1832 XML_charset
, charset
);
1836 && (GetPropertyAndState(rXPropSet
, rXPropState
, "CharFontNameComplex", eState
)
1837 && eState
== beans::PropertyState_DIRECT_VALUE
))
1839 && (GetPropertyAndState(rXPropSet
, rXPropState
, "CharFontNameAsian", eState
)
1840 && eState
== beans::PropertyState_DIRECT_VALUE
)))
1842 const char* const pitch
= nullptr;
1843 const char* const charset
= nullptr;
1844 OUString usTypeface
;
1846 mAny
>>= usTypeface
;
1847 OUString
aSubstName( GetSubsFontName( usTypeface
, SubsFontFlags::ONLYONE
| SubsFontFlags::MS
) );
1848 if (!aSubstName
.isEmpty())
1849 usTypeface
= aSubstName
;
1851 mpFS
->singleElementNS( XML_a
, bComplex
? XML_cs
: XML_ea
,
1852 XML_typeface
, usTypeface
.toUtf8(),
1853 XML_pitchFamily
, pitch
,
1854 XML_charset
, charset
);
1859 Reference
< XTextField
> rXTextField
;
1860 if (GetProperty(rXPropSet
, "TextField"))
1861 mAny
>>= rXTextField
;
1862 if( rXTextField
.is() )
1863 rXPropSet
.set( rXTextField
, UNO_QUERY
);
1866 // field properties starts here
1867 if (GetProperty(rXPropSet
, "URL"))
1872 if( !sURL
.isEmpty() ) {
1873 OUString sRelId
= mpFB
->addRelation( mpFS
->getOutputStream(),
1874 oox::getRelationship(Relationship::HYPERLINK
),
1877 mpFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), sRelId
.toUtf8());
1881 mpFS
->endElementNS( XML_a
, nElement
);
1884 OUString
DrawingML::GetFieldValue( const css::uno::Reference
< css::text::XTextRange
>& rRun
, bool& bIsURLField
)
1886 Reference
< XPropertySet
> rXPropSet( rRun
, UNO_QUERY
);
1887 OUString aFieldType
, aFieldValue
;
1889 if (GetProperty(rXPropSet
, "TextPortionType"))
1891 aFieldType
= *o3tl::doAccess
<OUString
>(mAny
);
1892 SAL_INFO("oox.shape", "field type: " << aFieldType
);
1895 if( aFieldType
== "TextField" )
1897 Reference
< XTextField
> rXTextField
;
1898 if (GetProperty(rXPropSet
, "TextField"))
1899 mAny
>>= rXTextField
;
1900 if( rXTextField
.is() )
1902 rXPropSet
.set( rXTextField
, UNO_QUERY
);
1903 if( rXPropSet
.is() )
1905 OUString
aFieldKind( rXTextField
->getPresentation( true ) );
1906 SAL_INFO("oox.shape", "field kind: " << aFieldKind
);
1907 if( aFieldKind
== "Page" )
1909 aFieldValue
= "slidenum";
1911 else if( aFieldKind
== "Pages" )
1913 aFieldValue
= "slidecount";
1915 else if( aFieldKind
== "PageName" )
1917 aFieldValue
= "slidename";
1919 else if( aFieldKind
== "URL" )
1922 if (GetProperty(rXPropSet
, "Representation"))
1923 mAny
>>= aFieldValue
;
1926 else if(aFieldKind
== "Date")
1928 sal_Int32 nNumFmt
= -1;
1929 rXPropSet
->getPropertyValue(UNO_TC_PROP_NUMFORMAT
) >>= nNumFmt
;
1930 switch(static_cast<SvxDateFormat
>(nNumFmt
))
1932 case SvxDateFormat::StdSmall
:
1933 case SvxDateFormat::A
: aFieldValue
= "datetime"; // 13/02/96
1935 case SvxDateFormat::B
: aFieldValue
= "datetime1"; // 13/02/1996
1937 case SvxDateFormat::StdBig
:
1938 case SvxDateFormat::D
: aFieldValue
= "datetime3"; // 13 February 1996
1943 else if(aFieldKind
== "ExtTime")
1945 sal_Int32 nNumFmt
= -1;
1946 rXPropSet
->getPropertyValue(UNO_TC_PROP_NUMFORMAT
) >>= nNumFmt
;
1947 switch(static_cast<SvxTimeFormat
>(nNumFmt
))
1949 case SvxTimeFormat::Standard
:
1950 case SvxTimeFormat::HH24_MM_SS
:
1951 aFieldValue
= "datetime11"; // 13:49:38
1953 case SvxTimeFormat::HH24_MM
:
1954 aFieldValue
= "datetime10"; // 13:49
1956 case SvxTimeFormat::HH12_MM
:
1957 aFieldValue
= "datetime12"; // 01:49 PM
1959 case SvxTimeFormat::HH12_MM_SS
:
1960 aFieldValue
= "datetime13"; // 01:49:38 PM
1965 else if(aFieldKind
== "ExtFile")
1967 sal_Int32 nNumFmt
= -1;
1968 rXPropSet
->getPropertyValue(UNO_TC_PROP_FILE_FORMAT
) >>= nNumFmt
;
1971 case 0: aFieldValue
= "file"; // Path/File name
1973 case 1: aFieldValue
= "file1"; // Path
1975 case 2: aFieldValue
= "file2"; // File name without extension
1977 case 3: aFieldValue
= "file3"; // File name with extension
1980 else if(aFieldKind
== "Author")
1982 aFieldValue
= "author";
1990 void DrawingML::WriteRun( const Reference
< XTextRange
>& rRun
,
1991 bool& rbOverridingCharHeight
, sal_Int32
& rnCharHeight
)
1993 Reference
< XPropertySet
> rXPropSet( rRun
, UNO_QUERY
);
1994 sal_Int16 nLevel
= -1;
1995 if (GetProperty(rXPropSet
, "NumberingLevel"))
1998 bool bNumberingIsNumber
= true;
1999 if (GetProperty(rXPropSet
, "NumberingIsNumber"))
2000 mAny
>>= bNumberingIsNumber
;
2002 bool bIsURLField
= false;
2003 OUString sFieldValue
= GetFieldValue( rRun
, bIsURLField
);
2004 bool bWriteField
= !( sFieldValue
.isEmpty() || bIsURLField
);
2006 OUString sText
= rRun
->getString();
2008 //if there is no text following the bullet, add a space after the bullet
2009 if (nLevel
!=-1 && bNumberingIsNumber
&& sText
.isEmpty() )
2013 sText
= sFieldValue
;
2015 if( sText
.isEmpty())
2017 Reference
< XPropertySet
> xPropSet( rRun
, UNO_QUERY
);
2021 if( !xPropSet
.is() || !( xPropSet
->getPropertyValue( "PlaceholderText" ) >>= sText
) )
2023 if( sText
.isEmpty() )
2026 catch (const Exception
&)
2034 mpFS
->singleElementNS(XML_a
, XML_br
);
2040 OString
sUUID(comphelper::xml::generateGUIDString());
2041 mpFS
->startElementNS( XML_a
, XML_fld
,
2042 XML_id
, sUUID
.getStr(),
2043 XML_type
, sFieldValue
.toUtf8() );
2047 mpFS
->startElementNS(XML_a
, XML_r
);
2050 Reference
< XPropertySet
> xPropSet( rRun
, uno::UNO_QUERY
);
2051 WriteRunProperties( xPropSet
, bIsURLField
, XML_rPr
, true, rbOverridingCharHeight
, rnCharHeight
);
2052 mpFS
->startElementNS(XML_a
, XML_t
);
2053 mpFS
->writeEscaped( sText
);
2054 mpFS
->endElementNS( XML_a
, XML_t
);
2057 mpFS
->endElementNS( XML_a
, XML_fld
);
2059 mpFS
->endElementNS( XML_a
, XML_r
);
2063 static OUString
GetAutoNumType(SvxNumType nNumberingType
, bool bSDot
, bool bPBehind
, bool bPBoth
)
2065 OUString sPrefixSuffix
;
2068 sPrefixSuffix
= "ParenBoth";
2070 sPrefixSuffix
= "ParenR";
2072 sPrefixSuffix
= "Period";
2074 switch( nNumberingType
)
2076 case SVX_NUM_CHARS_UPPER_LETTER_N
:
2077 case SVX_NUM_CHARS_UPPER_LETTER
:
2078 return "alphaUc" + sPrefixSuffix
;
2080 case SVX_NUM_CHARS_LOWER_LETTER_N
:
2081 case SVX_NUM_CHARS_LOWER_LETTER
:
2082 return "alphaLc" + sPrefixSuffix
;
2084 case SVX_NUM_ROMAN_UPPER
:
2085 return "romanUc" + sPrefixSuffix
;
2087 case SVX_NUM_ROMAN_LOWER
:
2088 return "romanLc" + sPrefixSuffix
;
2090 case SVX_NUM_ARABIC
:
2092 if (sPrefixSuffix
.isEmpty())
2093 return OUString("arabicPlain");
2095 return "arabic" + sPrefixSuffix
;
2104 void DrawingML::WriteParagraphNumbering(const Reference
< XPropertySet
>& rXPropSet
, float fFirstCharHeight
, sal_Int16 nLevel
)
2106 if (nLevel
< 0 || !GetProperty(rXPropSet
, "NumberingRules"))
2109 Reference
< XIndexAccess
> rXIndexAccess
;
2111 if (!(mAny
>>= rXIndexAccess
) || nLevel
>= rXIndexAccess
->getCount())
2114 SAL_INFO("oox.shape", "numbering rules");
2116 Sequence
<PropertyValue
> aPropertySequence
;
2117 rXIndexAccess
->getByIndex(nLevel
) >>= aPropertySequence
;
2119 if (!aPropertySequence
.hasElements())
2122 sal_Int32 nPropertyCount
= aPropertySequence
.getLength();
2124 const PropertyValue
* pPropValue
= aPropertySequence
.getArray();
2126 SvxNumType nNumberingType
= SVX_NUM_NUMBER_NONE
;
2128 bool bPBehind
= false;
2129 bool bPBoth
= false;
2130 sal_Unicode aBulletChar
= 0x2022; // a bullet
2131 awt::FontDescriptor aFontDesc
;
2132 bool bHasFontDesc
= false;
2133 uno::Reference
<graphic::XGraphic
> xGraphic
;
2134 sal_Int16 nBulletRelSize
= 0;
2135 sal_Int16 nStartWith
= 1;
2136 ::Color nBulletColor
;
2137 bool bHasBulletColor
= false;
2138 awt::Size aGraphicSize
;
2140 for ( sal_Int32 i
= 0; i
< nPropertyCount
; i
++ )
2142 OUString
aPropName( pPropValue
[ i
].Name
);
2143 SAL_INFO("oox.shape", "pro name: " << aPropName
);
2144 if ( aPropName
== "NumberingType" )
2146 nNumberingType
= static_cast<SvxNumType
>(*o3tl::doAccess
<sal_Int16
>(pPropValue
[i
].Value
));
2148 else if ( aPropName
== "Prefix" )
2150 if( *o3tl::doAccess
<OUString
>(pPropValue
[i
].Value
) == ")")
2153 else if ( aPropName
== "Suffix" )
2155 auto s
= o3tl::doAccess
<OUString
>(pPropValue
[i
].Value
);
2161 else if(aPropName
== "BulletColor")
2163 nBulletColor
= ::Color(*o3tl::doAccess
<sal_uInt32
>(pPropValue
[i
].Value
));
2164 bHasBulletColor
= true;
2166 else if ( aPropName
== "BulletChar" )
2168 aBulletChar
= (*o3tl::doAccess
<OUString
>(pPropValue
[i
].Value
))[ 0 ];
2170 else if ( aPropName
== "BulletFont" )
2172 aFontDesc
= *o3tl::doAccess
<awt::FontDescriptor
>(pPropValue
[i
].Value
);
2173 bHasFontDesc
= true;
2175 // Our numbullet dialog has set the wrong textencoding for our "StarSymbol" font,
2176 // instead of a Unicode encoding the encoding RTL_TEXTENCODING_SYMBOL was used.
2177 // Because there might exist a lot of damaged documemts I added this two lines
2178 // which fixes the bullet problem for the export.
2179 if ( aFontDesc
.Name
.equalsIgnoreAsciiCase("StarSymbol") )
2180 aFontDesc
.CharSet
= RTL_TEXTENCODING_MS_1252
;
2183 else if ( aPropName
== "BulletRelSize" )
2185 nBulletRelSize
= *o3tl::doAccess
<sal_Int16
>(pPropValue
[i
].Value
);
2187 else if ( aPropName
== "StartWith" )
2189 nStartWith
= *o3tl::doAccess
<sal_Int16
>(pPropValue
[i
].Value
);
2191 else if (aPropName
== "GraphicBitmap")
2193 auto xBitmap
= pPropValue
[i
].Value
.get
<uno::Reference
<awt::XBitmap
>>();
2194 xGraphic
.set(xBitmap
, uno::UNO_QUERY
);
2196 else if ( aPropName
== "GraphicSize" )
2198 aGraphicSize
= *o3tl::doAccess
<awt::Size
>(pPropValue
[i
].Value
);
2199 SAL_INFO("oox.shape", "graphic size: " << aGraphicSize
.Width
<< "x" << aGraphicSize
.Height
);
2203 if (nNumberingType
== SVX_NUM_NUMBER_NONE
)
2206 Graphic
aGraphic(xGraphic
);
2207 if (xGraphic
.is() && aGraphic
.GetType() != GraphicType::NONE
)
2209 long nFirstCharHeightMm
= TransformMetric(fFirstCharHeight
* 100.f
, FieldUnit::POINT
, FieldUnit::MM
);
2210 float fBulletSizeRel
= aGraphicSize
.Height
/ static_cast<float>(nFirstCharHeightMm
) / OOX_BULLET_LIST_SCALE_FACTOR
;
2212 OUString sRelationId
;
2214 if (fBulletSizeRel
< 1.0f
)
2216 // Add padding to get the bullet point centered in PPT
2217 Size
aDestSize(64, 64);
2218 float fBulletSizeRelX
= fBulletSizeRel
/ aGraphicSize
.Height
* aGraphicSize
.Width
;
2219 long nPaddingX
= std::max
<long>(0, std::lround((aDestSize
.Width() - fBulletSizeRelX
* aDestSize
.Width()) / 2.f
));
2220 long nPaddingY
= std::lround((aDestSize
.Height() - fBulletSizeRel
* aDestSize
.Height()) / 2.f
);
2221 tools::Rectangle
aDestRect(nPaddingX
, nPaddingY
, aDestSize
.Width() - nPaddingX
, aDestSize
.Height() - nPaddingY
);
2223 AlphaMask
aMask(aDestSize
);
2225 BitmapEx
aSourceBitmap(aGraphic
.GetBitmapEx());
2226 aSourceBitmap
.Scale(aDestRect
.GetSize());
2227 tools::Rectangle
aSourceRect(Point(0, 0), aDestRect
.GetSize());
2228 BitmapEx
aDestBitmap(Bitmap(aDestSize
, 24), aMask
);
2229 aDestBitmap
.CopyPixel(aDestRect
, aSourceRect
, &aSourceBitmap
);
2230 Graphic
aDestGraphic(aDestBitmap
);
2231 sRelationId
= WriteImage(aDestGraphic
);
2232 fBulletSizeRel
= 1.0f
;
2236 sRelationId
= WriteImage(aGraphic
);
2239 mpFS
->singleElementNS( XML_a
, XML_buSzPct
,
2240 XML_val
, OString::number(std::min
<sal_Int32
>(std::lround(100000.f
* fBulletSizeRel
), 400000)));
2241 mpFS
->startElementNS(XML_a
, XML_buBlip
);
2242 mpFS
->singleElementNS(XML_a
, XML_blip
, FSNS(XML_r
, XML_embed
), sRelationId
.toUtf8());
2243 mpFS
->endElementNS( XML_a
, XML_buBlip
);
2249 if (nBulletColor
== COL_AUTO
)
2251 nBulletColor
= ::Color(mbIsBackgroundDark
? 0xffffff : 0x000000);
2253 mpFS
->startElementNS(XML_a
, XML_buClr
);
2254 WriteColor( nBulletColor
);
2255 mpFS
->endElementNS( XML_a
, XML_buClr
);
2258 if( nBulletRelSize
&& nBulletRelSize
!= 100 )
2259 mpFS
->singleElementNS( XML_a
, XML_buSzPct
,
2260 XML_val
, OString::number(std::clamp
<sal_Int32
>(1000*nBulletRelSize
, 25000, 400000)));
2263 if ( SVX_NUM_CHAR_SPECIAL
== nNumberingType
)
2264 aBulletChar
= SubstituteBullet( aBulletChar
, aFontDesc
);
2265 mpFS
->singleElementNS( XML_a
, XML_buFont
,
2266 XML_typeface
, aFontDesc
.Name
.toUtf8(),
2267 XML_charset
, (aFontDesc
.CharSet
== awt::CharSet::SYMBOL
) ? "2" : nullptr );
2270 OUString aAutoNumType
= GetAutoNumType( nNumberingType
, bSDot
, bPBehind
, bPBoth
);
2272 if (!aAutoNumType
.isEmpty())
2274 mpFS
->singleElementNS(XML_a
, XML_buAutoNum
,
2275 XML_type
, aAutoNumType
.toUtf8(),
2276 XML_startAt
, nStartWith
> 1 ? OString::number(nStartWith
).getStr() : nullptr);
2280 mpFS
->singleElementNS(XML_a
, XML_buChar
, XML_char
, OUString(aBulletChar
).toUtf8());
2285 bool DrawingML::IsGroupShape( const Reference
< XShape
>& rXShape
)
2290 uno::Reference
<lang::XServiceInfo
> xServiceInfo(rXShape
, uno::UNO_QUERY_THROW
);
2291 bRet
= xServiceInfo
->supportsService("com.sun.star.drawing.GroupShape");
2296 bool DrawingML::IsDiagram(const Reference
<XShape
>& rXShape
)
2298 uno::Reference
<beans::XPropertySet
> xPropSet(rXShape
, uno::UNO_QUERY
);
2302 // if the shape doesn't have the InteropGrabBag property, it's not a diagram
2303 uno::Reference
<beans::XPropertySetInfo
> xPropSetInfo
= xPropSet
->getPropertySetInfo();
2304 OUString aName
= UNO_NAME_MISC_OBJ_INTEROPGRABBAG
;
2305 if (!xPropSetInfo
->hasPropertyByName(aName
))
2308 uno::Sequence
<beans::PropertyValue
> propList
;
2309 xPropSet
->getPropertyValue(aName
) >>= propList
;
2310 for (sal_Int32 nProp
= 0; nProp
< propList
.getLength(); ++nProp
)
2312 // if we find any of the diagram components, it's a diagram
2313 OUString propName
= propList
[nProp
].Name
;
2314 if (propName
== "OOXData" || propName
== "OOXLayout" || propName
== "OOXStyle"
2315 || propName
== "OOXColor" || propName
== "OOXDrawing")
2321 sal_Int32
DrawingML::getBulletMarginIndentation (const Reference
< XPropertySet
>& rXPropSet
,sal_Int16 nLevel
, const OUString
& propName
)
2323 if (nLevel
< 0 || !GetProperty(rXPropSet
, "NumberingRules"))
2326 Reference
< XIndexAccess
> rXIndexAccess
;
2328 if (!(mAny
>>= rXIndexAccess
) || nLevel
>= rXIndexAccess
->getCount())
2331 SAL_INFO("oox.shape", "numbering rules");
2333 Sequence
<PropertyValue
> aPropertySequence
;
2334 rXIndexAccess
->getByIndex(nLevel
) >>= aPropertySequence
;
2336 if (!aPropertySequence
.hasElements())
2339 sal_Int32 nPropertyCount
= aPropertySequence
.getLength();
2341 const PropertyValue
* pPropValue
= aPropertySequence
.getArray();
2343 for ( sal_Int32 i
= 0; i
< nPropertyCount
; i
++ )
2345 OUString
aPropName( pPropValue
[ i
].Name
);
2346 SAL_INFO("oox.shape", "pro name: " << aPropName
);
2347 if ( aPropName
== propName
)
2348 return *o3tl::doAccess
<sal_Int32
>(pPropValue
[i
].Value
);
2354 const char* DrawingML::GetAlignment( style::ParagraphAdjust nAlignment
)
2356 const char* sAlignment
= nullptr;
2358 switch( nAlignment
)
2360 case style::ParagraphAdjust_CENTER
:
2363 case style::ParagraphAdjust_RIGHT
:
2366 case style::ParagraphAdjust_BLOCK
:
2367 sAlignment
= "just";
2376 void DrawingML::WriteLinespacing( const LineSpacing
& rSpacing
)
2378 if( rSpacing
.Mode
== LineSpacingMode::PROP
)
2380 mpFS
->singleElementNS( XML_a
, XML_spcPct
,
2381 XML_val
, OString::number(static_cast<sal_Int32
>(rSpacing
.Height
)*1000));
2385 mpFS
->singleElementNS( XML_a
, XML_spcPts
,
2386 XML_val
, OString::number(std::lround(rSpacing
.Height
/ 25.4 * 72)));
2390 void DrawingML::WriteParagraphProperties( const Reference
< XTextContent
>& rParagraph
, float fFirstCharHeight
)
2392 Reference
< XPropertySet
> rXPropSet( rParagraph
, UNO_QUERY
);
2393 Reference
< XPropertyState
> rXPropState( rParagraph
, UNO_QUERY
);
2394 PropertyState eState
;
2396 if( !rXPropSet
.is() || !rXPropState
.is() )
2399 sal_Int16 nLevel
= -1;
2400 if (GetProperty(rXPropSet
, "NumberingLevel"))
2403 sal_Int16 nTmp
= sal_Int16(style::ParagraphAdjust_LEFT
);
2404 if (GetProperty(rXPropSet
, "ParaAdjust"))
2406 style::ParagraphAdjust nAlignment
= static_cast<style::ParagraphAdjust
>(nTmp
);
2408 bool bHasLinespacing
= false;
2409 LineSpacing aLineSpacing
;
2410 if (GetPropertyAndState(rXPropSet
, rXPropState
, "ParaLineSpacing", eState
)
2411 && eState
== beans::PropertyState_DIRECT_VALUE
)
2412 bHasLinespacing
= ( mAny
>>= aLineSpacing
);
2415 if (GetProperty(rXPropSet
, "WritingMode"))
2417 sal_Int16 nWritingMode
;
2418 if( ( mAny
>>= nWritingMode
) && nWritingMode
== text::WritingMode2::RL_TB
)
2424 sal_Int32 nParaLeftMargin
= 0;
2425 sal_Int32 nParaFirstLineIndent
= 0;
2427 if (GetProperty(rXPropSet
, "ParaLeftMargin"))
2428 mAny
>>= nParaLeftMargin
;
2429 if (GetProperty(rXPropSet
, "ParaFirstLineIndent"))
2430 mAny
>>= nParaFirstLineIndent
;
2432 sal_Int32 nParaTopMargin
= 0;
2433 sal_Int32 nParaBottomMargin
= 0;
2435 if (GetProperty(rXPropSet
, "ParaTopMargin"))
2436 mAny
>>= nParaTopMargin
;
2437 if (GetProperty(rXPropSet
, "ParaBottomMargin"))
2438 mAny
>>= nParaBottomMargin
;
2440 sal_Int32 nLeftMargin
= getBulletMarginIndentation ( rXPropSet
, nLevel
,"LeftMargin");
2441 sal_Int32 nLineIndentation
= getBulletMarginIndentation ( rXPropSet
, nLevel
,"FirstLineOffset");
2444 || nAlignment
!= style::ParagraphAdjust_LEFT
2445 || bHasLinespacing
)
2447 if (nParaLeftMargin
) // For Paragraph
2448 mpFS
->startElementNS( XML_a
, XML_pPr
,
2449 XML_lvl
, nLevel
> 0 ? OString::number(nLevel
).getStr() : nullptr,
2450 XML_marL
, nParaLeftMargin
> 0 ? OString::number(oox::drawingml::convertHmmToEmu(nParaLeftMargin
)).getStr() : nullptr,
2451 XML_indent
, nParaFirstLineIndent
? OString::number(oox::drawingml::convertHmmToEmu(nParaFirstLineIndent
)).getStr() : nullptr,
2452 XML_algn
, GetAlignment( nAlignment
),
2453 XML_rtl
, bRtl
? ToPsz10(bRtl
) : nullptr );
2455 mpFS
->startElementNS( XML_a
, XML_pPr
,
2456 XML_lvl
, nLevel
> 0 ? OString::number(nLevel
).getStr() : nullptr,
2457 XML_marL
, nLeftMargin
> 0 ? OString::number(oox::drawingml::convertHmmToEmu(nLeftMargin
)).getStr() : nullptr,
2458 XML_indent
, nLineIndentation
? OString::number(oox::drawingml::convertHmmToEmu(nLineIndentation
)).getStr() : nullptr,
2459 XML_algn
, GetAlignment( nAlignment
),
2460 XML_rtl
, bRtl
? ToPsz10(bRtl
) : nullptr );
2463 if( bHasLinespacing
)
2465 mpFS
->startElementNS(XML_a
, XML_lnSpc
);
2466 WriteLinespacing( aLineSpacing
);
2467 mpFS
->endElementNS( XML_a
, XML_lnSpc
);
2470 if( nParaTopMargin
!= 0 )
2472 mpFS
->startElementNS(XML_a
, XML_spcBef
);
2474 mpFS
->singleElementNS( XML_a
, XML_spcPts
,
2475 XML_val
, OString::number(std::lround(nParaTopMargin
/ 25.4 * 72)));
2477 mpFS
->endElementNS( XML_a
, XML_spcBef
);
2480 if( nParaBottomMargin
!= 0 )
2482 mpFS
->startElementNS(XML_a
, XML_spcAft
);
2484 mpFS
->singleElementNS( XML_a
, XML_spcPts
,
2485 XML_val
, OString::number(std::lround(nParaBottomMargin
/ 25.4 * 72)));
2487 mpFS
->endElementNS( XML_a
, XML_spcAft
);
2490 WriteParagraphNumbering( rXPropSet
, fFirstCharHeight
, nLevel
);
2492 mpFS
->endElementNS( XML_a
, XML_pPr
);
2496 void DrawingML::WriteParagraph( const Reference
< XTextContent
>& rParagraph
,
2497 bool& rbOverridingCharHeight
, sal_Int32
& rnCharHeight
)
2499 Reference
< XEnumerationAccess
> access( rParagraph
, UNO_QUERY
);
2503 Reference
< XEnumeration
> enumeration( access
->createEnumeration() );
2504 if( !enumeration
.is() )
2507 mpFS
->startElementNS(XML_a
, XML_p
);
2509 bool bPropertiesWritten
= false;
2510 while( enumeration
->hasMoreElements() )
2512 Reference
< XTextRange
> run
;
2513 Any
any ( enumeration
->nextElement() );
2517 if( !bPropertiesWritten
)
2519 float fFirstCharHeight
= rnCharHeight
/ 1000.;
2520 Reference
< XPropertySet
> xFirstRunPropSet (run
, UNO_QUERY
);
2521 Reference
< XPropertySetInfo
> xFirstRunPropSetInfo
= xFirstRunPropSet
->getPropertySetInfo();
2522 if( xFirstRunPropSetInfo
->hasPropertyByName("CharHeight") )
2523 fFirstCharHeight
= xFirstRunPropSet
->getPropertyValue("CharHeight").get
<float>();
2524 WriteParagraphProperties( rParagraph
, fFirstCharHeight
);
2525 bPropertiesWritten
= true;
2527 WriteRun( run
, rbOverridingCharHeight
, rnCharHeight
);
2530 Reference
< XPropertySet
> rXPropSet( rParagraph
, UNO_QUERY
);
2531 WriteRunProperties( rXPropSet
, false, XML_endParaRPr
, false, rbOverridingCharHeight
, rnCharHeight
);
2533 mpFS
->endElementNS( XML_a
, XML_p
);
2536 void DrawingML::WriteText( const Reference
< XInterface
>& rXIface
, const OUString
& presetWarp
, bool bBodyPr
, bool bText
, sal_Int32 nXmlNamespace
)
2538 Reference
< XText
> xXText( rXIface
, UNO_QUERY
);
2539 Reference
< XPropertySet
> rXPropSet( rXIface
, UNO_QUERY
);
2544 sal_Int32 nTextRotateAngle
= 0;
2546 #define DEFLRINS 254
2547 #define DEFTBINS 127
2548 sal_Int32 nLeft
, nRight
, nTop
, nBottom
;
2549 nLeft
= nRight
= DEFLRINS
;
2550 nTop
= nBottom
= DEFTBINS
;
2552 // top inset looks a bit different compared to ppt export
2553 // check if something related doesn't work as expected
2554 if (GetProperty(rXPropSet
, "TextLeftDistance"))
2556 if (GetProperty(rXPropSet
, "TextRightDistance"))
2558 if (GetProperty(rXPropSet
, "TextUpperDistance"))
2560 if (GetProperty(rXPropSet
, "TextLowerDistance"))
2563 TextVerticalAdjust
eVerticalAlignment( TextVerticalAdjust_TOP
);
2564 const char* sVerticalAlignment
= nullptr;
2565 if (GetProperty(rXPropSet
, "TextVerticalAdjust"))
2566 mAny
>>= eVerticalAlignment
;
2567 if( eVerticalAlignment
!= TextVerticalAdjust_TOP
)
2568 sVerticalAlignment
= GetTextVerticalAdjust(eVerticalAlignment
);
2570 const char* sWritingMode
= nullptr;
2571 bool bVertical
= false;
2572 if (GetProperty(rXPropSet
, "TextWritingMode"))
2576 if( ( mAny
>>= eMode
) && eMode
== WritingMode_TB_RL
)
2578 sWritingMode
= "vert";
2583 if (GetProperty(rXPropSet
, "CustomShapeGeometry"))
2585 Sequence
< PropertyValue
> aProps
;
2586 if ( mAny
>>= aProps
)
2588 for ( sal_Int32 i
= 0, nElems
= aProps
.getLength(); i
< nElems
; ++i
)
2590 if ( aProps
[ i
].Name
== "TextPreRotateAngle" && ( aProps
[ i
].Value
>>= nTextRotateAngle
) )
2592 if ( nTextRotateAngle
== -90 )
2594 sWritingMode
= "vert";
2597 else if ( nTextRotateAngle
== -270 )
2599 sWritingMode
= "vert270";
2608 TextHorizontalAdjust
eHorizontalAlignment( TextHorizontalAdjust_CENTER
);
2609 bool bHorizontalCenter
= false;
2610 if (GetProperty(rXPropSet
, "TextHorizontalAdjust"))
2611 mAny
>>= eHorizontalAlignment
;
2612 if( eHorizontalAlignment
== TextHorizontalAdjust_CENTER
)
2613 bHorizontalCenter
= true;
2614 else if( bVertical
&& eHorizontalAlignment
== TextHorizontalAdjust_LEFT
)
2615 sVerticalAlignment
= "b";
2617 bool bHasWrap
= false;
2619 // Only custom shapes obey the TextWordWrap option, normal text always wraps.
2620 if (dynamic_cast<SvxCustomShape
*>(rXIface
.get()) && GetProperty(rXPropSet
, "TextWordWrap"))
2628 const char* pWrap
= bHasWrap
&& !bWrap
? "none" : nullptr;
2629 if (GetDocumentType() == DOCUMENT_DOCX
)
2631 // In case of DOCX, if we want to have the same effect as
2632 // TextShape's automatic word wrapping, then we need to set
2633 // wrapping to square.
2634 uno::Reference
<lang::XServiceInfo
> xServiceInfo(rXIface
, uno::UNO_QUERY
);
2635 if (xServiceInfo
.is() && xServiceInfo
->supportsService("com.sun.star.drawing.TextShape"))
2638 mpFS
->startElementNS( (nXmlNamespace
? nXmlNamespace
: XML_a
), XML_bodyPr
,
2640 XML_lIns
, (nLeft
!= DEFLRINS
) ? OString::number(oox::drawingml::convertHmmToEmu(nLeft
)).getStr() : nullptr,
2641 XML_rIns
, (nRight
!= DEFLRINS
) ? OString::number(oox::drawingml::convertHmmToEmu(nRight
)).getStr() : nullptr,
2642 XML_tIns
, (nTop
!= DEFTBINS
) ? OString::number(oox::drawingml::convertHmmToEmu(nTop
)).getStr() : nullptr,
2643 XML_bIns
, (nBottom
!= DEFTBINS
) ? OString::number(oox::drawingml::convertHmmToEmu(nBottom
)).getStr() : nullptr,
2644 XML_anchor
, sVerticalAlignment
,
2645 XML_anchorCtr
, bHorizontalCenter
? "1" : nullptr,
2646 XML_vert
, sWritingMode
,
2647 XML_rot
, (nTextRotateAngle
!= 0) ? oox::drawingml::calcRotationValue( nTextRotateAngle
* 100 ).getStr() : nullptr );
2648 if( !presetWarp
.isEmpty())
2650 mpFS
->singleElementNS(XML_a
, XML_prstTxWarp
, XML_prst
, presetWarp
.toUtf8());
2652 if (GetDocumentType() == DOCUMENT_DOCX
|| GetDocumentType() == DOCUMENT_XLSX
)
2654 bool bTextAutoGrowHeight
= false;
2655 if (GetProperty(rXPropSet
, "TextAutoGrowHeight"))
2656 mAny
>>= bTextAutoGrowHeight
;
2657 mpFS
->singleElementNS(XML_a
, (bTextAutoGrowHeight
? XML_spAutoFit
: XML_noAutofit
));
2659 if (GetDocumentType() == DOCUMENT_PPTX
)
2661 TextFitToSizeType eFit
= TextFitToSizeType_NONE
;
2662 if (GetProperty(rXPropSet
, "TextFitToSize"))
2665 if (eFit
== TextFitToSizeType_AUTOFIT
)
2667 const sal_Int32 MAX_SCALE_VAL
= 100000;
2668 sal_Int32 nFontScale
= MAX_SCALE_VAL
;
2669 SvxShapeText
* pTextShape
= dynamic_cast<SvxShapeText
*>(rXIface
.get());
2672 SdrTextObj
* pTextObject
= dynamic_cast<SdrTextObj
*>(pTextShape
->GetSdrObject());
2675 double fScaleY
= pTextObject
->GetFontScaleY();
2676 nFontScale
= static_cast<sal_uInt32
>(fScaleY
* 100) * 1000;
2680 mpFS
->singleElementNS(XML_a
, XML_normAutofit
, XML_fontScale
,
2681 ( nFontScale
< MAX_SCALE_VAL
&& nFontScale
> 0 ) ? OString::number(nFontScale
).getStr() : nullptr);
2685 bool bTextAutoGrowHeight
= false;
2686 if (GetProperty(rXPropSet
, "TextAutoGrowHeight"))
2687 mAny
>>= bTextAutoGrowHeight
;
2688 mpFS
->singleElementNS(XML_a
, (bTextAutoGrowHeight
? XML_spAutoFit
: XML_noAutofit
));
2691 mpFS
->endElementNS((nXmlNamespace
? nXmlNamespace
: XML_a
), XML_bodyPr
);
2694 Reference
< XEnumerationAccess
> access( xXText
, UNO_QUERY
);
2695 if( !access
.is() || !bText
)
2698 Reference
< XEnumeration
> enumeration( access
->createEnumeration() );
2699 if( !enumeration
.is() )
2702 uno::Reference
<drawing::XShape
> xShape(rXIface
, uno::UNO_QUERY
);
2703 SdrObject
* pSdrObject
= xShape
.is() ? GetSdrObjectFromXShape(xShape
) : nullptr;
2704 const SdrTextObj
* pTxtObj
= dynamic_cast<SdrTextObj
*>( pSdrObject
);
2705 if (pTxtObj
&& mpTextExport
)
2707 const OutlinerParaObject
* pParaObj
= nullptr;
2708 bool bOwnParaObj
= false;
2712 When the object is actively being edited, that text is not set into
2713 the objects normal text object, but lives in a separate object.
2715 if (pTxtObj
->IsTextEditActive())
2717 pParaObj
= pTxtObj
->GetEditOutlinerParaObject().release();
2721 pParaObj
= pTxtObj
->GetOutlinerParaObject();
2725 // this is reached only in case some text is attached to the shape
2726 mpTextExport
->WriteOutliner(*pParaObj
);
2733 bool bOverridingCharHeight
= false;
2734 sal_Int32 nCharHeight
= -1;
2736 while( enumeration
->hasMoreElements() )
2738 Reference
< XTextContent
> paragraph
;
2739 Any
any ( enumeration
->nextElement() );
2741 if( any
>>= paragraph
)
2742 WriteParagraph( paragraph
, bOverridingCharHeight
, nCharHeight
);
2746 void DrawingML::WritePresetShape( const char* pShape
, std::vector
< std::pair
<sal_Int32
,sal_Int32
>> & rAvList
)
2748 mpFS
->startElementNS(XML_a
, XML_prstGeom
, XML_prst
, pShape
);
2749 if ( !rAvList
.empty() )
2752 mpFS
->startElementNS(XML_a
, XML_avLst
);
2753 for (auto const& elem
: rAvList
)
2755 OString sName
= OString("adj") + ( ( elem
.first
> 0 ) ? OString::number(elem
.first
) : OString() );
2756 OString sFmla
= OString("val ") + OString::number( elem
.second
);
2758 mpFS
->singleElementNS(XML_a
, XML_gd
, XML_name
, sName
, XML_fmla
, sFmla
);
2760 mpFS
->endElementNS( XML_a
, XML_avLst
);
2763 mpFS
->singleElementNS(XML_a
, XML_avLst
);
2765 mpFS
->endElementNS( XML_a
, XML_prstGeom
);
2768 void DrawingML::WritePresetShape( const char* pShape
)
2770 mpFS
->startElementNS(XML_a
, XML_prstGeom
, XML_prst
, pShape
);
2771 mpFS
->singleElementNS(XML_a
, XML_avLst
);
2772 mpFS
->endElementNS( XML_a
, XML_prstGeom
);
2775 static std::map
< OString
, std::vector
<OString
> > lcl_getAdjNames()
2777 std::map
< OString
, std::vector
<OString
> > aRet
;
2779 OUString
aPath("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER
"/filter/oox-drawingml-adj-names");
2780 rtl::Bootstrap::expandMacros(aPath
);
2781 SvFileStream
aStream(aPath
, StreamMode::READ
);
2782 if (aStream
.GetError() != ERRCODE_NONE
)
2783 SAL_WARN("oox.shape", "failed to open oox-drawingml-adj-names");
2785 bool bNotDone
= aStream
.ReadLine(aLine
);
2788 sal_Int32 nIndex
= 0;
2789 // Each line is in a "key\tvalue" format: read the key, the rest is the value.
2790 OString aKey
= aLine
.getToken(0, '\t', nIndex
);
2791 OString aValue
= aLine
.copy(nIndex
);
2792 aRet
[aKey
].push_back(aValue
);
2793 bNotDone
= aStream
.ReadLine(aLine
);
2798 void DrawingML::WritePresetShape( const char* pShape
, MSO_SPT eShapeType
, bool bPredefinedHandlesUsed
, const PropertyValue
& rProp
)
2800 static std::map
< OString
, std::vector
<OString
> > aAdjMap
= lcl_getAdjNames();
2801 // If there are predefined adj names for this shape type, look them up now.
2802 std::vector
<OString
> aAdjustments
;
2803 if (aAdjMap
.find(OString(pShape
)) != aAdjMap
.end())
2804 aAdjustments
= aAdjMap
[OString(pShape
)];
2806 mpFS
->startElementNS(XML_a
, XML_prstGeom
, XML_prst
, pShape
);
2807 mpFS
->startElementNS(XML_a
, XML_avLst
);
2809 Sequence
< drawing::EnhancedCustomShapeAdjustmentValue
> aAdjustmentSeq
;
2810 if ( ( rProp
.Value
>>= aAdjustmentSeq
)
2811 && eShapeType
!= mso_sptActionButtonForwardNext
// we have adjustments values for these type of shape, but MSO doesn't like them
2812 && eShapeType
!= mso_sptActionButtonBackPrevious
// so they are now disabled
2813 && OString(pShape
) != "rect" //some shape types are commented out in pCustomShapeTypeTranslationTable[] & are being defaulted to rect & rect does not have adjustment values/name.
2816 SAL_INFO("oox.shape", "adj seq len: " << aAdjustmentSeq
.getLength());
2817 sal_Int32 nAdjustmentsWhichNeedsToBeConverted
= 0;
2818 if ( bPredefinedHandlesUsed
)
2819 EscherPropertyContainer::LookForPolarHandles( eShapeType
, nAdjustmentsWhichNeedsToBeConverted
);
2821 sal_Int32 nValue
, nLength
= aAdjustmentSeq
.getLength();
2822 // 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.
2823 // Sometimes there are more values than needed, so we ignore the excessive ones.
2824 if (aAdjustments
.size() <= static_cast<sal_uInt32
>(nLength
))
2826 for (sal_Int32 i
= 0; i
< static_cast<sal_Int32
>(aAdjustments
.size()); i
++)
2828 if( EscherPropertyContainer::GetAdjustmentValue( aAdjustmentSeq
[ i
], i
, nAdjustmentsWhichNeedsToBeConverted
, nValue
) )
2830 // If the document model doesn't have an adjustment name (e.g. shape was created from VML), then take it from the predefined list.
2831 OString aAdjName
= aAdjustmentSeq
[i
].Name
.isEmpty()
2833 : aAdjustmentSeq
[i
].Name
.toUtf8();
2835 mpFS
->singleElementNS( XML_a
, XML_gd
,
2837 XML_fmla
, "val " + OString::number(nValue
));
2843 mpFS
->endElementNS( XML_a
, XML_avLst
);
2844 mpFS
->endElementNS( XML_a
, XML_prstGeom
);
2847 bool DrawingML::WriteCustomGeometry(
2848 const Reference
< XShape
>& rXShape
,
2849 const SdrObjCustomShape
& rSdrObjCustomShape
)
2851 uno::Reference
< beans::XPropertySet
> aXPropSet
;
2852 uno::Any
aAny( rXShape
->queryInterface(cppu::UnoType
<beans::XPropertySet
>::get()));
2854 if ( ! (aAny
>>= aXPropSet
) )
2859 aAny
= aXPropSet
->getPropertyValue( "CustomShapeGeometry" );
2860 if ( !aAny
.hasValue() )
2863 catch( const ::uno::Exception
& )
2869 auto pGeometrySeq
= o3tl::tryAccess
<uno::Sequence
<beans::PropertyValue
>>(aAny
);
2873 for( int i
= 0; i
< pGeometrySeq
->getLength(); ++i
)
2875 const beans::PropertyValue
& rProp
= (*pGeometrySeq
)[ i
];
2876 if ( rProp
.Name
== "Path" )
2878 uno::Sequence
<beans::PropertyValue
> aPathProp
;
2879 rProp
.Value
>>= aPathProp
;
2881 uno::Sequence
<drawing::EnhancedCustomShapeParameterPair
> aPairs
;
2882 uno::Sequence
<drawing::EnhancedCustomShapeSegment
> aSegments
;
2883 uno::Sequence
<awt::Size
> aPathSize
;
2884 for (int j
= 0; j
< aPathProp
.getLength(); ++j
)
2886 const beans::PropertyValue
& rPathProp
= aPathProp
[j
];
2887 if (rPathProp
.Name
== "Coordinates")
2888 rPathProp
.Value
>>= aPairs
;
2889 else if (rPathProp
.Name
== "Segments")
2890 rPathProp
.Value
>>= aSegments
;
2891 else if (rPathProp
.Name
== "SubViewSize")
2892 rPathProp
.Value
>>= aPathSize
;
2895 if ( !aPairs
.hasElements() )
2898 if ( !aSegments
.hasElements() )
2900 aSegments
= uno::Sequence
<drawing::EnhancedCustomShapeSegment
>(4);
2901 aSegments
[0].Count
= 1;
2902 aSegments
[0].Command
= drawing::EnhancedCustomShapeSegmentCommand::MOVETO
;
2903 aSegments
[1].Count
= static_cast<sal_Int16
>(std::min( aPairs
.getLength() - 1, sal_Int32(32767) ));
2904 aSegments
[1].Command
= drawing::EnhancedCustomShapeSegmentCommand::LINETO
;
2905 aSegments
[2].Count
= 0;
2906 aSegments
[2].Command
= drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH
;
2907 aSegments
[3].Count
= 0;
2908 aSegments
[3].Command
= drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH
;
2911 int nExpectedPairCount
= 0;
2912 for( int j
= 0; j
< aSegments
.getLength(); ++j
)
2914 nExpectedPairCount
+= aSegments
[j
].Count
;
2917 if ( nExpectedPairCount
> aPairs
.getLength() )
2919 SAL_WARN("oox.shape", "Segments need " << nExpectedPairCount
<< " coordinates, but Coordinates have only " << aPairs
.getLength() << " pairs.");
2923 mpFS
->startElementNS(XML_a
, XML_custGeom
);
2924 mpFS
->singleElementNS(XML_a
, XML_avLst
);
2925 mpFS
->singleElementNS(XML_a
, XML_gdLst
);
2926 mpFS
->singleElementNS(XML_a
, XML_ahLst
);
2927 mpFS
->singleElementNS(XML_a
, XML_rect
, XML_l
, "l", XML_t
, "t",
2928 XML_r
, "r", XML_b
, "b");
2929 mpFS
->startElementNS(XML_a
, XML_pathLst
);
2931 if ( aPathSize
.hasElements() )
2933 mpFS
->startElementNS( XML_a
, XML_path
,
2934 XML_w
, OString::number(aPathSize
[0].Width
),
2935 XML_h
, OString::number(aPathSize
[0].Height
) );
2940 aPairs
[0].First
.Value
>>= nXMin
;
2941 sal_Int32 nXMax
= nXMin
;
2943 aPairs
[0].Second
.Value
>>= nYMin
;
2944 sal_Int32 nYMax
= nYMin
;
2946 for ( int j
= 0; j
< aPairs
.getLength(); ++j
)
2948 sal_Int32 nX
= GetCustomGeometryPointValue(aPairs
[j
].First
, rSdrObjCustomShape
);
2949 sal_Int32 nY
= GetCustomGeometryPointValue(aPairs
[j
].Second
, rSdrObjCustomShape
);
2959 mpFS
->startElementNS( XML_a
, XML_path
,
2960 XML_w
, OString::number(nXMax
- nXMin
),
2961 XML_h
, OString::number(nYMax
- nYMin
) );
2967 for (int j
= 0; j
< aSegments
.getLength() && bOK
; ++j
)
2969 if ( aSegments
[ j
].Command
== drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH
)
2971 mpFS
->singleElementNS(XML_a
, XML_close
);
2973 for (int k
= 0; k
< aSegments
[j
].Count
&& bOK
; ++k
)
2975 switch( aSegments
[ j
].Command
)
2977 case drawing::EnhancedCustomShapeSegmentCommand::MOVETO
:
2979 if (nPairIndex
>= aPairs
.getLength())
2983 mpFS
->startElementNS(XML_a
, XML_moveTo
);
2984 WriteCustomGeometryPoint(aPairs
[nPairIndex
], rSdrObjCustomShape
);
2985 mpFS
->endElementNS( XML_a
, XML_moveTo
);
2990 case drawing::EnhancedCustomShapeSegmentCommand::LINETO
:
2992 if (nPairIndex
>= aPairs
.getLength())
2996 mpFS
->startElementNS(XML_a
, XML_lnTo
);
2997 WriteCustomGeometryPoint(aPairs
[nPairIndex
], rSdrObjCustomShape
);
2998 mpFS
->endElementNS( XML_a
, XML_lnTo
);
3003 case drawing::EnhancedCustomShapeSegmentCommand::CURVETO
:
3005 if (nPairIndex
+ 2 >= aPairs
.getLength())
3009 mpFS
->startElementNS(XML_a
, XML_cubicBezTo
);
3010 for( sal_uInt8 l
= 0; l
<= 2; ++l
)
3012 WriteCustomGeometryPoint(aPairs
[nPairIndex
+l
], rSdrObjCustomShape
);
3014 mpFS
->endElementNS( XML_a
, XML_cubicBezTo
);
3019 case drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO
:
3020 case drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE
:
3025 case drawing::EnhancedCustomShapeSegmentCommand::ARCTO
:
3026 case drawing::EnhancedCustomShapeSegmentCommand::ARC
:
3027 case drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO
:
3028 case drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC
:
3033 case drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX
:
3034 case drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY
:
3039 case drawing::EnhancedCustomShapeSegmentCommand::QUADRATICCURVETO
:
3041 if (nPairIndex
+ 1 >= aPairs
.getLength())
3045 mpFS
->startElementNS(XML_a
, XML_quadBezTo
);
3046 for( sal_uInt8 l
= 0; l
< 2; ++l
)
3048 WriteCustomGeometryPoint(aPairs
[nPairIndex
+l
], rSdrObjCustomShape
);
3050 mpFS
->endElementNS( XML_a
, XML_quadBezTo
);
3055 case drawing::EnhancedCustomShapeSegmentCommand::ARCANGLETO
:
3066 mpFS
->endElementNS( XML_a
, XML_path
);
3067 mpFS
->endElementNS( XML_a
, XML_pathLst
);
3068 mpFS
->endElementNS( XML_a
, XML_custGeom
);
3076 void DrawingML::WriteCustomGeometryPoint(
3077 const drawing::EnhancedCustomShapeParameterPair
& rParamPair
,
3078 const SdrObjCustomShape
& rSdrObjCustomShape
)
3080 sal_Int32 nX
= GetCustomGeometryPointValue(rParamPair
.First
, rSdrObjCustomShape
);
3081 sal_Int32 nY
= GetCustomGeometryPointValue(rParamPair
.Second
, rSdrObjCustomShape
);
3083 mpFS
->singleElementNS(XML_a
, XML_pt
, XML_x
, OString::number(nX
), XML_y
, OString::number(nY
));
3086 sal_Int32
DrawingML::GetCustomGeometryPointValue(
3087 const css::drawing::EnhancedCustomShapeParameter
& rParam
,
3088 const SdrObjCustomShape
& rSdrObjCustomShape
)
3090 const EnhancedCustomShape2d
aCustoShape2d(const_cast< SdrObjCustomShape
& >(rSdrObjCustomShape
));
3091 double fValue
= 0.0;
3092 aCustoShape2d
.GetParameter(fValue
, rParam
, false, false);
3093 sal_Int32
nValue(std::lround(fValue
));
3098 void DrawingML::WritePolyPolygon( const tools::PolyPolygon
& rPolyPolygon
)
3100 // In case of Writer, the parent element is <wps:spPr>, and there the
3101 // <a:custGeom> element is not optional.
3102 if (rPolyPolygon
.Count() < 1 && GetDocumentType() != DOCUMENT_DOCX
)
3105 mpFS
->startElementNS(XML_a
, XML_custGeom
);
3106 mpFS
->singleElementNS(XML_a
, XML_avLst
);
3107 mpFS
->singleElementNS(XML_a
, XML_gdLst
);
3108 mpFS
->singleElementNS(XML_a
, XML_ahLst
);
3109 mpFS
->singleElementNS(XML_a
, XML_rect
, XML_l
, "0", XML_t
, "0", XML_r
, "r", XML_b
, "b");
3111 mpFS
->startElementNS( XML_a
, XML_pathLst
);
3113 const tools::Rectangle
aRect( rPolyPolygon
.GetBoundRect() );
3115 // Put all polygons of rPolyPolygon in the same path element
3116 // to subtract the overlapped areas.
3117 mpFS
->startElementNS( XML_a
, XML_path
,
3118 XML_w
, OString::number(aRect
.GetWidth()),
3119 XML_h
, OString::number(aRect
.GetHeight()) );
3121 for( sal_uInt16 i
= 0; i
< rPolyPolygon
.Count(); i
++ )
3124 const tools::Polygon
& rPoly
= rPolyPolygon
[ i
];
3126 if( rPoly
.GetSize() > 0 )
3128 mpFS
->startElementNS(XML_a
, XML_moveTo
);
3130 mpFS
->singleElementNS( XML_a
, XML_pt
,
3131 XML_x
, OString::number(rPoly
[0].X() - aRect
.Left()),
3132 XML_y
, OString::number(rPoly
[0].Y() - aRect
.Top()) );
3134 mpFS
->endElementNS( XML_a
, XML_moveTo
);
3137 for( sal_uInt16 j
= 1; j
< rPoly
.GetSize(); j
++ )
3139 PolyFlags flags
= rPoly
.GetFlags(j
);
3140 if( flags
== PolyFlags::Control
)
3142 // a:cubicBezTo can only contain 3 a:pt elements, so we need to make sure of this
3143 if( j
+2 < rPoly
.GetSize() && rPoly
.GetFlags(j
+1) == PolyFlags::Control
&& rPoly
.GetFlags(j
+2) != PolyFlags::Control
)
3146 mpFS
->startElementNS(XML_a
, XML_cubicBezTo
);
3147 for( sal_uInt8 k
= 0; k
<= 2; ++k
)
3149 mpFS
->singleElementNS(XML_a
, XML_pt
,
3150 XML_x
, OString::number(rPoly
[j
+k
].X() - aRect
.Left()),
3151 XML_y
, OString::number(rPoly
[j
+k
].Y() - aRect
.Top()));
3154 mpFS
->endElementNS( XML_a
, XML_cubicBezTo
);
3158 else if( flags
== PolyFlags::Normal
)
3160 mpFS
->startElementNS(XML_a
, XML_lnTo
);
3161 mpFS
->singleElementNS( XML_a
, XML_pt
,
3162 XML_x
, OString::number(rPoly
[j
].X() - aRect
.Left()),
3163 XML_y
, OString::number(rPoly
[j
].Y() - aRect
.Top()) );
3164 mpFS
->endElementNS( XML_a
, XML_lnTo
);
3168 mpFS
->endElementNS( XML_a
, XML_path
);
3170 mpFS
->endElementNS( XML_a
, XML_pathLst
);
3172 mpFS
->endElementNS( XML_a
, XML_custGeom
);
3175 void DrawingML::WriteConnectorConnections( EscherConnectorListEntry
& rConnectorEntry
, sal_Int32 nStartID
, sal_Int32 nEndID
)
3177 if( nStartID
!= -1 )
3179 mpFS
->singleElementNS( XML_a
, XML_stCxn
,
3180 XML_id
, OString::number(nStartID
),
3181 XML_idx
, OString::number(rConnectorEntry
.GetConnectorRule(true)) );
3185 mpFS
->singleElementNS( XML_a
, XML_endCxn
,
3186 XML_id
, OString::number(nEndID
),
3187 XML_idx
, OString::number(rConnectorEntry
.GetConnectorRule(false)) );
3191 sal_Unicode
DrawingML::SubstituteBullet( sal_Unicode cBulletId
, css::awt::FontDescriptor
& rFontDesc
)
3193 if ( IsStarSymbol(rFontDesc
.Name
) )
3195 rtl_TextEncoding eCharSet
= rFontDesc
.CharSet
;
3196 cBulletId
= msfilter::util::bestFitOpenSymbolToMSFont(cBulletId
, eCharSet
, rFontDesc
.Name
);
3197 rFontDesc
.CharSet
= eCharSet
;
3203 sax_fastparser::FSHelperPtr
DrawingML::CreateOutputStream (
3204 const OUString
& sFullStream
,
3205 const OUString
& sRelativeStream
,
3206 const Reference
< XOutputStream
>& xParentRelation
,
3207 const char* sContentType
,
3208 const char* sRelationshipType
,
3209 OUString
* pRelationshipId
)
3211 OUString sRelationshipId
;
3212 if (xParentRelation
.is())
3213 sRelationshipId
= GetFB()->addRelation( xParentRelation
, OUString::createFromAscii( sRelationshipType
), sRelativeStream
);
3215 sRelationshipId
= GetFB()->addRelation( OUString::createFromAscii( sRelationshipType
), sRelativeStream
);
3217 if( pRelationshipId
)
3218 *pRelationshipId
= sRelationshipId
;
3220 sax_fastparser::FSHelperPtr p
= GetFB()->openFragmentStreamWithSerializer( sFullStream
, OUString::createFromAscii( sContentType
) );
3225 void DrawingML::WriteFill( const Reference
< XPropertySet
>& xPropSet
)
3227 if ( !GetProperty( xPropSet
, "FillStyle" ) )
3229 FillStyle
aFillStyle( FillStyle_NONE
);
3230 xPropSet
->getPropertyValue( "FillStyle" ) >>= aFillStyle
;
3232 if ( aFillStyle
== FillStyle_SOLID
&& GetProperty( xPropSet
, "FillTransparence" ) )
3234 // map full transparent background to no fill
3236 xPropSet
->getPropertyValue( "FillTransparence" ) >>= nVal
;
3238 aFillStyle
= FillStyle_NONE
;
3241 switch( aFillStyle
)
3243 case FillStyle_SOLID
:
3244 WriteSolidFill( xPropSet
);
3246 case FillStyle_GRADIENT
:
3247 WriteGradientFill( xPropSet
);
3249 case FillStyle_BITMAP
:
3250 WriteBlipFill( xPropSet
, "FillBitmap" );
3252 case FillStyle_HATCH
:
3253 WritePattFill( xPropSet
);
3255 case FillStyle_NONE
:
3256 mpFS
->singleElementNS(XML_a
, XML_noFill
);
3263 void DrawingML::WriteStyleProperties( sal_Int32 nTokenId
, const Sequence
< PropertyValue
>& aProperties
)
3265 if( aProperties
.hasElements() )
3267 OUString sSchemeClr
;
3268 sal_uInt32 nIdx
= 0;
3269 Sequence
< PropertyValue
> aTransformations
;
3270 for( sal_Int32 i
=0; i
< aProperties
.getLength(); ++i
)
3272 if( aProperties
[i
].Name
== "SchemeClr" )
3273 aProperties
[i
].Value
>>= sSchemeClr
;
3274 else if( aProperties
[i
].Name
== "Idx" )
3275 aProperties
[i
].Value
>>= nIdx
;
3276 else if( aProperties
[i
].Name
== "Transformations" )
3277 aProperties
[i
].Value
>>= aTransformations
;
3279 mpFS
->startElementNS(XML_a
, nTokenId
, XML_idx
, OString::number(nIdx
));
3280 WriteColor(sSchemeClr
, aTransformations
);
3281 mpFS
->endElementNS( XML_a
, nTokenId
);
3285 // write mock <a:*Ref> tag
3286 mpFS
->singleElementNS(XML_a
, nTokenId
, XML_idx
, OString::number(0));
3290 void DrawingML::WriteShapeStyle( const Reference
< XPropertySet
>& xPropSet
)
3292 // check existence of the grab bag
3293 if ( !GetProperty( xPropSet
, "InteropGrabBag" ) )
3296 // extract the relevant properties from the grab bag
3297 Sequence
< PropertyValue
> aGrabBag
;
3298 Sequence
< PropertyValue
> aFillRefProperties
, aLnRefProperties
, aEffectRefProperties
;
3300 for( sal_Int32 i
=0; i
< aGrabBag
.getLength(); ++i
)
3302 if( aGrabBag
[i
].Name
== "StyleFillRef" )
3303 aGrabBag
[i
].Value
>>= aFillRefProperties
;
3304 else if( aGrabBag
[i
].Name
== "StyleLnRef" )
3305 aGrabBag
[i
].Value
>>= aLnRefProperties
;
3306 else if( aGrabBag
[i
].Name
== "StyleEffectRef" )
3307 aGrabBag
[i
].Value
>>= aEffectRefProperties
;
3310 WriteStyleProperties( XML_lnRef
, aLnRefProperties
);
3311 WriteStyleProperties( XML_fillRef
, aFillRefProperties
);
3312 WriteStyleProperties( XML_effectRef
, aEffectRefProperties
);
3314 // write mock <a:fontRef>
3315 mpFS
->singleElementNS(XML_a
, XML_fontRef
, XML_idx
, "minor");
3318 void DrawingML::WriteShapeEffect( const OUString
& sName
, const Sequence
< PropertyValue
>& aEffectProps
)
3320 if( !aEffectProps
.hasElements() )
3323 // assign the proper tag and enable bContainsColor if necessary
3324 sal_Int32 nEffectToken
= 0;
3325 bool bContainsColor
= false;
3326 if( sName
== "outerShdw" )
3328 nEffectToken
= FSNS( XML_a
, XML_outerShdw
);
3329 bContainsColor
= true;
3331 else if( sName
== "innerShdw" )
3333 nEffectToken
= FSNS( XML_a
, XML_innerShdw
);
3334 bContainsColor
= true;
3336 else if( sName
== "glow" )
3338 nEffectToken
= FSNS( XML_a
, XML_glow
);
3339 bContainsColor
= true;
3341 else if( sName
== "softEdge" )
3342 nEffectToken
= FSNS( XML_a
, XML_softEdge
);
3343 else if( sName
== "reflection" )
3344 nEffectToken
= FSNS( XML_a
, XML_reflection
);
3345 else if( sName
== "blur" )
3346 nEffectToken
= FSNS( XML_a
, XML_blur
);
3348 OUString sSchemeClr
;
3350 sal_Int32 nAlpha
= MAX_PERCENT
;
3351 Sequence
< PropertyValue
> aTransformations
;
3352 sax_fastparser::FastAttributeList
*aOuterShdwAttrList
= FastSerializerHelper::createAttrList();
3353 sax_fastparser::XFastAttributeListRef
xOuterShdwAttrList( aOuterShdwAttrList
);
3354 for( sal_Int32 i
=0; i
< aEffectProps
.getLength(); ++i
)
3356 if( aEffectProps
[i
].Name
== "Attribs" )
3358 // read tag attributes
3359 uno::Sequence
< beans::PropertyValue
> aOuterShdwProps
;
3360 aEffectProps
[i
].Value
>>= aOuterShdwProps
;
3361 for( sal_Int32 j
=0; j
< aOuterShdwProps
.getLength(); ++j
)
3363 if( aOuterShdwProps
[j
].Name
== "algn" )
3366 aOuterShdwProps
[j
].Value
>>= sVal
;
3367 aOuterShdwAttrList
->add( XML_algn
, OUStringToOString( sVal
, RTL_TEXTENCODING_UTF8
).getStr() );
3369 else if( aOuterShdwProps
[j
].Name
== "blurRad" )
3372 aOuterShdwProps
[j
].Value
>>= nVal
;
3373 aOuterShdwAttrList
->add( XML_blurRad
, OString::number( nVal
).getStr() );
3375 else if( aOuterShdwProps
[j
].Name
== "dir" )
3378 aOuterShdwProps
[j
].Value
>>= nVal
;
3379 aOuterShdwAttrList
->add( XML_dir
, OString::number( nVal
).getStr() );
3381 else if( aOuterShdwProps
[j
].Name
== "dist" )
3384 aOuterShdwProps
[j
].Value
>>= nVal
;
3385 aOuterShdwAttrList
->add( XML_dist
, OString::number( nVal
).getStr() );
3387 else if( aOuterShdwProps
[j
].Name
== "kx" )
3390 aOuterShdwProps
[j
].Value
>>= nVal
;
3391 aOuterShdwAttrList
->add( XML_kx
, OString::number( nVal
).getStr() );
3393 else if( aOuterShdwProps
[j
].Name
== "ky" )
3396 aOuterShdwProps
[j
].Value
>>= nVal
;
3397 aOuterShdwAttrList
->add( XML_ky
, OString::number( nVal
).getStr() );
3399 else if( aOuterShdwProps
[j
].Name
== "rotWithShape" )
3402 aOuterShdwProps
[j
].Value
>>= nVal
;
3403 aOuterShdwAttrList
->add( XML_rotWithShape
, OString::number( nVal
).getStr() );
3405 else if( aOuterShdwProps
[j
].Name
== "sx" )
3408 aOuterShdwProps
[j
].Value
>>= nVal
;
3409 aOuterShdwAttrList
->add( XML_sx
, OString::number( nVal
).getStr() );
3411 else if( aOuterShdwProps
[j
].Name
== "sy" )
3414 aOuterShdwProps
[j
].Value
>>= nVal
;
3415 aOuterShdwAttrList
->add( XML_sy
, OString::number( nVal
).getStr() );
3417 else if( aOuterShdwProps
[j
].Name
== "rad" )
3420 aOuterShdwProps
[j
].Value
>>= nVal
;
3421 aOuterShdwAttrList
->add( XML_rad
, OString::number( nVal
).getStr() );
3423 else if( aOuterShdwProps
[j
].Name
== "endA" )
3426 aOuterShdwProps
[j
].Value
>>= nVal
;
3427 aOuterShdwAttrList
->add( XML_endA
, OString::number( nVal
).getStr() );
3429 else if( aOuterShdwProps
[j
].Name
== "endPos" )
3432 aOuterShdwProps
[j
].Value
>>= nVal
;
3433 aOuterShdwAttrList
->add( XML_endPos
, OString::number( nVal
).getStr() );
3435 else if( aOuterShdwProps
[j
].Name
== "fadeDir" )
3438 aOuterShdwProps
[j
].Value
>>= nVal
;
3439 aOuterShdwAttrList
->add( XML_fadeDir
, OString::number( nVal
).getStr() );
3441 else if( aOuterShdwProps
[j
].Name
== "stA" )
3444 aOuterShdwProps
[j
].Value
>>= nVal
;
3445 aOuterShdwAttrList
->add( XML_stA
, OString::number( nVal
).getStr() );
3447 else if( aOuterShdwProps
[j
].Name
== "stPos" )
3450 aOuterShdwProps
[j
].Value
>>= nVal
;
3451 aOuterShdwAttrList
->add( XML_stPos
, OString::number( nVal
).getStr() );
3453 else if( aOuterShdwProps
[j
].Name
== "grow" )
3456 aOuterShdwProps
[j
].Value
>>= nVal
;
3457 aOuterShdwAttrList
->add( XML_grow
, OString::number( nVal
).getStr() );
3461 else if(aEffectProps
[i
].Name
== "RgbClr")
3463 aEffectProps
[i
].Value
>>= nRgbClr
;
3465 else if(aEffectProps
[i
].Name
== "RgbClrTransparency")
3467 sal_Int32 nTransparency
;
3468 if (aEffectProps
[i
].Value
>>= nTransparency
)
3469 // Calculate alpha value (see oox/source/drawingml/color.cxx : getTransparency())
3470 nAlpha
= MAX_PERCENT
- ( PER_PERCENT
* nTransparency
);
3472 else if(aEffectProps
[i
].Name
== "SchemeClr")
3474 aEffectProps
[i
].Value
>>= sSchemeClr
;
3476 else if(aEffectProps
[i
].Name
== "SchemeClrTransformations")
3478 aEffectProps
[i
].Value
>>= aTransformations
;
3482 if( nEffectToken
> 0 )
3484 mpFS
->startElement( nEffectToken
, xOuterShdwAttrList
);
3486 if( bContainsColor
)
3488 if( sSchemeClr
.isEmpty() )
3489 WriteColor( nRgbClr
, nAlpha
);
3491 WriteColor( sSchemeClr
, aTransformations
);
3494 mpFS
->endElement( nEffectToken
);
3498 static sal_Int32
lcl_CalculateDist(const double dX
, const double dY
)
3500 return static_cast< sal_Int32
>(sqrt(dX
*dX
+ dY
*dY
) * 360);
3503 static sal_Int32
lcl_CalculateDir(const double dX
, const double dY
)
3505 return (static_cast< sal_Int32
>(basegfx::rad2deg(atan2(dY
,dX
)) * 60000) + 21600000) % 21600000;
3508 void DrawingML::WriteShapeEffects( const Reference
< XPropertySet
>& rXPropSet
)
3510 Sequence
< PropertyValue
> aGrabBag
, aEffects
, aOuterShdwProps
;
3511 if( GetProperty( rXPropSet
, "InteropGrabBag" ) )
3514 for( sal_Int32 i
=0; i
< aGrabBag
.getLength(); ++i
)
3516 if( aGrabBag
[i
].Name
== "EffectProperties" )
3518 aGrabBag
[i
].Value
>>= aEffects
;
3519 for( sal_Int32 j
=0; j
< aEffects
.getLength(); ++j
)
3521 if( aEffects
[j
].Name
== "outerShdw" )
3523 aEffects
[j
].Value
>>= aOuterShdwProps
;
3532 if( !aEffects
.hasElements() )
3534 bool bHasShadow
= false;
3535 if( GetProperty( rXPropSet
, "Shadow" ) )
3536 mAny
>>= bHasShadow
;
3539 Sequence
< PropertyValue
> aShadowGrabBag( 3 );
3540 Sequence
< PropertyValue
> aShadowAttribsGrabBag( 2 );
3542 double dX
= +0.0, dY
= +0.0;
3543 rXPropSet
->getPropertyValue( "ShadowXDistance" ) >>= dX
;
3544 rXPropSet
->getPropertyValue( "ShadowYDistance" ) >>= dY
;
3546 aShadowAttribsGrabBag
[0].Name
= "dist";
3547 aShadowAttribsGrabBag
[0].Value
<<= lcl_CalculateDist(dX
, dY
);
3548 aShadowAttribsGrabBag
[1].Name
= "dir";
3549 aShadowAttribsGrabBag
[1].Value
<<= lcl_CalculateDir(dX
, dY
);
3551 aShadowGrabBag
[0].Name
= "Attribs";
3552 aShadowGrabBag
[0].Value
<<= aShadowAttribsGrabBag
;
3553 aShadowGrabBag
[1].Name
= "RgbClr";
3554 aShadowGrabBag
[1].Value
= rXPropSet
->getPropertyValue( "ShadowColor" );
3555 aShadowGrabBag
[2].Name
= "RgbClrTransparency";
3556 aShadowGrabBag
[2].Value
= rXPropSet
->getPropertyValue( "ShadowTransparence" );
3558 mpFS
->startElementNS(XML_a
, XML_effectLst
);
3559 WriteShapeEffect( "outerShdw", aShadowGrabBag
);
3560 mpFS
->endElementNS(XML_a
, XML_effectLst
);
3565 for( sal_Int32 i
=0; i
< aOuterShdwProps
.getLength(); ++i
)
3567 if( aOuterShdwProps
[i
].Name
== "Attribs" )
3569 Sequence
< PropertyValue
> aAttribsProps
;
3570 aOuterShdwProps
[i
].Value
>>= aAttribsProps
;
3572 double dX
= +0.0, dY
= +0.0;
3573 rXPropSet
->getPropertyValue( "ShadowXDistance" ) >>= dX
;
3574 rXPropSet
->getPropertyValue( "ShadowYDistance" ) >>= dY
;
3576 for( sal_Int32 j
=0; j
< aAttribsProps
.getLength(); ++j
)
3578 if( aAttribsProps
[j
].Name
== "dist" )
3580 aAttribsProps
[j
].Value
<<= lcl_CalculateDist(dX
, dY
);
3582 else if( aAttribsProps
[j
].Name
== "dir" )
3584 aAttribsProps
[j
].Value
<<= lcl_CalculateDir(dX
, dY
);
3588 aOuterShdwProps
[i
].Value
<<= aAttribsProps
;
3590 else if( aOuterShdwProps
[i
].Name
== "RgbClr" )
3592 aOuterShdwProps
[i
].Value
= rXPropSet
->getPropertyValue( "ShadowColor" );
3594 else if( aOuterShdwProps
[i
].Name
== "RgbClrTransparency" )
3596 aOuterShdwProps
[i
].Value
= rXPropSet
->getPropertyValue( "ShadowTransparence" );
3600 mpFS
->startElementNS(XML_a
, XML_effectLst
);
3601 for( sal_Int32 i
=0; i
< aEffects
.getLength(); ++i
)
3603 if( aEffects
[i
].Name
== "outerShdw" )
3605 WriteShapeEffect( aEffects
[i
].Name
, aOuterShdwProps
);
3609 Sequence
< PropertyValue
> aEffectProps
;
3610 aEffects
[i
].Value
>>= aEffectProps
;
3611 WriteShapeEffect( aEffects
[i
].Name
, aEffectProps
);
3614 mpFS
->endElementNS(XML_a
, XML_effectLst
);
3618 void DrawingML::WriteShape3DEffects( const Reference
< XPropertySet
>& xPropSet
)
3620 // check existence of the grab bag
3621 if( !GetProperty( xPropSet
, "InteropGrabBag" ) )
3624 // extract the relevant properties from the grab bag
3625 Sequence
< PropertyValue
> aGrabBag
, aEffectProps
, aLightRigProps
, aShape3DProps
;
3627 for( sal_Int32 i
=0; i
< aGrabBag
.getLength(); ++i
)
3629 if( aGrabBag
[i
].Name
== "3DEffectProperties" )
3631 Sequence
< PropertyValue
> a3DEffectProps
;
3632 aGrabBag
[i
].Value
>>= a3DEffectProps
;
3633 for( sal_Int32 j
=0; j
< a3DEffectProps
.getLength(); ++j
)
3635 if( a3DEffectProps
[j
].Name
== "Camera" )
3636 a3DEffectProps
[j
].Value
>>= aEffectProps
;
3637 else if( a3DEffectProps
[j
].Name
== "LightRig" )
3638 a3DEffectProps
[j
].Value
>>= aLightRigProps
;
3639 else if( a3DEffectProps
[j
].Name
== "Shape3D" )
3640 a3DEffectProps
[j
].Value
>>= aShape3DProps
;
3645 if( !aEffectProps
.hasElements() && !aLightRigProps
.hasElements() && !aShape3DProps
.hasElements() )
3648 bool bCameraRotationPresent
= false;
3649 sax_fastparser::FastAttributeList
*aCameraAttrList
= FastSerializerHelper::createAttrList();
3650 sax_fastparser::XFastAttributeListRef
xCameraAttrList( aCameraAttrList
);
3651 sax_fastparser::FastAttributeList
*aCameraRotationAttrList
= FastSerializerHelper::createAttrList();
3652 sax_fastparser::XFastAttributeListRef
xRotAttrList( aCameraRotationAttrList
);
3653 for( sal_Int32 i
=0; i
< aEffectProps
.getLength(); ++i
)
3655 if( aEffectProps
[i
].Name
== "prst" )
3658 aEffectProps
[i
].Value
>>= sVal
;
3659 aCameraAttrList
->add( XML_prst
, OUStringToOString( sVal
, RTL_TEXTENCODING_UTF8
).getStr() );
3661 else if( aEffectProps
[i
].Name
== "fov" )
3664 aEffectProps
[i
].Value
>>= fVal
;
3665 aCameraAttrList
->add( XML_fov
, OString::number( fVal
* 60000 ).getStr() );
3667 else if( aEffectProps
[i
].Name
== "zoom" )
3670 aEffectProps
[i
].Value
>>= fVal
;
3671 aCameraAttrList
->add( XML_zoom
, OString::number( fVal
* 100000 ).getStr() );
3673 else if( aEffectProps
[i
].Name
== "rotLat" ||
3674 aEffectProps
[i
].Name
== "rotLon" ||
3675 aEffectProps
[i
].Name
== "rotRev" )
3677 sal_Int32 nVal
= 0, nToken
= XML_none
;
3678 aEffectProps
[i
].Value
>>= nVal
;
3679 if( aEffectProps
[i
].Name
== "rotLat" )
3681 else if( aEffectProps
[i
].Name
== "rotLon" )
3683 else if( aEffectProps
[i
].Name
== "rotRev" )
3685 aCameraRotationAttrList
->add( nToken
, OString::number( nVal
).getStr() );
3686 bCameraRotationPresent
= true;
3690 bool bLightRigRotationPresent
= false;
3691 sax_fastparser::FastAttributeList
*aLightRigAttrList
= FastSerializerHelper::createAttrList();
3692 sax_fastparser::XFastAttributeListRef
xLightAttrList( aLightRigAttrList
);
3693 sax_fastparser::FastAttributeList
*aLightRigRotationAttrList
= FastSerializerHelper::createAttrList();
3694 sax_fastparser::XFastAttributeListRef
xLightRotAttrList( aLightRigRotationAttrList
);
3695 for( sal_Int32 i
=0; i
< aLightRigProps
.getLength(); ++i
)
3697 if( aLightRigProps
[i
].Name
== "rig" || aLightRigProps
[i
].Name
== "dir" )
3700 sal_Int32 nToken
= XML_none
;
3701 aLightRigProps
[i
].Value
>>= sVal
;
3702 if( aLightRigProps
[i
].Name
== "rig" )
3704 else if( aLightRigProps
[i
].Name
== "dir" )
3706 aLightRigAttrList
->add( nToken
, OUStringToOString( sVal
, RTL_TEXTENCODING_UTF8
).getStr() );
3708 else if( aLightRigProps
[i
].Name
== "rotLat" ||
3709 aLightRigProps
[i
].Name
== "rotLon" ||
3710 aLightRigProps
[i
].Name
== "rotRev" )
3712 sal_Int32 nVal
= 0, nToken
= XML_none
;
3713 aLightRigProps
[i
].Value
>>= nVal
;
3714 if( aLightRigProps
[i
].Name
== "rotLat" )
3716 else if( aLightRigProps
[i
].Name
== "rotLon" )
3718 else if( aLightRigProps
[i
].Name
== "rotRev" )
3720 aLightRigRotationAttrList
->add( nToken
, OString::number( nVal
).getStr() );
3721 bLightRigRotationPresent
= true;
3725 mpFS
->startElementNS(XML_a
, XML_scene3d
);
3727 if( aEffectProps
.hasElements() )
3729 mpFS
->startElementNS( XML_a
, XML_camera
, xCameraAttrList
);
3730 if( bCameraRotationPresent
)
3732 mpFS
->singleElementNS( XML_a
, XML_rot
, xRotAttrList
);
3734 mpFS
->endElementNS( XML_a
, XML_camera
);
3738 // a:camera with Word default values - Word won't open the document if this is not present
3739 mpFS
->singleElementNS(XML_a
, XML_camera
, XML_prst
, "orthographicFront");
3742 if( aEffectProps
.hasElements() )
3744 mpFS
->startElementNS( XML_a
, XML_lightRig
, xLightAttrList
);
3745 if( bLightRigRotationPresent
)
3747 mpFS
->singleElementNS( XML_a
, XML_rot
, xLightRotAttrList
);
3749 mpFS
->endElementNS( XML_a
, XML_lightRig
);
3753 // a:lightRig with Word default values - Word won't open the document if this is not present
3754 mpFS
->singleElementNS(XML_a
, XML_lightRig
, XML_rig
, "threePt", XML_dir
, "t");
3757 mpFS
->endElementNS( XML_a
, XML_scene3d
);
3759 if( !aShape3DProps
.hasElements() )
3762 bool bBevelTPresent
= false, bBevelBPresent
= false;
3763 Sequence
< PropertyValue
> aExtrusionColorProps
, aContourColorProps
;
3764 sax_fastparser::FastAttributeList
*aBevelTAttrList
= FastSerializerHelper::createAttrList();
3765 sax_fastparser::XFastAttributeListRef
xBevelTAttrList( aBevelTAttrList
);
3766 sax_fastparser::FastAttributeList
*aBevelBAttrList
= FastSerializerHelper::createAttrList();
3767 sax_fastparser::XFastAttributeListRef
xBevelBAttrList( aBevelBAttrList
);
3768 sax_fastparser::FastAttributeList
*aShape3DAttrList
= FastSerializerHelper::createAttrList();
3769 for( sal_Int32 i
=0; i
< aShape3DProps
.getLength(); ++i
)
3771 if( aShape3DProps
[i
].Name
== "extrusionH" || aShape3DProps
[i
].Name
== "contourW" || aShape3DProps
[i
].Name
== "z" )
3773 sal_Int32 nVal
= 0, nToken
= XML_none
;
3774 aShape3DProps
[i
].Value
>>= nVal
;
3775 if( aShape3DProps
[i
].Name
== "extrusionH" )
3776 nToken
= XML_extrusionH
;
3777 else if( aShape3DProps
[i
].Name
== "contourW" )
3778 nToken
= XML_contourW
;
3779 else if( aShape3DProps
[i
].Name
== "z" )
3781 aShape3DAttrList
->add( nToken
, OString::number( nVal
).getStr() );
3783 else if( aShape3DProps
[i
].Name
== "prstMaterial" )
3786 aShape3DProps
[i
].Value
>>= sVal
;
3787 aShape3DAttrList
->add( XML_prstMaterial
, OUStringToOString( sVal
, RTL_TEXTENCODING_UTF8
).getStr() );
3789 else if( aShape3DProps
[i
].Name
== "extrusionClr" )
3791 aShape3DProps
[i
].Value
>>= aExtrusionColorProps
;
3793 else if( aShape3DProps
[i
].Name
== "contourClr" )
3795 aShape3DProps
[i
].Value
>>= aContourColorProps
;
3797 else if( aShape3DProps
[i
].Name
== "bevelT" || aShape3DProps
[i
].Name
== "bevelB" )
3799 Sequence
< PropertyValue
> aBevelProps
;
3800 aShape3DProps
[i
].Value
>>= aBevelProps
;
3801 if ( !aBevelProps
.hasElements() )
3804 sax_fastparser::FastAttributeList
*aBevelAttrList
= nullptr;
3805 if( aShape3DProps
[i
].Name
== "bevelT" )
3807 bBevelTPresent
= true;
3808 aBevelAttrList
= aBevelTAttrList
;
3812 bBevelBPresent
= true;
3813 aBevelAttrList
= aBevelBAttrList
;
3815 for( sal_Int32 j
=0; j
< aBevelProps
.getLength(); ++j
)
3817 if( aBevelProps
[j
].Name
== "w" || aBevelProps
[j
].Name
== "h" )
3819 sal_Int32 nVal
= 0, nToken
= XML_none
;
3820 aBevelProps
[j
].Value
>>= nVal
;
3821 if( aBevelProps
[j
].Name
== "w" )
3823 else if( aBevelProps
[j
].Name
== "h" )
3825 aBevelAttrList
->add( nToken
, OString::number( nVal
).getStr() );
3827 else if( aBevelProps
[j
].Name
== "prst" )
3830 aBevelProps
[j
].Value
>>= sVal
;
3831 aBevelAttrList
->add( XML_prst
, OUStringToOString( sVal
, RTL_TEXTENCODING_UTF8
).getStr() );
3838 sax_fastparser::XFastAttributeListRef
xAttrList( aShape3DAttrList
);
3839 mpFS
->startElementNS( XML_a
, XML_sp3d
, xAttrList
);
3840 if( bBevelTPresent
)
3842 mpFS
->singleElementNS( XML_a
, XML_bevelT
, xBevelTAttrList
);
3844 if( bBevelBPresent
)
3846 mpFS
->singleElementNS( XML_a
, XML_bevelB
, xBevelBAttrList
);
3848 if( aExtrusionColorProps
.hasElements() )
3850 OUString sSchemeClr
;
3852 sal_Int32
nTransparency(0);
3853 Sequence
< PropertyValue
> aColorTransformations
;
3854 for( sal_Int32 i
=0; i
< aExtrusionColorProps
.getLength(); ++i
)
3856 if( aExtrusionColorProps
[i
].Name
== "schemeClr" )
3857 aExtrusionColorProps
[i
].Value
>>= sSchemeClr
;
3858 else if( aExtrusionColorProps
[i
].Name
== "schemeClrTransformations" )
3859 aExtrusionColorProps
[i
].Value
>>= aColorTransformations
;
3860 else if( aExtrusionColorProps
[i
].Name
== "rgbClr" )
3861 aExtrusionColorProps
[i
].Value
>>= nColor
;
3862 else if( aExtrusionColorProps
[i
].Name
== "rgbClrTransparency" )
3863 aExtrusionColorProps
[i
].Value
>>= nTransparency
;
3865 mpFS
->startElementNS(XML_a
, XML_extrusionClr
);
3867 if( sSchemeClr
.isEmpty() )
3868 WriteColor( nColor
, MAX_PERCENT
- ( PER_PERCENT
* nTransparency
) );
3870 WriteColor( sSchemeClr
, aColorTransformations
);
3872 mpFS
->endElementNS( XML_a
, XML_extrusionClr
);
3874 if( aContourColorProps
.hasElements() )
3876 OUString sSchemeClr
;
3878 sal_Int32
nTransparency(0);
3879 Sequence
< PropertyValue
> aColorTransformations
;
3880 for( sal_Int32 i
=0; i
< aContourColorProps
.getLength(); ++i
)
3882 if( aContourColorProps
[i
].Name
== "schemeClr" )
3883 aContourColorProps
[i
].Value
>>= sSchemeClr
;
3884 else if( aContourColorProps
[i
].Name
== "schemeClrTransformations" )
3885 aContourColorProps
[i
].Value
>>= aColorTransformations
;
3886 else if( aContourColorProps
[i
].Name
== "rgbClr" )
3887 aContourColorProps
[i
].Value
>>= nColor
;
3888 else if( aContourColorProps
[i
].Name
== "rgbClrTransparency" )
3889 aContourColorProps
[i
].Value
>>= nTransparency
;
3891 mpFS
->startElementNS(XML_a
, XML_contourClr
);
3893 if( sSchemeClr
.isEmpty() )
3894 WriteColor( nColor
, MAX_PERCENT
- ( PER_PERCENT
* nTransparency
) );
3896 WriteColor( sSchemeClr
, aContourColorProps
);
3898 mpFS
->endElementNS( XML_a
, XML_contourClr
);
3900 mpFS
->endElementNS( XML_a
, XML_sp3d
);
3903 void DrawingML::WriteArtisticEffect( const Reference
< XPropertySet
>& rXPropSet
)
3905 if( !GetProperty( rXPropSet
, "InteropGrabBag" ) )
3908 PropertyValue aEffect
;
3909 Sequence
< PropertyValue
> aGrabBag
;
3911 for( sal_Int32 i
=0; i
< aGrabBag
.getLength(); ++i
)
3913 if( aGrabBag
[i
].Name
== "ArtisticEffectProperties" )
3915 aGrabBag
[i
].Value
>>= aEffect
;
3919 sal_Int32 nEffectToken
= ArtisticEffectProperties::getEffectToken( aEffect
.Name
);
3920 if( nEffectToken
== XML_none
)
3923 Sequence
< PropertyValue
> aAttrs
;
3924 aEffect
.Value
>>= aAttrs
;
3925 sax_fastparser::FastAttributeList
*aAttrList
= FastSerializerHelper::createAttrList();
3927 for( sal_Int32 i
=0; i
< aAttrs
.getLength(); ++i
)
3929 sal_Int32 nToken
= ArtisticEffectProperties::getEffectToken( aAttrs
[i
].Name
);
3930 if( nToken
!= XML_none
)
3933 aAttrs
[i
].Value
>>= nVal
;
3934 aAttrList
->add( nToken
, OString::number( nVal
).getStr() );
3936 else if( aAttrs
[i
].Name
== "OriginalGraphic" )
3938 Sequence
< PropertyValue
> aGraphic
;
3939 aAttrs
[i
].Value
>>= aGraphic
;
3940 Sequence
< sal_Int8
> aGraphicData
;
3941 OUString sGraphicId
;
3942 for( sal_Int32 j
=0; j
< aGraphic
.getLength(); ++j
)
3944 if( aGraphic
[j
].Name
== "Id" )
3945 aGraphic
[j
].Value
>>= sGraphicId
;
3946 else if( aGraphic
[j
].Name
== "Data" )
3947 aGraphic
[j
].Value
>>= aGraphicData
;
3949 sRelId
= WriteWdpPicture( sGraphicId
, aGraphicData
);
3953 mpFS
->startElementNS(XML_a
, XML_extLst
);
3954 mpFS
->startElementNS(XML_a
, XML_ext
, XML_uri
, "{BEBA8EAE-BF5A-486C-A8C5-ECC9F3942E4B}");
3955 mpFS
->startElementNS( XML_a14
, XML_imgProps
,
3956 FSNS(XML_xmlns
, XML_a14
), mpFB
->getNamespaceURL(OOX_NS(a14
)).toUtf8() );
3957 mpFS
->startElementNS(XML_a14
, XML_imgLayer
, FSNS(XML_r
, XML_embed
), sRelId
);
3958 mpFS
->startElementNS(XML_a14
, XML_imgEffect
);
3960 sax_fastparser::XFastAttributeListRef
xAttrList( aAttrList
);
3961 mpFS
->singleElementNS( XML_a14
, nEffectToken
, xAttrList
);
3963 mpFS
->endElementNS( XML_a14
, XML_imgEffect
);
3964 mpFS
->endElementNS( XML_a14
, XML_imgLayer
);
3965 mpFS
->endElementNS( XML_a14
, XML_imgProps
);
3966 mpFS
->endElementNS( XML_a
, XML_ext
);
3967 mpFS
->endElementNS( XML_a
, XML_extLst
);
3970 OString
DrawingML::WriteWdpPicture( const OUString
& rFileId
, const Sequence
< sal_Int8
>& rPictureData
)
3972 std::map
<OUString
, OUString
>::iterator aCachedItem
= maWdpCache
.find( rFileId
);
3973 if( aCachedItem
!= maWdpCache
.end() )
3974 return OUStringToOString( aCachedItem
->second
, RTL_TEXTENCODING_UTF8
);
3976 OUString sFileName
= "media/hdphoto" + OUString::number( mnWdpImageCounter
++ ) + ".wdp";
3977 Reference
< XOutputStream
> xOutStream
= mpFB
->openFragmentStream( OUStringBuffer()
3978 .appendAscii( GetComponentDir() )
3980 .append( sFileName
)
3981 .makeStringAndClear(),
3982 "image/vnd.ms-photo" );
3984 xOutStream
->writeBytes( rPictureData
);
3985 xOutStream
->closeOutput();
3987 sId
= mpFB
->addRelation( mpFS
->getOutputStream(),
3988 oox::getRelationship(Relationship::HDPHOTO
),
3990 .appendAscii( GetRelationCompPrefix() )
3991 .append( sFileName
)
3992 .makeStringAndClear() );
3994 maWdpCache
[rFileId
] = sId
;
3995 return OUStringToOString( sId
, RTL_TEXTENCODING_UTF8
);
3998 void DrawingML::WriteDiagram(const css::uno::Reference
<css::drawing::XShape
>& rXShape
, int nDiagramId
)
4000 uno::Reference
<beans::XPropertySet
> xPropSet(rXShape
, uno::UNO_QUERY
);
4002 uno::Reference
<xml::dom::XDocument
> dataDom
;
4003 uno::Reference
<xml::dom::XDocument
> layoutDom
;
4004 uno::Reference
<xml::dom::XDocument
> styleDom
;
4005 uno::Reference
<xml::dom::XDocument
> colorDom
;
4006 uno::Reference
<xml::dom::XDocument
> drawingDom
;
4007 uno::Sequence
<uno::Sequence
<uno::Any
>> xDataRelSeq
;
4008 uno::Sequence
<uno::Any
> diagramDrawing
;
4010 // retrieve the doms from the GrabBag
4011 uno::Sequence
<beans::PropertyValue
> propList
;
4012 xPropSet
->getPropertyValue(UNO_NAME_MISC_OBJ_INTEROPGRABBAG
) >>= propList
;
4013 for (sal_Int32 nProp
= 0; nProp
< propList
.getLength(); ++nProp
)
4015 OUString propName
= propList
[nProp
].Name
;
4016 if (propName
== "OOXData")
4017 propList
[nProp
].Value
>>= dataDom
;
4018 else if (propName
== "OOXLayout")
4019 propList
[nProp
].Value
>>= layoutDom
;
4020 else if (propName
== "OOXStyle")
4021 propList
[nProp
].Value
>>= styleDom
;
4022 else if (propName
== "OOXColor")
4023 propList
[nProp
].Value
>>= colorDom
;
4024 else if (propName
== "OOXDrawing")
4026 propList
[nProp
].Value
>>= diagramDrawing
;
4028 >>= drawingDom
; // if there is OOXDrawing property then set drawingDom here only.
4030 else if (propName
== "OOXDiagramDataRels")
4031 propList
[nProp
].Value
>>= xDataRelSeq
;
4034 // check that we have the 4 mandatory XDocuments
4035 // if not, there was an error importing and we won't output anything
4036 if (!dataDom
.is() || !layoutDom
.is() || !styleDom
.is() || !colorDom
.is())
4039 // generate an unique id
4040 sax_fastparser::FastAttributeList
* pDocPrAttrList
4041 = sax_fastparser::FastSerializerHelper::createAttrList();
4042 pDocPrAttrList
->add(XML_id
, OString::number(nDiagramId
).getStr());
4043 OUString sName
= "Diagram" + OUString::number(nDiagramId
);
4044 pDocPrAttrList
->add(XML_name
, OUStringToOString(sName
, RTL_TEXTENCODING_UTF8
).getStr());
4045 sax_fastparser::XFastAttributeListRef
xDocPrAttrListRef(pDocPrAttrList
);
4047 if (GetDocumentType() == DOCUMENT_DOCX
)
4049 mpFS
->singleElementNS(XML_wp
, XML_docPr
, xDocPrAttrListRef
);
4050 mpFS
->singleElementNS(XML_wp
, XML_cNvGraphicFramePr
);
4052 mpFS
->startElementNS(
4053 XML_a
, XML_graphic
, FSNS(XML_xmlns
, XML_a
),
4054 mpFB
->getNamespaceURL(OOX_NS(dml
)).toUtf8());
4058 mpFS
->startElementNS(XML_p
, XML_nvGraphicFramePr
);
4060 mpFS
->singleElementNS(XML_p
, XML_cNvPr
, xDocPrAttrListRef
);
4061 mpFS
->singleElementNS(XML_p
, XML_cNvGraphicFramePr
);
4063 mpFS
->startElementNS(XML_p
, XML_nvPr
);
4064 mpFS
->startElementNS(XML_p
, XML_extLst
);
4065 // change tracking extension - required in PPTX
4066 mpFS
->startElementNS(XML_p
, XML_ext
, XML_uri
, "{D42A27DB-BD31-4B8C-83A1-F6EECF244321}");
4067 mpFS
->singleElementNS(XML_p14
, XML_modId
,
4068 FSNS(XML_xmlns
, XML_p14
), mpFB
->getNamespaceURL(OOX_NS(p14
)).toUtf8(),
4070 OString::number(comphelper::rng::uniform_uint_distribution(1, SAL_MAX_UINT32
)));
4071 mpFS
->endElementNS(XML_p
, XML_ext
);
4072 mpFS
->endElementNS(XML_p
, XML_extLst
);
4073 mpFS
->endElementNS(XML_p
, XML_nvPr
);
4075 mpFS
->endElementNS(XML_p
, XML_nvGraphicFramePr
);
4077 awt::Point aPos
= rXShape
->getPosition();
4078 awt::Size aSize
= rXShape
->getSize();
4079 WriteTransformation(tools::Rectangle(Point(aPos
.X
, aPos
.Y
), Size(aSize
.Width
, aSize
.Height
)),
4080 XML_p
, false, false, 0, false);
4082 mpFS
->startElementNS(XML_a
, XML_graphic
);
4085 mpFS
->startElementNS(XML_a
, XML_graphicData
, XML_uri
,
4086 "http://schemas.openxmlformats.org/drawingml/2006/diagram");
4088 OUString sRelationCompPrefix
= OUString::createFromAscii(GetRelationCompPrefix());
4090 // add data relation
4091 OUString dataFileName
= "diagrams/data" + OUString::number(nDiagramId
) + ".xml";
4092 OString dataRelId
= OUStringToOString(
4093 mpFB
->addRelation(mpFS
->getOutputStream(), oox::getRelationship(Relationship::DIAGRAMDATA
),
4094 sRelationCompPrefix
+ dataFileName
),
4095 RTL_TEXTENCODING_UTF8
);
4097 // add layout relation
4098 OUString layoutFileName
= "diagrams/layout" + OUString::number(nDiagramId
) + ".xml";
4100 = OUStringToOString(mpFB
->addRelation(mpFS
->getOutputStream(),
4101 oox::getRelationship(Relationship::DIAGRAMLAYOUT
),
4102 sRelationCompPrefix
+ layoutFileName
),
4103 RTL_TEXTENCODING_UTF8
);
4105 // add style relation
4106 OUString styleFileName
= "diagrams/quickStyle" + OUString::number(nDiagramId
) + ".xml";
4108 = OUStringToOString(mpFB
->addRelation(mpFS
->getOutputStream(),
4109 oox::getRelationship(Relationship::DIAGRAMQUICKSTYLE
),
4110 sRelationCompPrefix
+ styleFileName
),
4111 RTL_TEXTENCODING_UTF8
);
4113 // add color relation
4114 OUString colorFileName
= "diagrams/colors" + OUString::number(nDiagramId
) + ".xml";
4116 = OUStringToOString(mpFB
->addRelation(mpFS
->getOutputStream(),
4117 oox::getRelationship(Relationship::DIAGRAMCOLORS
),
4118 sRelationCompPrefix
+ colorFileName
),
4119 RTL_TEXTENCODING_UTF8
);
4121 OUString drawingFileName
;
4122 if (drawingDom
.is())
4124 // add drawing relation
4125 drawingFileName
= "diagrams/drawing" + OUString::number(nDiagramId
) + ".xml";
4126 OUString drawingRelId
= mpFB
->addRelation(
4127 mpFS
->getOutputStream(), oox::getRelationship(Relationship::DIAGRAMDRAWING
),
4128 sRelationCompPrefix
+ drawingFileName
);
4130 // the data dom contains a reference to the drawing relation. We need to update it with the new generated
4131 // relation value before writing the dom to a file
4133 // Get the dsp:damaModelExt node from the dom
4134 uno::Reference
<xml::dom::XNodeList
> nodeList
= dataDom
->getElementsByTagNameNS(
4135 "http://schemas.microsoft.com/office/drawing/2008/diagram", "dataModelExt");
4137 // There must be one element only so get it
4138 uno::Reference
<xml::dom::XNode
> node
= nodeList
->item(0);
4140 // Get the list of attributes of the node
4141 uno::Reference
<xml::dom::XNamedNodeMap
> nodeMap
= node
->getAttributes();
4143 // Get the node with the relId attribute and set its new value
4144 uno::Reference
<xml::dom::XNode
> relIdNode
= nodeMap
->getNamedItem("relId");
4145 relIdNode
->setNodeValue(drawingRelId
);
4148 mpFS
->singleElementNS(XML_dgm
, XML_relIds
,
4149 FSNS(XML_xmlns
, XML_dgm
), mpFB
->getNamespaceURL(OOX_NS(dmlDiagram
)).toUtf8(),
4150 FSNS(XML_xmlns
, XML_r
), mpFB
->getNamespaceURL(OOX_NS(officeRel
)).toUtf8(),
4151 FSNS(XML_r
, XML_dm
), dataRelId
, FSNS(XML_r
, XML_lo
), layoutRelId
,
4152 FSNS(XML_r
, XML_qs
), styleRelId
, FSNS(XML_r
, XML_cs
), colorRelId
);
4154 mpFS
->endElementNS(XML_a
, XML_graphicData
);
4155 mpFS
->endElementNS(XML_a
, XML_graphic
);
4157 uno::Reference
<xml::sax::XSAXSerializable
> serializer
;
4158 uno::Reference
<xml::sax::XWriter
> writer
4159 = xml::sax::Writer::create(comphelper::getProcessComponentContext());
4161 OUString sDir
= OUString::createFromAscii(GetComponentDir());
4164 serializer
.set(dataDom
, uno::UNO_QUERY
);
4165 uno::Reference
<io::XOutputStream
> xDataOutputStream
= mpFB
->openFragmentStream(
4166 sDir
+ "/" + dataFileName
,
4167 "application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml");
4168 writer
->setOutputStream(xDataOutputStream
);
4169 serializer
->serialize(uno::Reference
<xml::sax::XDocumentHandler
>(writer
, uno::UNO_QUERY_THROW
),
4170 uno::Sequence
<beans::StringPair
>());
4172 // write the associated Images and rels for data file
4173 writeDiagramRels(xDataRelSeq
, xDataOutputStream
, "OOXDiagramDataRels", nDiagramId
);
4175 // write layout file
4176 serializer
.set(layoutDom
, uno::UNO_QUERY
);
4177 writer
->setOutputStream(mpFB
->openFragmentStream(
4178 sDir
+ "/" + layoutFileName
,
4179 "application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml"));
4180 serializer
->serialize(uno::Reference
<xml::sax::XDocumentHandler
>(writer
, uno::UNO_QUERY_THROW
),
4181 uno::Sequence
<beans::StringPair
>());
4184 serializer
.set(styleDom
, uno::UNO_QUERY
);
4185 writer
->setOutputStream(mpFB
->openFragmentStream(
4186 sDir
+ "/" + styleFileName
,
4187 "application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml"));
4188 serializer
->serialize(uno::Reference
<xml::sax::XDocumentHandler
>(writer
, uno::UNO_QUERY_THROW
),
4189 uno::Sequence
<beans::StringPair
>());
4192 serializer
.set(colorDom
, uno::UNO_QUERY
);
4193 writer
->setOutputStream(mpFB
->openFragmentStream(
4194 sDir
+ "/" + colorFileName
,
4195 "application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml"));
4196 serializer
->serialize(uno::Reference
<xml::sax::XDocumentHandler
>(writer
, uno::UNO_QUERY_THROW
),
4197 uno::Sequence
<beans::StringPair
>());
4199 // write drawing file
4200 if (drawingDom
.is())
4202 serializer
.set(drawingDom
, uno::UNO_QUERY
);
4203 uno::Reference
<io::XOutputStream
> xDrawingOutputStream
= mpFB
->openFragmentStream(
4204 sDir
+ "/" + drawingFileName
, "application/vnd.ms-office.drawingml.diagramDrawing+xml");
4205 writer
->setOutputStream(xDrawingOutputStream
);
4206 serializer
->serialize(
4207 uno::Reference
<xml::sax::XDocumentHandler
>(writer
, uno::UNO_QUERY_THROW
),
4208 uno::Sequence
<beans::StringPair
>());
4210 // write the associated Images and rels for drawing file
4211 uno::Sequence
<uno::Sequence
<uno::Any
>> xDrawingRelSeq
;
4212 diagramDrawing
[1] >>= xDrawingRelSeq
;
4213 writeDiagramRels(xDrawingRelSeq
, xDrawingOutputStream
, "OOXDiagramDrawingRels", nDiagramId
);
4217 void DrawingML::writeDiagramRels(const uno::Sequence
<uno::Sequence
<uno::Any
>>& xRelSeq
,
4218 const uno::Reference
<io::XOutputStream
>& xOutStream
,
4219 const OUString
& sGrabBagProperyName
, int nDiagramId
)
4221 // add image relationships of OOXData, OOXDiagram
4222 OUString
sType(oox::getRelationship(Relationship::IMAGE
));
4223 uno::Reference
<xml::sax::XWriter
> xWriter
4224 = xml::sax::Writer::create(comphelper::getProcessComponentContext());
4225 xWriter
->setOutputStream(xOutStream
);
4227 // retrieve the relationships from Sequence
4228 for (sal_Int32 j
= 0; j
< xRelSeq
.getLength(); j
++)
4230 // diagramDataRelTuple[0] => RID,
4231 // diagramDataRelTuple[1] => xInputStream
4232 // diagramDataRelTuple[2] => extension
4233 uno::Sequence
<uno::Any
> diagramDataRelTuple
= xRelSeq
[j
];
4236 OUString sExtension
;
4237 diagramDataRelTuple
[0] >>= sRelId
;
4238 diagramDataRelTuple
[2] >>= sExtension
;
4239 OUString sContentType
;
4240 if (sExtension
.equalsIgnoreAsciiCase(".WMF"))
4241 sContentType
= "image/x-wmf";
4243 sContentType
= "image/" + sExtension
.copy(1);
4244 sRelId
= sRelId
.copy(3);
4246 StreamDataSequence dataSeq
;
4247 diagramDataRelTuple
[1] >>= dataSeq
;
4248 uno::Reference
<io::XInputStream
> dataImagebin(
4249 new ::comphelper::SequenceInputStream(dataSeq
));
4251 //nDiagramId is used to make the name unique irrespective of the number of smart arts.
4252 OUString sFragment
= "media/" + sGrabBagProperyName
+ OUString::number(nDiagramId
) + "_"
4253 + OUString::number(j
) + sExtension
;
4255 PropertySet
aProps(xOutStream
);
4256 aProps
.setAnyProperty(PROP_RelId
, uno::makeAny(sRelId
.toInt32()));
4258 mpFB
->addRelation(xOutStream
, sType
, "../" + sFragment
);
4260 OUString sDir
= OUString::createFromAscii(GetComponentDir());
4261 uno::Reference
<io::XOutputStream
> xBinOutStream
4262 = mpFB
->openFragmentStream(sDir
+ "/" + sFragment
, sContentType
);
4266 comphelper::OStorageHelper::CopyInputToOutput(dataImagebin
, xBinOutStream
);
4268 catch (const uno::Exception
& rException
)
4270 SAL_WARN("oox.drawingml", "DrawingML::writeDiagramRels Failed to copy grabbaged Image: "
4273 dataImagebin
->closeInput();
4280 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */