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