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