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 "svgfilter.hxx"
21 : #include "svgfontexport.hxx"
22 : #include "svgwriter.hxx"
23 :
24 : #include <rtl/crc.h>
25 : #include <vcl/unohelp.hxx>
26 : #include <tools/helpers.hxx>
27 : #include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
28 : #include <sax/tools/converter.hxx>
29 :
30 : #include <boost/shared_array.hpp>
31 :
32 : using ::rtl::OUString;
33 :
34 : // -----------
35 : // - statics -
36 : // -----------
37 :
38 : static const char aXMLElemG[] = "g";
39 : static const char aXMLElemDefs[] = "defs";
40 : static const char aXMLElemLine[] = "line";
41 : static const char aXMLElemRect[] = "rect";
42 : static const char aXMLElemEllipse[] = "ellipse";
43 : static const char aXMLElemPath[] = "path";
44 : static const char aXMLElemText[] = "text";
45 : static const char aXMLElemTspan[] = "tspan";
46 : static const char aXMLElemImage[] = "image";
47 : static const char aXMLElemMask[] = "mask";
48 : static const char aXMLElemPattern[] = "pattern";
49 : static const char aXMLElemLinearGradient[] = "linearGradient";
50 : static const char aXMLElemRadialGradient[] = "radialGradient";
51 : static const char aXMLElemStop[] = "stop";
52 :
53 : // -----------------------------------------------------------------------------
54 :
55 : static const char aXMLAttrTransform[] = "transform";
56 : static const char aXMLAttrStyle[] = "style";
57 : static const char aXMLAttrId[] = "id";
58 : static const char aXMLAttrDX[] = "dx";
59 : static const char aXMLAttrDY[] = "dy";
60 : static const char aXMLAttrD[] = "d";
61 : static const char aXMLAttrX[] = "x";
62 : static const char aXMLAttrY[] = "y";
63 : static const char aXMLAttrX1[] = "x1";
64 : static const char aXMLAttrY1[] = "y1";
65 : static const char aXMLAttrX2[] = "x2";
66 : static const char aXMLAttrY2[] = "y2";
67 : static const char aXMLAttrCX[] = "cx";
68 : static const char aXMLAttrCY[] = "cy";
69 : static const char aXMLAttrR[] = "r";
70 : static const char aXMLAttrRX[] = "rx";
71 : static const char aXMLAttrRY[] = "ry";
72 : static const char aXMLAttrWidth[] = "width";
73 : static const char aXMLAttrHeight[] = "height";
74 : static const char aXMLAttrStroke[] = "stroke";
75 : static const char aXMLAttrStrokeOpacity[] = "stroke-opacity";
76 : static const char aXMLAttrStrokeWidth[] = "stroke-width";
77 : static const char aXMLAttrStrokeDashArray[] = "stroke-dasharray";
78 : static const char aXMLAttrFill[] = "fill";
79 : static const char aXMLAttrFillOpacity[] = "fill-opacity";
80 : static const char aXMLAttrFontFamily[] = "font-family";
81 : static const char aXMLAttrFontSize[] = "font-size";
82 : static const char aXMLAttrFontStyle[] = "font-style";
83 : static const char aXMLAttrFontWeight[] = "font-weight";
84 : static const char aXMLAttrTextDecoration[] = "text-decoration";
85 : static const char aXMLAttrXLinkHRef[] = "xlink:href";
86 : static const char aXMLAttrGradientUnits[] = "gradientUnits";
87 : static const char aXMLAttrPatternUnits[] = "patternUnits";
88 : static const char aXMLAttrOffset[] = "offset";
89 : static const char aXMLAttrStopColor[] = "stop-color";
90 : static const char aXMLAttrStrokeLinejoin[] = "stroke-linejoin";
91 : static const char aXMLAttrStrokeLinecap[] = "stroke-linecap";
92 :
93 :
94 : #define NSPREFIX "ooo:"
95 :
96 : static const char aOOOAttrNumberingType[] = NSPREFIX "numbering-type";
97 :
98 :
99 : static sal_Char const XML_UNO_NAME_NRULE_NUMBERINGTYPE[] = "NumberingType";
100 : static sal_Char const XML_UNO_NAME_NRULE_BULLET_CHAR[] = "BulletChar";
101 : // -----------------------------------------------------------------------------
102 :
103 :
104 : // ----------------------
105 : // - SVGAttributeWriter -
106 : // ----------------------
107 :
108 0 : SVGAttributeWriter::SVGAttributeWriter( SVGExport& rExport, SVGFontExport& rFontExport ) :
109 : mrExport( rExport ),
110 : mrFontExport( rFontExport ),
111 : mpElemFont( NULL ),
112 0 : mpElemPaint( NULL )
113 : {
114 0 : }
115 :
116 : // -----------------------------------------------------------------------------
117 :
118 0 : SVGAttributeWriter::~SVGAttributeWriter()
119 : {
120 0 : if( mpElemPaint )
121 0 : delete mpElemPaint;
122 0 : if( mpElemFont )
123 0 : delete mpElemFont;
124 0 : }
125 :
126 : // -----------------------------------------------------------------------------
127 :
128 0 : double SVGAttributeWriter::ImplRound( double fValue, sal_Int32 nDecs )
129 : {
130 0 : return( floor( fValue * pow( 10.0, (int)nDecs ) + 0.5 ) / pow( 10.0, (int)nDecs ) );
131 : }
132 :
133 : // -----------------------------------------------------------------------------
134 :
135 0 : void SVGAttributeWriter::ImplGetColorStr( const Color& rColor, ::rtl::OUString& rColorStr )
136 : {
137 0 : if( rColor.GetTransparency() == 255 )
138 0 : rColorStr = B2UCONST( "none" );
139 : else
140 : {
141 0 : ::rtl::OUStringBuffer aStyle;
142 0 : aStyle.appendAscii( "rgb(" );
143 0 : aStyle.append( (sal_Int32) rColor.GetRed() );
144 0 : aStyle.appendAscii( "," );
145 0 : aStyle.append( (sal_Int32) rColor.GetGreen() );
146 0 : aStyle.appendAscii( "," );
147 0 : aStyle.append( (sal_Int32) rColor.GetBlue() );
148 0 : aStyle.appendAscii( ")" );
149 0 : rColorStr = aStyle.makeStringAndClear();
150 : }
151 0 : }
152 :
153 : // -----------------------------------------------------------------------------
154 :
155 0 : void SVGAttributeWriter::AddColorAttr( const char* pColorAttrName,
156 : const char* pColorOpacityAttrName,
157 : const Color& rColor )
158 : {
159 0 : ::rtl::OUString aColor, aColorOpacity;
160 :
161 0 : ImplGetColorStr( rColor, aColor );
162 :
163 0 : if( rColor.GetTransparency() > 0 && rColor.GetTransparency() < 255 )
164 0 : aColorOpacity = ::rtl::OUString::valueOf( ImplRound( ( 255.0 - rColor.GetTransparency() ) / 255.0 ) );
165 :
166 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, pColorAttrName, aColor );
167 :
168 0 : if( !aColorOpacity.isEmpty() && mrExport.IsUseOpacity() )
169 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, pColorOpacityAttrName, aColorOpacity );
170 0 : }
171 :
172 : // -----------------------------------------------------------------------------
173 :
174 0 : void SVGAttributeWriter::AddPaintAttr( const Color& rLineColor, const Color& rFillColor,
175 : const Rectangle* pObjBoundRect, const Gradient* pFillGradient )
176 : {
177 : // Fill
178 0 : if( pObjBoundRect && pFillGradient )
179 : {
180 0 : ::rtl::OUString aGradientId;
181 :
182 0 : AddGradientDef( *pObjBoundRect, *pFillGradient, aGradientId );
183 :
184 0 : if( !aGradientId.isEmpty() )
185 : {
186 0 : ::rtl::OUString aGradientURL( B2UCONST( "url(#" ) );
187 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFill, ( aGradientURL += aGradientId ) += B2UCONST( ")" ) );
188 0 : }
189 : }
190 : else
191 0 : AddColorAttr( aXMLAttrFill, aXMLAttrFillOpacity, rFillColor );
192 :
193 : // Stroke
194 0 : AddColorAttr( aXMLAttrStroke, aXMLAttrStrokeOpacity, rLineColor );
195 0 : }
196 :
197 : // -----------------------------------------------------------------------------
198 :
199 0 : void SVGAttributeWriter::AddGradientDef( const Rectangle& rObjRect, const Gradient& rGradient, ::rtl::OUString& rGradientId )
200 : {
201 0 : if( rObjRect.GetWidth() && rObjRect.GetHeight() &&
202 0 : ( rGradient.GetStyle() == GradientStyle_LINEAR || rGradient.GetStyle() == GradientStyle_AXIAL ||
203 0 : rGradient.GetStyle() == GradientStyle_RADIAL || rGradient.GetStyle() == GradientStyle_ELLIPTICAL ) )
204 : {
205 0 : SvXMLElementExport aDesc( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, sal_True, sal_True );
206 0 : Color aStartColor( rGradient.GetStartColor() ), aEndColor( rGradient.GetEndColor() );
207 0 : sal_uInt16 nAngle = rGradient.GetAngle() % 3600;
208 0 : Point aObjRectCenter( rObjRect.Center() );
209 0 : Polygon aPoly( rObjRect );
210 : static sal_Int32 nCurGradientId = 1;
211 :
212 0 : aPoly.Rotate( aObjRectCenter, nAngle );
213 0 : Rectangle aRect( aPoly.GetBoundRect() );
214 :
215 : // adjust start/end colors with intensities
216 0 : aStartColor.SetRed( (sal_uInt8)( (long) aStartColor.GetRed() * rGradient.GetStartIntensity() ) / 100 );
217 0 : aStartColor.SetGreen( (sal_uInt8)( (long) aStartColor.GetGreen() * rGradient.GetStartIntensity() ) / 100 );
218 0 : aStartColor.SetBlue( (sal_uInt8)( (long) aStartColor.GetBlue() * rGradient.GetStartIntensity() ) / 100 );
219 :
220 0 : aEndColor.SetRed( (sal_uInt8)( (long) aEndColor.GetRed() * rGradient.GetEndIntensity() ) / 100 );
221 0 : aEndColor.SetGreen( (sal_uInt8)( (long) aEndColor.GetGreen() * rGradient.GetEndIntensity() ) / 100 );
222 0 : aEndColor.SetBlue( (sal_uInt8)( (long) aEndColor.GetBlue() * rGradient.GetEndIntensity() ) / 100 );
223 :
224 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId,
225 0 : ( rGradientId = B2UCONST( "Gradient_" ) ) += ::rtl::OUString::valueOf( nCurGradientId++ ) );
226 :
227 : {
228 0 : ::std::auto_ptr< SvXMLElementExport > apGradient;
229 0 : ::rtl::OUString aColorStr;
230 :
231 0 : if( rGradient.GetStyle() == GradientStyle_LINEAR || rGradient.GetStyle() == GradientStyle_AXIAL )
232 : {
233 0 : Polygon aLinePoly( 2 );
234 :
235 0 : aLinePoly[ 0 ] = Point( aObjRectCenter.X(), aRect.Top() );
236 0 : aLinePoly[ 1 ] = Point( aObjRectCenter.X(), aRect.Bottom() );
237 :
238 0 : aLinePoly.Rotate( aObjRectCenter, nAngle );
239 :
240 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits, B2UCONST( "userSpaceOnUse" ) );
241 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, ::rtl::OUString::valueOf( aLinePoly[ 0 ].X() ) );
242 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, ::rtl::OUString::valueOf( aLinePoly[ 0 ].Y() ) );
243 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, ::rtl::OUString::valueOf( aLinePoly[ 1 ].X() ) );
244 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, ::rtl::OUString::valueOf( aLinePoly[ 1 ].Y() ) );
245 :
246 0 : apGradient.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemLinearGradient, sal_True, sal_True ) );
247 :
248 : // write stop values
249 0 : double fBorder = static_cast< double >( rGradient.GetBorder() ) *
250 0 : ( ( rGradient.GetStyle() == GradientStyle_AXIAL ) ? 0.005 : 0.01 );
251 :
252 0 : ImplGetColorStr( ( rGradient.GetStyle() == GradientStyle_AXIAL ) ? aEndColor : aStartColor, aColorStr );
253 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, ::rtl::OUString::valueOf( fBorder ) );
254 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
255 :
256 : {
257 0 : SvXMLElementExport aDesc2( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
258 : }
259 :
260 0 : if( rGradient.GetStyle() == GradientStyle_AXIAL )
261 : {
262 0 : ImplGetColorStr( aStartColor, aColorStr );
263 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, ::rtl::OUString::valueOf( 0.5 ) );
264 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
265 :
266 : {
267 0 : SvXMLElementExport aDesc3( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
268 : }
269 : }
270 :
271 0 : if( rGradient.GetStyle() != GradientStyle_AXIAL )
272 0 : fBorder = 0.0;
273 :
274 0 : ImplGetColorStr( aEndColor, aColorStr );
275 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, ::rtl::OUString::valueOf( ImplRound( 1.0 - fBorder ) ) );
276 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
277 :
278 : {
279 0 : SvXMLElementExport aDesc4( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
280 0 : }
281 : }
282 : else
283 : {
284 0 : const double fCenterX = rObjRect.Left() + rObjRect.GetWidth() * rGradient.GetOfsX() * 0.01;
285 0 : const double fCenterY = rObjRect.Top() + rObjRect.GetHeight() * rGradient.GetOfsY() * 0.01;
286 0 : const double fRadius = sqrt( static_cast< double >( rObjRect.GetWidth() ) * rObjRect.GetWidth() +
287 0 : rObjRect.GetHeight() * rObjRect.GetHeight() ) * 0.5;
288 :
289 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits, B2UCONST( "userSpaceOnUse" ) );
290 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCX, ::rtl::OUString::valueOf( ImplRound( fCenterX ) ) );
291 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCY, ::rtl::OUString::valueOf( ImplRound( fCenterY ) ) );
292 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrR, ::rtl::OUString::valueOf( ImplRound( fRadius ) ) );
293 :
294 0 : apGradient.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemRadialGradient, sal_True, sal_True ) );
295 :
296 : // write stop values
297 0 : ImplGetColorStr( aEndColor, aColorStr );
298 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, ::rtl::OUString::valueOf( 0.0 ) );
299 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
300 :
301 : {
302 0 : SvXMLElementExport aDesc5( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
303 : }
304 :
305 0 : ImplGetColorStr( aStartColor, aColorStr );
306 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset,
307 0 : ::rtl::OUString::valueOf( ImplRound( 1.0 - rGradient.GetBorder() * 0.01 ) ) );
308 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
309 :
310 : {
311 0 : SvXMLElementExport aDesc6( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
312 : }
313 0 : }
314 0 : }
315 : }
316 : else
317 0 : rGradientId = ::rtl::OUString();
318 0 : }
319 :
320 : // -----------------------------------------------------------------------------
321 :
322 0 : void SVGAttributeWriter::SetFontAttr( const Font& rFont )
323 : {
324 0 : if( rFont != maCurFont )
325 : {
326 0 : ::rtl::OUString aFontStyle, aFontWeight, aTextDecoration;
327 : sal_Int32 nFontWeight;
328 :
329 0 : maCurFont = rFont;
330 :
331 : // Font Family
332 0 : setFontFamily();
333 :
334 : // Font Size
335 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontSize,
336 0 : ::rtl::OUString::valueOf( rFont.GetHeight() ) + B2UCONST( "px" ) );
337 :
338 : // Font Style
339 0 : if( rFont.GetItalic() != ITALIC_NONE )
340 : {
341 0 : if( rFont.GetItalic() == ITALIC_OBLIQUE )
342 0 : aFontStyle = B2UCONST( "oblique" );
343 : else
344 0 : aFontStyle = B2UCONST( "italic" );
345 : }
346 : else
347 0 : aFontStyle = B2UCONST( "normal" );
348 :
349 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontStyle, aFontStyle );
350 :
351 : // Font Weight
352 0 : switch( rFont.GetWeight() )
353 : {
354 0 : case WEIGHT_THIN: nFontWeight = 100; break;
355 0 : case WEIGHT_ULTRALIGHT: nFontWeight = 200; break;
356 0 : case WEIGHT_LIGHT: nFontWeight = 300; break;
357 0 : case WEIGHT_SEMILIGHT: nFontWeight = 400; break;
358 0 : case WEIGHT_NORMAL: nFontWeight = 400; break;
359 0 : case WEIGHT_MEDIUM: nFontWeight = 500; break;
360 0 : case WEIGHT_SEMIBOLD: nFontWeight = 600; break;
361 0 : case WEIGHT_BOLD: nFontWeight = 700; break;
362 0 : case WEIGHT_ULTRABOLD: nFontWeight = 800; break;
363 0 : case WEIGHT_BLACK: nFontWeight = 900; break;
364 0 : default: nFontWeight = 400; break;
365 : }
366 :
367 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontWeight, ::rtl::OUString::valueOf( nFontWeight ) );
368 :
369 0 : if( mrExport.IsUseNativeTextDecoration() )
370 : {
371 0 : if( rFont.GetUnderline() != UNDERLINE_NONE || rFont.GetStrikeout() != STRIKEOUT_NONE )
372 : {
373 0 : if( rFont.GetUnderline() != UNDERLINE_NONE )
374 0 : aTextDecoration = B2UCONST( "underline " );
375 :
376 0 : if( rFont.GetStrikeout() != STRIKEOUT_NONE )
377 0 : aTextDecoration += B2UCONST( "line-through " );
378 : }
379 : else
380 0 : aTextDecoration = B2UCONST( "none" );
381 :
382 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTextDecoration, aTextDecoration );
383 : }
384 :
385 0 : startFontSettings();
386 : }
387 0 : }
388 :
389 0 : void SVGAttributeWriter::startFontSettings()
390 : {
391 0 : endFontSettings();
392 0 : if( mrExport.IsUsePositionedCharacters() )
393 : {
394 0 : mpElemFont = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
395 : }
396 : else
397 : {
398 0 : mpElemFont = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, sal_True, sal_True );
399 : }
400 0 : }
401 :
402 0 : void SVGAttributeWriter::endFontSettings()
403 : {
404 0 : if( mpElemFont )
405 : {
406 0 : delete mpElemFont;
407 0 : mpElemFont = NULL;
408 : }
409 0 : }
410 :
411 0 : void SVGAttributeWriter::setFontFamily()
412 : {
413 0 : if( mrExport.IsUsePositionedCharacters() )
414 : {
415 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontFamily, mrFontExport.GetMappedFontName( maCurFont.GetName() ) );
416 : }
417 : else
418 : {
419 0 : sal_Int32 nNextTokenPos( 0 );
420 0 : const ::rtl::OUString& rsFontName = maCurFont.GetName();
421 0 : ::rtl::OUString sFontFamily( rsFontName.getToken( 0, ';', nNextTokenPos ) );
422 0 : FontPitch ePitch = maCurFont.GetPitch();
423 0 : if( ePitch == PITCH_FIXED )
424 : {
425 0 : sFontFamily += B2UCONST( ", monospace" );
426 : }
427 : else
428 : {
429 0 : FontFamily eFamily = maCurFont.GetFamily();
430 0 : if( eFamily == FAMILY_ROMAN )
431 0 : sFontFamily += B2UCONST( ", serif" );
432 0 : else if( eFamily == FAMILY_SWISS )
433 0 : sFontFamily += B2UCONST( ", sans-serif" );
434 : }
435 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontFamily, sFontFamily );
436 : }
437 0 : }
438 :
439 : // -------------------
440 : // - SVGTextWriter -
441 : // -------------------
442 :
443 0 : SVGTextWriter::SVGTextWriter( SVGExport& rExport )
444 : : mrExport( rExport ),
445 : mpContext( NULL ),
446 : mpVDev( NULL ),
447 : mbIsTextShapeStarted( sal_False ),
448 : mrTextShape(),
449 : msShapeId(),
450 : mrParagraphEnumeration(),
451 : mrCurrentTextParagraph(),
452 : mrTextPortionEnumeration(),
453 : mrCurrentTextPortion(),
454 : mpTextEmbeddedBitmapMtf( NULL ),
455 : mpTargetMapMode( NULL ),
456 : mpTextShapeElem( NULL ),
457 : mpTextParagraphElem( NULL ),
458 : mpTextPositionElem( NULL ),
459 : mnLeftTextPortionLength( 0 ),
460 : maTextPos(0,0),
461 : mnTextWidth(0),
462 : mbPositioningNeeded( sal_False ),
463 : mbIsNewListItem( sal_False ),
464 : maBulletListItemMap(),
465 : mbIsListLevelStyleImage( sal_False ),
466 : mbLineBreak( sal_False ),
467 : mbIsURLField( sal_False ),
468 : msUrl(),
469 : mbIsPlacehlolderShape( sal_False ),
470 : mbIWS( sal_False ),
471 : maCurrentFont(),
472 0 : maParentFont()
473 : {
474 0 : }
475 :
476 : // -----------------------------------------------------------------------------
477 :
478 0 : SVGTextWriter::~SVGTextWriter()
479 : {
480 0 : endTextParagraph();
481 0 : }
482 :
483 : // -----------------------------------------------------------------------------
484 :
485 0 : void SVGTextWriter::implRegisterInterface( const Reference< XInterface >& rxIf )
486 : {
487 0 : if( rxIf.is() )
488 0 : (mrExport.getInterfaceToIdentifierMapper()).registerReference( rxIf );
489 0 : }
490 :
491 : // -----------------------------------------------------------------------------
492 :
493 0 : const ::rtl::OUString & SVGTextWriter::implGetValidIDFromInterface( const Reference< XInterface >& rxIf )
494 : {
495 0 : return (mrExport.getInterfaceToIdentifierMapper()).getIdentifier( rxIf );
496 : }
497 :
498 : // -----------------------------------------------------------------------------
499 :
500 0 : void SVGTextWriter::implMap( const Size& rSz, Size& rDstSz ) const
501 : {
502 0 : if( mpVDev && mpTargetMapMode )
503 0 : rDstSz = mpVDev->LogicToLogic( rSz, mpVDev->GetMapMode(), *mpTargetMapMode );
504 : else
505 : OSL_FAIL( "SVGTextWriter::implMap: invalid virtual device or map mode." );
506 0 : }
507 :
508 : // -----------------------------------------------------------------------------
509 :
510 0 : void SVGTextWriter::implMap( const Point& rPt, Point& rDstPt ) const
511 : {
512 0 : if( mpVDev && mpTargetMapMode )
513 0 : rDstPt = mpVDev->LogicToLogic( rPt, mpVDev->GetMapMode(), *mpTargetMapMode );
514 : else
515 : OSL_FAIL( "SVGTextWriter::implMap: invalid virtual device or map mode." );
516 0 : }
517 :
518 : // -----------------------------------------------------------------------------
519 :
520 0 : void SVGTextWriter::implSetCurrentFont()
521 : {
522 0 : if( mpVDev )
523 : {
524 0 : maCurrentFont = mpVDev->GetFont();
525 0 : Size aSz;
526 :
527 0 : implMap( Size( 0, maCurrentFont.GetHeight() ), aSz );
528 :
529 0 : maCurrentFont.SetHeight( aSz.Height() );
530 : }
531 : else
532 : {
533 : OSL_FAIL( "SVGTextWriter::implSetCorrectFontHeight: invalid virtual device." );
534 : }
535 0 : }
536 : // -----------------------------------------------------------------------------
537 :
538 : template< typename SubType >
539 0 : sal_Bool SVGTextWriter::implGetTextPosition( const MetaAction* pAction, Point& raPos, sal_Bool& rbEmpty )
540 : {
541 0 : const SubType* pA = (const SubType*) pAction;
542 0 : sal_uInt16 nLength = pA->GetLen();
543 0 : rbEmpty = ( nLength == 0 );
544 0 : if( !rbEmpty )
545 : {
546 0 : raPos = pA->GetPoint();
547 0 : return sal_True;
548 : }
549 0 : return sal_False;
550 : }
551 :
552 : // -----------------------------------------------------------------------------
553 :
554 : template<>
555 0 : sal_Bool SVGTextWriter::implGetTextPosition<MetaTextRectAction>( const MetaAction* pAction, Point& raPos, sal_Bool& rbEmpty )
556 : {
557 0 : const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction;
558 0 : sal_uInt16 nLength = pA->GetText().getLength();
559 0 : rbEmpty = ( nLength == 0 );
560 0 : if( !rbEmpty )
561 : {
562 0 : raPos = pA->GetRect().TopLeft();
563 0 : return sal_True;
564 : }
565 0 : return sal_False;
566 : }
567 :
568 : // -----------------------------------------------------------------------------
569 :
570 : template< typename SubType >
571 0 : sal_Bool SVGTextWriter::implGetTextPositionFromBitmap( const MetaAction* pAction, Point& raPos, sal_Bool& rbEmpty )
572 : {
573 0 : const SubType* pA = (const SubType*) pAction;
574 0 : raPos = pA->GetPoint();
575 0 : rbEmpty = sal_False;
576 0 : return sal_True;
577 : }
578 :
579 : // -----------------------------------------------------------------------------
580 :
581 : /** setTextPosition
582 : * Set the start position of the next line of text. In case no text is found
583 : * the current action index is updated to the index value we reached while
584 : * searching for text.
585 : *
586 : * @returns {sal_Int32}
587 : * -2 if no text found and end of line is reached
588 : * -1 if no text found and end of paragraph is reached
589 : * 0 if no text found and end of text shape is reached
590 : * 1 if text found!
591 : */
592 0 : sal_Int32 SVGTextWriter::setTextPosition( const GDIMetaFile& rMtf, sal_uLong& nCurAction )
593 : {
594 0 : Point aPos;
595 0 : sal_uLong nCount = rMtf.GetActionSize();
596 0 : sal_Bool bEOL = sal_False;
597 0 : sal_Bool bEOP = sal_False;
598 0 : sal_Bool bETS = sal_False;
599 0 : sal_Bool bConfigured = sal_False;
600 0 : sal_Bool bEmpty = sal_True;
601 :
602 0 : sal_uLong nActionIndex = nCurAction + 1;
603 0 : for( ; nActionIndex < nCount; ++nActionIndex )
604 : {
605 0 : const MetaAction* pAction = rMtf.GetAction( nActionIndex );
606 0 : const sal_uInt16 nType = pAction->GetType();
607 :
608 0 : switch( nType )
609 : {
610 : case( META_TEXT_ACTION ):
611 : {
612 0 : bConfigured = implGetTextPosition<MetaTextAction>( pAction, aPos, bEmpty );
613 : }
614 0 : break;
615 :
616 : case( META_TEXTRECT_ACTION ):
617 : {
618 0 : bConfigured = implGetTextPosition<MetaTextRectAction>( pAction, aPos, bEmpty );
619 : }
620 0 : break;
621 :
622 : case( META_TEXTARRAY_ACTION ):
623 : {
624 0 : bConfigured = implGetTextPosition<MetaTextArrayAction>( pAction, aPos, bEmpty );
625 : }
626 0 : break;
627 :
628 : case( META_STRETCHTEXT_ACTION ):
629 : {
630 0 : bConfigured = implGetTextPosition<MetaStretchTextAction>( pAction, aPos, bEmpty );
631 : }
632 0 : break;
633 :
634 : case( META_BMPSCALE_ACTION ):
635 : {
636 0 : bConfigured = implGetTextPositionFromBitmap<MetaBmpScaleAction>( pAction, aPos, bEmpty );
637 : }
638 0 : break;
639 :
640 : case( META_BMPEXSCALE_ACTION ):
641 : {
642 0 : bConfigured = implGetTextPositionFromBitmap<MetaBmpExScaleAction>( pAction, aPos, bEmpty );
643 : }
644 0 : break;
645 :
646 : // If we reach the end of the current line, paragraph or text shape
647 : // without finding any text we stop searching
648 : case( META_COMMENT_ACTION ):
649 : {
650 0 : const MetaCommentAction* pA = (const MetaCommentAction*) pAction;
651 0 : const ::rtl::OString& rsComment = pA->GetComment();
652 0 : if( rsComment.equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_EOL" ) ) )
653 : {
654 0 : bEOL = true;
655 : }
656 0 : else if( rsComment.equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_EOP" ) ) )
657 : {
658 0 : bEOP = true;
659 :
660 0 : ::rtl::OUString sContent;
661 0 : while( nextTextPortion() )
662 : {
663 0 : sContent = mrCurrentTextPortion->getString();
664 0 : if( sContent.isEmpty() )
665 : {
666 0 : continue;
667 : }
668 : else
669 : {
670 0 : if( sContent.equalsAscii( "\n" ) )
671 0 : mbLineBreak = sal_True;
672 : }
673 : }
674 0 : if( nextParagraph() )
675 : {
676 0 : while( nextTextPortion() )
677 : {
678 0 : sContent = mrCurrentTextPortion->getString();
679 0 : if( sContent.isEmpty() )
680 : {
681 0 : continue;
682 : }
683 : else
684 : {
685 0 : if( sContent.equalsAscii( "\n" ) )
686 0 : mbLineBreak = sal_True;
687 : }
688 : }
689 0 : }
690 : }
691 0 : else if( rsComment.equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_PAINTSHAPE_END" ) ) )
692 : {
693 0 : bETS = true;
694 : }
695 : }
696 0 : break;
697 : }
698 0 : if( bConfigured || bEOL || bEOP || bETS ) break;
699 : }
700 0 : implMap( aPos, maTextPos );
701 :
702 0 : if( bEmpty )
703 : {
704 0 : nCurAction = nActionIndex;
705 0 : return ( (bEOL) ? -2 : ( (bEOP) ? -1 : 0 ) );
706 : }
707 : else
708 : {
709 0 : return 1;
710 : }
711 : }
712 :
713 : // -----------------------------------------------------------------------------
714 :
715 0 : void SVGTextWriter::setTextProperties( const GDIMetaFile& rMtf, sal_uLong nCurAction )
716 : {
717 0 : sal_uLong nCount = rMtf.GetActionSize();
718 0 : sal_Bool bEOP = sal_False;
719 0 : sal_Bool bConfigured = sal_False;
720 0 : for( sal_uLong nActionIndex = nCurAction + 1; nActionIndex < nCount; ++nActionIndex )
721 : {
722 0 : const MetaAction* pAction = rMtf.GetAction( nActionIndex );
723 0 : const sal_uInt16 nType = pAction->GetType();
724 0 : switch( nType )
725 : {
726 : case( META_TEXTLINECOLOR_ACTION ):
727 : case( META_TEXTFILLCOLOR_ACTION ):
728 : case( META_TEXTCOLOR_ACTION ):
729 : case( META_TEXTALIGN_ACTION ):
730 : case( META_FONT_ACTION ):
731 : case( META_LAYOUTMODE_ACTION ):
732 : {
733 0 : ( (MetaAction*) pAction )->Execute( mpVDev );
734 : }
735 0 : break;
736 :
737 : case( META_TEXT_ACTION ):
738 : {
739 0 : const MetaTextAction* pA = (const MetaTextAction*) pAction;
740 0 : if( pA->GetLen() > 2 )
741 0 : bConfigured = true;
742 : }
743 0 : break;
744 : case( META_TEXTRECT_ACTION ):
745 : {
746 0 : const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction;
747 0 : if( pA->GetText().getLength() > 2 )
748 0 : bConfigured = true;
749 : }
750 0 : break;
751 : case( META_TEXTARRAY_ACTION ):
752 : {
753 0 : const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pAction;
754 0 : if( pA->GetLen() > 2 )
755 0 : bConfigured = true;
756 : }
757 0 : break;
758 : case( META_STRETCHTEXT_ACTION ):
759 : {
760 0 : const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction;
761 0 : if( pA->GetLen() > 2 )
762 0 : bConfigured = true;
763 : }
764 0 : break;
765 : // If we reach the end of the paragraph without finding any text
766 : // we stop searching
767 : case( META_COMMENT_ACTION ):
768 : {
769 0 : const MetaCommentAction* pA = (const MetaCommentAction*) pAction;
770 0 : const ::rtl::OString& rsComment = pA->GetComment();
771 0 : if( rsComment.equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_EOP" ) ) )
772 : {
773 0 : bEOP = true;
774 : }
775 : }
776 0 : break;
777 : }
778 0 : if( bConfigured || bEOP ) break;
779 : }
780 0 : }
781 :
782 : // -----------------------------------------------------------------------------
783 :
784 0 : void SVGTextWriter::addFontAttributes( sal_Bool bIsTextContainer )
785 : {
786 0 : implSetCurrentFont();
787 :
788 0 : if( maCurrentFont != maParentFont )
789 : {
790 0 : const String& rsCurFontName = maCurrentFont.GetName();
791 0 : long int nCurFontSize = maCurrentFont.GetHeight();
792 0 : FontItalic eCurFontItalic = maCurrentFont.GetItalic();
793 0 : FontWeight eCurFontWeight = maCurrentFont.GetWeight();
794 :
795 0 : const String& rsParFontName = maParentFont.GetName();
796 0 : long int nParFontSize = maParentFont.GetHeight();
797 0 : FontItalic eParFontItalic = maParentFont.GetItalic();
798 0 : FontWeight eParFontWeight = maParentFont.GetWeight();
799 :
800 :
801 : // Font Family
802 0 : if( rsCurFontName != rsParFontName )
803 : {
804 0 : implSetFontFamily();
805 : }
806 :
807 : // Font Size
808 0 : if( nCurFontSize != nParFontSize )
809 : {
810 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontSize,
811 0 : ::rtl::OUString::valueOf( nCurFontSize ) + B2UCONST( "px" ) );
812 : }
813 :
814 : // Font Style
815 0 : if( eCurFontItalic != eParFontItalic )
816 : {
817 0 : ::rtl::OUString sFontStyle;
818 0 : if( eCurFontItalic != ITALIC_NONE )
819 : {
820 0 : if( eCurFontItalic == ITALIC_OBLIQUE )
821 0 : sFontStyle = B2UCONST( "oblique" );
822 : else
823 0 : sFontStyle = B2UCONST( "italic" );
824 : }
825 : else
826 : {
827 0 : sFontStyle = B2UCONST( "normal" );
828 : }
829 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontStyle, sFontStyle );
830 : }
831 :
832 : // Font Weight
833 0 : if( eCurFontWeight != eParFontWeight )
834 : {
835 : sal_Int32 nFontWeight;
836 0 : switch( eCurFontWeight )
837 : {
838 0 : case WEIGHT_THIN: nFontWeight = 100; break;
839 0 : case WEIGHT_ULTRALIGHT: nFontWeight = 200; break;
840 0 : case WEIGHT_LIGHT: nFontWeight = 300; break;
841 0 : case WEIGHT_SEMILIGHT: nFontWeight = 400; break;
842 0 : case WEIGHT_NORMAL: nFontWeight = 400; break;
843 0 : case WEIGHT_MEDIUM: nFontWeight = 500; break;
844 0 : case WEIGHT_SEMIBOLD: nFontWeight = 600; break;
845 0 : case WEIGHT_BOLD: nFontWeight = 700; break;
846 0 : case WEIGHT_ULTRABOLD: nFontWeight = 800; break;
847 0 : case WEIGHT_BLACK: nFontWeight = 900; break;
848 0 : default: nFontWeight = 400; break;
849 : }
850 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontWeight, ::rtl::OUString::valueOf( nFontWeight ) );
851 : }
852 :
853 0 : if( bIsTextContainer )
854 0 : maParentFont = maCurrentFont;
855 : }
856 :
857 0 : if( mrExport.IsUseNativeTextDecoration() )
858 : {
859 0 : FontUnderline eCurFontUnderline = maCurrentFont.GetUnderline();
860 0 : FontStrikeout eCurFontStrikeout = maCurrentFont.GetStrikeout();
861 :
862 0 : FontUnderline eParFontUnderline = maParentFont.GetUnderline();
863 0 : FontStrikeout eParFontStrikeout = maParentFont.GetStrikeout();
864 :
865 0 : ::rtl::OUString sTextDecoration;
866 :
867 0 : if( eCurFontUnderline != eParFontUnderline )
868 : {
869 0 : if( eCurFontUnderline != UNDERLINE_NONE )
870 0 : sTextDecoration = B2UCONST( "underline " );
871 : }
872 0 : if( eCurFontStrikeout != eParFontStrikeout )
873 : {
874 0 : if( eCurFontStrikeout != STRIKEOUT_NONE )
875 0 : sTextDecoration += B2UCONST( "line-through " );
876 : }
877 0 : if( !sTextDecoration.isEmpty() )
878 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTextDecoration, sTextDecoration );
879 : }
880 0 : }
881 :
882 : // -----------------------------------------------------------------------------
883 :
884 0 : void SVGTextWriter::implSetFontFamily()
885 : {
886 0 : sal_Int32 nNextTokenPos( 0 );
887 0 : const ::rtl::OUString& rsFontName = maCurrentFont.GetName();
888 0 : ::rtl::OUString sFontFamily( rsFontName.getToken( 0, ';', nNextTokenPos ) );
889 0 : FontPitch ePitch = maCurrentFont.GetPitch();
890 0 : if( ePitch == PITCH_FIXED )
891 : {
892 0 : sFontFamily += B2UCONST( ", monospace" );
893 : }
894 : else
895 : {
896 0 : FontFamily eFamily = maCurrentFont.GetFamily();
897 0 : if( eFamily == FAMILY_ROMAN )
898 0 : sFontFamily += B2UCONST( ", serif" );
899 0 : else if( eFamily == FAMILY_SWISS )
900 0 : sFontFamily += B2UCONST( ", sans-serif" );
901 : }
902 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontFamily, sFontFamily );
903 0 : }
904 :
905 : // -----------------------------------------------------------------------------
906 :
907 0 : sal_Bool SVGTextWriter::createParagraphEnumeration()
908 : {
909 0 : if( mrTextShape.is() )
910 : {
911 0 : Reference< XInterface > xRef( mrTextShape, UNO_QUERY );
912 0 : msShapeId = implGetValidIDFromInterface( xRef );
913 :
914 0 : Reference< XEnumerationAccess > xEnumerationAccess( mrTextShape, UNO_QUERY_THROW );
915 0 : Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
916 0 : if( xEnumeration.is() )
917 : {
918 0 : mrParagraphEnumeration.set( xEnumeration );
919 0 : return sal_True;
920 : }
921 : else
922 : {
923 : OSL_FAIL( "SVGTextWriter::createParagraphEnumeration: no valid xEnumeration interface found." );
924 0 : }
925 : }
926 : else
927 : {
928 : OSL_FAIL( "SVGTextWriter::createParagraphEnumeration: no valid XText interface found." );
929 : }
930 0 : return sal_False;
931 : }
932 :
933 : // -----------------------------------------------------------------------------
934 :
935 0 : sal_Bool SVGTextWriter::nextParagraph()
936 : {
937 0 : mrTextPortionEnumeration.clear();
938 0 : mrCurrentTextParagraph.clear();
939 0 : mbIsNewListItem = sal_False;
940 0 : mbIsListLevelStyleImage = sal_False;
941 :
942 : #if OSL_DEBUG_LEVEL > 0
943 : if( mrParagraphEnumeration.is() && mrParagraphEnumeration->hasMoreElements() )
944 : {
945 : Reference < XTextContent > xTextContent( mrParagraphEnumeration->nextElement(), UNO_QUERY_THROW );
946 : if( xTextContent.is() )
947 : {
948 : Reference< XServiceInfo > xServiceInfo( xTextContent, UNO_QUERY_THROW );
949 : if( xServiceInfo.is() )
950 : {
951 : OUString sInfo;
952 : if( xServiceInfo->supportsService( B2UCONST( "com.sun.star.text.Paragraph" ) ) )
953 : {
954 : mrCurrentTextParagraph.set( xTextContent );
955 : Reference< XPropertySet > xPropSet( xTextContent, UNO_QUERY_THROW );
956 : Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
957 : if( xPropSetInfo->hasPropertyByName( B2UCONST( "NumberingLevel" ) ) )
958 : {
959 : sal_Int16 nListLevel = 0;
960 : if( xPropSet->getPropertyValue( B2UCONST( "NumberingLevel" ) ) >>= nListLevel )
961 : {
962 : mbIsNewListItem = sal_True;
963 : sInfo = B2UCONST( "NumberingLevel: " );
964 : sInfo += OUString::valueOf( (sal_Int32)nListLevel );
965 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "style", sInfo );
966 :
967 : Reference< XIndexReplace > xNumRules;
968 : if( xPropSetInfo->hasPropertyByName( B2UCONST( "NumberingRules" ) ) )
969 : {
970 : xPropSet->getPropertyValue( B2UCONST( "NumberingRules" ) ) >>= xNumRules;
971 : }
972 : if( xNumRules.is() && ( nListLevel < xNumRules->getCount() ) )
973 : {
974 : sal_Bool bIsNumbered = sal_True;
975 : OUString msNumberingIsNumber(RTL_CONSTASCII_USTRINGPARAM("NumberingIsNumber"));
976 : if( xPropSetInfo->hasPropertyByName( msNumberingIsNumber ) )
977 : {
978 : if( !(xPropSet->getPropertyValue( msNumberingIsNumber ) >>= bIsNumbered ) )
979 : {
980 : OSL_FAIL( "numbered paragraph without number info" );
981 : bIsNumbered = sal_False;
982 : }
983 : if( bIsNumbered )
984 : {
985 : sInfo = B2UCONST( "true" );
986 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "is-numbered", sInfo );
987 : }
988 : }
989 : mbIsNewListItem = bIsNumbered;
990 :
991 : if( bIsNumbered )
992 : {
993 : Sequence<PropertyValue> aProps;
994 : if( xNumRules->getByIndex( nListLevel ) >>= aProps )
995 : {
996 : sal_Int16 eType = NumberingType::CHAR_SPECIAL;
997 : sal_Unicode cBullet = 0xf095;
998 : const sal_Int32 nCount = aProps.getLength();
999 : const PropertyValue* pPropArray = aProps.getConstArray();
1000 : for( sal_Int32 i = 0; i < nCount; ++i )
1001 : {
1002 : const PropertyValue& rProp = pPropArray[i];
1003 : if( rProp.Name.equalsAsciiL( XML_UNO_NAME_NRULE_NUMBERINGTYPE, sizeof(XML_UNO_NAME_NRULE_NUMBERINGTYPE)-1 ) )
1004 : {
1005 : rProp.Value >>= eType;
1006 : }
1007 : else if( rProp.Name.equalsAsciiL( XML_UNO_NAME_NRULE_BULLET_CHAR, sizeof(XML_UNO_NAME_NRULE_BULLET_CHAR)-1 ) )
1008 : {
1009 : OUString sValue;
1010 : rProp.Value >>= sValue;
1011 : if( !sValue.isEmpty() )
1012 : {
1013 : cBullet = (sal_Unicode)sValue[0];
1014 : }
1015 : }
1016 : }
1017 : meNumberingType = eType;
1018 : mbIsListLevelStyleImage = ( NumberingType::BITMAP == meNumberingType );
1019 : if( NumberingType::CHAR_SPECIAL == meNumberingType )
1020 : {
1021 : if( cBullet )
1022 : {
1023 : if( cBullet < ' ' )
1024 : {
1025 : cBullet = 0xF000 + 149;
1026 : }
1027 : mcBulletChar = cBullet;
1028 : sInfo = OUString::valueOf( (sal_Int32) cBullet );
1029 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "bullet-char", sInfo );
1030 : }
1031 :
1032 : }
1033 : }
1034 : }
1035 : }
1036 :
1037 : }
1038 : }
1039 :
1040 : Reference< XEnumerationAccess > xEnumerationAccess( xTextContent, UNO_QUERY_THROW );
1041 : Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1042 : if( xEnumeration.is() && xEnumeration->hasMoreElements() )
1043 : {
1044 : mrTextPortionEnumeration.set( xEnumeration );
1045 : }
1046 : sInfo = B2UCONST( "Paragraph" );
1047 : }
1048 : else if( xServiceInfo->supportsService( B2UCONST( "com.sun.star.text.Table" ) ) )
1049 : {
1050 : OSL_FAIL( "SVGTextWriter::nextParagraph: text tables are not handled." );
1051 : sInfo = B2UCONST( "Table" );
1052 : }
1053 : else
1054 : {
1055 : OSL_FAIL( "SVGTextWriter::nextParagraph: Unknown text content." );
1056 : return sal_False;
1057 : }
1058 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", sInfo );
1059 : SvXMLElementExport aParaElem( mrExport, XML_NAMESPACE_NONE, "desc", mbIWS, mbIWS );
1060 : }
1061 : else
1062 : {
1063 : OSL_FAIL( "SVGTextWriter::nextParagraph: no XServiceInfo interface available for text content." );
1064 : return sal_False;
1065 : }
1066 :
1067 : Reference< XInterface > xRef( xTextContent, UNO_QUERY );
1068 : const OUString& rParagraphId = implGetValidIDFromInterface( xRef );
1069 : if( !rParagraphId.isEmpty() )
1070 : {
1071 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", rParagraphId );
1072 : }
1073 : return sal_True;
1074 : }
1075 : }
1076 : #else
1077 0 : if( mrParagraphEnumeration.is() && mrParagraphEnumeration->hasMoreElements() )
1078 : {
1079 0 : Reference < XTextContent > xTextContent( mrParagraphEnumeration->nextElement(), UNO_QUERY_THROW );
1080 0 : if( xTextContent.is() )
1081 : {
1082 0 : Reference< XServiceInfo > xServiceInfo( xTextContent, UNO_QUERY_THROW );
1083 0 : if( xServiceInfo.is() )
1084 : {
1085 0 : if( xServiceInfo->supportsService( B2UCONST( "com.sun.star.text.Paragraph" ) ) )
1086 : {
1087 0 : mrCurrentTextParagraph.set( xTextContent );
1088 0 : Reference< XPropertySet > xPropSet( xTextContent, UNO_QUERY_THROW );
1089 0 : Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1090 0 : if( xPropSetInfo->hasPropertyByName( B2UCONST( "NumberingLevel" ) ) )
1091 : {
1092 0 : sal_Int16 nListLevel = 0;
1093 0 : if( xPropSet->getPropertyValue( B2UCONST( "NumberingLevel" ) ) >>= nListLevel )
1094 : {
1095 0 : mbIsNewListItem = sal_True;
1096 :
1097 0 : Reference< XIndexReplace > xNumRules;
1098 0 : if( xPropSetInfo->hasPropertyByName( B2UCONST( "NumberingRules" ) ) )
1099 : {
1100 0 : xPropSet->getPropertyValue( B2UCONST( "NumberingRules" ) ) >>= xNumRules;
1101 : }
1102 0 : if( xNumRules.is() && ( nListLevel < xNumRules->getCount() ) )
1103 : {
1104 0 : sal_Bool bIsNumbered = sal_True;
1105 0 : OUString msNumberingIsNumber(RTL_CONSTASCII_USTRINGPARAM("NumberingIsNumber"));
1106 0 : if( xPropSetInfo->hasPropertyByName( msNumberingIsNumber ) )
1107 : {
1108 0 : if( !(xPropSet->getPropertyValue( msNumberingIsNumber ) >>= bIsNumbered ) )
1109 : {
1110 : OSL_FAIL( "numbered paragraph without number info" );
1111 0 : bIsNumbered = sal_False;
1112 : }
1113 : }
1114 0 : mbIsNewListItem = bIsNumbered;
1115 :
1116 0 : if( bIsNumbered )
1117 : {
1118 0 : Sequence<PropertyValue> aProps;
1119 0 : if( xNumRules->getByIndex( nListLevel ) >>= aProps )
1120 : {
1121 0 : sal_Int16 eType = NumberingType::CHAR_SPECIAL;
1122 0 : sal_Unicode cBullet = 0xf095;
1123 0 : const sal_Int32 nCount = aProps.getLength();
1124 0 : const PropertyValue* pPropArray = aProps.getConstArray();
1125 0 : for( sal_Int32 i = 0; i < nCount; ++i )
1126 : {
1127 0 : const PropertyValue& rProp = pPropArray[i];
1128 0 : if( rProp.Name.equalsAsciiL( XML_UNO_NAME_NRULE_NUMBERINGTYPE, sizeof(XML_UNO_NAME_NRULE_NUMBERINGTYPE)-1 ) )
1129 : {
1130 0 : rProp.Value >>= eType;
1131 : }
1132 0 : else if( rProp.Name.equalsAsciiL( XML_UNO_NAME_NRULE_BULLET_CHAR, sizeof(XML_UNO_NAME_NRULE_BULLET_CHAR)-1 ) )
1133 : {
1134 0 : OUString sValue;
1135 0 : rProp.Value >>= sValue;
1136 0 : if( !sValue.isEmpty() )
1137 : {
1138 0 : cBullet = (sal_Unicode)sValue[0];
1139 0 : }
1140 : }
1141 : }
1142 0 : meNumberingType = eType;
1143 0 : mbIsListLevelStyleImage = ( NumberingType::BITMAP == meNumberingType );
1144 0 : if( NumberingType::CHAR_SPECIAL == meNumberingType )
1145 : {
1146 0 : if( cBullet )
1147 : {
1148 0 : if( cBullet < ' ' )
1149 : {
1150 0 : cBullet = 0xF000 + 149;
1151 : }
1152 0 : mcBulletChar = cBullet;
1153 : }
1154 :
1155 : }
1156 0 : }
1157 0 : }
1158 0 : }
1159 :
1160 : }
1161 : }
1162 :
1163 0 : Reference< XEnumerationAccess > xEnumerationAccess( xTextContent, UNO_QUERY_THROW );
1164 0 : Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1165 0 : if( xEnumeration.is() && xEnumeration->hasMoreElements() )
1166 : {
1167 0 : mrTextPortionEnumeration.set( xEnumeration );
1168 0 : }
1169 : }
1170 0 : else if( xServiceInfo->supportsService( B2UCONST( "com.sun.star.text.Table" ) ) )
1171 : {
1172 : OSL_FAIL( "SVGTextWriter::nextParagraph: text tables are not handled." );
1173 : }
1174 : else
1175 : {
1176 : OSL_FAIL( "SVGTextWriter::nextParagraph: Unknown text content." );
1177 0 : return sal_False;
1178 : }
1179 : }
1180 : else
1181 : {
1182 : OSL_FAIL( "SVGTextWriter::nextParagraph: no XServiceInfo interface available for text content." );
1183 0 : return sal_False;
1184 : }
1185 :
1186 0 : Reference< XInterface > xRef( xTextContent, UNO_QUERY );
1187 0 : const OUString& rParagraphId = implGetValidIDFromInterface( xRef );
1188 0 : if( !rParagraphId.isEmpty() )
1189 : {
1190 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", rParagraphId );
1191 : }
1192 0 : return sal_True;
1193 0 : }
1194 : }
1195 : #endif
1196 0 : return sal_False;
1197 : }
1198 :
1199 : // -----------------------------------------------------------------------------
1200 :
1201 0 : sal_Bool SVGTextWriter::nextTextPortion()
1202 : {
1203 0 : mrCurrentTextPortion.clear();
1204 0 : mbIsURLField = sal_False;
1205 0 : mbIsPlacehlolderShape = sal_False;
1206 : #if OSL_DEBUG_LEVEL > 0
1207 : if( mrTextPortionEnumeration.is() && mrTextPortionEnumeration->hasMoreElements() )
1208 : {
1209 : OUString sInfo;
1210 : Reference< XPropertySet > xPortionPropSet( mrTextPortionEnumeration->nextElement(), UNO_QUERY );
1211 : Reference< XPropertySetInfo > xPortionPropInfo( xPortionPropSet->getPropertySetInfo() );
1212 : Reference < XTextRange > xPortionTextRange( xPortionPropSet, UNO_QUERY);
1213 : if( xPortionPropSet.is() && xPortionPropInfo.is()
1214 : && xPortionPropInfo->hasPropertyByName( B2UCONST( "TextPortionType" ) ) )
1215 : {
1216 : ::rtl::OUString sPortionType;
1217 : if( xPortionPropSet->getPropertyValue( B2UCONST( "TextPortionType" ) ) >>= sPortionType )
1218 : {
1219 : sInfo = B2UCONST( "type: " );
1220 : sInfo += sPortionType;
1221 : sInfo += B2UCONST( "; " );
1222 : }
1223 : if( xPortionTextRange.is() )
1224 : {
1225 : sInfo += B2UCONST( "content: " );
1226 : sInfo += xPortionTextRange->getString();
1227 : sInfo += B2UCONST( "; " );
1228 :
1229 : mrCurrentTextPortion.set( xPortionTextRange );
1230 :
1231 : Reference < XPropertySet > xRangePropSet( xPortionTextRange, UNO_QUERY );
1232 : if( xRangePropSet.is() && xRangePropSet->getPropertySetInfo()->hasPropertyByName( B2UCONST( "TextField" ) ) )
1233 : {
1234 : Reference < XTextField > xTextField( xRangePropSet->getPropertyValue( B2UCONST( "TextField" ) ), UNO_QUERY );
1235 : if( xTextField.is() )
1236 : {
1237 : const ::rtl::OUString sServicePrefix( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.textfield.") );
1238 : const ::rtl::OUString sPresentationServicePrefix( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.presentation.TextField.") );
1239 :
1240 : Reference< XServiceInfo > xService( xTextField, UNO_QUERY );
1241 : const Sequence< OUString > aServices = xService->getSupportedServiceNames();
1242 :
1243 : const OUString* pNames = aServices.getConstArray();
1244 : sal_Int32 nCount = aServices.getLength();
1245 :
1246 : OUString sFieldName; // service name postfix of current field
1247 :
1248 : // search for TextField service name
1249 : while( nCount-- )
1250 : {
1251 : if ( pNames->matchIgnoreAsciiCase( sServicePrefix ) )
1252 : {
1253 : // TextField found => postfix is field type!
1254 : sFieldName = pNames->copy( sServicePrefix.getLength() );
1255 : break;
1256 : }
1257 : else if( 0 == pNames->compareTo( sPresentationServicePrefix, sPresentationServicePrefix.getLength() ) )
1258 : {
1259 : // TextField found => postfix is field type!
1260 : sFieldName = pNames->copy( sPresentationServicePrefix.getLength() );
1261 : break;
1262 : }
1263 :
1264 : ++pNames;
1265 : }
1266 :
1267 : sInfo += B2UCONST( "text field type: " );
1268 : sInfo += sFieldName;
1269 : sInfo += B2UCONST( "; " );
1270 :
1271 : sInfo += B2UCONST( "content: " );
1272 : sInfo += xTextField->getPresentation( /* show command: */ sal_False );
1273 : sInfo += B2UCONST( "; " );
1274 :
1275 : if( sFieldName.equalsAscii( "DateTime" ) || sFieldName.equalsAscii( "Header" )
1276 : || sFieldName.equalsAscii( "Footer" ) || sFieldName.equalsAscii( "PageNumber" ) )
1277 : {
1278 : mbIsPlacehlolderShape = sal_True;
1279 : }
1280 : else
1281 : {
1282 : mbIsURLField = sFieldName.equalsAscii( "URL" );
1283 :
1284 : if( mbIsURLField )
1285 : {
1286 : Reference<XPropertySet> xTextFieldPropSet(xTextField, UNO_QUERY);
1287 : if( xTextFieldPropSet.is() )
1288 : {
1289 : OUString sURL;
1290 : if( ( xTextFieldPropSet->getPropertyValue( sFieldName ) ) >>= sURL )
1291 : {
1292 : sInfo += B2UCONST( "url: " );
1293 : sInfo += mrExport.GetRelativeReference( sURL );
1294 :
1295 : msUrl = mrExport.GetRelativeReference( sURL );
1296 : if( !msUrl.isEmpty() )
1297 : {
1298 : implRegisterInterface( xPortionTextRange );
1299 :
1300 : Reference< XInterface > xRef( xPortionTextRange, UNO_QUERY );
1301 : const OUString& rTextPortionId = implGetValidIDFromInterface( xRef );
1302 : if( !rTextPortionId.isEmpty() )
1303 : {
1304 : msHyperlinkIdList += rTextPortionId;
1305 : msHyperlinkIdList += B2UCONST( " " );
1306 : }
1307 : }
1308 : }
1309 : }
1310 : }
1311 : }
1312 : }
1313 : }
1314 : }
1315 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "TextPortion" ) );
1316 : SvXMLElementExport aPortionElem( mrExport, XML_NAMESPACE_NONE, "desc", mbIWS, mbIWS );
1317 : mrExport.GetDocHandler()->characters( sInfo );
1318 : return sal_True;
1319 : }
1320 : }
1321 : #else
1322 0 : if( mrTextPortionEnumeration.is() && mrTextPortionEnumeration->hasMoreElements() )
1323 : {
1324 0 : OUString sInfo;
1325 0 : Reference< XPropertySet > xPortionPropSet( mrTextPortionEnumeration->nextElement(), UNO_QUERY );
1326 0 : Reference< XPropertySetInfo > xPortionPropInfo( xPortionPropSet->getPropertySetInfo() );
1327 0 : Reference < XTextRange > xPortionTextRange( xPortionPropSet, UNO_QUERY);
1328 0 : if( xPortionPropSet.is() && xPortionPropInfo.is()
1329 0 : && xPortionPropInfo->hasPropertyByName( B2UCONST( "TextPortionType" ) ) )
1330 : {
1331 0 : if( xPortionTextRange.is() )
1332 : {
1333 0 : mrCurrentTextPortion.set( xPortionTextRange );
1334 :
1335 0 : Reference < XPropertySet > xRangePropSet( xPortionTextRange, UNO_QUERY );
1336 0 : if( xRangePropSet.is() && xRangePropSet->getPropertySetInfo()->hasPropertyByName( B2UCONST( "TextField" ) ) )
1337 : {
1338 0 : Reference < XTextField > xTextField( xRangePropSet->getPropertyValue( B2UCONST( "TextField" ) ), UNO_QUERY );
1339 0 : if( xTextField.is() )
1340 : {
1341 0 : const ::rtl::OUString sServicePrefix( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.textfield.") );
1342 0 : const ::rtl::OUString sPresentationServicePrefix( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.presentation.TextField.") );
1343 :
1344 0 : Reference< XServiceInfo > xService( xTextField, UNO_QUERY );
1345 0 : const Sequence< OUString > aServices = xService->getSupportedServiceNames();
1346 :
1347 0 : const OUString* pNames = aServices.getConstArray();
1348 0 : sal_Int32 nCount = aServices.getLength();
1349 :
1350 0 : OUString sFieldName; // service name postfix of current field
1351 :
1352 : // search for TextField service name
1353 0 : while( nCount-- )
1354 : {
1355 0 : if ( pNames->matchIgnoreAsciiCase( sServicePrefix ) )
1356 : {
1357 : // TextField found => postfix is field type!
1358 0 : sFieldName = pNames->copy( sServicePrefix.getLength() );
1359 0 : break;
1360 : }
1361 0 : else if( 0 == pNames->compareTo( sPresentationServicePrefix, sPresentationServicePrefix.getLength() ) )
1362 : {
1363 : // TextField found => postfix is field type!
1364 0 : sFieldName = pNames->copy( sPresentationServicePrefix.getLength() );
1365 0 : break;
1366 : }
1367 :
1368 0 : ++pNames;
1369 : }
1370 :
1371 0 : if( sFieldName.equalsAscii( "DateTime" ) || sFieldName.equalsAscii( "Header" )
1372 0 : || sFieldName.equalsAscii( "Footer" ) || sFieldName.equalsAscii( "PageNumber" ) )
1373 : {
1374 0 : mbIsPlacehlolderShape = sal_True;
1375 : }
1376 : else
1377 : {
1378 0 : mbIsURLField = sFieldName.equalsAscii( "URL" );
1379 0 : if( mbIsURLField )
1380 : {
1381 0 : Reference<XPropertySet> xTextFieldPropSet(xTextField, UNO_QUERY);
1382 0 : if( xTextFieldPropSet.is() )
1383 : {
1384 0 : OUString sURL;
1385 0 : if( ( xTextFieldPropSet->getPropertyValue( sFieldName ) ) >>= sURL )
1386 : {
1387 0 : msUrl = mrExport.GetRelativeReference( sURL );
1388 0 : if( !msUrl.isEmpty() )
1389 : {
1390 0 : implRegisterInterface( xPortionTextRange );
1391 :
1392 0 : Reference< XInterface > xRef( xPortionTextRange, UNO_QUERY );
1393 0 : const OUString& rTextPortionId = implGetValidIDFromInterface( xRef );
1394 0 : if( !rTextPortionId.isEmpty() )
1395 : {
1396 0 : msHyperlinkIdList += rTextPortionId;
1397 0 : msHyperlinkIdList += B2UCONST( " " );
1398 0 : }
1399 : }
1400 0 : }
1401 0 : }
1402 : }
1403 0 : }
1404 0 : }
1405 0 : }
1406 : }
1407 0 : return sal_True;
1408 0 : }
1409 : }
1410 : #endif
1411 0 : return sal_False;
1412 : }
1413 :
1414 : // -----------------------------------------------------------------------------
1415 :
1416 0 : void SVGTextWriter::startTextShape()
1417 : {
1418 0 : if( mpTextShapeElem )
1419 : {
1420 : OSL_FAIL( "SVGTextWriter::startTextShape: text shape already defined." );
1421 : }
1422 :
1423 : {
1424 0 : mbIsTextShapeStarted = sal_True;
1425 0 : maParentFont = Font();
1426 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "TextShape" ) );
1427 0 : mpTextShapeElem = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, mbIWS );
1428 0 : startTextParagraph();
1429 : }
1430 0 : }
1431 :
1432 : // -----------------------------------------------------------------------------
1433 :
1434 0 : void SVGTextWriter::endTextShape()
1435 : {
1436 0 : endTextParagraph();
1437 0 : if( mrTextShape.is() )
1438 0 : mrTextShape.clear();
1439 0 : if( mrParagraphEnumeration.is() )
1440 0 : mrParagraphEnumeration.clear();
1441 0 : if( mrCurrentTextParagraph.is() )
1442 0 : mrCurrentTextParagraph.clear();
1443 0 : if( mpTextShapeElem )
1444 : {
1445 0 : delete mpTextShapeElem;
1446 0 : mpTextShapeElem = NULL;
1447 : }
1448 0 : mbIsTextShapeStarted = sal_False;
1449 : // these need to be invoked after the <text> element has been closed
1450 0 : implExportHyperlinkIds();
1451 0 : implWriteBulletChars();
1452 0 : implWriteEmbeddedBitmaps();
1453 :
1454 0 : }
1455 :
1456 : // -----------------------------------------------------------------------------
1457 :
1458 0 : void SVGTextWriter::startTextParagraph()
1459 : {
1460 0 : endTextParagraph();
1461 0 : nextParagraph();
1462 0 : if( mbIsNewListItem )
1463 : {
1464 0 : OUString sNumberingType;
1465 0 : switch( meNumberingType )
1466 : {
1467 : case( NumberingType::CHAR_SPECIAL ):
1468 0 : sNumberingType = B2UCONST( "bullet-style" );
1469 0 : break;
1470 : case( NumberingType::BITMAP ):
1471 0 : sNumberingType = B2UCONST( "image-style" );
1472 0 : break;
1473 : default:
1474 0 : sNumberingType = B2UCONST( "number-style" );
1475 0 : break;
1476 : }
1477 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aOOOAttrNumberingType, sNumberingType );
1478 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "ListItem" ) );
1479 : }
1480 : else
1481 : {
1482 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "TextParagraph" ) );
1483 : }
1484 0 : maParentFont = Font();
1485 0 : addFontAttributes( /* isTexTContainer: */ true );
1486 0 : mpTextParagraphElem = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1487 0 : if( !mbIsListLevelStyleImage )
1488 : {
1489 0 : startTextPosition();
1490 : }
1491 0 : }
1492 :
1493 : // -----------------------------------------------------------------------------
1494 :
1495 0 : void SVGTextWriter::endTextParagraph()
1496 : {
1497 0 : mrCurrentTextPortion.clear();
1498 0 : endTextPosition();
1499 0 : mbIsNewListItem = sal_False;
1500 0 : mbIsListLevelStyleImage = sal_False;
1501 0 : mbPositioningNeeded = sal_False;
1502 :
1503 0 : if( mpTextParagraphElem )
1504 : {
1505 0 : delete mpTextParagraphElem;
1506 0 : mpTextParagraphElem = NULL;
1507 : }
1508 :
1509 0 : }
1510 :
1511 : // -----------------------------------------------------------------------------
1512 :
1513 0 : void SVGTextWriter::startTextPosition( sal_Bool bExportX, sal_Bool bExportY )
1514 : {
1515 0 : endTextPosition();
1516 0 : mnTextWidth = 0;
1517 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "TextPosition" ) );
1518 0 : if( bExportX )
1519 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, ::rtl::OUString::valueOf( maTextPos.X() ) );
1520 0 : if( bExportY )
1521 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( maTextPos.Y() ) );
1522 :
1523 : // if text is rotated, set transform matrix at new tspan element
1524 0 : const Font& rFont = mpVDev->GetFont();
1525 0 : if( rFont.GetOrientation() )
1526 : {
1527 0 : Point aRot( maTextPos );
1528 0 : OUString aTransform( "translate(" );
1529 0 : aTransform += OUString::valueOf( aRot.X() ) + ",";
1530 0 : aTransform += OUString::valueOf( aRot.Y() ) + ")";
1531 :
1532 0 : aTransform += " rotate(";
1533 0 : aTransform += OUString::valueOf( rFont.GetOrientation() * -0.1 );
1534 0 : aTransform += ")";
1535 :
1536 0 : aTransform += " translate(";
1537 0 : aTransform += OUString::valueOf( -aRot.X() ) + ",";
1538 0 : aTransform += OUString::valueOf( -aRot.Y() ) + ")";
1539 :
1540 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform, aTransform );
1541 : }
1542 :
1543 0 : mpTextPositionElem = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1544 0 : }
1545 :
1546 : // -----------------------------------------------------------------------------
1547 :
1548 0 : void SVGTextWriter::endTextPosition()
1549 : {
1550 0 : if( mpTextPositionElem )
1551 : {
1552 0 : delete mpTextPositionElem;
1553 0 : mpTextPositionElem = NULL;
1554 : }
1555 0 : }
1556 :
1557 : // -----------------------------------------------------------------------------
1558 :
1559 0 : void SVGTextWriter::implExportHyperlinkIds()
1560 : {
1561 0 : if( !msHyperlinkIdList.isEmpty() )
1562 : {
1563 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "HyperlinkIdList" ) );
1564 0 : SvXMLElementExport aDescElem( mrExport, XML_NAMESPACE_NONE, "desc", sal_True, sal_False );
1565 0 : mrExport.GetDocHandler()->characters( msHyperlinkIdList.trim() );
1566 0 : msHyperlinkIdList = OUString();
1567 : }
1568 0 : }
1569 :
1570 : // -----------------------------------------------------------------------------
1571 :
1572 0 : void SVGTextWriter::implWriteBulletChars()
1573 : {
1574 0 : if( maBulletListItemMap.empty() )
1575 0 : return;
1576 :
1577 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "BulletChars" ) );
1578 0 : SvXMLElementExport aGroupElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
1579 :
1580 0 : BulletListItemInfoMap::const_iterator it = maBulletListItemMap.begin();
1581 0 : BulletListItemInfoMap::const_iterator end = maBulletListItemMap.end();
1582 0 : OUString sId, sPosition, sScaling, sRefId;
1583 0 : for( ; it != end; ++it )
1584 : {
1585 : // <g id="?" > (used by animations)
1586 : {
1587 : // As id we use the id of the text portion placeholder wrapped
1588 : // by bullet-char(*)
1589 0 : sId = B2UCONST( "bullet-char(" );
1590 0 : sId += it->first;
1591 0 : sId += B2UCONST( ")" );
1592 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
1593 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "BulletChar" ) );
1594 0 : SvXMLElementExport aBulletCharElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
1595 :
1596 : // <g transform="translate(x,y)" >
1597 : {
1598 0 : const BulletListItemInfo& rInfo = it->second;
1599 :
1600 : // Add positioning attribute through a translation
1601 0 : sPosition = B2UCONST( "translate(" );
1602 0 : sPosition += OUString::valueOf( rInfo.aPos.X() );
1603 0 : sPosition += B2UCONST( "," );
1604 0 : sPosition += OUString::valueOf( rInfo.aPos.Y() );
1605 0 : sPosition += B2UCONST( ")" );
1606 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "transform", sPosition );
1607 :
1608 0 : mpContext->AddPaintAttr( COL_TRANSPARENT, rInfo.aColor );
1609 :
1610 0 : SvXMLElementExport aPositioningElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
1611 :
1612 : // <use transform="scale(font-size)" xlink:ref="/" >
1613 : {
1614 : // Add size attribute through a scaling
1615 0 : sScaling = B2UCONST( "scale(" );
1616 0 : sScaling += OUString::valueOf( rInfo.nFontSize );
1617 0 : sScaling += B2UCONST( "," );
1618 0 : sScaling += OUString::valueOf( rInfo.nFontSize );
1619 0 : sScaling += B2UCONST( ")" );
1620 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "transform", sScaling );
1621 :
1622 : // Add ref attribute
1623 0 : sRefId = B2UCONST( "#bullet-char-template(" );
1624 0 : sRefId += OUString::valueOf( (sal_Int32)( rInfo.cBulletChar ) );
1625 0 : sRefId += B2UCONST( ")" );
1626 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, sRefId );
1627 :
1628 0 : SvXMLElementExport aRefElem( mrExport, XML_NAMESPACE_NONE, "use", sal_True, sal_True );
1629 0 : }
1630 0 : } // close aPositioningElem
1631 : } // close aBulletCharElem
1632 : }
1633 :
1634 :
1635 : // clear the map
1636 0 : maBulletListItemMap.clear();
1637 : }
1638 :
1639 : // -----------------------------------------------------------------------------
1640 :
1641 : template< typename MetaBitmapActionType >
1642 0 : void SVGTextWriter::writeBitmapPlaceholder( const MetaBitmapActionType* pAction )
1643 : {
1644 : // text position element
1645 0 : const Point& rPos = pAction->GetPoint();
1646 0 : implMap( rPos, maTextPos );
1647 0 : startTextPosition();
1648 0 : mbPositioningNeeded = sal_True;
1649 0 : if( mbIsNewListItem )
1650 : {
1651 0 : mbIsNewListItem = sal_False;
1652 0 : mbIsListLevelStyleImage = sal_False;
1653 : }
1654 :
1655 : // bitmap placeholder element
1656 0 : sal_uLong nId = SVGActionWriter::GetChecksum( pAction );
1657 0 : OUString sId = B2UCONST( "bitmap-placeholder(" );
1658 0 : sId += msShapeId;
1659 0 : sId += B2UCONST( "." );
1660 0 : sId += OUString::valueOf( (sal_Int64)nId );
1661 0 : sId += B2UCONST( ")" );
1662 :
1663 : {
1664 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
1665 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "BitmapPlaceholder" ) );
1666 0 : SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1667 : }
1668 0 : endTextPosition();
1669 0 : }
1670 :
1671 : // -----------------------------------------------------------------------------
1672 :
1673 0 : void SVGTextWriter::implWriteEmbeddedBitmaps()
1674 : {
1675 0 : if( mpTextEmbeddedBitmapMtf && mpTextEmbeddedBitmapMtf->GetActionSize() )
1676 : {
1677 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "EmbeddedBitmaps" ) );
1678 0 : SvXMLElementExport aEmbBitmapGroupElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
1679 :
1680 0 : const GDIMetaFile& rMtf = *mpTextEmbeddedBitmapMtf;
1681 :
1682 0 : OUString sId, sRefId;
1683 0 : sal_uLong nId, nChecksum = 0;
1684 0 : Point aPt;
1685 0 : Size aSz;
1686 0 : sal_uLong nCount = rMtf.GetActionSize();
1687 0 : for( sal_uLong nCurAction = 0; nCurAction < nCount; nCurAction++ )
1688 : {
1689 :
1690 0 : const MetaAction* pAction = rMtf.GetAction( nCurAction );
1691 0 : const sal_uInt16 nType = pAction->GetType();
1692 :
1693 0 : switch( nType )
1694 : {
1695 : case( META_BMPSCALE_ACTION ):
1696 : {
1697 0 : const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction;
1698 0 : nChecksum = pA->GetBitmap().GetChecksum();
1699 0 : aPt = pA->GetPoint();
1700 0 : aSz = pA->GetSize();
1701 : }
1702 0 : break;
1703 : case( META_BMPEXSCALE_ACTION ):
1704 : {
1705 0 : const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction;
1706 0 : nChecksum = pA->GetBitmapEx().GetChecksum();
1707 0 : aPt = pA->GetPoint();
1708 0 : aSz = pA->GetSize();
1709 : }
1710 0 : break;
1711 : }
1712 :
1713 : // <g id="?" > (used by animations)
1714 : {
1715 : // embedded bitmap id
1716 0 : nId = SVGActionWriter::GetChecksum( pAction );
1717 0 : sId = B2UCONST( "embedded-bitmap(" );
1718 0 : sId += msShapeId;
1719 0 : sId += B2UCONST( "." );
1720 0 : sId += OUString::valueOf( (sal_Int64)nId );
1721 0 : sId += B2UCONST( ")" );
1722 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
1723 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "EmbeddedBitmap" ) );
1724 :
1725 0 : SvXMLElementExport aEmbBitmapElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
1726 :
1727 : // <use x="?" y="?" xlink:ref="?" >
1728 : {
1729 : // referenced bitmap template
1730 0 : sRefId = B2UCONST( "#bitmap(" );
1731 0 : sRefId += OUString::valueOf( (sal_Int64)nChecksum );
1732 0 : sRefId += B2UCONST( ")" );
1733 :
1734 0 : Point aPoint;
1735 0 : Size aSize;
1736 0 : implMap( aPt, aPoint );
1737 0 : implMap( aSz, aSize );
1738 :
1739 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::valueOf( aPoint.X() ) );
1740 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::valueOf( aPoint.Y() ) );
1741 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, sRefId );
1742 :
1743 0 : SvXMLElementExport aRefElem( mrExport, XML_NAMESPACE_NONE, "use", sal_True, sal_True );
1744 0 : }
1745 : } // close aEmbBitmapElem
1746 0 : }
1747 : }
1748 0 : }
1749 :
1750 : // -----------------------------------------------------------------------------
1751 :
1752 0 : void SVGTextWriter::writeTextPortion( const Point& rPos,
1753 : const String& rText,
1754 : sal_Bool bApplyMapping )
1755 : {
1756 0 : if( rText.Len() == 0 )
1757 0 : return;
1758 :
1759 0 : mbLineBreak = sal_False;
1760 :
1761 0 : if( !mbIsNewListItem || mbIsListLevelStyleImage )
1762 : {
1763 0 : bool bNotSync = true;
1764 0 : OUString sContent;
1765 : sal_Int32 nStartPos;
1766 0 : while( bNotSync )
1767 : {
1768 0 : if( mnLeftTextPortionLength <= 0 )
1769 : {
1770 0 : if( !nextTextPortion() )
1771 0 : break;
1772 : else
1773 : {
1774 0 : sContent = mrCurrentTextPortion->getString();
1775 0 : if( mbIsURLField && sContent.isEmpty() )
1776 : {
1777 0 : Reference < XPropertySet > xPropSet( mrCurrentTextPortion, UNO_QUERY );
1778 0 : Reference < XTextField > xTextField( xPropSet->getPropertyValue( B2UCONST( "TextField" ) ), UNO_QUERY );
1779 0 : sContent = xTextField->getPresentation( /* show command: */ sal_False );
1780 0 : if( sContent.isEmpty() )
1781 0 : OSL_FAIL( "SVGTextWriter::writeTextPortion: content of URL TextField is empty." );
1782 : }
1783 0 : mnLeftTextPortionLength = sContent.getLength();
1784 : }
1785 : }
1786 : else
1787 : {
1788 0 : sContent = mrCurrentTextPortion->getString();
1789 : }
1790 :
1791 0 : nStartPos = sContent.getLength() - mnLeftTextPortionLength;
1792 0 : if( nStartPos < 0 ) nStartPos = 0;
1793 0 : mnLeftTextPortionLength -= rText.Len();
1794 :
1795 0 : if( sContent.isEmpty() )
1796 0 : continue;
1797 0 : if( sContent.equalsAscii( "\n" ) )
1798 0 : mbLineBreak = sal_True;
1799 0 : if( sContent.match( rText, nStartPos ) )
1800 0 : bNotSync = false;
1801 0 : }
1802 : }
1803 :
1804 0 : if( !mpVDev )
1805 : OSL_FAIL( "SVGTextWriter::writeTextPortion: invalid virtual device." );
1806 :
1807 0 : const FontMetric aMetric( mpVDev->GetFontMetric() );
1808 :
1809 0 : bool bTextSpecial = aMetric.IsShadow() || aMetric.IsOutline() || (aMetric.GetRelief() != RELIEF_NONE);
1810 :
1811 : if( true || !bTextSpecial )
1812 : {
1813 0 : implWriteTextPortion( rPos, rText, mpVDev->GetTextColor(), bApplyMapping );
1814 : }
1815 : else
1816 : {
1817 : // to be implemented
1818 0 : }
1819 :
1820 : }
1821 :
1822 : // -----------------------------------------------------------------------------
1823 :
1824 0 : void SVGTextWriter::implWriteTextPortion( const Point& rPos,
1825 : const String& rText,
1826 : Color aTextColor,
1827 : sal_Bool bApplyMapping )
1828 : {
1829 0 : if( !mpContext )
1830 : OSL_FAIL( "SVGTextWriter::implWriteTextPortion: invalid context object." );
1831 :
1832 0 : Point aPos;
1833 0 : Point aBaseLinePos( rPos );
1834 0 : const FontMetric aMetric( mpVDev->GetFontMetric() );
1835 0 : const Font& rFont = mpVDev->GetFont();
1836 :
1837 0 : if( rFont.GetAlign() == ALIGN_TOP )
1838 0 : aBaseLinePos.Y() += aMetric.GetAscent();
1839 0 : else if( rFont.GetAlign() == ALIGN_BOTTOM )
1840 0 : aBaseLinePos.Y() -= aMetric.GetDescent();
1841 :
1842 0 : if( bApplyMapping )
1843 0 : implMap( rPos, aPos );
1844 : else
1845 0 : aPos = rPos;
1846 :
1847 0 : if( mbPositioningNeeded )
1848 : {
1849 0 : mbPositioningNeeded = sal_False;
1850 0 : maTextPos.setX( aPos.X() );
1851 0 : maTextPos.setY( aPos.Y() );
1852 0 : startTextPosition();
1853 : }
1854 0 : else if( maTextPos.Y() != aPos.Y() )
1855 : {
1856 : // In case the text position moved backward we could have a line break
1857 : // so we end the current line and start a new one.
1858 0 : if( mbLineBreak || ( ( maTextPos.X() + mnTextWidth ) > aPos.X() ) )
1859 : {
1860 0 : mbLineBreak = sal_False;
1861 0 : maTextPos.setX( aPos.X() );
1862 0 : maTextPos.setY( aPos.Y() );
1863 0 : startTextPosition();
1864 : }
1865 : else // superscript, subscript, list item numbering
1866 : {
1867 0 : maTextPos.setY( aPos.Y() );
1868 0 : startTextPosition( sal_False /* do not export x attribute */ );
1869 : }
1870 : }
1871 : // we are dealing with a bullet, so set up this for the next text portion
1872 0 : if( mbIsNewListItem )
1873 : {
1874 0 : mbIsNewListItem = sal_False;
1875 0 : mbPositioningNeeded = sal_True;
1876 :
1877 0 : if( meNumberingType == NumberingType::CHAR_SPECIAL )
1878 : {
1879 : // Create an id for the current text portion
1880 0 : implRegisterInterface( mrCurrentTextParagraph );
1881 :
1882 : // Add the needed info to the BulletListItemMap
1883 0 : Reference< XInterface > xRef( mrCurrentTextParagraph, UNO_QUERY );
1884 0 : OUString sId = implGetValidIDFromInterface( xRef );
1885 0 : if( !sId.isEmpty() )
1886 : {
1887 0 : sId += ".bp";
1888 0 : BulletListItemInfo& aBulletListItemInfo = maBulletListItemMap[ sId ];
1889 0 : aBulletListItemInfo.nFontSize = rFont.GetHeight();
1890 0 : aBulletListItemInfo.aColor = aTextColor;
1891 0 : aBulletListItemInfo.aPos = maTextPos;
1892 0 : aBulletListItemInfo.cBulletChar = mcBulletChar;
1893 :
1894 : // Make this text portion a bullet placeholder
1895 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
1896 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "BulletPlaceholder" ) );
1897 0 : SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1898 0 : return;
1899 0 : }
1900 : }
1901 : }
1902 :
1903 0 : Reference< XInterface > xRef( mrCurrentTextPortion, UNO_QUERY );
1904 0 : const OUString& rTextPortionId = implGetValidIDFromInterface( xRef );
1905 0 : if( !rTextPortionId.isEmpty() )
1906 : {
1907 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", rTextPortionId );
1908 : }
1909 :
1910 0 : if( mbIsPlacehlolderShape )
1911 : {
1912 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "PlaceholderText" ) );
1913 0 : mbIsPlacehlolderShape = sal_False;
1914 : }
1915 0 : else if( mbIsURLField && !msUrl.isEmpty() )
1916 : {
1917 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "UrlField" ) );
1918 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, msUrl );
1919 0 : mbIsURLField = sal_False;
1920 : }
1921 :
1922 :
1923 0 : addFontAttributes( /* isTexTContainer: */ false );
1924 0 : mpContext->AddPaintAttr( COL_TRANSPARENT, aTextColor );
1925 :
1926 0 : SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1927 0 : OUString sTextContent = rText;
1928 0 : mrExport.GetDocHandler()->characters( sTextContent );
1929 0 : mnTextWidth += mpVDev->GetTextWidth( sTextContent );
1930 : }
1931 :
1932 : // -------------------
1933 : // - SVGActionWriter -
1934 : // -------------------
1935 :
1936 0 : SVGActionWriter::SVGActionWriter( SVGExport& rExport, SVGFontExport& rFontExport ) :
1937 : mnCurGradientId( 1 ),
1938 : mnCurMaskId( 1 ),
1939 : mnCurPatternId( 1 ),
1940 : mrExport( rExport ),
1941 : mrFontExport( rFontExport ),
1942 : mpContext( NULL ),
1943 : maTextWriter( rExport ),
1944 : mnInnerMtfCount( 0 ),
1945 0 : mbClipAttrChanged( sal_False )
1946 : {
1947 0 : mpVDev = new VirtualDevice;
1948 0 : mpVDev->EnableOutput( sal_False );
1949 0 : maTargetMapMode = MAP_100TH_MM;
1950 0 : maTextWriter.setVirtualDevice( mpVDev, maTargetMapMode );
1951 0 : }
1952 :
1953 : // -----------------------------------------------------------------------------
1954 :
1955 0 : SVGActionWriter::~SVGActionWriter()
1956 : {
1957 : DBG_ASSERT( !mpContext, "Not all contexts are closed" );
1958 0 : delete mpVDev;
1959 0 : }
1960 :
1961 : // -----------------------------------------------------------------------------
1962 :
1963 0 : long SVGActionWriter::ImplMap( sal_Int32 nVal ) const
1964 : {
1965 0 : Size aSz( nVal, nVal );
1966 :
1967 0 : return( ImplMap( aSz, aSz ).Width() );
1968 : }
1969 :
1970 : // -----------------------------------------------------------------------------
1971 :
1972 0 : Point& SVGActionWriter::ImplMap( const Point& rPt, Point& rDstPt ) const
1973 : {
1974 0 : return( rDstPt = mpVDev->LogicToLogic( rPt, mpVDev->GetMapMode(), maTargetMapMode ) );
1975 : }
1976 :
1977 : // -----------------------------------------------------------------------------
1978 :
1979 0 : Size& SVGActionWriter::ImplMap( const Size& rSz, Size& rDstSz ) const
1980 : {
1981 0 : return( rDstSz = mpVDev->LogicToLogic( rSz, mpVDev->GetMapMode(), maTargetMapMode ) );
1982 : }
1983 :
1984 : // -----------------------------------------------------------------------------
1985 :
1986 0 : Rectangle& SVGActionWriter::ImplMap( const Rectangle& rRect, Rectangle& rDstRect ) const
1987 : {
1988 0 : Point aTL( rRect.TopLeft() );
1989 0 : Size aSz( rRect.GetSize() );
1990 :
1991 0 : return( rDstRect = Rectangle( ImplMap( aTL, aTL ), ImplMap( aSz, aSz ) ) );
1992 : }
1993 :
1994 :
1995 : // -----------------------------------------------------------------------------
1996 :
1997 0 : Polygon& SVGActionWriter::ImplMap( const Polygon& rPoly, Polygon& rDstPoly ) const
1998 : {
1999 0 : rDstPoly = Polygon( rPoly.GetSize() );
2000 :
2001 0 : for( sal_uInt16 i = 0, nSize = rPoly.GetSize(); i < nSize; ++i )
2002 : {
2003 0 : ImplMap( rPoly[ i ], rDstPoly[ i ] );
2004 0 : rDstPoly.SetFlags( i, rPoly.GetFlags( i ) );
2005 : }
2006 :
2007 0 : return( rDstPoly );
2008 : }
2009 :
2010 : // -----------------------------------------------------------------------------
2011 :
2012 0 : PolyPolygon& SVGActionWriter::ImplMap( const PolyPolygon& rPolyPoly, PolyPolygon& rDstPolyPoly ) const
2013 : {
2014 0 : Polygon aPoly;
2015 :
2016 0 : rDstPolyPoly = PolyPolygon();
2017 :
2018 0 : for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; ++i )
2019 : {
2020 0 : rDstPolyPoly.Insert( ImplMap( rPolyPoly[ i ], aPoly ) );
2021 : }
2022 :
2023 0 : return( rDstPolyPoly );
2024 : }
2025 :
2026 : // -----------------------------------------------------------------------------
2027 :
2028 0 : ::rtl::OUString SVGActionWriter::GetPathString( const PolyPolygon& rPolyPoly, sal_Bool bLine )
2029 : {
2030 0 : ::rtl::OUString aPathData;
2031 0 : const ::rtl::OUString aBlank( B2UCONST( " " ) );
2032 0 : const ::rtl::OUString aComma( B2UCONST( "," ) );
2033 0 : Point aPolyPoint;
2034 :
2035 0 : for( long i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ )
2036 : {
2037 0 : const Polygon& rPoly = rPolyPoly[ (sal_uInt16) i ];
2038 0 : sal_uInt16 n = 1, nSize = rPoly.GetSize();
2039 :
2040 0 : if( nSize > 1 )
2041 : {
2042 0 : aPathData += B2UCONST( "M " );
2043 0 : aPathData += ::rtl::OUString::valueOf( ( aPolyPoint = rPoly[ 0 ] ).X() );
2044 0 : aPathData += aComma;
2045 0 : aPathData += ::rtl::OUString::valueOf( aPolyPoint.Y() );
2046 :
2047 0 : sal_Char nCurrentMode = 0;
2048 0 : const bool bClose(!bLine || rPoly[0] == rPoly[nSize - 1]);
2049 0 : while( n < nSize )
2050 : {
2051 0 : aPathData += aBlank;
2052 :
2053 0 : if ( ( rPoly.GetFlags( n ) == POLY_CONTROL ) && ( ( n + 2 ) < nSize ) )
2054 : {
2055 0 : if ( nCurrentMode != 'C' )
2056 : {
2057 0 : nCurrentMode = 'C';
2058 0 : aPathData += B2UCONST( "C " );
2059 : }
2060 0 : for ( int j = 0; j < 3; j++ )
2061 : {
2062 0 : if ( j )
2063 0 : aPathData += aBlank;
2064 0 : aPathData += ::rtl::OUString::valueOf( ( aPolyPoint = rPoly[ n++ ] ).X() );
2065 0 : aPathData += aComma;
2066 0 : aPathData += ::rtl::OUString::valueOf( aPolyPoint.Y() );
2067 : }
2068 : }
2069 : else
2070 : {
2071 0 : if ( nCurrentMode != 'L' )
2072 : {
2073 0 : nCurrentMode = 'L';
2074 0 : aPathData += B2UCONST( "L " );
2075 : }
2076 0 : aPathData += ::rtl::OUString::valueOf( ( aPolyPoint = rPoly[ n++ ] ).X() );
2077 0 : aPathData += aComma;
2078 0 : aPathData += ::rtl::OUString::valueOf( aPolyPoint.Y() );
2079 : }
2080 : }
2081 :
2082 0 : if(bClose)
2083 0 : aPathData += B2UCONST( " Z" );
2084 :
2085 0 : if( i < ( nCount - 1 ) )
2086 0 : aPathData += aBlank;
2087 : }
2088 : }
2089 :
2090 0 : return aPathData;
2091 : }
2092 :
2093 : // -----------------------------------------------------------------------------
2094 :
2095 0 : sal_uLong SVGActionWriter::GetChecksum( const MetaAction* pAction )
2096 : {
2097 0 : GDIMetaFile aMtf;
2098 0 : MetaAction* pA = (MetaAction*)pAction;
2099 0 : pA->Duplicate();
2100 0 : aMtf.AddAction( pA );
2101 0 : return aMtf.GetChecksum();
2102 : }
2103 :
2104 : // -----------------------------------------------------------------------------
2105 :
2106 0 : void SVGActionWriter::ImplWriteLine( const Point& rPt1, const Point& rPt2,
2107 : const Color* pLineColor, sal_Bool bApplyMapping )
2108 : {
2109 0 : Point aPt1, aPt2;
2110 :
2111 0 : if( bApplyMapping )
2112 : {
2113 0 : ImplMap( rPt1, aPt1 );
2114 0 : ImplMap( rPt2, aPt2 );
2115 : }
2116 : else
2117 : {
2118 0 : aPt1 = rPt1;
2119 0 : aPt2 = rPt2;
2120 : }
2121 :
2122 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, ::rtl::OUString::valueOf( aPt1.X() ) );
2123 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, ::rtl::OUString::valueOf( aPt1.Y() ) );
2124 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, ::rtl::OUString::valueOf( aPt2.X() ) );
2125 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, ::rtl::OUString::valueOf( aPt2.Y() ) );
2126 :
2127 : if( pLineColor )
2128 : {
2129 : // !!! mrExport.AddAttribute( XML_NAMESPACE_NONE, ... )
2130 : OSL_FAIL( "SVGActionWriter::ImplWriteLine: Line color not implemented" );
2131 : }
2132 :
2133 : {
2134 0 : SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemLine, sal_True, sal_True );
2135 : }
2136 0 : }
2137 :
2138 : // -----------------------------------------------------------------------------
2139 :
2140 0 : void SVGActionWriter::ImplWriteRect( const Rectangle& rRect, long nRadX, long nRadY,
2141 : sal_Bool bApplyMapping )
2142 : {
2143 0 : Rectangle aRect;
2144 :
2145 0 : if( bApplyMapping )
2146 0 : ImplMap( rRect, aRect );
2147 : else
2148 0 : aRect = rRect;
2149 :
2150 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, ::rtl::OUString::valueOf( aRect.Left() ) );
2151 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( aRect.Top() ) );
2152 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrWidth, ::rtl::OUString::valueOf( aRect.GetWidth() ) );
2153 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrHeight, ::rtl::OUString::valueOf( aRect.GetHeight() ) );
2154 :
2155 0 : if( nRadX )
2156 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRX, ::rtl::OUString::valueOf( bApplyMapping ? ImplMap( nRadX ) : nRadX ) );
2157 :
2158 0 : if( nRadY )
2159 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRY, ::rtl::OUString::valueOf( bApplyMapping ? ImplMap( nRadY ) : nRadY ) );
2160 :
2161 : {
2162 0 : SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemRect, sal_True, sal_True );
2163 : }
2164 0 : }
2165 :
2166 : // -----------------------------------------------------------------------------
2167 :
2168 0 : void SVGActionWriter::ImplWriteEllipse( const Point& rCenter, long nRadX, long nRadY,
2169 : sal_Bool bApplyMapping )
2170 : {
2171 0 : Point aCenter;
2172 :
2173 0 : if( bApplyMapping )
2174 0 : ImplMap( rCenter, aCenter );
2175 : else
2176 0 : aCenter = rCenter;
2177 :
2178 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCX, ::rtl::OUString::valueOf( aCenter.X() ) );
2179 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCY, ::rtl::OUString::valueOf( aCenter.Y() ) );
2180 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRX, ::rtl::OUString::valueOf( bApplyMapping ? ImplMap( nRadX ) : nRadX ) );
2181 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRY, ::rtl::OUString::valueOf( bApplyMapping ? ImplMap( nRadY ) : nRadY ) );
2182 :
2183 : {
2184 0 : SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemEllipse, sal_True, sal_True );
2185 : }
2186 0 : }
2187 :
2188 : // -----------------------------------------------------------------------------
2189 :
2190 0 : void SVGActionWriter::ImplWritePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bLineOnly,
2191 : sal_Bool bApplyMapping )
2192 : {
2193 0 : PolyPolygon aPolyPoly;
2194 :
2195 0 : if( bApplyMapping )
2196 0 : ImplMap( rPolyPoly, aPolyPoly );
2197 : else
2198 0 : aPolyPoly = rPolyPoly;
2199 :
2200 : // add path data attribute
2201 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrD, GetPathString( aPolyPoly, bLineOnly ) );
2202 :
2203 : {
2204 : // write polyline/polygon element
2205 0 : SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemPath, sal_True, sal_True );
2206 0 : }
2207 0 : }
2208 :
2209 : // -----------------------------------------------------------------------------
2210 :
2211 0 : void SVGActionWriter::ImplWriteShape( const SVGShapeDescriptor& rShape, sal_Bool bApplyMapping )
2212 : {
2213 0 : PolyPolygon aPolyPoly;
2214 :
2215 0 : if( bApplyMapping )
2216 0 : ImplMap( rShape.maShapePolyPoly, aPolyPoly );
2217 : else
2218 0 : aPolyPoly = rShape.maShapePolyPoly;
2219 :
2220 0 : const sal_Bool bLineOnly = ( rShape.maShapeFillColor == Color( COL_TRANSPARENT ) ) && ( !rShape.mapShapeGradient.get() );
2221 0 : Rectangle aBoundRect( aPolyPoly.GetBoundRect() );
2222 :
2223 0 : mpContext->AddPaintAttr( rShape.maShapeLineColor, rShape.maShapeFillColor, &aBoundRect, rShape.mapShapeGradient.get() );
2224 :
2225 0 : if( !rShape.maId.isEmpty() )
2226 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, rShape.maId );
2227 :
2228 0 : if( rShape.mnStrokeWidth )
2229 : {
2230 0 : sal_Int32 nStrokeWidth = ( bApplyMapping ? ImplMap( rShape.mnStrokeWidth ) : rShape.mnStrokeWidth );
2231 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeWidth, ::rtl::OUString::valueOf( nStrokeWidth ) );
2232 : }
2233 :
2234 : // support for LineJoin
2235 0 : switch(rShape.maLineJoin)
2236 : {
2237 : default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE
2238 : case basegfx::B2DLINEJOIN_MITER:
2239 : {
2240 : // miter is Svg default, so no need to write until the exporter might write styles.
2241 : // If this happens, activate here
2242 : // mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, ::rtl::OUString::createFromAscii("miter"));
2243 0 : break;
2244 : }
2245 : case basegfx::B2DLINEJOIN_BEVEL:
2246 : {
2247 0 : mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, ::rtl::OUString::createFromAscii("bevel"));
2248 0 : break;
2249 : }
2250 : case basegfx::B2DLINEJOIN_ROUND:
2251 : {
2252 0 : mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, ::rtl::OUString::createFromAscii("round"));
2253 0 : break;
2254 : }
2255 : }
2256 :
2257 : // support for LineCap
2258 0 : switch(rShape.maLineCap)
2259 : {
2260 : default: /* com::sun::star::drawing::LineCap_BUTT */
2261 : {
2262 : // butt is Svg default, so no need to write until the exporter might write styles.
2263 : // If this happens, activate here
2264 : // mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, ::rtl::OUString::createFromAscii("butt"));
2265 0 : break;
2266 : }
2267 : case com::sun::star::drawing::LineCap_ROUND:
2268 : {
2269 0 : mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, ::rtl::OUString::createFromAscii("round"));
2270 0 : break;
2271 : }
2272 : case com::sun::star::drawing::LineCap_SQUARE:
2273 : {
2274 0 : mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, ::rtl::OUString::createFromAscii("square"));
2275 0 : break;
2276 : }
2277 : }
2278 :
2279 0 : if( rShape.maDashArray.size() )
2280 : {
2281 0 : const ::rtl::OUString aComma( B2UCONST( "," ) );
2282 0 : ::rtl::OUString aDashArrayStr;
2283 :
2284 0 : for( unsigned int k = 0; k < rShape.maDashArray.size(); ++k )
2285 : {
2286 : const sal_Int32 nDash = ( bApplyMapping ?
2287 0 : ImplMap( FRound( rShape.maDashArray[ k ] ) ) :
2288 0 : FRound( rShape.maDashArray[ k ] ) );
2289 :
2290 0 : if( k )
2291 0 : aDashArrayStr += aComma;
2292 :
2293 0 : aDashArrayStr += ::rtl::OUString::valueOf( nDash );
2294 : }
2295 :
2296 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeDashArray, aDashArrayStr );
2297 : }
2298 :
2299 0 : ImplWritePolyPolygon( aPolyPoly, bLineOnly, sal_False );
2300 0 : }
2301 :
2302 : // -----------------------------------------------------------------------------
2303 :
2304 0 : void SVGActionWriter::ImplWritePattern( const PolyPolygon& rPolyPoly,
2305 : const Hatch* pHatch,
2306 : const Gradient* pGradient,
2307 : sal_uInt32 nWriteFlags )
2308 : {
2309 0 : if( rPolyPoly.Count() )
2310 : {
2311 0 : SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
2312 :
2313 0 : ::rtl::OUString aPatternId;
2314 0 : aPatternId += B2UCONST( "pattern" );
2315 0 : aPatternId += OUString::valueOf( mnCurPatternId++ );
2316 :
2317 : {
2318 0 : SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, sal_True, sal_True );
2319 :
2320 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aPatternId );
2321 :
2322 0 : Rectangle aRect;
2323 0 : ImplMap( rPolyPoly.GetBoundRect(), aRect );
2324 :
2325 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::valueOf( aRect.Left() ) );
2326 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::valueOf( aRect.Top() ) );
2327 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrWidth, OUString::valueOf( aRect.GetWidth() ) );
2328 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrHeight, OUString::valueOf( aRect.GetHeight() ) );
2329 :
2330 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrPatternUnits, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "userSpaceOnUse") ) );
2331 :
2332 : {
2333 0 : SvXMLElementExport aElemPattern( mrExport, XML_NAMESPACE_NONE, aXMLElemPattern, sal_True, sal_True );
2334 :
2335 : // The origin of a pattern is positioned at (aRect.Left(), aRect.Top()).
2336 : // So we need to adjust the pattern coordinate.
2337 0 : ::rtl::OUString aTransform;
2338 0 : aTransform += B2UCONST( "translate" );
2339 0 : aTransform += B2UCONST( "(" );
2340 0 : aTransform += OUString::valueOf( -aRect.Left() );
2341 0 : aTransform += B2UCONST( "," );
2342 0 : aTransform += OUString::valueOf( -aRect.Top() );
2343 0 : aTransform += B2UCONST( ")" );
2344 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform, aTransform );
2345 :
2346 : {
2347 0 : SvXMLElementExport aElemG2( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
2348 :
2349 0 : GDIMetaFile aTmpMtf;
2350 0 : if( pHatch )
2351 0 : mpVDev->AddHatchActions( rPolyPoly, *pHatch, aTmpMtf );
2352 0 : else if ( pGradient )
2353 0 : mpVDev->AddGradientActions( rPolyPoly.GetBoundRect(), *pGradient, aTmpMtf );
2354 0 : ImplWriteActions( aTmpMtf, nWriteFlags, NULL );
2355 0 : }
2356 0 : }
2357 : }
2358 :
2359 0 : ::rtl::OUString aPatternStyle;
2360 0 : aPatternStyle += B2UCONST( "fill:url(#" );
2361 0 : aPatternStyle += aPatternId;
2362 0 : aPatternStyle += B2UCONST( ")" );
2363 :
2364 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aPatternStyle );
2365 0 : ImplWritePolyPolygon( rPolyPoly, sal_False );
2366 : }
2367 0 : }
2368 :
2369 : // -----------------------------------------------------------------------------
2370 :
2371 0 : void SVGActionWriter::ImplWriteGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient,
2372 : sal_uInt32 nWriteFlags, sal_Bool bApplyMapping )
2373 : {
2374 0 : PolyPolygon aPolyPoly;
2375 :
2376 0 : if( bApplyMapping )
2377 0 : ImplMap( rPolyPoly, aPolyPoly );
2378 : else
2379 0 : aPolyPoly = rPolyPoly;
2380 :
2381 0 : if ( rGradient.GetStyle() == GradientStyle_LINEAR ||
2382 0 : rGradient.GetStyle() == GradientStyle_AXIAL )
2383 : {
2384 0 : ImplWriteGradientLinear( aPolyPoly, rGradient );
2385 : }
2386 : else
2387 : {
2388 0 : ImplWritePattern( aPolyPoly, NULL, &rGradient, nWriteFlags );
2389 0 : }
2390 0 : }
2391 :
2392 : // -----------------------------------------------------------------------------
2393 :
2394 0 : void SVGActionWriter::ImplWriteGradientLinear( const PolyPolygon& rPolyPoly,
2395 : const Gradient& rGradient )
2396 : {
2397 0 : if( rPolyPoly.Count() )
2398 : {
2399 0 : SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
2400 :
2401 0 : ::rtl::OUString aGradientId;
2402 0 : aGradientId += B2UCONST( "gradient" );
2403 0 : aGradientId += OUString::valueOf( mnCurGradientId++ );
2404 :
2405 : {
2406 0 : SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, sal_True, sal_True );
2407 :
2408 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aGradientId );
2409 : {
2410 0 : Rectangle aTmpRect, aRect;
2411 0 : Point aTmpCenter, aCenter;
2412 :
2413 0 : rGradient.GetBoundRect( rPolyPoly.GetBoundRect(), aTmpRect, aTmpCenter );
2414 0 : ImplMap( aTmpRect, aRect );
2415 0 : ImplMap( aTmpCenter, aCenter );
2416 0 : const sal_uInt16 nAngle = rGradient.GetAngle() % 3600;
2417 :
2418 0 : Polygon aPoly( 2 );
2419 : // Setting x value of a gradient vector to rotation center to
2420 : // place a gradient vector in a target polygon.
2421 : // This would help editing it in SVG editors like inkscape.
2422 0 : aPoly[ 0 ].X() = aPoly[ 1 ].X() = aCenter.X();
2423 0 : aPoly[ 0 ].Y() = aRect.Top();
2424 0 : aPoly[ 1 ].Y() = aRect.Bottom();
2425 0 : aPoly.Rotate( aCenter, nAngle );
2426 :
2427 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, OUString::valueOf( aPoly[ 0 ].X() ) );
2428 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, OUString::valueOf( aPoly[ 0 ].Y() ) );
2429 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, OUString::valueOf( aPoly[ 1 ].X() ) );
2430 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, OUString::valueOf( aPoly[ 1 ].Y() ) );
2431 :
2432 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits,
2433 0 : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "userSpaceOnUse" ) ) );
2434 : }
2435 :
2436 : {
2437 0 : SvXMLElementExport aElemLinearGradient( mrExport, XML_NAMESPACE_NONE, aXMLElemLinearGradient, sal_True, sal_True );
2438 :
2439 0 : const Color aStartColor = ImplGetColorWithIntensity( rGradient.GetStartColor(), rGradient.GetStartIntensity() );
2440 0 : const Color aEndColor = ImplGetColorWithIntensity( rGradient.GetEndColor(), rGradient.GetEndIntensity() );
2441 0 : double fBorderOffset = rGradient.GetBorder() / 100.0;
2442 0 : const sal_uInt16 nSteps = rGradient.GetSteps();
2443 0 : if( rGradient.GetStyle() == GradientStyle_LINEAR )
2444 : {
2445 : // Emulate non-smooth gradient
2446 0 : if( 0 < nSteps && nSteps < 100 )
2447 : {
2448 0 : double fOffsetStep = ( 1.0 - fBorderOffset ) / (double)nSteps;
2449 0 : for( sal_uInt16 i = 0; i < nSteps; i++ ) {
2450 0 : Color aColor = ImplGetGradientColor( aStartColor, aEndColor, i / (double) nSteps );
2451 0 : ImplWriteGradientStop( aColor, fBorderOffset + ( i + 1 ) * fOffsetStep );
2452 0 : aColor = ImplGetGradientColor( aStartColor, aEndColor, ( i + 1 ) / (double) nSteps );
2453 0 : ImplWriteGradientStop( aColor, fBorderOffset + ( i + 1 ) * fOffsetStep );
2454 0 : }
2455 : }
2456 : else
2457 : {
2458 0 : ImplWriteGradientStop( aStartColor, fBorderOffset );
2459 0 : ImplWriteGradientStop( aEndColor, 1.0 );
2460 : }
2461 : }
2462 : else
2463 : {
2464 0 : fBorderOffset /= 2;
2465 : // Emulate non-smooth gradient
2466 0 : if( 0 < nSteps && nSteps < 100 )
2467 : {
2468 0 : double fOffsetStep = ( 0.5 - fBorderOffset ) / (double)nSteps;
2469 : // Upper half
2470 0 : for( sal_uInt16 i = 0; i < nSteps; i++ )
2471 : {
2472 0 : Color aColor = ImplGetGradientColor( aEndColor, aStartColor, i / (double) nSteps );
2473 0 : ImplWriteGradientStop( aColor, fBorderOffset + i * fOffsetStep );
2474 0 : aColor = ImplGetGradientColor( aEndColor, aStartColor, (i + 1 ) / (double) nSteps );
2475 0 : ImplWriteGradientStop( aColor, fBorderOffset + i * fOffsetStep );
2476 : }
2477 : // Lower half
2478 0 : for( sal_uInt16 i = 0; i < nSteps; i++ )
2479 : {
2480 0 : Color aColor = ImplGetGradientColor( aStartColor, aEndColor, i / (double) nSteps );
2481 0 : ImplWriteGradientStop( aColor, 0.5 + (i + 1) * fOffsetStep );
2482 0 : aColor = ImplGetGradientColor( aStartColor, aEndColor, (i + 1 ) / (double) nSteps );
2483 0 : ImplWriteGradientStop( aColor, 0.5 + (i + 1) * fOffsetStep );
2484 0 : }
2485 : }
2486 : else
2487 : {
2488 0 : ImplWriteGradientStop( aEndColor, fBorderOffset );
2489 0 : ImplWriteGradientStop( aStartColor, 0.5 );
2490 0 : ImplWriteGradientStop( aEndColor, 1.0 - fBorderOffset );
2491 : }
2492 0 : }
2493 0 : }
2494 : }
2495 :
2496 0 : ::rtl::OUString aGradientStyle;
2497 0 : aGradientStyle += B2UCONST( "fill:" );
2498 0 : aGradientStyle += B2UCONST( "url(#" );
2499 0 : aGradientStyle += aGradientId;
2500 0 : aGradientStyle += B2UCONST( ")" );
2501 :
2502 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aGradientStyle );
2503 0 : ImplWritePolyPolygon( rPolyPoly, sal_False );
2504 : }
2505 0 : }
2506 :
2507 0 : void SVGActionWriter::ImplWriteGradientStop( const Color& rColor, double fOffset )
2508 : {
2509 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, rtl::OUString::valueOf( fOffset ) );
2510 :
2511 0 : ::rtl::OUString aStyle, aColor;
2512 0 : aStyle += B2UCONST( "stop-color:" );
2513 0 : SVGAttributeWriter::ImplGetColorStr ( rColor, aColor );
2514 0 : aStyle += aColor;
2515 :
2516 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aStyle );
2517 : {
2518 0 : SvXMLElementExport aElemStartStop( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
2519 0 : }
2520 0 : }
2521 :
2522 0 : Color SVGActionWriter::ImplGetColorWithIntensity( const Color& rColor,
2523 : sal_uInt16 nIntensity )
2524 : {
2525 0 : sal_uInt8 nNewRed = (sal_uInt8)( (long)rColor.GetRed() * nIntensity / 100L );
2526 0 : sal_uInt8 nNewGreen = (sal_uInt8)( (long)rColor.GetGreen() * nIntensity / 100L );
2527 0 : sal_uInt8 nNewBlue = (sal_uInt8)( (long)rColor.GetBlue() * nIntensity / 100L );
2528 0 : return Color( nNewRed, nNewGreen, nNewBlue);
2529 : }
2530 :
2531 0 : Color SVGActionWriter::ImplGetGradientColor( const Color& rStartColor,
2532 : const Color& rEndColor,
2533 : double fOffset )
2534 : {
2535 0 : long nRedStep = rEndColor.GetRed() - rStartColor.GetRed();
2536 0 : long nNewRed = rStartColor.GetRed() + (long)( nRedStep * fOffset );
2537 0 : nNewRed = ( nNewRed < 0 ) ? 0 : ( nNewRed > 0xFF) ? 0xFF : nNewRed;
2538 :
2539 0 : long nGreenStep = rEndColor.GetGreen() - rStartColor.GetGreen();
2540 0 : long nNewGreen = rStartColor.GetGreen() + (long)( nGreenStep * fOffset );
2541 0 : nNewGreen = ( nNewGreen < 0 ) ? 0 : ( nNewGreen > 0xFF) ? 0xFF : nNewGreen;
2542 :
2543 0 : long nBlueStep = rEndColor.GetBlue() - rStartColor.GetBlue();
2544 0 : long nNewBlue = rStartColor.GetBlue() + (long)( nBlueStep * fOffset );
2545 0 : nNewBlue = ( nNewBlue < 0 ) ? 0 : ( nNewBlue > 0xFF) ? 0xFF : nNewBlue;
2546 :
2547 0 : return Color( (sal_uInt8)nNewRed, (sal_uInt8)nNewGreen, (sal_uInt8)nNewBlue );
2548 : }
2549 :
2550 : // -----------------------------------------------------------------------------
2551 :
2552 0 : void SVGActionWriter::ImplWriteMask( GDIMetaFile& rMtf,
2553 : const Point& rDestPt,
2554 : const Size& rDestSize,
2555 : const Gradient& rGradient,
2556 : sal_uInt32 nWriteFlags )
2557 : {
2558 0 : Point aSrcPt( rMtf.GetPrefMapMode().GetOrigin() );
2559 0 : const Size aSrcSize( rMtf.GetPrefSize() );
2560 0 : const double fScaleX = aSrcSize.Width() ? (double) rDestSize.Width() / aSrcSize.Width() : 1.0;
2561 0 : const double fScaleY = aSrcSize.Height() ? (double) rDestSize.Height() / aSrcSize.Height() : 1.0;
2562 : long nMoveX, nMoveY;
2563 :
2564 0 : if( fScaleX != 1.0 || fScaleY != 1.0 )
2565 : {
2566 0 : rMtf.Scale( fScaleX, fScaleY );
2567 0 : aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
2568 : }
2569 :
2570 0 : nMoveX = rDestPt.X() - aSrcPt.X(), nMoveY = rDestPt.Y() - aSrcPt.Y();
2571 :
2572 0 : if( nMoveX || nMoveY )
2573 0 : rMtf.Move( nMoveX, nMoveY );
2574 :
2575 0 : ::rtl::OUString aMaskId;
2576 0 : aMaskId += B2UCONST( "mask" );
2577 0 : aMaskId += OUString::valueOf( mnCurMaskId++ );
2578 :
2579 : {
2580 0 : SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, sal_True, sal_True );
2581 :
2582 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aMaskId );
2583 : {
2584 0 : SvXMLElementExport aElemMask( mrExport, XML_NAMESPACE_NONE, aXMLElemMask, sal_True, sal_True );
2585 :
2586 0 : const PolyPolygon aPolyPolygon( PolyPolygon( Rectangle( rDestPt, rDestSize ) ) );
2587 0 : Gradient aGradient( rGradient );
2588 :
2589 : // swap gradient stops to adopt SVG mask
2590 0 : Color aTmpColor( aGradient.GetStartColor() );
2591 0 : sal_uInt16 nTmpIntensity( aGradient.GetStartIntensity() );
2592 0 : aGradient.SetStartColor( aGradient.GetEndColor() );
2593 0 : aGradient.SetStartIntensity( aGradient.GetEndIntensity() ) ;
2594 0 : aGradient.SetEndColor( aTmpColor );
2595 0 : aGradient.SetEndIntensity( nTmpIntensity );
2596 :
2597 0 : ImplWriteGradientEx( aPolyPolygon, aGradient, nWriteFlags );
2598 0 : }
2599 : }
2600 :
2601 0 : ::rtl::OUString aMaskStyle;
2602 0 : aMaskStyle += B2UCONST( "mask:url(#" );
2603 0 : aMaskStyle += aMaskId;
2604 0 : aMaskStyle += B2UCONST( ")" );
2605 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aMaskStyle );
2606 :
2607 : {
2608 0 : SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
2609 :
2610 0 : mpVDev->Push();
2611 0 : ImplWriteActions( rMtf, nWriteFlags, NULL );
2612 0 : mpVDev->Pop();
2613 0 : }
2614 0 : }
2615 :
2616 : // -----------------------------------------------------------------------------
2617 :
2618 0 : void SVGActionWriter::ImplWriteText( const Point& rPos, const String& rText,
2619 : const sal_Int32* pDXArray, long nWidth,
2620 : sal_Bool bApplyMapping )
2621 : {
2622 0 : const FontMetric aMetric( mpVDev->GetFontMetric() );
2623 :
2624 0 : bool bTextSpecial = aMetric.IsShadow() || aMetric.IsOutline() || (aMetric.GetRelief() != RELIEF_NONE);
2625 :
2626 0 : if( !bTextSpecial )
2627 : {
2628 0 : ImplWriteText( rPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2629 : }
2630 : else
2631 : {
2632 0 : if( aMetric.GetRelief() != RELIEF_NONE )
2633 : {
2634 0 : Color aReliefColor( COL_LIGHTGRAY );
2635 0 : Color aTextColor( mpVDev->GetTextColor() );
2636 :
2637 0 : if ( aTextColor.GetColor() == COL_BLACK )
2638 0 : aTextColor = Color( COL_WHITE );
2639 :
2640 0 : if ( aTextColor.GetColor() == COL_WHITE )
2641 0 : aReliefColor = Color( COL_BLACK );
2642 :
2643 :
2644 0 : Point aPos( rPos );
2645 0 : Point aOffset( 6, 6 );
2646 :
2647 0 : if ( aMetric.GetRelief() == RELIEF_ENGRAVED )
2648 : {
2649 0 : aPos -= aOffset;
2650 : }
2651 : else
2652 : {
2653 0 : aPos += aOffset;
2654 : }
2655 :
2656 0 : ImplWriteText( aPos, rText, pDXArray, nWidth, aReliefColor, bApplyMapping );
2657 0 : ImplWriteText( rPos, rText, pDXArray, nWidth, aTextColor, bApplyMapping );
2658 : }
2659 : else
2660 : {
2661 0 : if( aMetric.IsShadow() )
2662 : {
2663 0 : long nOff = 1 + ((aMetric.GetLineHeight()-24)/24);
2664 0 : if ( aMetric.IsOutline() )
2665 0 : nOff += 6;
2666 :
2667 0 : Color aTextColor( mpVDev->GetTextColor() );
2668 0 : Color aShadowColor = Color( COL_BLACK );
2669 :
2670 0 : if ( (aTextColor.GetColor() == COL_BLACK) || (aTextColor.GetLuminance() < 8) )
2671 0 : aShadowColor = Color( COL_LIGHTGRAY );
2672 :
2673 0 : Point aPos( rPos );
2674 0 : aPos += Point( nOff, nOff );
2675 0 : ImplWriteText( aPos, rText, pDXArray, nWidth, aShadowColor, bApplyMapping );
2676 :
2677 0 : if( !aMetric.IsOutline() )
2678 : {
2679 0 : ImplWriteText( rPos, rText, pDXArray, nWidth, aTextColor, bApplyMapping );
2680 : }
2681 : }
2682 :
2683 0 : if( aMetric.IsOutline() )
2684 : {
2685 0 : Point aPos = rPos + Point( -6, -6 );
2686 0 : ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2687 0 : aPos = rPos + Point( +6, +6);
2688 0 : ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2689 0 : aPos = rPos + Point( -6, +0);
2690 0 : ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2691 0 : aPos = rPos + Point( -6, +6);
2692 0 : ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2693 0 : aPos = rPos + Point( +0, +6);
2694 0 : ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2695 0 : aPos = rPos + Point( +0, -6);
2696 0 : ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2697 0 : aPos = rPos + Point( +6, -1);
2698 0 : ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2699 0 : aPos = rPos + Point( +6, +0);
2700 0 : ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2701 :
2702 0 : ImplWriteText( rPos, rText, pDXArray, nWidth, Color( COL_WHITE ), bApplyMapping );
2703 : }
2704 : }
2705 0 : }
2706 0 : }
2707 :
2708 0 : void SVGActionWriter::ImplWriteText( const Point& rPos, const String& rText,
2709 : const sal_Int32* pDXArray, long nWidth,
2710 : Color aTextColor, sal_Bool bApplyMapping )
2711 : {
2712 0 : sal_Int32 nLen = rText.Len();
2713 0 : Size aNormSize;
2714 0 : Point aPos;
2715 0 : Point aBaseLinePos( rPos );
2716 0 : const FontMetric aMetric( mpVDev->GetFontMetric() );
2717 0 : const Font& rFont = mpVDev->GetFont();
2718 :
2719 0 : if( rFont.GetAlign() == ALIGN_TOP )
2720 0 : aBaseLinePos.Y() += aMetric.GetAscent();
2721 0 : else if( rFont.GetAlign() == ALIGN_BOTTOM )
2722 0 : aBaseLinePos.Y() -= aMetric.GetDescent();
2723 :
2724 0 : if( bApplyMapping )
2725 0 : ImplMap( rPos, aPos );
2726 : else
2727 0 : aPos = rPos;
2728 :
2729 0 : boost::shared_array<sal_Int32> xTmpArray(new sal_Int32[nLen]);
2730 : // get text sizes
2731 0 : if( pDXArray )
2732 : {
2733 0 : aNormSize = Size( mpVDev->GetTextWidth( rText ), 0 );
2734 0 : memcpy(xTmpArray.get(), pDXArray, nLen * sizeof(sal_Int32));
2735 : }
2736 : else
2737 : {
2738 0 : aNormSize = Size( mpVDev->GetTextArray( rText, xTmpArray.get() ), 0 );
2739 : }
2740 0 : sal_Int32* pDX = xTmpArray.get();
2741 :
2742 : // if text is rotated, set transform matrix at new g element
2743 0 : if( rFont.GetOrientation() )
2744 : {
2745 0 : Point aRot( aPos );
2746 0 : String aTransform;
2747 :
2748 0 : aTransform = String( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "translate" ) ) );
2749 0 : aTransform += '(';
2750 0 : aTransform += String( ::rtl::OUString::valueOf( aRot.X() ) );
2751 0 : aTransform += ',';
2752 0 : aTransform += String( ::rtl::OUString::valueOf( aRot.Y() ) );
2753 0 : aTransform += ')';
2754 :
2755 0 : aTransform += String( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( " rotate" ) ) );
2756 0 : aTransform += '(';
2757 0 : aTransform += String( ::rtl::OUString::valueOf( rFont.GetOrientation() * -0.1 ) );
2758 0 : aTransform += ')';
2759 :
2760 0 : aTransform += String( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( " translate" ) ) );
2761 0 : aTransform += '(';
2762 0 : aTransform += String( ::rtl::OUString::valueOf( -aRot.X() ) );
2763 0 : aTransform += ',';
2764 0 : aTransform += String( ::rtl::OUString::valueOf( -aRot.Y() ) );
2765 0 : aTransform += ')';
2766 :
2767 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform, aTransform );
2768 : }
2769 :
2770 :
2771 0 : mpContext->AddPaintAttr( COL_TRANSPARENT, aTextColor );
2772 :
2773 : // for each line of text there should be at least one group element
2774 0 : SvXMLElementExport aSVGGElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_False );
2775 :
2776 0 : sal_Bool bIsPlaceholderField = sal_False;
2777 :
2778 0 : if( mbIsPlacehlolderShape )
2779 : {
2780 0 : OUString sTextContent = rText;
2781 0 : bIsPlaceholderField = sTextContent.match( sPlaceholderTag );
2782 : // for a placeholder text field we export only one <text> svg element
2783 0 : if( bIsPlaceholderField )
2784 : {
2785 0 : OUString sCleanTextContent;
2786 0 : static const sal_Int32 nFrom = sPlaceholderTag.getLength();
2787 0 : if( sTextContent.getLength() > nFrom )
2788 : {
2789 0 : sCleanTextContent = sTextContent.copy( nFrom );
2790 : }
2791 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "PlaceholderText" ) );
2792 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, ::rtl::OUString::valueOf( aPos.X() ) );
2793 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( aPos.Y() ) );
2794 : {
2795 0 : SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, sal_False );
2796 : // At least for the single slide case we need really to export placeholder text
2797 0 : mrExport.GetDocHandler()->characters( sCleanTextContent );
2798 0 : }
2799 0 : }
2800 : }
2801 :
2802 0 : if( !bIsPlaceholderField )
2803 : {
2804 0 : if( nLen > 1 )
2805 : {
2806 0 : aNormSize.Width() = pDX[ nLen - 2 ] + mpVDev->GetTextWidth( rtl::OUString(rText.GetChar(nLen - 1)) );
2807 :
2808 0 : if( nWidth && aNormSize.Width() && ( nWidth != aNormSize.Width() ) )
2809 : {
2810 : long i;
2811 0 : const double fFactor = (double) nWidth / aNormSize.Width();
2812 :
2813 0 : for( i = 0; i < ( nLen - 1 ); i++ )
2814 0 : pDX[ i ] = FRound( pDX[ i ] * fFactor );
2815 : }
2816 : else
2817 : {
2818 0 : ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xBI( ::vcl::unohelper::CreateBreakIterator() );
2819 0 : const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetLanguageTag().getLocale();
2820 0 : sal_Int32 nCurPos = 0, nLastPos = 0, nX = aPos.X();
2821 :
2822 : // write single glyphs at absolute text positions
2823 0 : for( sal_Bool bCont = sal_True; bCont; )
2824 : {
2825 0 : sal_Int32 nCount = 1;
2826 :
2827 0 : nLastPos = nCurPos;
2828 0 : nCurPos = xBI->nextCharacters( rText, nCurPos, rLocale,
2829 : ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL,
2830 0 : nCount, nCount );
2831 :
2832 0 : nCount = nCurPos - nLastPos;
2833 0 : bCont = ( nCurPos < rText.Len() ) && nCount;
2834 :
2835 0 : if( nCount )
2836 : {
2837 0 : const ::rtl::OUString aGlyph( rText.Copy( nLastPos, nCount ) );
2838 :
2839 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, ::rtl::OUString::valueOf( nX ) );
2840 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( aPos.Y() ) );
2841 :
2842 : {
2843 0 : SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, sal_False );
2844 0 : mrExport.GetDocHandler()->characters( aGlyph );
2845 : }
2846 :
2847 0 : if( bCont )
2848 : {
2849 : // #118796# do NOT access pDXArray, it may be zero (!)
2850 0 : nX = aPos.X() + pDX[ nCurPos - 1 ];
2851 0 : }
2852 : }
2853 0 : }
2854 : }
2855 : }
2856 : else
2857 : {
2858 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, ::rtl::OUString::valueOf( aPos.X() ) );
2859 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( aPos.Y() ) );
2860 :
2861 : {
2862 0 : SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, sal_False );
2863 0 : mrExport.GetDocHandler()->characters( rText );
2864 : }
2865 : }
2866 : }
2867 :
2868 :
2869 0 : if( !mrExport.IsUseNativeTextDecoration() )
2870 : {
2871 0 : if( rFont.GetStrikeout() != STRIKEOUT_NONE || rFont.GetUnderline() != UNDERLINE_NONE )
2872 : {
2873 0 : Polygon aPoly( 4 );
2874 0 : const long nLineHeight = Max( (long) FRound( aMetric.GetLineHeight() * 0.05 ), (long) 1 );
2875 :
2876 0 : if( rFont.GetStrikeout() )
2877 : {
2878 0 : const long nYLinePos = aBaseLinePos.Y() - FRound( aMetric.GetAscent() * 0.26 );
2879 :
2880 0 : aPoly[ 0 ].X() = aBaseLinePos.X(); aPoly[ 0 ].Y() = nYLinePos - ( nLineHeight >> 1 );
2881 0 : aPoly[ 1 ].X() = aBaseLinePos.X() + aNormSize.Width() - 1; aPoly[ 1 ].Y() = aPoly[ 0 ].Y();
2882 0 : aPoly[ 2 ].X() = aPoly[ 1 ].X(); aPoly[ 2 ].Y() = aPoly[ 0 ].Y() + nLineHeight - 1;
2883 0 : aPoly[ 3 ].X() = aPoly[ 0 ].X(); aPoly[ 3 ].Y() = aPoly[ 2 ].Y();
2884 :
2885 0 : ImplWritePolyPolygon( aPoly, sal_False );
2886 : }
2887 :
2888 0 : if( rFont.GetUnderline() )
2889 : {
2890 0 : const long nYLinePos = aBaseLinePos.Y() + ( nLineHeight << 1 );
2891 :
2892 0 : aPoly[ 0 ].X() = aBaseLinePos.X(); aPoly[ 0 ].Y() = nYLinePos - ( nLineHeight >> 1 );
2893 0 : aPoly[ 1 ].X() = aBaseLinePos.X() + aNormSize.Width() - 1; aPoly[ 1 ].Y() = aPoly[ 0 ].Y();
2894 0 : aPoly[ 2 ].X() = aPoly[ 1 ].X(); aPoly[ 2 ].Y() = aPoly[ 0 ].Y() + nLineHeight - 1;
2895 0 : aPoly[ 3 ].X() = aPoly[ 0 ].X(); aPoly[ 3 ].Y() = aPoly[ 2 ].Y();
2896 :
2897 0 : ImplWritePolyPolygon( aPoly, sal_False );
2898 0 : }
2899 : }
2900 0 : }
2901 0 : }
2902 :
2903 : // -----------------------------------------------------------------------------
2904 :
2905 0 : void SVGActionWriter::ImplWriteBmp( const BitmapEx& rBmpEx,
2906 : const Point& rPt, const Size& rSz,
2907 : const Point& rSrcPt, const Size& rSrcSz,
2908 : sal_Bool bApplyMapping )
2909 : {
2910 0 : if( !!rBmpEx )
2911 : {
2912 0 : BitmapEx aBmpEx( rBmpEx );
2913 0 : Point aPoint = Point();
2914 0 : const Rectangle aBmpRect( aPoint, rBmpEx.GetSizePixel() );
2915 0 : const Rectangle aSrcRect( rSrcPt, rSrcSz );
2916 :
2917 0 : if( aSrcRect != aBmpRect )
2918 0 : aBmpEx.Crop( aSrcRect );
2919 :
2920 0 : if( !!aBmpEx )
2921 : {
2922 0 : SvMemoryStream aOStm( 65535, 65535 );
2923 :
2924 0 : if( GraphicConverter::Export( aOStm, rBmpEx, CVT_PNG ) == ERRCODE_NONE )
2925 : {
2926 0 : Point aPt;
2927 0 : Size aSz;
2928 0 : Sequence< sal_Int8 > aSeq( (sal_Int8*) aOStm.GetData(), aOStm.Tell() );
2929 0 : rtl::OUStringBuffer aBuffer;
2930 0 : aBuffer.appendAscii( "data:image/png;base64," );
2931 0 : ::sax::Converter::encodeBase64( aBuffer, aSeq );
2932 :
2933 0 : if( bApplyMapping )
2934 : {
2935 0 : ImplMap( rPt, aPt );
2936 0 : ImplMap( rSz, aSz );
2937 : }
2938 : else
2939 : {
2940 0 : aPt = rPt;
2941 0 : aSz = rSz;
2942 : }
2943 :
2944 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::valueOf( aPt.X() ) );
2945 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::valueOf( aPt.Y() ) );
2946 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrWidth, OUString::valueOf( aSz.Width() ) );
2947 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrHeight, OUString::valueOf( aSz.Height() ) );
2948 0 : mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, aBuffer.makeStringAndClear() );
2949 : {
2950 0 : SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemImage, sal_True, sal_True );
2951 0 : }
2952 0 : }
2953 0 : }
2954 : }
2955 0 : }
2956 :
2957 : // -----------------------------------------------------------------------------
2958 :
2959 0 : void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
2960 : sal_uInt32 nWriteFlags,
2961 : const ::rtl::OUString* pElementId,
2962 : const Reference< XShape >* pxShape,
2963 : const GDIMetaFile* pTextEmbeddedBitmapMtf )
2964 : {
2965 : // need a counter fo rthe actions written per shape to avoid double ID
2966 : // generation
2967 0 : sal_Int32 nEntryCount(0);
2968 :
2969 0 : if( mnInnerMtfCount )
2970 0 : nWriteFlags |= SVGWRITER_NO_SHAPE_COMMENTS;
2971 :
2972 :
2973 : #if OSL_DEBUG_LEVEL > 0
2974 : bool bIsTextShape = false;
2975 : if( !mrExport.IsUsePositionedCharacters() && pxShape
2976 : && Reference< XText >( *pxShape, UNO_QUERY ).is() )
2977 : {
2978 : bIsTextShape = true;
2979 : }
2980 : #endif
2981 0 : mbIsPlacehlolderShape = false;
2982 0 : if( ( pElementId != NULL ) && ( *pElementId == sPlaceholderTag ) )
2983 : {
2984 0 : mbIsPlacehlolderShape = true;
2985 : // since we utilize pElementId in an improper way we reset it to NULL before to go on
2986 0 : pElementId = NULL;
2987 : }
2988 :
2989 0 : for( sal_uLong nCurAction = 0, nCount = rMtf.GetActionSize(); nCurAction < nCount; nCurAction++ )
2990 : {
2991 0 : const MetaAction* pAction = rMtf.GetAction( nCurAction );
2992 0 : const sal_uInt16 nType = pAction->GetType();
2993 :
2994 : #if OSL_DEBUG_LEVEL > 0
2995 : if( bIsTextShape )
2996 : {
2997 : try
2998 : {
2999 : SvXMLElementExport aElem( mrExport,
3000 : XML_NAMESPACE_NONE, "desc", sal_False, sal_False );
3001 : OUStringBuffer sType;
3002 : sType.append(static_cast<sal_Int32>(nType));
3003 : if (pAction && (nType == META_COMMENT_ACTION))
3004 : {
3005 : sType.append(": ");
3006 : const MetaCommentAction* pA = (const MetaCommentAction*) pAction;
3007 : rtl::OString sComment = pA->GetComment();
3008 : if (!sComment.isEmpty())
3009 : {
3010 : OUString ssComment = OUString( sComment.getStr(),
3011 : sComment.getLength(), RTL_TEXTENCODING_UTF8 );
3012 : sType.append(ssComment);
3013 : }
3014 : if (sComment.equalsIgnoreAsciiCaseL(
3015 : RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_BEGIN")))
3016 : {
3017 : sal_uInt8 const*const pData = pA->GetData();
3018 : if (pData && (pA->GetDataSize()))
3019 : {
3020 : sal_uInt16 sz = (sal_uInt16)((pA->GetDataSize()) / 2);
3021 : if (sz)
3022 : {
3023 : sType.append("; ");
3024 : sType.append(
3025 : reinterpret_cast<sal_Unicode const*>(pData),
3026 : sz);
3027 : }
3028 : }
3029 : }
3030 : }
3031 : if (sType.getLength())
3032 : {
3033 : mrExport.GetDocHandler()->characters(
3034 : sType.makeStringAndClear());
3035 : }
3036 : }
3037 : catch( ... )
3038 : {
3039 : const MetaCommentAction* pA = (const MetaCommentAction*) pAction;
3040 : OSL_FAIL( pA->GetComment().getStr() );
3041 : }
3042 :
3043 : }
3044 : #endif
3045 0 : switch( nType )
3046 : {
3047 : case( META_PIXEL_ACTION ):
3048 : {
3049 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3050 : {
3051 0 : const MetaPixelAction* pA = (const MetaPixelAction*) pAction;
3052 :
3053 0 : mpContext->AddPaintAttr( pA->GetColor(), pA->GetColor() );
3054 0 : ImplWriteLine( pA->GetPoint(), pA->GetPoint(), &pA->GetColor() );
3055 : }
3056 : }
3057 0 : break;
3058 :
3059 : case( META_POINT_ACTION ):
3060 : {
3061 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3062 : {
3063 0 : const MetaPointAction* pA = (const MetaPointAction*) pAction;
3064 :
3065 0 : mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetLineColor() );
3066 0 : ImplWriteLine( pA->GetPoint(), pA->GetPoint(), NULL );
3067 : }
3068 : }
3069 0 : break;
3070 :
3071 : case( META_LINE_ACTION ):
3072 : {
3073 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3074 : {
3075 0 : const MetaLineAction* pA = (const MetaLineAction*) pAction;
3076 :
3077 0 : mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetLineColor() );
3078 0 : ImplWriteLine( pA->GetStartPoint(), pA->GetEndPoint(), NULL );
3079 : }
3080 : }
3081 0 : break;
3082 :
3083 : case( META_RECT_ACTION ):
3084 : {
3085 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3086 : {
3087 0 : mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
3088 0 : ImplWriteRect( ( (const MetaRectAction*) pAction )->GetRect(), 0, 0 );
3089 : }
3090 : }
3091 0 : break;
3092 :
3093 : case( META_ROUNDRECT_ACTION ):
3094 : {
3095 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3096 : {
3097 0 : const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pAction;
3098 :
3099 0 : mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
3100 0 : ImplWriteRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
3101 : }
3102 : }
3103 0 : break;
3104 :
3105 : case( META_ELLIPSE_ACTION ):
3106 : {
3107 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3108 : {
3109 0 : const MetaEllipseAction* pA = (const MetaEllipseAction*) pAction;
3110 0 : const Rectangle& rRect = pA->GetRect();
3111 :
3112 0 : mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
3113 0 : ImplWriteEllipse( rRect.Center(), rRect.GetWidth() >> 1, rRect.GetHeight() >> 1 );
3114 : }
3115 : }
3116 0 : break;
3117 :
3118 : case( META_ARC_ACTION ):
3119 : case( META_PIE_ACTION ):
3120 : case( META_CHORD_ACTION ):
3121 : case( META_POLYGON_ACTION ):
3122 : {
3123 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3124 : {
3125 0 : Polygon aPoly;
3126 :
3127 0 : switch( nType )
3128 : {
3129 : case( META_ARC_ACTION ):
3130 : {
3131 0 : const MetaArcAction* pA = (const MetaArcAction*) pAction;
3132 0 : aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC );
3133 : }
3134 0 : break;
3135 :
3136 : case( META_PIE_ACTION ):
3137 : {
3138 0 : const MetaPieAction* pA = (const MetaPieAction*) pAction;
3139 0 : aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE );
3140 : }
3141 0 : break;
3142 :
3143 : case( META_CHORD_ACTION ):
3144 : {
3145 0 : const MetaChordAction* pA = (const MetaChordAction*) pAction;
3146 0 : aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD );
3147 : }
3148 0 : break;
3149 :
3150 : case( META_POLYGON_ACTION ):
3151 0 : aPoly = ( (const MetaPolygonAction*) pAction )->GetPolygon();
3152 0 : break;
3153 : }
3154 :
3155 0 : if( aPoly.GetSize() )
3156 : {
3157 0 : mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
3158 0 : ImplWritePolyPolygon( aPoly, sal_False );
3159 0 : }
3160 : }
3161 : }
3162 0 : break;
3163 :
3164 : case( META_POLYLINE_ACTION ):
3165 : {
3166 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3167 : {
3168 0 : const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pAction;
3169 0 : const Polygon& rPoly = pA->GetPolygon();
3170 :
3171 0 : if( rPoly.GetSize() )
3172 : {
3173 0 : mpContext->AddPaintAttr( mpVDev->GetLineColor(), Color( COL_TRANSPARENT ) );
3174 0 : ImplWritePolyPolygon( rPoly, sal_True );
3175 : }
3176 : }
3177 : }
3178 0 : break;
3179 :
3180 : case( META_POLYPOLYGON_ACTION ):
3181 : {
3182 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3183 : {
3184 0 : const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*) pAction;
3185 0 : const PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
3186 :
3187 0 : if( rPolyPoly.Count() )
3188 : {
3189 0 : mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
3190 0 : ImplWritePolyPolygon( rPolyPoly, sal_False );
3191 : }
3192 : }
3193 : }
3194 0 : break;
3195 :
3196 : case( META_GRADIENT_ACTION ):
3197 : {
3198 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3199 : {
3200 0 : const MetaGradientAction* pA = (const MetaGradientAction*) pAction;
3201 0 : const Polygon aRectPoly( pA->GetRect() );
3202 0 : const PolyPolygon aRectPolyPoly( aRectPoly );
3203 :
3204 0 : ImplWriteGradientEx( aRectPolyPoly, pA->GetGradient(), nWriteFlags );
3205 : }
3206 : }
3207 0 : break;
3208 :
3209 : case( META_GRADIENTEX_ACTION ):
3210 : {
3211 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3212 : {
3213 0 : const MetaGradientExAction* pA = (const MetaGradientExAction*) pAction;
3214 0 : ImplWriteGradientEx( pA->GetPolyPolygon(), pA->GetGradient(), nWriteFlags );
3215 : }
3216 : }
3217 0 : break;
3218 :
3219 : case META_HATCH_ACTION:
3220 : {
3221 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3222 : {
3223 0 : const MetaHatchAction* pA = (const MetaHatchAction*) pAction;
3224 0 : ImplWritePattern( pA->GetPolyPolygon(), &pA->GetHatch(), NULL, nWriteFlags );
3225 : }
3226 : }
3227 0 : break;
3228 :
3229 : case( META_TRANSPARENT_ACTION ):
3230 : {
3231 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3232 : {
3233 0 : const MetaTransparentAction* pA = (const MetaTransparentAction*) pAction;
3234 0 : const PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
3235 :
3236 0 : if( rPolyPoly.Count() )
3237 : {
3238 0 : Color aNewLineColor( mpVDev->GetLineColor() ), aNewFillColor( mpVDev->GetFillColor() );
3239 :
3240 0 : aNewLineColor.SetTransparency( sal::static_int_cast<sal_uInt8>( FRound( pA->GetTransparence() * 2.55 ) ) );
3241 0 : aNewFillColor.SetTransparency( sal::static_int_cast<sal_uInt8>( FRound( pA->GetTransparence() * 2.55 ) ) );
3242 :
3243 0 : mpContext->AddPaintAttr( aNewLineColor, aNewFillColor );
3244 0 : ImplWritePolyPolygon( rPolyPoly, sal_False );
3245 : }
3246 : }
3247 : }
3248 0 : break;
3249 :
3250 : case( META_FLOATTRANSPARENT_ACTION ):
3251 : {
3252 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3253 : {
3254 0 : const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pAction;
3255 0 : GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
3256 0 : ImplWriteMask( aTmpMtf, pA->GetPoint(), pA->GetSize(),
3257 0 : pA->GetGradient(), nWriteFlags );
3258 : }
3259 : }
3260 0 : break;
3261 :
3262 : case( META_EPS_ACTION ):
3263 : {
3264 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3265 : {
3266 0 : const MetaEPSAction* pA = (const MetaEPSAction*) pAction;
3267 0 : const GDIMetaFile aGDIMetaFile( pA->GetSubstitute() );
3268 0 : sal_Bool bFound = sal_False;
3269 :
3270 0 : for( sal_uInt32 k = 0, nCount2 = aGDIMetaFile.GetActionSize(); ( k < nCount2 ) && !bFound; ++k )
3271 : {
3272 0 : const MetaAction* pSubstAct = aGDIMetaFile.GetAction( k );
3273 :
3274 0 : if( pSubstAct->GetType() == META_BMPSCALE_ACTION )
3275 : {
3276 0 : bFound = sal_True;
3277 0 : const MetaBmpScaleAction* pBmpScaleAction = (const MetaBmpScaleAction*) pSubstAct;
3278 0 : ImplWriteBmp( pBmpScaleAction->GetBitmap(),
3279 0 : pA->GetPoint(), pA->GetSize(),
3280 0 : Point(), pBmpScaleAction->GetBitmap().GetSizePixel() );
3281 : }
3282 0 : }
3283 : }
3284 : }
3285 0 : break;
3286 :
3287 : case( META_COMMENT_ACTION ):
3288 : {
3289 0 : const MetaCommentAction* pA = (const MetaCommentAction*) pAction;
3290 0 : String aSkipComment;
3291 :
3292 0 : if( ( pA->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XGRAD_SEQ_BEGIN")) ) &&
3293 : ( nWriteFlags & SVGWRITER_WRITE_FILL ) )
3294 : {
3295 0 : const MetaGradientExAction* pGradAction = NULL;
3296 0 : sal_Bool bDone = sal_False;
3297 :
3298 0 : while( !bDone && ( ++nCurAction < nCount ) )
3299 : {
3300 0 : pAction = rMtf.GetAction( nCurAction );
3301 :
3302 0 : if( pAction->GetType() == META_GRADIENTEX_ACTION )
3303 0 : pGradAction = (const MetaGradientExAction*) pAction;
3304 0 : else if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
3305 0 : ( ( (const MetaCommentAction*) pAction )->GetComment().
3306 0 : equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XGRAD_SEQ_END")) ) )
3307 : {
3308 0 : bDone = sal_True;
3309 : }
3310 : }
3311 :
3312 0 : if( pGradAction )
3313 0 : ImplWriteGradientEx( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), nWriteFlags );
3314 : }
3315 0 : else if( ( pA->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHFILL_SEQ_BEGIN")) ) &&
3316 0 : ( nWriteFlags & SVGWRITER_WRITE_FILL ) && !( nWriteFlags & SVGWRITER_NO_SHAPE_COMMENTS ) &&
3317 0 : pA->GetDataSize() )
3318 : {
3319 : // write open shape in every case
3320 0 : if( mapCurShape.get() )
3321 : {
3322 0 : ImplWriteShape( *mapCurShape );
3323 0 : mapCurShape.reset();
3324 : }
3325 :
3326 0 : SvMemoryStream aMemStm( (void*) pA->GetData(), pA->GetDataSize(), STREAM_READ );
3327 0 : SvtGraphicFill aFill;
3328 :
3329 0 : aMemStm >> aFill;
3330 :
3331 0 : sal_Bool bGradient = SvtGraphicFill::fillGradient == aFill.getFillType() &&
3332 0 : ( SvtGraphicFill::gradientLinear == aFill.getGradientType() ||
3333 0 : SvtGraphicFill::gradientRadial == aFill.getGradientType() );
3334 0 : sal_Bool bSkip = ( SvtGraphicFill::fillSolid == aFill.getFillType() || bGradient );
3335 :
3336 0 : if( bSkip )
3337 : {
3338 0 : PolyPolygon aShapePolyPoly;
3339 :
3340 0 : aFill.getPath( aShapePolyPoly );
3341 :
3342 0 : if( aShapePolyPoly.Count() )
3343 : {
3344 0 : mapCurShape.reset( new SVGShapeDescriptor );
3345 :
3346 0 : if( pElementId )
3347 : {
3348 0 : mapCurShape->maId = *pElementId + B2UCONST("_") + ::rtl::OUString::valueOf(nEntryCount++);
3349 : }
3350 :
3351 0 : mapCurShape->maShapePolyPoly = aShapePolyPoly;
3352 0 : mapCurShape->maShapeFillColor = aFill.getFillColor();
3353 0 : mapCurShape->maShapeFillColor.SetTransparency( (sal_uInt8) FRound( 255.0 * aFill.getTransparency() ) );
3354 :
3355 0 : if( bGradient )
3356 : {
3357 : // step through following actions until the first Gradient/GradientEx action is found
3358 0 : while( !mapCurShape->mapShapeGradient.get() && bSkip && ( ++nCurAction < nCount ) )
3359 : {
3360 0 : pAction = rMtf.GetAction( nCurAction );
3361 :
3362 0 : if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
3363 0 : ( ( (const MetaCommentAction*) pAction )->GetComment().
3364 0 : equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHFILL_SEQ_END")) ) )
3365 : {
3366 0 : bSkip = sal_False;
3367 : }
3368 0 : else if( pAction->GetType() == META_GRADIENTEX_ACTION )
3369 : {
3370 0 : mapCurShape->mapShapeGradient.reset( new Gradient(
3371 0 : static_cast< const MetaGradientExAction* >( pAction )->GetGradient() ) );
3372 : }
3373 0 : else if( pAction->GetType() == META_GRADIENT_ACTION )
3374 : {
3375 0 : mapCurShape->mapShapeGradient.reset( new Gradient(
3376 0 : static_cast< const MetaGradientAction* >( pAction )->GetGradient() ) );
3377 : }
3378 : }
3379 : }
3380 : }
3381 : else
3382 0 : bSkip = sal_False;
3383 : }
3384 :
3385 : // skip rest of comment
3386 0 : while( bSkip && ( ++nCurAction < nCount ) )
3387 : {
3388 0 : pAction = rMtf.GetAction( nCurAction );
3389 :
3390 0 : if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
3391 0 : ( ( (const MetaCommentAction*) pAction )->GetComment().
3392 0 : equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHFILL_SEQ_END")) ) )
3393 : {
3394 0 : bSkip = sal_False;
3395 : }
3396 0 : }
3397 : }
3398 0 : else if( ( pA->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHSTROKE_SEQ_BEGIN")) ) &&
3399 0 : ( nWriteFlags & SVGWRITER_WRITE_FILL ) && !( nWriteFlags & SVGWRITER_NO_SHAPE_COMMENTS ) &&
3400 0 : pA->GetDataSize() )
3401 : {
3402 0 : SvMemoryStream aMemStm( (void*) pA->GetData(), pA->GetDataSize(), STREAM_READ );
3403 0 : SvtGraphicStroke aStroke;
3404 0 : PolyPolygon aStartArrow, aEndArrow;
3405 :
3406 0 : aMemStm >> aStroke;
3407 0 : aStroke.getStartArrow( aStartArrow );
3408 0 : aStroke.getEndArrow( aEndArrow );
3409 :
3410 : // Currently no support for strokes with start/end arrow(s)
3411 0 : sal_Bool bSkip = ( !aStartArrow.Count() && !aEndArrow.Count() );
3412 :
3413 0 : if( bSkip )
3414 : {
3415 0 : Polygon aPoly;
3416 :
3417 0 : aStroke.getPath(aPoly);
3418 :
3419 0 : if(mapCurShape.get())
3420 : {
3421 0 : if(1 != mapCurShape->maShapePolyPoly.Count()
3422 0 : || !mapCurShape->maShapePolyPoly[0].IsEqual(aPoly))
3423 : {
3424 : // this path action is not covering the same path than the already existing
3425 : // fill polypolygon, so write out the fill polygon
3426 0 : ImplWriteShape( *mapCurShape );
3427 0 : mapCurShape.reset();
3428 : }
3429 : }
3430 :
3431 0 : if( !mapCurShape.get() )
3432 : {
3433 0 : mapCurShape.reset( new SVGShapeDescriptor );
3434 :
3435 0 : if( pElementId )
3436 : {
3437 0 : mapCurShape->maId = *pElementId + B2UCONST("_") + ::rtl::OUString::valueOf(nEntryCount++);
3438 : }
3439 :
3440 0 : aStroke.getPath( aPoly );
3441 0 : mapCurShape->maShapePolyPoly = aPoly;
3442 : }
3443 :
3444 0 : mapCurShape->maShapeLineColor = mpVDev->GetLineColor();
3445 0 : mapCurShape->maShapeLineColor.SetTransparency( (sal_uInt8) FRound( aStroke.getTransparency() * 255.0 ) );
3446 0 : mapCurShape->mnStrokeWidth = FRound( aStroke.getStrokeWidth() );
3447 0 : aStroke.getDashArray( mapCurShape->maDashArray );
3448 : }
3449 :
3450 : // support for LineJoin
3451 0 : switch(aStroke.getJoinType())
3452 : {
3453 : default: /* SvtGraphicStroke::joinMiter, SvtGraphicStroke::joinNone */
3454 : {
3455 0 : mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_MITER;
3456 0 : break;
3457 : }
3458 : case SvtGraphicStroke::joinRound:
3459 : {
3460 0 : mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_ROUND;
3461 0 : break;
3462 : }
3463 : case SvtGraphicStroke::joinBevel:
3464 : {
3465 0 : mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_BEVEL;
3466 0 : break;
3467 : }
3468 : }
3469 :
3470 : // support for LineCap
3471 0 : switch(aStroke.getCapType())
3472 : {
3473 : default: /* SvtGraphicStroke::capButt */
3474 : {
3475 0 : mapCurShape->maLineCap = com::sun::star::drawing::LineCap_BUTT;
3476 0 : break;
3477 : }
3478 : case SvtGraphicStroke::capRound:
3479 : {
3480 0 : mapCurShape->maLineCap = com::sun::star::drawing::LineCap_ROUND;
3481 0 : break;
3482 : }
3483 : case SvtGraphicStroke::capSquare:
3484 : {
3485 0 : mapCurShape->maLineCap = com::sun::star::drawing::LineCap_SQUARE;
3486 0 : break;
3487 : }
3488 : }
3489 :
3490 : // write open shape in every case
3491 0 : if( mapCurShape.get() )
3492 : {
3493 0 : ImplWriteShape( *mapCurShape );
3494 0 : mapCurShape.reset();
3495 : }
3496 :
3497 : // skip rest of comment
3498 0 : while( bSkip && ( ++nCurAction < nCount ) )
3499 : {
3500 0 : pAction = rMtf.GetAction( nCurAction );
3501 :
3502 0 : if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
3503 0 : ( ( (const MetaCommentAction*) pAction )->GetComment().
3504 0 : equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHSTROKE_SEQ_END")) ) )
3505 : {
3506 0 : bSkip = sal_False;
3507 : }
3508 0 : }
3509 : }
3510 0 : else if( !mrExport.IsUsePositionedCharacters() && ( nWriteFlags & SVGWRITER_WRITE_TEXT ) )
3511 : {
3512 0 : if( ( pA->GetComment().equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_PAINTSHAPE_BEGIN" ) ) ) )
3513 : {
3514 0 : if( pxShape )
3515 : {
3516 0 : Reference< XText > xText( *pxShape, UNO_QUERY );
3517 0 : if( xText.is() )
3518 0 : maTextWriter.setTextShape( xText, pTextEmbeddedBitmapMtf );
3519 : }
3520 0 : maTextWriter.createParagraphEnumeration();
3521 : {
3522 : // nTextFound == -1 => no text found
3523 : // nTextFound == 0 => no text found and end of text shape reached
3524 : // nTextFound == 1 => text found!
3525 0 : sal_Int32 nTextFound = -1;
3526 0 : while( ( nTextFound < 0 ) && ( nCurAction < nCount ) )
3527 : {
3528 0 : nTextFound = maTextWriter.setTextPosition( rMtf, nCurAction );
3529 : }
3530 : // We found some text in the current text shape.
3531 0 : if( nTextFound > 0 )
3532 : {
3533 0 : maTextWriter.setTextProperties( rMtf, nCurAction );
3534 0 : maTextWriter.startTextShape();
3535 : }
3536 : // We reached the end of the current text shape
3537 : // without finding any text. So we need to go back
3538 : // by one action in order to handle the
3539 : // XTEXT_PAINTSHAPE_END action because on the next
3540 : // loop the nCurAction is incremented by one.
3541 : else
3542 : {
3543 0 : --nCurAction;
3544 : }
3545 : }
3546 : }
3547 0 : else if( ( pA->GetComment().equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_PAINTSHAPE_END" ) ) ) )
3548 : {
3549 0 : maTextWriter.endTextShape();
3550 : }
3551 0 : else if( ( pA->GetComment().equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_EOP" ) ) ) )
3552 : {
3553 0 : const MetaAction* pNextAction = rMtf.GetAction( nCurAction + 1 );
3554 0 : if( !( ( pNextAction->GetType() == META_COMMENT_ACTION ) &&
3555 0 : ( ( (const MetaCommentAction*) pNextAction )->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XTEXT_PAINTSHAPE_END") ) ) ))
3556 : {
3557 : // nTextFound == -1 => no text found and end of paragraph reached
3558 : // nTextFound == 0 => no text found and end of text shape reached
3559 : // nTextFound == 1 => text found!
3560 0 : sal_Int32 nTextFound = -1;
3561 0 : while( ( nTextFound < 0 ) && ( nCurAction < nCount ) )
3562 : {
3563 0 : nTextFound = maTextWriter.setTextPosition( rMtf, nCurAction );
3564 : }
3565 : // We found a paragraph with some text in the
3566 : // current text shape.
3567 0 : if( nTextFound > 0 )
3568 : {
3569 0 : maTextWriter.setTextProperties( rMtf, nCurAction );
3570 0 : maTextWriter.startTextParagraph();
3571 : }
3572 : // We reached the end of the current text shape
3573 : // without finding any text. So we need to go back
3574 : // by one action in order to handle the
3575 : // XTEXT_PAINTSHAPE_END action because on the next
3576 : // loop the nCurAction is incremented by one.
3577 : else
3578 : {
3579 0 : --nCurAction;
3580 : }
3581 :
3582 : }
3583 : }
3584 0 : else if( ( pA->GetComment().equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_EOL" ) ) ) )
3585 : {
3586 0 : const MetaAction* pNextAction = rMtf.GetAction( nCurAction + 1 );
3587 0 : if( !( ( pNextAction->GetType() == META_COMMENT_ACTION ) &&
3588 0 : ( ( (const MetaCommentAction*) pNextAction )->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOP") ) ) ) )
3589 : {
3590 : // nTextFound == -2 => no text found and end of line reached
3591 : // nTextFound == -1 => no text found and end of paragraph reached
3592 : // nTextFound == 1 => text found!
3593 0 : sal_Int32 nTextFound = -2;
3594 0 : while( ( nTextFound < -1 ) && ( nCurAction < nCount ) )
3595 : {
3596 0 : nTextFound = maTextWriter.setTextPosition( rMtf, nCurAction );
3597 : }
3598 : // We found a line with some text in the current
3599 : // paragraph.
3600 0 : if( nTextFound > 0 )
3601 : {
3602 0 : maTextWriter.startTextPosition();
3603 : }
3604 : // We reached the end of the current paragraph
3605 : // without finding any text. So we need to go back
3606 : // by one action in order to handle the XTEXT_EOP
3607 : // action because on the next loop the nCurAction is
3608 : // incremented by one.
3609 : else
3610 : {
3611 0 : --nCurAction;
3612 : }
3613 : }
3614 : }
3615 0 : }
3616 : }
3617 0 : break;
3618 :
3619 : case( META_BMP_ACTION ):
3620 : {
3621 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3622 : {
3623 0 : const MetaBmpAction* pA = (const MetaBmpAction*) pAction;
3624 :
3625 0 : ImplWriteBmp( pA->GetBitmap(),
3626 0 : pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmap().GetSizePixel() ),
3627 0 : Point(), pA->GetBitmap().GetSizePixel() );
3628 : }
3629 : }
3630 0 : break;
3631 :
3632 : case( META_BMPSCALE_ACTION ):
3633 : {
3634 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3635 : {
3636 0 : const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction;
3637 :
3638 : // Bitmaps embedded into text shapes are collected and exported elsewhere.
3639 0 : if( maTextWriter.isTextShapeStarted() )
3640 : {
3641 0 : maTextWriter.writeBitmapPlaceholder( pA );
3642 : }
3643 : else
3644 : {
3645 0 : ImplWriteBmp( pA->GetBitmap(),
3646 0 : pA->GetPoint(), pA->GetSize(),
3647 0 : Point(), pA->GetBitmap().GetSizePixel() );
3648 : }
3649 : }
3650 : }
3651 0 : break;
3652 :
3653 : case( META_BMPSCALEPART_ACTION ):
3654 : {
3655 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3656 : {
3657 0 : const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pAction;
3658 :
3659 0 : ImplWriteBmp( pA->GetBitmap(),
3660 0 : pA->GetDestPoint(), pA->GetDestSize(),
3661 0 : pA->GetSrcPoint(), pA->GetSrcSize() );
3662 : }
3663 : }
3664 0 : break;
3665 :
3666 : case( META_BMPEX_ACTION ):
3667 : {
3668 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3669 : {
3670 0 : const MetaBmpExAction* pA = (const MetaBmpExAction*) pAction;
3671 :
3672 0 : ImplWriteBmp( pA->GetBitmapEx(),
3673 0 : pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmapEx().GetSizePixel() ),
3674 0 : Point(), pA->GetBitmapEx().GetSizePixel() );
3675 : }
3676 : }
3677 0 : break;
3678 :
3679 : case( META_BMPEXSCALE_ACTION ):
3680 : {
3681 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3682 : {
3683 0 : const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction;
3684 :
3685 : // Bitmaps embedded into text shapes are collected and exported elsewhere.
3686 0 : if( maTextWriter.isTextShapeStarted() )
3687 : {
3688 0 : maTextWriter.writeBitmapPlaceholder( pA );
3689 : }
3690 : else
3691 : {
3692 0 : ImplWriteBmp( pA->GetBitmapEx(),
3693 0 : pA->GetPoint(), pA->GetSize(),
3694 0 : Point(), pA->GetBitmapEx().GetSizePixel() );
3695 : }
3696 : }
3697 : }
3698 0 : break;
3699 :
3700 : case( META_BMPEXSCALEPART_ACTION ):
3701 : {
3702 0 : if( nWriteFlags & SVGWRITER_WRITE_FILL )
3703 : {
3704 0 : const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pAction;
3705 :
3706 0 : ImplWriteBmp( pA->GetBitmapEx(),
3707 0 : pA->GetDestPoint(), pA->GetDestSize(),
3708 0 : pA->GetSrcPoint(), pA->GetSrcSize() );
3709 : }
3710 : }
3711 0 : break;
3712 :
3713 : case( META_TEXT_ACTION ):
3714 : {
3715 0 : if( nWriteFlags & SVGWRITER_WRITE_TEXT )
3716 : {
3717 0 : const MetaTextAction* pA = (const MetaTextAction*) pAction;
3718 0 : const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
3719 :
3720 0 : if( aText.Len() )
3721 : {
3722 0 : if( mrExport.IsUsePositionedCharacters() )
3723 : {
3724 0 : Font aFont = ImplSetCorrectFontHeight();
3725 0 : mpContext->SetFontAttr( aFont );
3726 0 : ImplWriteText( pA->GetPoint(), aText, NULL, 0 );
3727 : }
3728 : else
3729 : {
3730 0 : maTextWriter.writeTextPortion( pA->GetPoint(), aText );
3731 : }
3732 :
3733 0 : }
3734 : }
3735 : }
3736 0 : break;
3737 :
3738 : case( META_TEXTRECT_ACTION ):
3739 : {
3740 0 : if( nWriteFlags & SVGWRITER_WRITE_TEXT )
3741 : {
3742 0 : const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction;
3743 :
3744 0 : if (!pA->GetText().isEmpty())
3745 : {
3746 0 : if( mrExport.IsUsePositionedCharacters() )
3747 : {
3748 0 : Font aFont = ImplSetCorrectFontHeight();
3749 0 : mpContext->SetFontAttr( aFont );
3750 0 : ImplWriteText( pA->GetRect().TopLeft(), pA->GetText(), NULL, 0 );
3751 : }
3752 : {
3753 0 : maTextWriter.writeTextPortion( pA->GetRect().TopLeft(), pA->GetText() );
3754 : }
3755 : }
3756 : }
3757 : }
3758 0 : break;
3759 :
3760 : case( META_TEXTARRAY_ACTION ):
3761 : {
3762 0 : if( nWriteFlags & SVGWRITER_WRITE_TEXT )
3763 : {
3764 0 : const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pAction;
3765 0 : const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
3766 :
3767 0 : if( aText.Len() )
3768 : {
3769 0 : if( mrExport.IsUsePositionedCharacters() )
3770 : {
3771 0 : Font aFont = ImplSetCorrectFontHeight();
3772 0 : mpContext->SetFontAttr( aFont );
3773 0 : ImplWriteText( pA->GetPoint(), aText, pA->GetDXArray(), 0 );
3774 : }
3775 : else
3776 : {
3777 0 : maTextWriter.writeTextPortion( pA->GetPoint(), aText );
3778 : }
3779 0 : }
3780 : }
3781 : }
3782 0 : break;
3783 :
3784 : case( META_STRETCHTEXT_ACTION ):
3785 : {
3786 0 : if( nWriteFlags & SVGWRITER_WRITE_TEXT )
3787 : {
3788 0 : const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction;
3789 0 : const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
3790 :
3791 0 : if( aText.Len() )
3792 : {
3793 0 : if( mrExport.IsUsePositionedCharacters() )
3794 : {
3795 0 : Font aFont = ImplSetCorrectFontHeight();
3796 0 : mpContext->SetFontAttr( aFont );
3797 0 : ImplWriteText( pA->GetPoint(), aText, NULL, pA->GetWidth() );
3798 : }
3799 : else
3800 : {
3801 0 : maTextWriter.writeTextPortion( pA->GetPoint(), aText );
3802 : }
3803 0 : }
3804 : }
3805 : }
3806 0 : break;
3807 :
3808 : case( META_CLIPREGION_ACTION ):
3809 : case( META_ISECTRECTCLIPREGION_ACTION ):
3810 : case( META_ISECTREGIONCLIPREGION_ACTION ):
3811 : case( META_MOVECLIPREGION_ACTION ):
3812 : {
3813 0 : ( (MetaAction*) pAction )->Execute( mpVDev );
3814 0 : mbClipAttrChanged = sal_True;
3815 : }
3816 0 : break;
3817 :
3818 : case( META_REFPOINT_ACTION ):
3819 : case( META_MAPMODE_ACTION ):
3820 : case( META_LINECOLOR_ACTION ):
3821 : case( META_FILLCOLOR_ACTION ):
3822 : case( META_TEXTLINECOLOR_ACTION ):
3823 : case( META_TEXTFILLCOLOR_ACTION ):
3824 : case( META_TEXTCOLOR_ACTION ):
3825 : case( META_TEXTALIGN_ACTION ):
3826 : case( META_FONT_ACTION ):
3827 : case( META_PUSH_ACTION ):
3828 : case( META_POP_ACTION ):
3829 : case( META_LAYOUTMODE_ACTION ):
3830 : {
3831 0 : ( (MetaAction*) pAction )->Execute( mpVDev );
3832 : }
3833 0 : break;
3834 :
3835 : case( META_RASTEROP_ACTION ):
3836 : case( META_MASK_ACTION ):
3837 : case( META_MASKSCALE_ACTION ):
3838 : case( META_MASKSCALEPART_ACTION ):
3839 : case( META_WALLPAPER_ACTION ):
3840 : case( META_TEXTLINE_ACTION ):
3841 : {
3842 : // !!! >>> we don't want to support these actions
3843 : }
3844 0 : break;
3845 :
3846 : default:
3847 : OSL_FAIL( "SVGActionWriter::ImplWriteActions: unsupported MetaAction #" );
3848 0 : break;
3849 : }
3850 : }
3851 0 : }
3852 :
3853 : // -----------------------------------------------------------------------------
3854 0 : Font SVGActionWriter::ImplSetCorrectFontHeight() const
3855 : {
3856 0 : Font aFont( mpVDev->GetFont() );
3857 0 : Size aSz;
3858 :
3859 0 : ImplMap( Size( 0, aFont.GetHeight() ), aSz );
3860 :
3861 0 : aFont.SetHeight( aSz.Height() );
3862 :
3863 0 : return aFont;
3864 : }
3865 :
3866 : // -----------------------------------------------------------------------------
3867 :
3868 0 : void SVGActionWriter::WriteMetaFile( const Point& rPos100thmm,
3869 : const Size& rSize100thmm,
3870 : const GDIMetaFile& rMtf,
3871 : sal_uInt32 nWriteFlags,
3872 : const ::rtl::OUString* pElementId,
3873 : const Reference< XShape >* pXShape,
3874 : const GDIMetaFile* pTextEmbeddedBitmapMtf )
3875 : {
3876 0 : MapMode aMapMode( rMtf.GetPrefMapMode() );
3877 0 : Size aPrefSize( rMtf.GetPrefSize() );
3878 0 : Fraction aFractionX( aMapMode.GetScaleX() );
3879 0 : Fraction aFractionY( aMapMode.GetScaleY() );
3880 :
3881 0 : mpVDev->Push();
3882 :
3883 0 : Size aSize( OutputDevice::LogicToLogic( rSize100thmm, MAP_100TH_MM, aMapMode ) );
3884 0 : aMapMode.SetScaleX( aFractionX *= Fraction( aSize.Width(), aPrefSize.Width() ) );
3885 0 : aMapMode.SetScaleY( aFractionY *= Fraction( aSize.Height(), aPrefSize.Height() ) );
3886 :
3887 0 : Point aOffset( OutputDevice::LogicToLogic( rPos100thmm, MAP_100TH_MM, aMapMode ) );
3888 0 : aMapMode.SetOrigin( aOffset += aMapMode.GetOrigin() );
3889 :
3890 0 : mpVDev->SetMapMode( aMapMode );
3891 0 : ImplAcquireContext();
3892 :
3893 0 : mapCurShape.reset();
3894 :
3895 0 : ImplWriteActions( rMtf, nWriteFlags, pElementId, pXShape, pTextEmbeddedBitmapMtf );
3896 :
3897 : // draw open shape that doesn't have a border
3898 0 : if( mapCurShape.get() )
3899 : {
3900 0 : ImplWriteShape( *mapCurShape );
3901 0 : mapCurShape.reset();
3902 : }
3903 :
3904 0 : ImplReleaseContext();
3905 0 : mpVDev->Pop();
3906 0 : }
3907 :
3908 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|