xref: /AOO41X/main/filter/source/svg/svgwriter.cxx (revision ec549e9140931025a1eda10a4f4815070fe48e77)
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 optinal, 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 optinal, 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