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