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