xref: /trunk/main/filter/source/svg/svgwriter.cxx (revision ffebe23a)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26 
27 #include "svgfontexport.hxx"
28 #include "svgwriter.hxx"
29 #include <vcl/unohelp.hxx>
30 
31 // -----------
32 // - statics -
33 // -----------
34 
35 static const char	aXMLElemG[] = "g";
36 static const char	aXMLElemDefs[] = "defs";
37 static const char	aXMLElemLine[] = "line";
38 static const char	aXMLElemRect[] = "rect";
39 static const char	aXMLElemEllipse[] = "ellipse";
40 static const char	aXMLElemPath[] = "path";
41 static const char	aXMLElemPolygon[] = "polygon";
42 static const char	aXMLElemPolyLine[] = "polyline";
43 static const char	aXMLElemText[] = "text";
44 static const char	aXMLElemTSpan[] = "tspan";
45 static const char	aXMLElemImage[] = "image";
46 static const char   aXMLElemLinearGradient[] = "linearGradient";
47 static const char   aXMLElemRadialGradient[] = "radialGradient";
48 static const char   aXMLElemStop[] = "stop";
49 
50 // -----------------------------------------------------------------------------
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	aXMLAttrPoints[] = "points";
70 static const char   aXMLAttrStroke[] = "stroke";
71 static const char   aXMLAttrStrokeOpacity[] = "stroke-opacity";
72 static const char   aXMLAttrStrokeWidth[] = "stroke-width";
73 static const char   aXMLAttrStrokeDashArray[] = "stroke-dasharray";
74 static const char   aXMLAttrFill[] = "fill";
75 static const char   aXMLAttrFillOpacity[] = "fill-opacity";
76 static const char   aXMLAttrFontFamily[] = "font-family";
77 static const char   aXMLAttrFontSize[] = "font-size";
78 static const char   aXMLAttrFontStyle[] = "font-style";
79 static const char   aXMLAttrFontWeight[] = "font-weight";
80 static const char   aXMLAttrTextDecoration[] = "text-decoration";
81 static const char	aXMLAttrXLinkHRef[] = "xlink:href";
82 static const char   aXMLAttrGradientUnits[] = "gradientUnits";
83 static const char   aXMLAttrOffset[] = "offset";
84 static const char   aXMLAttrStopColor[] = "stop-color";
85 
86 // added support for LineJoin and LineCap
87 static const char   aXMLAttrStrokeLinejoin[] = "stroke-linejoin";
88 static const char   aXMLAttrStrokeLinecap[] = "stroke-linecap";
89 
90 // -----------------------------------------------------------------------------
91 
92 static const sal_Unicode pBase64[] =
93 {
94 	//0   1   2   3   4   5   6   7
95 	 'A','B','C','D','E','F','G','H', // 0
96 	 'I','J','K','L','M','N','O','P', // 1
97 	 'Q','R','S','T','U','V','W','X', // 2
98 	 'Y','Z','a','b','c','d','e','f', // 3
99 	 'g','h','i','j','k','l','m','n', // 4
100 	 'o','p','q','r','s','t','u','v', // 5
101 	 'w','x','y','z','0','1','2','3', // 6
102 	 '4','5','6','7','8','9','+','/'  // 7
103 };
104 
105 // ----------------------
106 // - SVGAttributeWriter -
107 // ----------------------
108 
SVGAttributeWriter(SVGExport & rExport,SVGFontExport & rFontExport)109 SVGAttributeWriter::SVGAttributeWriter( SVGExport& rExport, SVGFontExport& rFontExport ) :
110 	mrExport( rExport ),
111     mrFontExport( rFontExport ),
112 	mpElemFont( NULL ),
113 	mpElemPaint( NULL )
114 {
115 }
116 
117 // -----------------------------------------------------------------------------
118 
~SVGAttributeWriter()119 SVGAttributeWriter::~SVGAttributeWriter()
120 {
121 	delete mpElemPaint;
122 	delete mpElemFont;
123 }
124 
125 // -----------------------------------------------------------------------------
126 
ImplRound(double fValue,sal_Int32 nDecs)127 double SVGAttributeWriter::ImplRound( double fValue, sal_Int32 nDecs )
128 {
129       return( floor( fValue * pow( 10.0, (int)nDecs ) + 0.5 ) / pow( 10.0, (int)nDecs ) );
130 }
131 
132 // -----------------------------------------------------------------------------
133 
ImplGetColorStr(const Color & rColor,::rtl::OUString & rColorStr)134 void SVGAttributeWriter::ImplGetColorStr( const Color& rColor, ::rtl::OUString& rColorStr )
135 {
136     if( rColor.GetTransparency() == 255 )
137         rColorStr = B2UCONST( "none" );
138     else
139     {
140         rColorStr  = B2UCONST( "rgb(" );
141         rColorStr += ::rtl::OUString::valueOf( static_cast< sal_Int32 >( rColor.GetRed() ) );
142         rColorStr += B2UCONST( "," );
143         rColorStr += ::rtl::OUString::valueOf( static_cast< sal_Int32 >( rColor.GetGreen() ) );
144         rColorStr += B2UCONST( "," );
145         rColorStr += ::rtl::OUString::valueOf( static_cast< sal_Int32 >( rColor.GetBlue() ) );
146         rColorStr += B2UCONST( ")" );
147     }
148 }
149 
150 // -----------------------------------------------------------------------------
151 
AddColorAttr(const char * pColorAttrName,const char * pColorOpacityAttrName,const Color & rColor)152 void SVGAttributeWriter::AddColorAttr( const char* pColorAttrName,
153                                        const char* pColorOpacityAttrName,
154                                        const Color& rColor )
155 {
156     ::rtl::OUString aColor, aColorOpacity;
157 
158     ImplGetColorStr( rColor, aColor );
159 
160     if( rColor.GetTransparency() > 0 && rColor.GetTransparency() < 255 )
161         aColorOpacity = ::rtl::OUString::valueOf( ImplRound( ( 255.0 - rColor.GetTransparency() ) / 255.0 ) );
162 
163     mrExport.AddAttribute( XML_NAMESPACE_NONE, pColorAttrName, aColor );
164 
165     if( aColorOpacity.getLength() && mrExport.IsUseOpacity() )
166         mrExport.AddAttribute( XML_NAMESPACE_NONE, pColorOpacityAttrName, aColorOpacity );
167 }
168 
169 // -----------------------------------------------------------------------------
170 
AddPaintAttr(const Color & rLineColor,const Color & rFillColor,const Rectangle * pObjBoundRect,const Gradient * pFillGradient)171 void SVGAttributeWriter::AddPaintAttr( const Color& rLineColor, const Color& rFillColor,
172                                        const Rectangle* pObjBoundRect, const Gradient* pFillGradient )
173 {
174     // Fill
175     if( pObjBoundRect && pFillGradient )
176     {
177         ::rtl::OUString aGradientId;
178 
179         AddGradientDef( *pObjBoundRect, *pFillGradient, aGradientId );
180 
181         if( aGradientId.getLength() )
182         {
183             ::rtl::OUString aGradientURL( B2UCONST( "url(#" ) );
184             mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFill, ( aGradientURL += aGradientId ) += B2UCONST( ")" ) );
185         }
186     }
187     else
188         AddColorAttr( aXMLAttrFill, aXMLAttrFillOpacity, rFillColor );
189 
190     // Stroke
191     AddColorAttr( aXMLAttrStroke, aXMLAttrStrokeOpacity, rLineColor );
192 }
193 
194 // -----------------------------------------------------------------------------
195 
AddGradientDef(const Rectangle & rObjRect,const Gradient & rGradient,::rtl::OUString & rGradientId)196 void SVGAttributeWriter::AddGradientDef( const Rectangle& rObjRect, const Gradient& rGradient, ::rtl::OUString& rGradientId )
197 {
198     if( rObjRect.GetWidth() && rObjRect.GetHeight() &&
199         ( rGradient.GetStyle() == GRADIENT_LINEAR || rGradient.GetStyle() == GRADIENT_AXIAL ||
200           rGradient.GetStyle() == GRADIENT_RADIAL || rGradient.GetStyle() == GRADIENT_ELLIPTICAL ) )
201     {
202         SvXMLElementExport  aDesc( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, sal_True, sal_True );
203         Color               aStartColor( rGradient.GetStartColor() ), aEndColor( rGradient.GetEndColor() );
204         sal_uInt16          nAngle = rGradient.GetAngle() % 3600;
205         Point               aObjRectCenter( rObjRect.Center() );
206         Polygon             aPoly( rObjRect );
207         static sal_Int32    nCurGradientId = 1;
208 
209         aPoly.Rotate( aObjRectCenter, nAngle );
210         Rectangle aRect( aPoly.GetBoundRect() );
211 
212         // adjust start/end colors with intensities
213         aStartColor.SetRed( (sal_uInt8)( ( (long) aStartColor.GetRed() * rGradient.GetStartIntensity() ) / 100 ) );
214         aStartColor.SetGreen( (sal_uInt8)( ( (long) aStartColor.GetGreen() * rGradient.GetStartIntensity() ) / 100 ) );
215         aStartColor.SetBlue( (sal_uInt8)( ( (long) aStartColor.GetBlue() * rGradient.GetStartIntensity() ) / 100 ) );
216 
217         aEndColor.SetRed( (sal_uInt8)( ( (long) aEndColor.GetRed() * rGradient.GetEndIntensity() ) / 100 ) );
218         aEndColor.SetGreen( (sal_uInt8)( ( (long) aEndColor.GetGreen() * rGradient.GetEndIntensity() ) / 100 ) );
219         aEndColor.SetBlue( (sal_uInt8)( ( (long) aEndColor.GetBlue() * rGradient.GetEndIntensity() ) / 100 ) );
220 
221         mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId,
222                             ( rGradientId = B2UCONST( "Gradient_" ) ) += ::rtl::OUString::valueOf( nCurGradientId++ ) );
223 
224         {
225             ::std::auto_ptr< SvXMLElementExport >   apGradient;
226             ::rtl::OUString                         aColorStr;
227 
228             if( rGradient.GetStyle() == GRADIENT_LINEAR || rGradient.GetStyle() == GRADIENT_AXIAL )
229             {
230                 Polygon aLinePoly( 2 );
231 
232                 aLinePoly[ 0 ] = Point( aObjRectCenter.X(), aRect.Top() );
233                 aLinePoly[ 1 ] = Point( aObjRectCenter.X(), aRect.Bottom() );
234 
235                 aLinePoly.Rotate( aObjRectCenter, nAngle );
236 
237                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits, B2UCONST( "userSpaceOnUse" ) );
238                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, ::rtl::OUString::valueOf( aLinePoly[ 0 ].X() ) );
239                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, ::rtl::OUString::valueOf( aLinePoly[ 0 ].Y() ) );
240                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, ::rtl::OUString::valueOf( aLinePoly[ 1 ].X() ) );
241                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, ::rtl::OUString::valueOf( aLinePoly[ 1 ].Y() ) );
242 
243                 apGradient.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemLinearGradient, sal_True, sal_True ) );
244 
245                 // write stop values
246                 double fBorder = static_cast< double >( rGradient.GetBorder() ) *
247                                 ( ( rGradient.GetStyle() == GRADIENT_AXIAL ) ? 0.005 : 0.01 );
248 
249                 ImplGetColorStr( ( rGradient.GetStyle() == GRADIENT_AXIAL ) ? aEndColor : aStartColor, aColorStr );
250                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, ::rtl::OUString::valueOf( fBorder ) );
251                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
252 
253                 {
254                     SvXMLElementExport aDesc2( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
255                 }
256 
257                 if( rGradient.GetStyle() == GRADIENT_AXIAL )
258                 {
259                     ImplGetColorStr( aStartColor, aColorStr );
260                     mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, ::rtl::OUString::valueOf( 0.5 ) );
261                     mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
262 
263                     {
264                         SvXMLElementExport aDesc3( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
265                     }
266                 }
267 
268                 if( rGradient.GetStyle() != GRADIENT_AXIAL )
269                     fBorder = 0.0;
270 
271                 ImplGetColorStr( aEndColor, aColorStr );
272                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, ::rtl::OUString::valueOf( ImplRound( 1.0 - fBorder ) ) );
273                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
274 
275                 {
276                     SvXMLElementExport aDesc4( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
277                 }
278             }
279             else
280             {
281                 const double    fCenterX = rObjRect.Left() + rObjRect.GetWidth() * rGradient.GetOfsX() * 0.01;
282                 const double    fCenterY = rObjRect.Top() + rObjRect.GetHeight() * rGradient.GetOfsY() * 0.01;
283                 const double    fRadius = sqrt( static_cast< double >( rObjRect.GetWidth() ) * rObjRect.GetWidth() +
284                                                 rObjRect.GetHeight() * rObjRect.GetHeight() ) * 0.5;
285 
286                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits, B2UCONST( "userSpaceOnUse" ) );
287                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCX, ::rtl::OUString::valueOf( ImplRound( fCenterX ) ) );
288                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCY, ::rtl::OUString::valueOf( ImplRound( fCenterY ) ) );
289                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrR, ::rtl::OUString::valueOf( ImplRound( fRadius ) ) );
290 
291                 apGradient.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemRadialGradient, sal_True, sal_True ) );
292 
293                 // write stop values
294                 ImplGetColorStr( aEndColor, aColorStr );
295                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, ::rtl::OUString::valueOf( 0.0 ) );
296                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
297 
298                 {
299                     SvXMLElementExport aDesc5( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
300                 }
301 
302                 ImplGetColorStr( aStartColor, aColorStr );
303                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset,
304                                        ::rtl::OUString::valueOf( ImplRound( 1.0 - rGradient.GetBorder() * 0.01 ) ) );
305                 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
306 
307                 {
308                     SvXMLElementExport aDesc6( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
309                 }
310             }
311         }
312     }
313     else
314         rGradientId = ::rtl::OUString();
315 }
316 
317 // -----------------------------------------------------------------------------
318 
SetFontAttr(const Font & rFont)319 void SVGAttributeWriter::SetFontAttr( const Font& rFont )
320 {
321     if( !mpElemFont || ( rFont != maCurFont ) )
322     {
323         ::rtl::OUString  aFontStyle, aFontWeight, aTextDecoration;
324         sal_Int32        nFontWeight;
325 
326         delete mpElemPaint, mpElemPaint = NULL;
327         delete mpElemFont;
328         maCurFont = rFont;
329 
330         // Font Family
331         mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontFamily, mrFontExport.GetMappedFontName( rFont.GetName() ) );
332 
333         // Font Size
334         mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontSize, ::rtl::OUString::valueOf( rFont.GetHeight() ) );
335 
336         // Font Style
337         if( rFont.GetItalic() != ITALIC_NONE )
338         {
339             if( rFont.GetItalic() == ITALIC_OBLIQUE )
340                 aFontStyle = B2UCONST( "oblique" );
341             else
342                 aFontStyle = B2UCONST( "italic" );
343         }
344         else
345             aFontStyle = B2UCONST( "normal" );
346 
347         mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontStyle, aFontStyle );
348 
349         // Font Weight
350         switch( rFont.GetWeight() )
351         {
352             case WEIGHT_THIN:           nFontWeight = 100; break;
353             case WEIGHT_ULTRALIGHT:     nFontWeight = 200; break;
354             case WEIGHT_LIGHT:          nFontWeight = 300; break;
355             case WEIGHT_SEMILIGHT:      nFontWeight = 400; break;
356             case WEIGHT_NORMAL:         nFontWeight = 400; break;
357             case WEIGHT_MEDIUM:         nFontWeight = 500; break;
358             case WEIGHT_SEMIBOLD:       nFontWeight = 600; break;
359             case WEIGHT_BOLD:           nFontWeight = 700; break;
360             case WEIGHT_ULTRABOLD:      nFontWeight = 800; break;
361             case WEIGHT_BLACK:          nFontWeight = 900; break;
362             default:                    nFontWeight = 400; break;
363         }
364 
365         mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontWeight, ::rtl::OUString::valueOf( nFontWeight ) );
366 
367         if( mrExport.IsUseNativeTextDecoration() )
368         {
369             if( rFont.GetUnderline() != UNDERLINE_NONE || rFont.GetStrikeout() != STRIKEOUT_NONE )
370             {
371                 if( rFont.GetUnderline() != UNDERLINE_NONE )
372                     aTextDecoration = B2UCONST( "underline " );
373 
374                 if( rFont.GetStrikeout() != STRIKEOUT_NONE )
375                     aTextDecoration += B2UCONST( "line-through " );
376             }
377             else
378                 aTextDecoration = B2UCONST( "none" );
379 
380             mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTextDecoration, aTextDecoration );
381         }
382 
383         mpElemFont = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
384     }
385 }
386 
387 // -------------------
388 // - SVGActionWriter -
389 // -------------------
390 
SVGActionWriter(SVGExport & rExport,SVGFontExport & rFontExport)391 SVGActionWriter::SVGActionWriter( SVGExport& rExport, SVGFontExport& rFontExport ) :
392 	mrExport( rExport ),
393     mrFontExport( rFontExport ),
394 	mpContext( NULL ),
395     mnInnerMtfCount( 0 ),
396 	mbClipAttrChanged( sal_False )
397 {
398 	mpVDev = new VirtualDevice;
399 	mpVDev->EnableOutput( sal_False );
400 	maTargetMapMode = MAP_100TH_MM;
401 }
402 
403 // -----------------------------------------------------------------------------
404 
~SVGActionWriter()405 SVGActionWriter::~SVGActionWriter()
406 {
407 	DBG_ASSERT( !mpContext, "Not all contexts are closed" );
408 	delete mpVDev;
409 }
410 
411 // -----------------------------------------------------------------------------
412 
ImplMap(sal_Int32 nVal) const413 long SVGActionWriter::ImplMap( sal_Int32 nVal ) const
414 {
415     Size aSz( nVal, nVal );
416 
417 	return( ImplMap( aSz, aSz ).Width() );
418 }
419 
420 // -----------------------------------------------------------------------------
421 
ImplMap(const Point & rPt,Point & rDstPt) const422 Point& SVGActionWriter::ImplMap( const Point& rPt, Point& rDstPt ) const
423 {
424     return( rDstPt = mpVDev->LogicToLogic( rPt, mpVDev->GetMapMode(), maTargetMapMode ) );
425 }
426 
427 // -----------------------------------------------------------------------------
428 
ImplMap(const Size & rSz,Size & rDstSz) const429 Size& SVGActionWriter::ImplMap( const Size& rSz, Size& rDstSz ) const
430 {
431 	return( rDstSz = mpVDev->LogicToLogic( rSz, mpVDev->GetMapMode(), maTargetMapMode ) );
432 }
433 
434 // -----------------------------------------------------------------------------
435 
ImplMap(const Rectangle & rRect,Rectangle & rDstRect) const436 Rectangle& SVGActionWriter::ImplMap( const Rectangle& rRect, Rectangle& rDstRect ) const
437 {
438     Point   aTL( rRect.TopLeft() );
439     Size    aSz( rRect.GetSize() );
440 
441     return( rDstRect = Rectangle( ImplMap( aTL, aTL ), ImplMap( aSz, aSz ) ) );
442 }
443 
444 
445 // -----------------------------------------------------------------------------
446 
ImplMap(const Polygon & rPoly,Polygon & rDstPoly) const447 Polygon& SVGActionWriter::ImplMap( const Polygon& rPoly, Polygon& rDstPoly ) const
448 {
449     rDstPoly = Polygon( rPoly.GetSize() );
450 
451     for( sal_uInt16 i = 0, nSize = rPoly.GetSize(); i < nSize; ++i )
452     {
453         ImplMap( rPoly[ i ], rDstPoly[ i ] );
454         rDstPoly.SetFlags( i, rPoly.GetFlags( i ) );
455     }
456 
457     return( rDstPoly );
458 }
459 
460 // -----------------------------------------------------------------------------
461 
ImplMap(const PolyPolygon & rPolyPoly,PolyPolygon & rDstPolyPoly) const462 PolyPolygon& SVGActionWriter::ImplMap( const PolyPolygon& rPolyPoly, PolyPolygon& rDstPolyPoly ) const
463 {
464     Polygon aPoly;
465 
466     rDstPolyPoly = PolyPolygon();
467 
468     for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; ++i )
469     {
470         rDstPolyPoly.Insert( ImplMap( rPolyPoly[ i ], aPoly ) );
471     }
472 
473     return( rDstPolyPoly );
474 }
475 
476 // -----------------------------------------------------------------------------
477 
GetPathString(const PolyPolygon & rPolyPoly,sal_Bool bLine)478 ::rtl::OUString	SVGActionWriter::GetPathString( const PolyPolygon& rPolyPoly, sal_Bool bLine )
479 {
480 	::rtl::OUString         aPathData;
481 	const ::rtl::OUString   aBlank( B2UCONST( " " ) );
482 	const ::rtl::OUString   aComma( B2UCONST( "," ) );
483 	Point                      aPolyPoint;
484 
485 	for( long i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ )
486 	{
487 		const Polygon&	rPoly = rPolyPoly[ (sal_uInt16) i ];
488 		sal_uInt16		n = 1, nSize = rPoly.GetSize();
489 
490 		if( nSize > 1 )
491 		{
492 			aPathData += B2UCONST( "M " );
493 			aPathData += ::rtl::OUString::valueOf( ( aPolyPoint = rPoly[ 0 ] ).X() );
494 			aPathData += aComma;
495 			aPathData += ::rtl::OUString::valueOf( aPolyPoint.Y() );
496             sal_Char nCurrentMode = 0;
497             const bool bClose(!bLine || rPoly[0] == rPoly[nSize - 1]);
498 
499 			while( n < nSize )
500 			{
501 				aPathData += aBlank;
502 
503                 if ( ( rPoly.GetFlags( n ) == POLY_CONTROL ) && ( ( n + 2 ) < nSize ) )
504 				{
505 					if ( nCurrentMode != 'C' )
506 					{
507 						nCurrentMode = 'C';
508 						aPathData += B2UCONST( "C " );
509 					}
510 					for ( int j = 0; j < 3; j++ )
511 					{
512 						if ( j )
513 							aPathData += aBlank;
514 						aPathData += ::rtl::OUString::valueOf( ( aPolyPoint = rPoly[ n++ ] ).X() );
515 						aPathData += aComma;
516 						aPathData += ::rtl::OUString::valueOf( aPolyPoint.Y() );
517 					}
518 				}
519 				else
520 				{
521 					if ( nCurrentMode != 'L' )
522 					{
523 						nCurrentMode = 'L';
524 						aPathData += B2UCONST( "L " );
525 					}
526 					aPathData += ::rtl::OUString::valueOf( ( aPolyPoint = rPoly[ n++ ] ).X() );
527 					aPathData += aComma;
528 					aPathData += ::rtl::OUString::valueOf( aPolyPoint.Y() );
529 				}
530 			}
531 
532 			if(bClose)
533 				aPathData += B2UCONST( " Z" );
534 
535 			if( i < ( nCount - 1 ) )
536 				aPathData += aBlank;
537 		}
538 	}
539 
540  	return aPathData;
541 }
542 
543 // -----------------------------------------------------------------------------
544 
ImplWriteLine(const Point & rPt1,const Point & rPt2,const Color * pLineColor,sal_Bool bApplyMapping)545 void SVGActionWriter::ImplWriteLine( const Point& rPt1, const Point& rPt2,
546                                      const Color* pLineColor, sal_Bool bApplyMapping )
547 {
548 	Point aPt1, aPt2;
549 
550     if( bApplyMapping )
551     {
552         ImplMap( rPt1, aPt1 );
553         ImplMap( rPt2, aPt2 );
554     }
555     else
556     {
557         aPt1 = rPt1;
558         aPt2 = rPt2;
559     }
560 
561 	mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, ::rtl::OUString::valueOf( aPt1.X() ) );
562 	mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, ::rtl::OUString::valueOf( aPt1.Y() ) );
563 	mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, ::rtl::OUString::valueOf( aPt2.X() ) );
564 	mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, ::rtl::OUString::valueOf( aPt2.Y() ) );
565 
566 	if( pLineColor )
567 	{
568 		// !!! mrExport.AddAttribute( XML_NAMESPACE_NONE, ... )
569 		DBG_ERROR( "SVGActionWriter::ImplWriteLine: Line color not implemented" );
570 	}
571 
572 	{
573 		SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemLine, sal_True, sal_True );
574 	}
575 }
576 
577 // -----------------------------------------------------------------------------
578 
ImplWriteRect(const Rectangle & rRect,long nRadX,long nRadY,sal_Bool bApplyMapping)579 void SVGActionWriter::ImplWriteRect( const Rectangle& rRect, long nRadX, long nRadY,
580                                      sal_Bool bApplyMapping )
581 {
582 	Rectangle aRect;
583 
584     if( bApplyMapping )
585         ImplMap( rRect, aRect );
586     else
587         aRect = rRect;
588 
589 	mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, ::rtl::OUString::valueOf( aRect.Left() ) );
590 	mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( aRect.Top() ) );
591 	mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrWidth, ::rtl::OUString::valueOf( aRect.GetWidth() ) );
592 	mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrHeight, ::rtl::OUString::valueOf( aRect.GetHeight() ) );
593 
594 	if( nRadX )
595 		mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRX, ::rtl::OUString::valueOf( bApplyMapping ? ImplMap( nRadX ) : nRadX ) );
596 
597 	if( nRadY )
598 		mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRY, ::rtl::OUString::valueOf( bApplyMapping ? ImplMap( nRadY ) : nRadY ) );
599 
600 	{
601 		SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemRect, sal_True, sal_True );
602 	}
603 }
604 
605 // -----------------------------------------------------------------------------
606 
ImplWriteEllipse(const Point & rCenter,long nRadX,long nRadY,sal_Bool bApplyMapping)607 void SVGActionWriter::ImplWriteEllipse( const Point& rCenter, long nRadX, long nRadY,
608                                         sal_Bool bApplyMapping )
609 {
610 	Point aCenter;
611 
612     if( bApplyMapping )
613         ImplMap( rCenter, aCenter );
614     else
615         aCenter = rCenter;
616 
617 	mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCX, ::rtl::OUString::valueOf( aCenter.X() ) );
618 	mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCY, ::rtl::OUString::valueOf( aCenter.Y() ) );
619 	mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRX, ::rtl::OUString::valueOf( bApplyMapping ? ImplMap( nRadX ) : nRadX ) );
620 	mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRY, ::rtl::OUString::valueOf( bApplyMapping ? ImplMap( nRadY ) : nRadY ) );
621 
622 	{
623 		SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemEllipse, sal_True, sal_True );
624 	}
625 }
626 
627 // -----------------------------------------------------------------------------
628 
ImplWritePolyPolygon(const PolyPolygon & rPolyPoly,sal_Bool bLineOnly,sal_Bool bApplyMapping)629 void SVGActionWriter::ImplWritePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bLineOnly,
630                                             sal_Bool bApplyMapping )
631 {
632     PolyPolygon	aPolyPoly;
633 
634     if( bApplyMapping )
635         ImplMap( rPolyPoly, aPolyPoly );
636     else
637         aPolyPoly = rPolyPoly;
638 
639     if( mrExport.hasClip() )
640     {
641         const ::basegfx::B2DPolyPolygon aB2DPolyPoly( ::basegfx::tools::correctOrientations( aPolyPoly.getB2DPolyPolygon() ) );
642 
643         aPolyPoly = PolyPolygon( ::basegfx::tools::clipPolyPolygonOnPolyPolygon(
644                         *mrExport.getCurClip(), aB2DPolyPoly, sal_False, sal_False ) );
645     }
646 
647     // add path data attribute
648     mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrD, GetPathString( aPolyPoly, bLineOnly ) );
649 
650     {
651         // write polyline/polygon element
652         SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemPath, sal_True, sal_True );
653     }
654 }
655 
656 // -----------------------------------------------------------------------------
657 
ImplWriteShape(const SVGShapeDescriptor & rShape,sal_Bool bApplyMapping)658 void SVGActionWriter::ImplWriteShape( const SVGShapeDescriptor& rShape, sal_Bool bApplyMapping )
659 {
660     PolyPolygon aPolyPoly;
661 
662     if( bApplyMapping )
663         ImplMap( rShape.maShapePolyPoly, aPolyPoly );
664     else
665         aPolyPoly = rShape.maShapePolyPoly;
666 
667     const sal_Bool  bLineOnly = ( rShape.maShapeFillColor == Color( COL_TRANSPARENT ) ) && ( !rShape.mapShapeGradient.get() );
668     Rectangle   aBoundRect( aPolyPoly.GetBoundRect() );
669 
670     mpContext->AddPaintAttr( rShape.maShapeLineColor, rShape.maShapeFillColor, &aBoundRect, rShape.mapShapeGradient.get() );
671 
672     if( rShape.maId.getLength() )
673         mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, rShape.maId );
674 
675     if( rShape.mnStrokeWidth )
676     {
677         sal_Int32 nStrokeWidth = ( bApplyMapping ? ImplMap( rShape.mnStrokeWidth ) : rShape.mnStrokeWidth );
678         mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeWidth, ::rtl::OUString::valueOf( nStrokeWidth ) );
679     }
680 
681     // support for LineJoin
682     switch(rShape.maLineJoin)
683     {
684         default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE
685         case basegfx::B2DLINEJOIN_MITER:
686         {
687             // miter is Svg default, so no need to write until the exporter might write styles.
688             // If this happens, activate here
689             // mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, ::rtl::OUString::createFromAscii("miter"));
690             break;
691         }
692         case basegfx::B2DLINEJOIN_BEVEL:
693         {
694             mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, ::rtl::OUString::createFromAscii("bevel"));
695             break;
696         }
697         case basegfx::B2DLINEJOIN_ROUND:
698         {
699             mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, ::rtl::OUString::createFromAscii("round"));
700             break;
701         }
702     }
703 
704     // support for LineCap
705     switch(rShape.maLineCap)
706     {
707         default: /* com::sun::star::drawing::LineCap_BUTT */
708         {
709             // butt is Svg default, so no need to write until the exporter might write styles.
710             // If this happens, activate here
711             // mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, ::rtl::OUString::createFromAscii("butt"));
712             break;
713         }
714         case com::sun::star::drawing::LineCap_ROUND:
715         {
716             mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, ::rtl::OUString::createFromAscii("round"));
717             break;
718         }
719         case com::sun::star::drawing::LineCap_SQUARE:
720         {
721             mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, ::rtl::OUString::createFromAscii("square"));
722             break;
723         }
724     }
725 
726     if( rShape.maDashArray.size() )
727     {
728         const ::rtl::OUString   aComma( B2UCONST( "," ) );
729         ::rtl::OUString         aDashArrayStr;
730 
731         for( unsigned int k = 0; k < rShape.maDashArray.size(); ++k )
732         {
733             const sal_Int32 nDash = ( bApplyMapping ?
734                                         ImplMap( FRound( rShape.maDashArray[ k ] ) ) :
735                                         FRound( rShape.maDashArray[ k ] ) );
736 
737             if( k )
738                 aDashArrayStr += aComma;
739 
740             aDashArrayStr += ::rtl::OUString::valueOf( nDash );
741         }
742 
743         mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeDashArray, aDashArrayStr );
744     }
745 
746     ImplWritePolyPolygon( aPolyPoly, bLineOnly, sal_False );
747 }
748 
749 // -----------------------------------------------------------------------------
750 
ImplWriteGradientEx(const PolyPolygon & rPolyPoly,const Gradient & rGradient,sal_uInt32 nWriteFlags,sal_Bool bApplyMapping)751 void SVGActionWriter::ImplWriteGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient,
752                                            sal_uInt32 nWriteFlags, sal_Bool bApplyMapping )
753 {
754     PolyPolygon aPolyPoly;
755 
756     if( bApplyMapping )
757         ImplMap( rPolyPoly, aPolyPoly );
758     else
759         aPolyPoly = rPolyPoly;
760 
761     if( rGradient.GetStyle() == GRADIENT_LINEAR || rGradient.GetStyle() == GRADIENT_AXIAL ||
762         rGradient.GetStyle() == GRADIENT_RADIAL || rGradient.GetStyle() == GRADIENT_ELLIPTICAL )
763     {
764         SVGShapeDescriptor aShapeDesc;
765 
766         aShapeDesc.maShapePolyPoly = aPolyPoly;
767         aShapeDesc.mapShapeGradient.reset( new Gradient( rGradient ) );
768 
769         ImplWriteShape( aShapeDesc, sal_False );
770     }
771     else
772     {
773         GDIMetaFile aTmpMtf;
774 
775         mrExport.pushClip( aPolyPoly.getB2DPolyPolygon() );
776         mpVDev->AddGradientActions( rPolyPoly.GetBoundRect(), rGradient, aTmpMtf );
777         ++mnInnerMtfCount;
778 
779         ImplWriteActions( aTmpMtf, nWriteFlags, NULL );
780 
781         --mnInnerMtfCount;
782         mrExport.popClip();
783     }
784 }
785 
786 // -----------------------------------------------------------------------------
787 
ImplWriteText(const Point & rPos,const String & rText,const sal_Int32 * pDXArray,long nWidth,sal_Bool bApplyMapping)788 void SVGActionWriter::ImplWriteText( const Point& rPos, const String& rText,
789 									 const sal_Int32* pDXArray, long nWidth,
790                                      sal_Bool bApplyMapping )
791 {
792 	sal_Int32                               nLen = rText.Len(), i;
793     Size                                    aNormSize;
794     ::std::auto_ptr< sal_Int32 >            apTmpArray;
795     ::std::auto_ptr< SvXMLElementExport >	apTransform;
796     sal_Int32*                              pDX;
797     Point                                   aPos;
798     Point                                   aBaseLinePos( rPos );
799     const FontMetric                        aMetric( mpVDev->GetFontMetric() );
800     const Font&                             rFont = mpVDev->GetFont();
801 
802     if( rFont.GetAlign() == ALIGN_TOP )
803         aBaseLinePos.Y() += aMetric.GetAscent();
804     else if( rFont.GetAlign() == ALIGN_BOTTOM )
805         aBaseLinePos.Y() -= aMetric.GetDescent();
806 
807     if( bApplyMapping )
808         ImplMap( rPos, aPos );
809     else
810         aPos = rPos;
811 
812     // get text sizes
813     if( pDXArray )
814     {
815         aNormSize = Size( mpVDev->GetTextWidth( rText ), 0 );
816         pDX = const_cast< sal_Int32* >( pDXArray );
817     }
818     else
819     {
820         apTmpArray.reset( new sal_Int32[ nLen ] );
821         aNormSize = Size( mpVDev->GetTextArray( rText, apTmpArray.get() ), 0 );
822         pDX = apTmpArray.get();
823     }
824 
825     // if text is rotated, set transform matrix at new g element
826     if( rFont.GetOrientation() )
827     {
828         Point   aRot( aPos );
829         String  aTransform;
830 
831         aTransform = String( ::rtl::OUString::createFromAscii( "translate" ) );
832         aTransform += '(';
833         aTransform += String( ::rtl::OUString::valueOf( aRot.X() ) );
834         aTransform += ',';
835         aTransform += String( ::rtl::OUString::valueOf( aRot.Y() ) );
836         aTransform += ')';
837 
838         aTransform += String( ::rtl::OUString::createFromAscii( " rotate" ) );
839         aTransform += '(';
840         aTransform += String( ::rtl::OUString::valueOf( rFont.GetOrientation() * -0.1 ) );
841         aTransform += ')';
842 
843         aTransform += String( ::rtl::OUString::createFromAscii( " translate" ) );
844         aTransform += '(';
845         aTransform += String( ::rtl::OUString::valueOf( -aRot.X() ) );
846         aTransform += ',';
847         aTransform += String( ::rtl::OUString::valueOf( -aRot.Y() ) );
848         aTransform += ')';
849 
850         mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform, aTransform );
851         apTransform.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True ) );
852     }
853 
854     if( nLen > 1 )
855     {
856 		::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xBI( ::vcl::unohelper::CreateBreakIterator() );
857 		const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetLocale();
858 		sal_Int32 nCurPos = 0, nLastPos = 0, nX = aPos.X();
859 
860 		if ( mrExport.IsUseTSpans() )
861 		{
862 			mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, ::rtl::OUString::valueOf( aPos.X() ) );
863 			mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( aPos.Y() ) );
864 			SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, sal_False );
865 			{
866 				rtl::OUString aString;
867 				for( sal_Bool bCont = sal_True; bCont; )
868 				{
869 					sal_Int32 nCount = 1;
870 					const ::rtl::OUString	aSpace( ' ' );
871 
872 					nLastPos = nCurPos;
873 					nCurPos = xBI->nextCharacters( rText, nCurPos, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount );
874 					nCount = nCurPos - nLastPos;
875 					bCont = ( nCurPos < rText.Len() ) && nCount;
876 
877 					if( nCount )
878 					{
879 						aString += rtl::OUString::valueOf( nX );
880 						if( bCont )
881 						{
882 							sal_Int32 nWidth = pDX[ nCurPos - 1 ];
883 							if ( bApplyMapping )
884 								nWidth = ImplMap( nWidth );
885 							nX = aPos.X() + nWidth;
886 							aString += aSpace;
887 						}
888 					}
889 				}
890 				mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, aString );
891 				SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTSpan, sal_True, sal_False );
892 				mrExport.GetDocHandler()->characters( rText );
893 			}
894 		}
895 		else
896 		{
897 			aNormSize.Width() = pDX[ nLen - 2 ] + mpVDev->GetTextWidth( rText.GetChar(  nLen - 1 ) );
898 
899 			if( nWidth && aNormSize.Width() && ( nWidth != aNormSize.Width() ) )
900 			{
901 				const double fFactor = (double) nWidth / aNormSize.Width();
902 
903 				for( i = 0; i < ( nLen - 1 ); i++ )
904 					pDX[ i ] = FRound( pDX[ i ] * fFactor );
905 			}
906 			else
907 			{
908 				// write single glyphs at absolute text positions
909 				for( sal_Bool bCont = sal_True; bCont; )
910 				{
911 					sal_Int32 nCount = 1;
912 
913 					nLastPos = nCurPos;
914 					nCurPos = xBI->nextCharacters( rText, nCurPos, rLocale,
915 												::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL,
916 												nCount, nCount );
917 
918 					nCount = nCurPos - nLastPos;
919 					bCont = ( nCurPos < rText.Len() ) && nCount;
920 
921 					if( nCount )
922 					{
923 						const ::rtl::OUString aGlyph( rText.Copy( nLastPos, nCount ) );
924 
925 						mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, ::rtl::OUString::valueOf( nX ) );
926 						mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( aPos.Y() ) );
927 
928 						{
929 							SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, sal_False );
930 							mrExport.GetDocHandler()->characters( aGlyph );
931 						}
932 
933 						if( bCont )
934 						{
935 							// #118796# do NOT access pDXArray, it may be zero (!)
936 							sal_Int32 nWidth = pDX[ nCurPos - 1 ];
937 							if ( bApplyMapping )
938 								nWidth = ImplMap( nWidth );
939 							nX = aPos.X() + nWidth;
940 						}
941 					}
942 				}
943 			}
944 		}
945     }
946     else
947     {
948         mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, ::rtl::OUString::valueOf( aPos.X() ) );
949         mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( aPos.Y() ) );
950 
951         {
952             SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, sal_False );
953             mrExport.GetDocHandler()->characters( rText );
954         }
955     }
956 
957     if( !mrExport.IsUseNativeTextDecoration() )
958     {
959         if( rFont.GetStrikeout() != STRIKEOUT_NONE || rFont.GetUnderline() != UNDERLINE_NONE )
960         {
961             Polygon     aPoly( 4 );
962             const long  nLineHeight = Max( (long) FRound( aMetric.GetLineHeight() * 0.05 ), (long) 1 );
963 
964             if( rFont.GetStrikeout() )
965             {
966                 const long nYLinePos = aBaseLinePos.Y() - FRound( aMetric.GetAscent() * 0.26 );
967 
968                 aPoly[ 0 ].X() = aBaseLinePos.X(); aPoly[ 0 ].Y() = nYLinePos - ( nLineHeight >> 1 );
969                 aPoly[ 1 ].X() = aBaseLinePos.X() + aNormSize.Width() - 1; aPoly[ 1 ].Y() = aPoly[ 0 ].Y();
970                 aPoly[ 2 ].X() = aPoly[ 1 ].X(); aPoly[ 2 ].Y() = aPoly[ 0 ].Y() + nLineHeight - 1;
971                 aPoly[ 3 ].X() = aPoly[ 0 ].X(); aPoly[ 3 ].Y() = aPoly[ 2 ].Y();
972 
973                 ImplWritePolyPolygon( aPoly, sal_False );
974             }
975 
976             if( rFont.GetUnderline() )
977             {
978                 const long	nYLinePos = aBaseLinePos.Y() + ( nLineHeight << 1 );
979 
980                 aPoly[ 0 ].X() = aBaseLinePos.X(); aPoly[ 0 ].Y() = nYLinePos - ( nLineHeight >> 1 );
981                 aPoly[ 1 ].X() = aBaseLinePos.X() + aNormSize.Width() - 1; aPoly[ 1 ].Y() = aPoly[ 0 ].Y();
982                 aPoly[ 2 ].X() = aPoly[ 1 ].X(); aPoly[ 2 ].Y() = aPoly[ 0 ].Y() + nLineHeight - 1;
983                 aPoly[ 3 ].X() = aPoly[ 0 ].X(); aPoly[ 3 ].Y() = aPoly[ 2 ].Y();
984 
985                 ImplWritePolyPolygon( aPoly, sal_False );
986             }
987         }
988     }
989 }
990 
991 // -----------------------------------------------------------------------------
992 
ImplWriteBmp(const BitmapEx & rBmpEx,const Point & rPt,const Size & rSz,const Point & rSrcPt,const Size & rSrcSz,sal_Bool bApplyMapping)993 void SVGActionWriter::ImplWriteBmp( const BitmapEx& rBmpEx,
994 									const Point& rPt, const Size& rSz,
995 									const Point& rSrcPt, const Size& rSrcSz,
996                                     sal_Bool bApplyMapping )
997 {
998 	if( !!rBmpEx )
999 	{
1000 		BitmapEx		aBmpEx( rBmpEx );
1001 	 	Point aPoint = Point();
1002 		const Rectangle	aBmpRect( aPoint, rBmpEx.GetSizePixel() );
1003 		const Rectangle aSrcRect( rSrcPt, rSrcSz );
1004 
1005 		if( aSrcRect != aBmpRect )
1006 			aBmpEx.Crop( aSrcRect );
1007 
1008 		if( !!aBmpEx )
1009 		{
1010 			SvMemoryStream aOStm( 65535, 65535 );
1011 
1012 			if( GraphicConverter::Export( aOStm, rBmpEx, CVT_PNG ) == ERRCODE_NONE )
1013 			{
1014 				Point							            aPt;
1015 				Size								        aSz;
1016 
1017                 // #119735# Do not copy the stream data to a ::rtl::OUString any longer, this is not needed and
1018                 // (of course) throws many exceptions with the used RTL_TEXTENCODING_ASCII_US. Keeping that line
1019                 // to show what I'm talking about
1020                 // ::rtl::OUString aImageData( (sal_Char*) aOStm.GetData(), aOStm.Tell(), RTL_TEXTENCODING_ASCII_US );
1021                 const sal_Char* pImageData = (sal_Char*)aOStm.GetData();
1022                 const sal_uInt32 nImageDataLength = aOStm.Tell();
1023 				REF( NMSP_SAX::XExtendedDocumentHandler )	xExtDocHandler( mrExport.GetDocHandler(), NMSP_UNO::UNO_QUERY );
1024 
1025                 if( bApplyMapping )
1026                 {
1027                     ImplMap( rPt, aPt );
1028                     ImplMap( rSz, aSz );
1029                 }
1030                 else
1031                 {
1032                     aPt = rPt;
1033                     aSz = rSz;
1034                 }
1035 				const Rectangle aRect( aPt, aSz );
1036 				if( mrExport.IsVisible( aRect ) && xExtDocHandler.is() )
1037 				{
1038 					static const sal_uInt32		nPartLen = 64;
1039 					const ::rtl::OUString	aSpace( ' ' );
1040 					const ::rtl::OUString	aLineFeed( ::rtl::OUString::valueOf( (sal_Unicode) 0x0a ) );
1041 					::rtl::OUString			aString;
1042 
1043 					aString = aLineFeed;
1044 					aString +=  B2UCONST( "<" );
1045 					aString += ::rtl::OUString::createFromAscii( aXMLElemImage );
1046 					aString += aSpace;
1047 
1048 					aString += ::rtl::OUString::createFromAscii( aXMLAttrX );
1049 					aString += B2UCONST( "=\"" );
1050 					aString += ::rtl::OUString::valueOf( aPt.X() );
1051 					aString += B2UCONST( "\" " );
1052 
1053 					aString += ::rtl::OUString::createFromAscii( aXMLAttrY );
1054 					aString += B2UCONST( "=\"" );
1055 					aString += ::rtl::OUString::valueOf( aPt.Y() );
1056 					aString += B2UCONST( "\" " );
1057 
1058 					aString += ::rtl::OUString::createFromAscii( aXMLAttrWidth );
1059 					aString += B2UCONST( "=\"" );
1060 					aString += ::rtl::OUString::valueOf( aSz.Width() );
1061 					aString += B2UCONST( "\" " );
1062 
1063 					aString += ::rtl::OUString::createFromAscii( aXMLAttrHeight );
1064 					aString += B2UCONST( "=\"" );
1065 					aString += ::rtl::OUString::valueOf( aSz.Height() );
1066 					aString += B2UCONST( "\" " );
1067 
1068 					aString += ::rtl::OUString::createFromAscii( aXMLAttrXLinkHRef );
1069 					aString += B2UCONST( "=\"data:image/png;base64," );
1070 
1071                     xExtDocHandler->unknown( aString );
1072 
1073                     // #119735#
1074                     const sal_uInt32 nQuadCount = nImageDataLength / 3;
1075                     const sal_uInt32 nRest = nImageDataLength % 3;
1076 
1077                     if( nQuadCount || nRest )
1078                     {
1079                         sal_Int32           nBufLen = ( ( nQuadCount + ( nRest ? 1 : 0 ) ) << 2 );
1080                         const sal_Char* pSrc = pImageData;
1081 
1082                         sal_Unicode*        pBuffer = new sal_Unicode[ nBufLen * sizeof( sal_Unicode ) ];
1083                         sal_Unicode*        pTmpDst = pBuffer;
1084 
1085                         for( sal_uInt32 i = 0; i < nQuadCount; ++i )
1086                         {
1087                             const sal_Int32 nA = *pSrc++;
1088                             const sal_Int32 nB = *pSrc++;
1089                             const sal_Int32 nC = *pSrc++;
1090 
1091                             *pTmpDst++ = pBase64[ ( nA >> 2 ) & 0x3f ];
1092                             *pTmpDst++ = pBase64[ ( ( nA << 4 ) & 0x30 ) + ( ( nB >> 4 ) & 0xf ) ];
1093                             *pTmpDst++ = pBase64[ ( ( nB << 2 ) & 0x3c ) + ( ( nC >> 6 ) & 0x3 ) ];
1094                             *pTmpDst++ = pBase64[ nC & 0x3f ];
1095                         }
1096 
1097                         if( nRest )
1098                         {
1099                             const sal_Int32 nA = *pSrc++;
1100 
1101                             *pTmpDst++ = pBase64[ ( nA >> 2 ) & 0x3f ];
1102 
1103                             if( 2 == nRest )
1104                             {
1105                                 const sal_Int32 nB = *pSrc;
1106 
1107                                 *pTmpDst++ = pBase64[ ( ( nA << 4 ) & 0x30 ) + ( ( nB >> 4 ) & 0xf ) ];
1108                                 *pTmpDst++ = pBase64[ ( nB << 2 ) & 0x3c ];
1109                             }
1110                             else
1111                             {
1112                                 *pTmpDst++ = pBase64[ ( nA << 4 ) & 0x30 ];
1113                                 *pTmpDst++ = '=';
1114                             }
1115 
1116                             *pTmpDst = '=';
1117                         }
1118 
1119                         for( sal_Int32 nCurPos = 0; nCurPos < nBufLen; nCurPos += nPartLen )
1120                         {
1121                             const ::rtl::OUString aPart( pBuffer + nCurPos, ::std::min< sal_Int32 >( nPartLen, nBufLen - nCurPos ) );
1122 
1123                             xExtDocHandler->unknown( aLineFeed );
1124                             xExtDocHandler->unknown( aPart );
1125                         }
1126 
1127                         delete[] pBuffer;
1128                     }
1129 
1130                     xExtDocHandler->unknown( B2UCONST( "\"/>" ) );
1131                 }
1132 			}
1133 		}
1134 	}
1135 }
1136 
1137 // -----------------------------------------------------------------------------
1138 
ImplWriteActions(const GDIMetaFile & rMtf,sal_uInt32 nWriteFlags,const::rtl::OUString * pElementId)1139 void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
1140                                         sal_uInt32 nWriteFlags,
1141                                         const ::rtl::OUString* pElementId )
1142 {
1143     // need a counter fo rthe actions written per shape to avoid double ID
1144     // generation
1145     sal_Int32 nEntryCount(0);
1146 
1147     if( mnInnerMtfCount )
1148         nWriteFlags |= SVGWRITER_NO_SHAPE_COMMENTS;
1149 
1150 	for( sal_uLong nCurAction = 0, nCount = rMtf.GetActionCount(); nCurAction < nCount; nCurAction++ )
1151 	{
1152 		const MetaAction*	pAction = rMtf.GetAction( nCurAction );
1153 		const sal_uInt16		nType = pAction->GetType();
1154 
1155 		switch( nType )
1156 		{
1157 			case( META_PIXEL_ACTION	):
1158 			{
1159 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1160 				{
1161 					const MetaPixelAction* pA = (const MetaPixelAction*) pAction;
1162 
1163 					mpContext->AddPaintAttr( pA->GetColor(), pA->GetColor() );
1164 					ImplWriteLine( pA->GetPoint(), pA->GetPoint(), &pA->GetColor() );
1165 				}
1166 			}
1167 			break;
1168 
1169 			case( META_POINT_ACTION	):
1170 			{
1171 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1172 				{
1173 					const MetaPointAction* pA = (const MetaPointAction*) pAction;
1174 
1175 					mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetLineColor() );
1176 					ImplWriteLine( pA->GetPoint(), pA->GetPoint(), NULL );
1177 				}
1178 			}
1179 			break;
1180 
1181 			case( META_LINE_ACTION ):
1182 			{
1183 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1184 				{
1185 					const MetaLineAction* pA = (const MetaLineAction*) pAction;
1186 
1187 					mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetLineColor() );
1188 					ImplWriteLine( pA->GetStartPoint(), pA->GetEndPoint(), NULL );
1189 				}
1190 			}
1191 			break;
1192 
1193 			case( META_RECT_ACTION ):
1194 			{
1195 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1196 				{
1197 					mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
1198 					ImplWriteRect( ( (const MetaRectAction*) pAction )->GetRect(), 0, 0 );
1199 				}
1200 			}
1201 			break;
1202 
1203 			case( META_ROUNDRECT_ACTION	):
1204 			{
1205 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1206 				{
1207 					const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pAction;
1208 
1209 					mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
1210 					ImplWriteRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
1211 				}
1212 			}
1213 			break;
1214 
1215 			case( META_ELLIPSE_ACTION ):
1216 			{
1217 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1218 				{
1219 					const MetaEllipseAction*	pA = (const MetaEllipseAction*) pAction;
1220 					const Rectangle&			rRect = pA->GetRect();
1221 
1222 					mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
1223 					ImplWriteEllipse( rRect.Center(), rRect.GetWidth() >> 1, rRect.GetHeight() >> 1 );
1224 				}
1225 			}
1226 			break;
1227 
1228 			case( META_ARC_ACTION ):
1229 			case( META_PIE_ACTION ):
1230 			case( META_CHORD_ACTION	):
1231 			case( META_POLYGON_ACTION ):
1232 			{
1233 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1234 				{
1235 					Polygon aPoly;
1236 
1237 					switch( nType )
1238 					{
1239 						case( META_ARC_ACTION ):
1240 						{
1241 							const MetaArcAction* pA = (const MetaArcAction*) pAction;
1242 							aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC );
1243 						}
1244 						break;
1245 
1246 						case( META_PIE_ACTION ):
1247 						{
1248 							const MetaPieAction* pA = (const MetaPieAction*) pAction;
1249 							aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE );
1250 						}
1251 						break;
1252 
1253 						case( META_CHORD_ACTION	):
1254 						{
1255 							const MetaChordAction* pA = (const MetaChordAction*) pAction;
1256 							aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD );
1257 						}
1258 						break;
1259 
1260 						case( META_POLYGON_ACTION ):
1261 							aPoly = ( (const MetaPolygonAction*) pAction )->GetPolygon();
1262 						break;
1263 					}
1264 
1265 					if( aPoly.GetSize() )
1266 					{
1267 						mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
1268 						ImplWritePolyPolygon( aPoly, sal_False );
1269 					}
1270 				}
1271 			}
1272 			break;
1273 
1274 			case( META_POLYLINE_ACTION ):
1275 			{
1276 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1277 				{
1278 					const MetaPolyLineAction*	pA = (const MetaPolyLineAction*) pAction;
1279 					const Polygon&				rPoly = pA->GetPolygon();
1280 
1281 					if( rPoly.GetSize() )
1282 					{
1283                         const LineInfo& rLineInfo = pA->GetLineInfo();
1284 
1285                         if(rLineInfo.GetWidth())
1286                         {
1287                             sal_Int32 nStrokeWidth = ImplMap(rLineInfo.GetWidth());
1288                             mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeWidth, ::rtl::OUString::valueOf( nStrokeWidth ) );
1289                         }
1290 
1291 						mpContext->AddPaintAttr( mpVDev->GetLineColor(), Color( COL_TRANSPARENT ) );
1292 						ImplWritePolyPolygon( rPoly, sal_True );
1293 					}
1294 				}
1295 			}
1296 			break;
1297 
1298 			case( META_POLYPOLYGON_ACTION ):
1299 			{
1300 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1301 				{
1302 					const MetaPolyPolygonAction*	pA = (const MetaPolyPolygonAction*) pAction;
1303 					const PolyPolygon&				rPolyPoly = pA->GetPolyPolygon();
1304 
1305 					if( rPolyPoly.Count() )
1306 					{
1307 						mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
1308 						ImplWritePolyPolygon( rPolyPoly, sal_False );
1309 					}
1310 				}
1311 			}
1312 			break;
1313 
1314 			case( META_GRADIENT_ACTION ):
1315 			{
1316 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1317 				{
1318 					const MetaGradientAction*	pA = (const MetaGradientAction*) pAction;
1319 					const Polygon				aRectPoly( pA->GetRect() );
1320 					const PolyPolygon			aRectPolyPoly( aRectPoly );
1321 
1322 					ImplWriteGradientEx( aRectPolyPoly, pA->GetGradient(), nWriteFlags );
1323 				}
1324 			}
1325 			break;
1326 
1327 			case( META_GRADIENTEX_ACTION ):
1328 			{
1329 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1330 				{
1331 					const MetaGradientExAction*	pA = (const MetaGradientExAction*) pAction;
1332 					ImplWriteGradientEx( pA->GetPolyPolygon(), pA->GetGradient(), nWriteFlags );
1333 				}
1334 			}
1335 			break;
1336 
1337 			case META_HATCH_ACTION:
1338 			{
1339 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1340 				{
1341 					const MetaHatchAction*	pA = (const MetaHatchAction*) pAction;
1342 					GDIMetaFile				aTmpMtf;
1343 
1344 					mpVDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
1345 
1346                     ++mnInnerMtfCount;
1347 
1348                     ImplWriteActions( aTmpMtf, nWriteFlags, NULL );
1349 
1350                     --mnInnerMtfCount;
1351 				}
1352 			}
1353 			break;
1354 
1355 			case( META_TRANSPARENT_ACTION ):
1356 			{
1357 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1358 				{
1359 					const MetaTransparentAction*	pA = (const MetaTransparentAction*) pAction;
1360 					const PolyPolygon&				rPolyPoly = pA->GetPolyPolygon();
1361 
1362 					if( rPolyPoly.Count() )
1363 					{
1364                         Color aNewLineColor( mpVDev->GetLineColor() ), aNewFillColor( mpVDev->GetFillColor() );
1365 
1366                         aNewLineColor.SetTransparency( sal::static_int_cast<sal_uInt8>( FRound( pA->GetTransparence() * 2.55 ) ) );
1367                         aNewFillColor.SetTransparency( sal::static_int_cast<sal_uInt8>( FRound( pA->GetTransparence() * 2.55 ) ) );
1368 
1369 						mpContext->AddPaintAttr( aNewLineColor, aNewFillColor );
1370 						ImplWritePolyPolygon( rPolyPoly, sal_False );
1371 					}
1372 				}
1373 			}
1374 			break;
1375 
1376 			case( META_FLOATTRANSPARENT_ACTION ):
1377 			{
1378 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1379 				{
1380 					const MetaFloatTransparentAction*	pA = (const MetaFloatTransparentAction*) pAction;
1381 					GDIMetaFile							aTmpMtf( pA->GetGDIMetaFile() );
1382 					Point								aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1383 					const Size							aSrcSize( aTmpMtf.GetPrefSize() );
1384 					const Point							aDestPt( pA->GetPoint() );
1385 					const Size							aDestSize( pA->GetSize() );
1386 					const double						fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
1387 					const double						fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
1388 					long								nMoveX, nMoveY;
1389 
1390 					if( fScaleX != 1.0 || fScaleY != 1.0 )
1391 					{
1392 						aTmpMtf.Scale( fScaleX, fScaleY );
1393 						aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
1394 					}
1395 
1396 					nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y();
1397 
1398 					if( nMoveX || nMoveY )
1399 						aTmpMtf.Move( nMoveX, nMoveY );
1400 
1401 					mpVDev->Push();
1402                     ++mnInnerMtfCount;
1403 
1404                     ImplWriteActions( aTmpMtf, nWriteFlags, NULL );
1405 
1406                     --mnInnerMtfCount;
1407 					mpVDev->Pop();
1408 				}
1409 			}
1410 			break;
1411 
1412 			case( META_EPS_ACTION ):
1413 			{
1414 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1415 				{
1416 					const MetaEPSAction*	pA = (const MetaEPSAction*) pAction;
1417 					const GDIMetaFile		aGDIMetaFile( pA->GetSubstitute() );
1418 					sal_Bool				bFound = sal_False;
1419 
1420 					for( sal_uInt32 k = 0, nCount2 = aGDIMetaFile.GetActionCount(); ( k < nCount2 ) && !bFound; ++k )
1421 					{
1422 						const MetaAction* pSubstAct = aGDIMetaFile.GetAction( k );
1423 
1424 						if( pSubstAct->GetType() == META_BMPSCALE_ACTION )
1425 						{
1426 							bFound = sal_True;
1427 							const MetaBmpScaleAction* pBmpScaleAction = (const MetaBmpScaleAction*) pSubstAct;
1428 							ImplWriteBmp( pBmpScaleAction->GetBitmap(),
1429 										  pA->GetPoint(), pA->GetSize(),
1430 										  Point(), pBmpScaleAction->GetBitmap().GetSizePixel() );
1431 						}
1432 					}
1433 				}
1434 			}
1435 			break;
1436 
1437 			case( META_COMMENT_ACTION ):
1438 			{
1439 				const MetaCommentAction*	pA = (const MetaCommentAction*) pAction;
1440 				String						aSkipComment;
1441 
1442 				if( ( pA->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL ) &&
1443 					( nWriteFlags & SVGWRITER_WRITE_FILL ) )
1444 				{
1445 					const MetaGradientExAction*	pGradAction = NULL;
1446 					sal_Bool					bDone = sal_False;
1447 
1448 					while( !bDone && ( ++nCurAction < nCount ) )
1449 					{
1450 						pAction = rMtf.GetAction( nCurAction );
1451 
1452 						if( pAction->GetType() == META_GRADIENTEX_ACTION )
1453 							pGradAction = (const MetaGradientExAction*) pAction;
1454 						else if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
1455 								 ( ( (const MetaCommentAction*) pAction )->GetComment().
1456                                         CompareIgnoreCaseToAscii( "XGRAD_SEQ_END" ) == COMPARE_EQUAL ) )
1457 						{
1458 							bDone = sal_True;
1459 						}
1460 					}
1461 
1462 					if( pGradAction )
1463 						ImplWriteGradientEx( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), nWriteFlags );
1464 				}
1465                 else if( ( pA->GetComment().CompareIgnoreCaseToAscii( "XPATHFILL_SEQ_BEGIN" ) == COMPARE_EQUAL ) &&
1466                          ( nWriteFlags & SVGWRITER_WRITE_FILL ) && !( nWriteFlags & SVGWRITER_NO_SHAPE_COMMENTS ) &&
1467                          pA->GetDataSize() )
1468                 {
1469                     // write open shape in every case
1470                     if( mapCurShape.get() )
1471                     {
1472                         ImplWriteShape( *mapCurShape );
1473                         mapCurShape.reset();
1474                     }
1475 
1476                     SvMemoryStream  aMemStm( (void*) pA->GetData(), pA->GetDataSize(), STREAM_READ );
1477                     SvtGraphicFill  aFill;
1478 
1479                     aMemStm >> aFill;
1480 
1481                     sal_Bool bGradient = SvtGraphicFill::fillGradient == aFill.getFillType() &&
1482                                      ( SvtGraphicFill::gradientLinear == aFill.getGradientType() ||
1483                                        SvtGraphicFill::gradientRadial == aFill.getGradientType() );
1484                     sal_Bool bSkip = ( SvtGraphicFill::fillSolid == aFill.getFillType() || bGradient );
1485 
1486                     if( bSkip )
1487                     {
1488                         PolyPolygon aShapePolyPoly;
1489 
1490                         aFill.getPath( aShapePolyPoly );
1491 
1492                         if( aShapePolyPoly.Count() )
1493                         {
1494                             mapCurShape.reset( new SVGShapeDescriptor );
1495 
1496                             if( pElementId )
1497                             {
1498                                 mapCurShape->maId = *pElementId + B2UCONST("_") + ::rtl::OUString::valueOf(nEntryCount++);
1499                             }
1500 
1501                             mapCurShape->maShapePolyPoly = aShapePolyPoly;
1502                             mapCurShape->maShapeFillColor = aFill.getFillColor();
1503                             mapCurShape->maShapeFillColor.SetTransparency( (sal_uInt8) FRound( 255.0 * aFill.getTransparency() ) );
1504 
1505                             if( bGradient )
1506                             {
1507                                 // step through following actions until the first Gradient/GradientEx action is found
1508                                 while( !mapCurShape->mapShapeGradient.get() && bSkip && ( ++nCurAction < nCount ) )
1509                                 {
1510                                     pAction = rMtf.GetAction( nCurAction );
1511 
1512                                     if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
1513                                         ( ( (const MetaCommentAction*) pAction )->GetComment().
1514                                         CompareIgnoreCaseToAscii( "XPATHFILL_SEQ_END" ) == COMPARE_EQUAL ) )
1515                                     {
1516                                         bSkip = sal_False;
1517                                     }
1518                                     else if( pAction->GetType() == META_GRADIENTEX_ACTION )
1519                                     {
1520                                         mapCurShape->mapShapeGradient.reset( new Gradient(
1521                                             static_cast< const MetaGradientExAction* >( pAction )->GetGradient() ) );
1522                                     }
1523                                     else if( pAction->GetType() == META_GRADIENT_ACTION )
1524                                     {
1525                                         mapCurShape->mapShapeGradient.reset( new Gradient(
1526                                             static_cast< const MetaGradientAction* >( pAction )->GetGradient() ) );
1527                                     }
1528                                 }
1529                             }
1530                         }
1531                         else
1532                             bSkip = sal_False;
1533                     }
1534 
1535                     // skip rest of comment
1536                     while( bSkip && ( ++nCurAction < nCount ) )
1537                     {
1538                         pAction = rMtf.GetAction( nCurAction );
1539 
1540                         if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
1541                                     ( ( (const MetaCommentAction*) pAction )->GetComment().
1542                                     CompareIgnoreCaseToAscii( "XPATHFILL_SEQ_END" ) == COMPARE_EQUAL ) )
1543                         {
1544                             bSkip = sal_False;
1545                         }
1546                     }
1547                 }
1548                 else if( ( pA->GetComment().CompareIgnoreCaseToAscii( "XPATHSTROKE_SEQ_BEGIN" ) == COMPARE_EQUAL ) &&
1549                          ( nWriteFlags & SVGWRITER_WRITE_FILL ) && !( nWriteFlags & SVGWRITER_NO_SHAPE_COMMENTS ) &&
1550                          pA->GetDataSize() )
1551                 {
1552                     SvMemoryStream      aMemStm( (void*) pA->GetData(), pA->GetDataSize(), STREAM_READ );
1553                     SvtGraphicStroke    aStroke;
1554                     PolyPolygon         aStartArrow, aEndArrow;
1555 
1556                     aMemStm >> aStroke;
1557                     aStroke.getStartArrow( aStartArrow );
1558                     aStroke.getEndArrow( aEndArrow );
1559 
1560                     // Currently no support for strokes with start/end arrow(s)
1561                     // added that support
1562                     Polygon aPoly;
1563 
1564                     aStroke.getPath(aPoly);
1565 
1566                     if(mapCurShape.get())
1567                     {
1568                         if(1 != mapCurShape->maShapePolyPoly.Count()
1569                             || !mapCurShape->maShapePolyPoly[0].IsEqual(aPoly))
1570                         {
1571                             // this path action is not covering the same path than the already existing
1572                             // fill polypolygon, so write out the fill polygon
1573                             ImplWriteShape( *mapCurShape );
1574                             mapCurShape.reset();
1575                         }
1576                     }
1577 
1578                     if( !mapCurShape.get() )
1579                     {
1580 
1581                         mapCurShape.reset( new SVGShapeDescriptor );
1582 
1583                         if( pElementId )
1584                         {
1585                             mapCurShape->maId = *pElementId + B2UCONST("_") + ::rtl::OUString::valueOf(nEntryCount++);
1586                         }
1587 
1588                         mapCurShape->maShapePolyPoly = aPoly;
1589                     }
1590 
1591                     mapCurShape->maShapeLineColor = mpVDev->GetLineColor();
1592                     mapCurShape->maShapeLineColor.SetTransparency( (sal_uInt8) FRound( aStroke.getTransparency() * 255.0 ) );
1593                     mapCurShape->mnStrokeWidth = FRound( aStroke.getStrokeWidth() );
1594                     aStroke.getDashArray( mapCurShape->maDashArray );
1595 
1596                     // added support for LineJoin
1597                     switch(aStroke.getJoinType())
1598                     {
1599                         default: /* SvtGraphicStroke::joinMiter,  SvtGraphicStroke::joinNone */
1600                         {
1601                             mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_MITER;
1602                             break;
1603                         }
1604                         case SvtGraphicStroke::joinRound:
1605                         {
1606                             mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_ROUND;
1607                             break;
1608                         }
1609                         case SvtGraphicStroke::joinBevel:
1610                         {
1611                             mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_BEVEL;
1612                             break;
1613                         }
1614                     }
1615 
1616                     // added support for LineCap
1617                     switch(aStroke.getCapType())
1618                     {
1619                         default: /* SvtGraphicStroke::capButt */
1620                         {
1621                             mapCurShape->maLineCap = com::sun::star::drawing::LineCap_BUTT;
1622                             break;
1623                         }
1624                         case SvtGraphicStroke::capRound:
1625                         {
1626                             mapCurShape->maLineCap = com::sun::star::drawing::LineCap_ROUND;
1627                             break;
1628                         }
1629                         case SvtGraphicStroke::capSquare:
1630                         {
1631                             mapCurShape->maLineCap = com::sun::star::drawing::LineCap_SQUARE;
1632                             break;
1633                         }
1634                     }
1635 
1636                     if(mapCurShape.get() &&(aStartArrow.Count() || aEndArrow.Count()))
1637                     {
1638                         ImplWriteShape( *mapCurShape );
1639 
1640                         mapCurShape->maShapeFillColor = mapCurShape->maShapeLineColor;
1641                         mapCurShape->maShapeLineColor = Color(COL_TRANSPARENT);
1642                         mapCurShape->mnStrokeWidth = 0;
1643                         mapCurShape->maDashArray.clear();
1644                         mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_MITER;
1645                         mapCurShape->maLineCap = com::sun::star::drawing::LineCap_BUTT;
1646 
1647                         if(aStartArrow.Count())
1648                         {
1649                             mapCurShape->maShapePolyPoly = aStartArrow;
1650 
1651                             if( pElementId ) // #i124825# pElementId is optional, may be zero
1652                             {
1653                                 mapCurShape->maId = *pElementId + B2UCONST("_") + ::rtl::OUString::valueOf(nEntryCount++);
1654                             }
1655 
1656                             ImplWriteShape( *mapCurShape );
1657                         }
1658 
1659                         if(aEndArrow.Count())
1660                         {
1661                             mapCurShape->maShapePolyPoly = aEndArrow;
1662 
1663                             if( pElementId ) // #i124825# pElementId is optional, may be zero
1664                             {
1665                                 mapCurShape->maId = *pElementId + B2UCONST("_") + ::rtl::OUString::valueOf(nEntryCount++);
1666                             }
1667 
1668                             ImplWriteShape( *mapCurShape );
1669                         }
1670 
1671                         mapCurShape.reset();
1672                     }
1673 
1674                     // write open shape in every case
1675                     if( mapCurShape.get() )
1676                     {
1677                         ImplWriteShape( *mapCurShape );
1678                         mapCurShape.reset();
1679                     }
1680 
1681                     // skip rest of comment
1682                     sal_Bool bSkip = true;
1683 
1684                     while( bSkip && ( ++nCurAction < nCount ) )
1685                     {
1686                         pAction = rMtf.GetAction( nCurAction );
1687 
1688                         if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
1689                                     ( ( (const MetaCommentAction*) pAction )->GetComment().
1690                                     CompareIgnoreCaseToAscii( "XPATHSTROKE_SEQ_END" ) == COMPARE_EQUAL ) )
1691                         {
1692                             bSkip = sal_False;
1693                         }
1694                     }
1695                 }
1696 			}
1697 			break;
1698 
1699 			case( META_BMP_ACTION ):
1700 			{
1701 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1702 				{
1703 					const MetaBmpAction* pA = (const MetaBmpAction*) pAction;
1704 
1705 					ImplWriteBmp( pA->GetBitmap(),
1706 								  pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmap().GetSizePixel() ),
1707 								  Point(), pA->GetBitmap().GetSizePixel() );
1708 				}
1709 			}
1710 			break;
1711 
1712 			case( META_BMPSCALE_ACTION ):
1713 			{
1714 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1715 				{
1716 					const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction;
1717 
1718 					ImplWriteBmp( pA->GetBitmap(),
1719 								  pA->GetPoint(), pA->GetSize(),
1720 								  Point(), pA->GetBitmap().GetSizePixel() );
1721 				}
1722 			}
1723 			break;
1724 
1725 			case( META_BMPSCALEPART_ACTION ):
1726 			{
1727 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1728 				{
1729 					const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pAction;
1730 
1731 					ImplWriteBmp( pA->GetBitmap(),
1732 								  pA->GetDestPoint(), pA->GetDestSize(),
1733 								  pA->GetSrcPoint(), pA->GetSrcSize() );
1734 				}
1735 			}
1736 			break;
1737 
1738 			case( META_BMPEX_ACTION	):
1739 			{
1740 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1741 				{
1742 					const MetaBmpExAction*	pA = (const MetaBmpExAction*) pAction;
1743 
1744 					ImplWriteBmp( pA->GetBitmapEx(),
1745 								  pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmapEx().GetSizePixel() ),
1746 								  Point(), pA->GetBitmapEx().GetSizePixel() );
1747 				}
1748 			}
1749 			break;
1750 
1751 			case( META_BMPEXSCALE_ACTION ):
1752 			{
1753 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1754 				{
1755 					const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction;
1756 
1757 					ImplWriteBmp( pA->GetBitmapEx(),
1758 								  pA->GetPoint(), pA->GetSize(),
1759 								  Point(), pA->GetBitmapEx().GetSizePixel() );
1760 				}
1761 			}
1762 			break;
1763 
1764 			case( META_BMPEXSCALEPART_ACTION ):
1765 			{
1766 				if( nWriteFlags & SVGWRITER_WRITE_FILL )
1767 				{
1768 					const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pAction;
1769 
1770 					ImplWriteBmp( pA->GetBitmapEx(),
1771 								  pA->GetDestPoint(), pA->GetDestSize(),
1772 								  pA->GetSrcPoint(), pA->GetSrcSize() );
1773 				}
1774 			}
1775 			break;
1776 
1777 			case( META_TEXT_ACTION ):
1778 			{
1779 				if( nWriteFlags & SVGWRITER_WRITE_TEXT )
1780 				{
1781 					const MetaTextAction*   pA = (const MetaTextAction*) pAction;
1782                     const String            aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
1783 
1784                     if( aText.Len() )
1785                     {
1786                         Font    aFont( mpVDev->GetFont() );
1787                         Size    aSz;
1788 
1789                         ImplMap( Size( 0, aFont.GetHeight() ), aSz );
1790 
1791                         aFont.SetHeight( aSz.Height() );
1792                         mpContext->AddPaintAttr( COL_TRANSPARENT, mpVDev->GetTextColor() );
1793                         mpContext->SetFontAttr( aFont );
1794                         ImplWriteText( pA->GetPoint(), aText, NULL, 0 );
1795                     }
1796 				}
1797 			}
1798 			break;
1799 
1800 			case( META_TEXTRECT_ACTION ):
1801 			{
1802 				if( nWriteFlags & SVGWRITER_WRITE_TEXT )
1803 				{
1804 					const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction;
1805 
1806                     if( pA->GetText().Len() )
1807                     {
1808                         Font    aFont( mpVDev->GetFont() );
1809                         Size    aSz;
1810 
1811                         ImplMap( Size( 0, aFont.GetHeight() ), aSz );
1812 
1813                         aFont.SetHeight( aSz.Height() );
1814                         mpContext->AddPaintAttr( COL_TRANSPARENT, mpVDev->GetTextColor() );
1815                         mpContext->SetFontAttr( aFont );
1816                         ImplWriteText( pA->GetRect().TopLeft(), pA->GetText(), NULL, 0 );
1817                     }
1818 				}
1819 			}
1820 			break;
1821 
1822 			case( META_TEXTARRAY_ACTION	):
1823 			{
1824 				if( nWriteFlags & SVGWRITER_WRITE_TEXT )
1825 				{
1826 					const MetaTextArrayAction*	pA = (const MetaTextArrayAction*) pAction;
1827                     const String                aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
1828 
1829                     if( aText.Len() )
1830                     {
1831                         Font    aFont( mpVDev->GetFont() );
1832                         Size    aSz;
1833 
1834                         ImplMap( Size( 0, aFont.GetHeight() ), aSz );
1835 
1836                         aFont.SetHeight( aSz.Height() );
1837                         mpContext->AddPaintAttr( COL_TRANSPARENT, mpVDev->GetTextColor() );
1838                         mpContext->SetFontAttr( aFont );
1839                         ImplWriteText( pA->GetPoint(), aText, pA->GetDXArray(), 0 );
1840                     }
1841 				}
1842 			}
1843 			break;
1844 
1845 			case( META_STRETCHTEXT_ACTION ):
1846 			{
1847 				if( nWriteFlags & SVGWRITER_WRITE_TEXT )
1848 				{
1849 					const MetaStretchTextAction*    pA = (const MetaStretchTextAction*) pAction;
1850                     const String                    aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
1851 
1852                     if( aText.Len() )
1853                     {
1854                         Font    aFont( mpVDev->GetFont() );
1855                         Size    aSz;
1856 
1857                         ImplMap( Size( 0, aFont.GetHeight() ), aSz );
1858 
1859                         aFont.SetHeight( aSz.Height() );
1860                         mpContext->AddPaintAttr( COL_TRANSPARENT, mpVDev->GetTextColor() );
1861                         mpContext->SetFontAttr( aFont );
1862                         ImplWriteText( pA->GetPoint(), aText, NULL, pA->GetWidth() );
1863                     }
1864 				}
1865 			}
1866 			break;
1867 
1868 			case( META_CLIPREGION_ACTION ):
1869 			case( META_ISECTRECTCLIPREGION_ACTION ):
1870 			case( META_ISECTREGIONCLIPREGION_ACTION	):
1871 			case( META_MOVECLIPREGION_ACTION ):
1872 			{
1873 				( (MetaAction*) pAction )->Execute( mpVDev );
1874 				mbClipAttrChanged = sal_True;
1875 			}
1876 			break;
1877 
1878 			case( META_REFPOINT_ACTION ):
1879 			case( META_MAPMODE_ACTION ):
1880 			case( META_LINECOLOR_ACTION	):
1881 			case( META_FILLCOLOR_ACTION	):
1882 			case( META_TEXTLINECOLOR_ACTION ):
1883 			case( META_TEXTFILLCOLOR_ACTION	):
1884 			case( META_TEXTCOLOR_ACTION	):
1885 			case( META_TEXTALIGN_ACTION	):
1886 			case( META_FONT_ACTION ):
1887 			case( META_PUSH_ACTION ):
1888 			case( META_POP_ACTION ):
1889 			case( META_LAYOUTMODE_ACTION ):
1890 			{
1891 				( (MetaAction*) pAction )->Execute( mpVDev );
1892 			}
1893 			break;
1894 
1895 			case( META_RASTEROP_ACTION ):
1896 			case( META_MASK_ACTION ):
1897 			case( META_MASKSCALE_ACTION	):
1898 			case( META_MASKSCALEPART_ACTION	):
1899 			case( META_WALLPAPER_ACTION	):
1900 			case( META_TEXTLINE_ACTION ):
1901 			{
1902 				// !!! >>> we don't want to support these actions
1903 			}
1904 			break;
1905 
1906 			default:
1907 				DBG_ERROR( "SVGActionWriter::ImplWriteActions: unsupported MetaAction #" );
1908 			break;
1909 		}
1910 	}
1911 }
1912 
1913 // -----------------------------------------------------------------------------
1914 
WriteMetaFile(const Point & rPos100thmm,const Size & rSize100thmm,const GDIMetaFile & rMtf,sal_uInt32 nWriteFlags,const::rtl::OUString * pElementId)1915 void SVGActionWriter::WriteMetaFile( const Point& rPos100thmm,
1916                                      const Size& rSize100thmm,
1917 									 const GDIMetaFile& rMtf,
1918 									 sal_uInt32 nWriteFlags,
1919                                      const ::rtl::OUString* pElementId )
1920 {
1921 	MapMode	    aMapMode( rMtf.GetPrefMapMode() );
1922     Size        aPrefSize( rMtf.GetPrefSize() );
1923     Fraction    aFractionX( aMapMode.GetScaleX() );
1924     Fraction    aFractionY( aMapMode.GetScaleY() );
1925 
1926 	mpVDev->Push();
1927 
1928 	Size aSize( OutputDevice::LogicToLogic( rSize100thmm, MAP_100TH_MM, aMapMode ) );
1929     aMapMode.SetScaleX( aFractionX *= Fraction( aSize.Width(), aPrefSize.Width() ) );
1930     aMapMode.SetScaleY( aFractionY *= Fraction( aSize.Height(), aPrefSize.Height() ) );
1931 
1932     Point aOffset( OutputDevice::LogicToLogic( rPos100thmm, MAP_100TH_MM, aMapMode ) );
1933 	aMapMode.SetOrigin( aOffset += aMapMode.GetOrigin() );
1934 
1935 	mpVDev->SetMapMode( aMapMode );
1936     ImplAcquireContext();
1937 
1938     mapCurShape.reset();
1939 
1940     ImplWriteActions( rMtf, nWriteFlags, pElementId );
1941 
1942     // draw open shape that doesn't have a border
1943     if( mapCurShape.get() )
1944     {
1945         ImplWriteShape( *mapCurShape );
1946         mapCurShape.reset();
1947     }
1948 
1949     ImplReleaseContext();
1950 	mpVDev->Pop();
1951 }
1952 
1953 // -------------
1954 // - SVGWriter -
1955 // -------------
1956 
SVGWriter(const REF (NMSP_LANG::XMultiServiceFactory)& rxMgr)1957 SVGWriter::SVGWriter( const REF( NMSP_LANG::XMultiServiceFactory )& rxMgr ) :
1958 	mxFact( rxMgr )
1959 {
1960 }
1961 
1962 // -----------------------------------------------------------------------------
1963 
~SVGWriter()1964 SVGWriter::~SVGWriter()
1965 {
1966 }
1967 
1968 // -----------------------------------------------------------------------------
1969 
1970 
queryInterface(const NMSP_UNO::Type & rType)1971 ANY SAL_CALL SVGWriter::queryInterface( const NMSP_UNO::Type & rType ) throw( NMSP_UNO::RuntimeException )
1972 {
1973 	const ANY aRet( NMSP_CPPU::queryInterface( rType,
1974 			static_cast< NMSP_SVG::XSVGWriter* >( this ),
1975 			static_cast< NMSP_LANG::XInitialization* >( this ) ) );
1976 	return( aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ) );
1977 }
1978 
1979 // -----------------------------------------------------------------------------
1980 
acquire()1981 void SAL_CALL SVGWriter::acquire() throw()
1982 {
1983 	OWeakObject::acquire();
1984 }
1985 
1986 // -----------------------------------------------------------------------------
1987 
release()1988 void SAL_CALL SVGWriter::release() throw()
1989 {
1990 	OWeakObject::release();
1991 }
1992 
1993 // -----------------------------------------------------------------------------
1994 
write(const REF (NMSP_SAX::XDocumentHandler)& rxDocHandler,const SEQ (sal_Int8)& rMtfSeq)1995 void SAL_CALL SVGWriter::write( const REF( NMSP_SAX::XDocumentHandler )& rxDocHandler,
1996 								const SEQ( sal_Int8 )& rMtfSeq ) throw( NMSP_UNO::RuntimeException )
1997 {
1998 	SvMemoryStream	aMemStm( (char*) rMtfSeq.getConstArray(), rMtfSeq.getLength(), STREAM_READ );
1999 	GDIMetaFile		aMtf;
2000 
2001 	aMemStm.SetCompressMode( COMPRESSMODE_FULL );
2002 	aMemStm >> aMtf;
2003 
2004 	const REF( NMSP_SAX::XDocumentHandler ) xDocumentHandler( rxDocHandler );
2005 	SVGExport* pWriter = new SVGExport( mxFact, xDocumentHandler, maFilterData );
2006 
2007 	pWriter->writeMtf( aMtf );
2008 	delete pWriter;
2009 }
2010 
2011 // -----------------------------------------------------------------------------
2012 
initialize(const::com::sun::star::uno::Sequence<::com::sun::star::uno::Any> & aArguments)2013 void SVGWriter::initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments )
2014 	throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
2015 {
2016 	if ( aArguments.getLength() == 1 )
2017 	{
2018 		::com::sun::star::uno::Any aArg = aArguments.getConstArray()[0];
2019 		aArg >>= maFilterData;
2020 	}
2021 }
2022 
2023 // -----------------------------------------------------------------------------
2024 
2025 #define SVG_WRITER_SERVICE_NAME         "com.sun.star.svg.SVGWriter"
2026 #define SVG_WRITER_IMPLEMENTATION_NAME  "com.sun.star.comp.Draw.SVGWriter"
2027 
SVGWriter_getImplementationName()2028 rtl::OUString SVGWriter_getImplementationName()
2029 	throw (RuntimeException)
2030 {
2031 	return rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM( SVG_WRITER_IMPLEMENTATION_NAME ) );
2032 }
2033 
2034 // -----------------------------------------------------------------------------
2035 
SVGWriter_getImplementationId()2036 Sequence< sal_Int8 > SAL_CALL SVGWriter_getImplementationId()
2037     throw(RuntimeException)
2038 {
2039     static const ::cppu::OImplementationId aId;
2040 
2041     return( aId.getImplementationId() );
2042 }
2043 
2044 // -----------------------------------------------------------------------------
2045 
SVGWriter_getSupportedServiceNames()2046 Sequence< rtl::OUString > SAL_CALL SVGWriter_getSupportedServiceNames()
2047     throw (RuntimeException)
2048 {
2049 	Sequence< rtl::OUString > aRet( 1 );
2050 
2051 	aRet.getArray()[ 0 ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SVG_WRITER_SERVICE_NAME ) );
2052 
2053     return aRet;
2054 }
2055 
2056 // -----------------------------------------------------------------------------
2057 
SVGWriter_createInstance(const Reference<XMultiServiceFactory> & rSMgr)2058 Reference< XInterface > SAL_CALL SVGWriter_createInstance( const Reference< XMultiServiceFactory > & rSMgr )
2059     throw( Exception )
2060 {
2061     return( static_cast< cppu::OWeakObject* >( new SVGWriter( rSMgr ) ) );
2062 }
2063