bump product version to 4.1.6.2
[LibreOffice.git] / filter / source / svg / svgwriter.cxx
blob410215a499aa1684f71c0f48831a044fcbbdd870
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "svgfilter.hxx"
21 #include "svgfontexport.hxx"
22 #include "svgwriter.hxx"
24 #include <rtl/crc.h>
25 #include <vcl/unohelp.hxx>
26 #include <tools/helpers.hxx>
27 #include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
28 #include <sax/tools/converter.hxx>
30 #include <boost/shared_array.hpp>
33 static const char aXMLElemG[] = "g";
34 static const char aXMLElemA[] = "a";
35 static const char aXMLElemDefs[] = "defs";
36 static const char aXMLElemLine[] = "line";
37 static const char aXMLElemRect[] = "rect";
38 static const char aXMLElemEllipse[] = "ellipse";
39 static const char aXMLElemPath[] = "path";
40 static const char aXMLElemText[] = "text";
41 static const char aXMLElemTspan[] = "tspan";
42 static const char aXMLElemImage[] = "image";
43 static const char aXMLElemMask[] = "mask";
44 static const char aXMLElemPattern[] = "pattern";
45 static const char aXMLElemLinearGradient[] = "linearGradient";
46 static const char aXMLElemRadialGradient[] = "radialGradient";
47 static const char aXMLElemStop[] = "stop";
49 static const char aXMLAttrTransform[] = "transform";
50 static const char aXMLAttrStyle[] = "style";
51 static const char aXMLAttrId[] = "id";
52 static const char aXMLAttrDX[] = "dx";
53 static const char aXMLAttrDY[] = "dy";
54 static const char aXMLAttrD[] = "d";
55 static const char aXMLAttrX[] = "x";
56 static const char aXMLAttrY[] = "y";
57 static const char aXMLAttrX1[] = "x1";
58 static const char aXMLAttrY1[] = "y1";
59 static const char aXMLAttrX2[] = "x2";
60 static const char aXMLAttrY2[] = "y2";
61 static const char aXMLAttrCX[] = "cx";
62 static const char aXMLAttrCY[] = "cy";
63 static const char aXMLAttrR[] = "r";
64 static const char aXMLAttrRX[] = "rx";
65 static const char aXMLAttrRY[] = "ry";
66 static const char aXMLAttrWidth[] = "width";
67 static const char aXMLAttrHeight[] = "height";
68 static const char aXMLAttrStroke[] = "stroke";
69 static const char aXMLAttrStrokeOpacity[] = "stroke-opacity";
70 static const char aXMLAttrStrokeWidth[] = "stroke-width";
71 static const char aXMLAttrStrokeDashArray[] = "stroke-dasharray";
72 static const char aXMLAttrFill[] = "fill";
73 static const char aXMLAttrFillOpacity[] = "fill-opacity";
74 static const char aXMLAttrFontFamily[] = "font-family";
75 static const char aXMLAttrFontSize[] = "font-size";
76 static const char aXMLAttrFontStyle[] = "font-style";
77 static const char aXMLAttrFontWeight[] = "font-weight";
78 static const char aXMLAttrTextDecoration[] = "text-decoration";
79 static const char aXMLAttrXLinkHRef[] = "xlink:href";
80 static const char aXMLAttrGradientUnits[] = "gradientUnits";
81 static const char aXMLAttrPatternUnits[] = "patternUnits";
82 static const char aXMLAttrOffset[] = "offset";
83 static const char aXMLAttrStopColor[] = "stop-color";
84 static const char aXMLAttrStrokeLinejoin[] = "stroke-linejoin";
85 static const char aXMLAttrStrokeLinecap[] = "stroke-linecap";
88 #define NSPREFIX "ooo:"
90 static const char aOOOAttrNumberingType[] = NSPREFIX "numbering-type";
93 static sal_Char const XML_UNO_NAME_NRULE_NUMBERINGTYPE[] = "NumberingType";
94 static sal_Char const XML_UNO_NAME_NRULE_BULLET_CHAR[] = "BulletChar";
96 SVGAttributeWriter::SVGAttributeWriter( SVGExport& rExport, SVGFontExport& rFontExport ) :
97 mrExport( rExport ),
98 mrFontExport( rFontExport ),
99 mpElemFont( NULL ),
100 mpElemPaint( NULL )
104 SVGAttributeWriter::~SVGAttributeWriter()
106 if( mpElemPaint )
107 delete mpElemPaint;
108 if( mpElemFont )
109 delete mpElemFont;
112 double SVGAttributeWriter::ImplRound( double fValue, sal_Int32 nDecs )
114 return( floor( fValue * pow( 10.0, (int)nDecs ) + 0.5 ) / pow( 10.0, (int)nDecs ) );
117 void SVGAttributeWriter::ImplGetColorStr( const Color& rColor, OUString& rColorStr )
119 if( rColor.GetTransparency() == 255 )
120 rColorStr = "none";
121 else
123 rColorStr = "rgb(" + OUString::number(rColor.GetRed()) + "," + OUString::number(rColor.GetGreen()) +
124 "," + OUString::number(rColor.GetBlue()) + ")";
128 void SVGAttributeWriter::AddColorAttr( const char* pColorAttrName,
129 const char* pColorOpacityAttrName,
130 const Color& rColor )
132 OUString aColor, aColorOpacity;
134 ImplGetColorStr( rColor, aColor );
136 if( rColor.GetTransparency() > 0 && rColor.GetTransparency() < 255 )
137 aColorOpacity = OUString::valueOf( ImplRound( ( 255.0 - rColor.GetTransparency() ) / 255.0 ) );
139 mrExport.AddAttribute( XML_NAMESPACE_NONE, pColorAttrName, aColor );
141 if( !aColorOpacity.isEmpty() && mrExport.IsUseOpacity() )
142 mrExport.AddAttribute( XML_NAMESPACE_NONE, pColorOpacityAttrName, aColorOpacity );
145 void SVGAttributeWriter::AddPaintAttr( const Color& rLineColor, const Color& rFillColor,
146 const Rectangle* pObjBoundRect, const Gradient* pFillGradient )
148 // Fill
149 if( pObjBoundRect && pFillGradient )
151 OUString aGradientId;
153 AddGradientDef( *pObjBoundRect, *pFillGradient, aGradientId );
155 if( !aGradientId.isEmpty() )
157 OUString aGradientURL = "url(#" + aGradientId + ")";
158 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFill, aGradientURL );
161 else
162 AddColorAttr( aXMLAttrFill, aXMLAttrFillOpacity, rFillColor );
164 // Stroke
165 AddColorAttr( aXMLAttrStroke, aXMLAttrStrokeOpacity, rLineColor );
168 void SVGAttributeWriter::AddGradientDef( const Rectangle& rObjRect, const Gradient& rGradient, OUString& rGradientId )
170 if( rObjRect.GetWidth() && rObjRect.GetHeight() &&
171 ( rGradient.GetStyle() == GradientStyle_LINEAR || rGradient.GetStyle() == GradientStyle_AXIAL ||
172 rGradient.GetStyle() == GradientStyle_RADIAL || rGradient.GetStyle() == GradientStyle_ELLIPTICAL ) )
174 SvXMLElementExport aDesc( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, sal_True, sal_True );
175 Color aStartColor( rGradient.GetStartColor() ), aEndColor( rGradient.GetEndColor() );
176 sal_uInt16 nAngle = rGradient.GetAngle() % 3600;
177 Point aObjRectCenter( rObjRect.Center() );
178 Polygon aPoly( rObjRect );
179 static sal_Int32 nCurGradientId = 1;
181 aPoly.Rotate( aObjRectCenter, nAngle );
182 Rectangle aRect( aPoly.GetBoundRect() );
184 // adjust start/end colors with intensities
185 aStartColor.SetRed( (sal_uInt8)( (long) aStartColor.GetRed() * rGradient.GetStartIntensity() ) / 100 );
186 aStartColor.SetGreen( (sal_uInt8)( (long) aStartColor.GetGreen() * rGradient.GetStartIntensity() ) / 100 );
187 aStartColor.SetBlue( (sal_uInt8)( (long) aStartColor.GetBlue() * rGradient.GetStartIntensity() ) / 100 );
189 aEndColor.SetRed( (sal_uInt8)( (long) aEndColor.GetRed() * rGradient.GetEndIntensity() ) / 100 );
190 aEndColor.SetGreen( (sal_uInt8)( (long) aEndColor.GetGreen() * rGradient.GetEndIntensity() ) / 100 );
191 aEndColor.SetBlue( (sal_uInt8)( (long) aEndColor.GetBlue() * rGradient.GetEndIntensity() ) / 100 );
193 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId,
194 ( rGradientId = "Gradient_" ) += OUString::valueOf( nCurGradientId++ ) );
197 ::std::auto_ptr< SvXMLElementExport > apGradient;
198 OUString aColorStr;
200 if( rGradient.GetStyle() == GradientStyle_LINEAR || rGradient.GetStyle() == GradientStyle_AXIAL )
202 Polygon aLinePoly( 2 );
204 aLinePoly[ 0 ] = Point( aObjRectCenter.X(), aRect.Top() );
205 aLinePoly[ 1 ] = Point( aObjRectCenter.X(), aRect.Bottom() );
207 aLinePoly.Rotate( aObjRectCenter, nAngle );
209 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits, "userSpaceOnUse" );
210 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, OUString::valueOf( aLinePoly[ 0 ].X() ) );
211 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, OUString::valueOf( aLinePoly[ 0 ].Y() ) );
212 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, OUString::valueOf( aLinePoly[ 1 ].X() ) );
213 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, OUString::valueOf( aLinePoly[ 1 ].Y() ) );
215 apGradient.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemLinearGradient, sal_True, sal_True ) );
217 // write stop values
218 double fBorder = static_cast< double >( rGradient.GetBorder() ) *
219 ( ( rGradient.GetStyle() == GradientStyle_AXIAL ) ? 0.005 : 0.01 );
221 ImplGetColorStr( ( rGradient.GetStyle() == GradientStyle_AXIAL ) ? aEndColor : aStartColor, aColorStr );
222 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, OUString::valueOf( fBorder ) );
223 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
226 SvXMLElementExport aDesc2( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
229 if( rGradient.GetStyle() == GradientStyle_AXIAL )
231 ImplGetColorStr( aStartColor, aColorStr );
232 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, OUString::valueOf( 0.5 ) );
233 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
236 SvXMLElementExport aDesc3( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
240 if( rGradient.GetStyle() != GradientStyle_AXIAL )
241 fBorder = 0.0;
243 ImplGetColorStr( aEndColor, aColorStr );
244 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, OUString::valueOf( ImplRound( 1.0 - fBorder ) ) );
245 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
248 SvXMLElementExport aDesc4( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
251 else
253 const double fCenterX = rObjRect.Left() + rObjRect.GetWidth() * rGradient.GetOfsX() * 0.01;
254 const double fCenterY = rObjRect.Top() + rObjRect.GetHeight() * rGradient.GetOfsY() * 0.01;
255 const double fRadius = sqrt( static_cast< double >( rObjRect.GetWidth() ) * rObjRect.GetWidth() +
256 rObjRect.GetHeight() * rObjRect.GetHeight() ) * 0.5;
258 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits, "userSpaceOnUse" );
259 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCX, OUString::valueOf( ImplRound( fCenterX ) ) );
260 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCY, OUString::valueOf( ImplRound( fCenterY ) ) );
261 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrR, OUString::valueOf( ImplRound( fRadius ) ) );
263 apGradient.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemRadialGradient, sal_True, sal_True ) );
265 // write stop values
266 ImplGetColorStr( aEndColor, aColorStr );
267 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, OUString::valueOf( 0.0 ) );
268 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
271 SvXMLElementExport aDesc5( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
274 ImplGetColorStr( aStartColor, aColorStr );
275 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset,
276 OUString::valueOf( ImplRound( 1.0 - rGradient.GetBorder() * 0.01 ) ) );
277 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
280 SvXMLElementExport aDesc6( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
285 else
286 rGradientId = OUString();
289 void SVGAttributeWriter::SetFontAttr( const Font& rFont )
291 if( rFont != maCurFont )
293 OUString aFontStyle, aTextDecoration;
294 sal_Int32 nFontWeight;
296 maCurFont = rFont;
298 // Font Family
299 setFontFamily();
301 // Font Size
302 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontSize,
303 OUString::valueOf( rFont.GetHeight() ) + "px" );
305 // Font Style
306 if( rFont.GetItalic() != ITALIC_NONE )
308 if( rFont.GetItalic() == ITALIC_OBLIQUE )
309 aFontStyle = "oblique";
310 else
311 aFontStyle = "italic";
313 else
314 aFontStyle = "normal";
316 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontStyle, aFontStyle );
318 // Font Weight
319 switch( rFont.GetWeight() )
321 case WEIGHT_THIN: nFontWeight = 100; break;
322 case WEIGHT_ULTRALIGHT: nFontWeight = 200; break;
323 case WEIGHT_LIGHT: nFontWeight = 300; break;
324 case WEIGHT_SEMILIGHT: nFontWeight = 400; break;
325 case WEIGHT_NORMAL: nFontWeight = 400; break;
326 case WEIGHT_MEDIUM: nFontWeight = 500; break;
327 case WEIGHT_SEMIBOLD: nFontWeight = 600; break;
328 case WEIGHT_BOLD: nFontWeight = 700; break;
329 case WEIGHT_ULTRABOLD: nFontWeight = 800; break;
330 case WEIGHT_BLACK: nFontWeight = 900; break;
331 default: nFontWeight = 400; break;
334 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontWeight, OUString::valueOf( nFontWeight ) );
336 if( mrExport.IsUseNativeTextDecoration() )
338 if( rFont.GetUnderline() != UNDERLINE_NONE || rFont.GetStrikeout() != STRIKEOUT_NONE )
340 if( rFont.GetUnderline() != UNDERLINE_NONE )
341 aTextDecoration = "underline ";
343 if( rFont.GetStrikeout() != STRIKEOUT_NONE )
344 aTextDecoration += "line-through ";
346 else
347 aTextDecoration = "none";
349 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTextDecoration, aTextDecoration );
352 startFontSettings();
356 void SVGAttributeWriter::startFontSettings()
358 endFontSettings();
359 if( mrExport.IsUsePositionedCharacters() )
361 mpElemFont = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
363 else
365 mpElemFont = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, sal_True, sal_True );
369 void SVGAttributeWriter::endFontSettings()
371 if( mpElemFont )
373 delete mpElemFont;
374 mpElemFont = NULL;
378 void SVGAttributeWriter::setFontFamily()
380 if( mrExport.IsUsePositionedCharacters() )
382 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontFamily, mrFontExport.GetMappedFontName( maCurFont.GetName() ) );
384 else
386 sal_Int32 nNextTokenPos( 0 );
387 const OUString& rsFontName = maCurFont.GetName();
388 OUString sFontFamily( rsFontName.getToken( 0, ';', nNextTokenPos ) );
389 FontPitch ePitch = maCurFont.GetPitch();
390 if( ePitch == PITCH_FIXED )
392 sFontFamily += ", monospace";
394 else
396 FontFamily eFamily = maCurFont.GetFamily();
397 if( eFamily == FAMILY_ROMAN )
398 sFontFamily += ", serif";
399 else if( eFamily == FAMILY_SWISS )
400 sFontFamily += ", sans-serif";
402 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontFamily, sFontFamily );
406 SVGTextWriter::SVGTextWriter( SVGExport& rExport )
407 : mrExport( rExport ),
408 mpContext( NULL ),
409 mpVDev( NULL ),
410 mbIsTextShapeStarted( sal_False ),
411 mrTextShape(),
412 msShapeId(),
413 mrParagraphEnumeration(),
414 mrCurrentTextParagraph(),
415 mrTextPortionEnumeration(),
416 mrCurrentTextPortion(),
417 mpTextEmbeddedBitmapMtf( NULL ),
418 mpTargetMapMode( NULL ),
419 mpTextShapeElem( NULL ),
420 mpTextParagraphElem( NULL ),
421 mpTextPositionElem( NULL ),
422 mnLeftTextPortionLength( 0 ),
423 maTextPos(0,0),
424 mnTextWidth(0),
425 mbPositioningNeeded( sal_False ),
426 mbIsNewListItem( sal_False ),
427 maBulletListItemMap(),
428 mbIsListLevelStyleImage( sal_False ),
429 mbLineBreak( sal_False ),
430 mbIsURLField( sal_False ),
431 msUrl(),
432 mbIsPlacehlolderShape( sal_False ),
433 mbIWS( sal_False ),
434 maCurrentFont(),
435 maParentFont()
439 SVGTextWriter::~SVGTextWriter()
441 endTextParagraph();
444 void SVGTextWriter::implRegisterInterface( const Reference< XInterface >& rxIf )
446 if( rxIf.is() )
447 (mrExport.getInterfaceToIdentifierMapper()).registerReference( rxIf );
450 const OUString & SVGTextWriter::implGetValidIDFromInterface( const Reference< XInterface >& rxIf )
452 return (mrExport.getInterfaceToIdentifierMapper()).getIdentifier( rxIf );
455 void SVGTextWriter::implMap( const Size& rSz, Size& rDstSz ) const
457 if( mpVDev && mpTargetMapMode )
458 rDstSz = mpVDev->LogicToLogic( rSz, mpVDev->GetMapMode(), *mpTargetMapMode );
459 else
460 OSL_FAIL( "SVGTextWriter::implMap: invalid virtual device or map mode." );
463 void SVGTextWriter::implMap( const Point& rPt, Point& rDstPt ) const
465 if( mpVDev && mpTargetMapMode )
466 rDstPt = mpVDev->LogicToLogic( rPt, mpVDev->GetMapMode(), *mpTargetMapMode );
467 else
468 OSL_FAIL( "SVGTextWriter::implMap: invalid virtual device or map mode." );
471 void SVGTextWriter::implSetCurrentFont()
473 if( mpVDev )
475 maCurrentFont = mpVDev->GetFont();
476 Size aSz;
478 implMap( Size( 0, maCurrentFont.GetHeight() ), aSz );
480 maCurrentFont.SetHeight( aSz.Height() );
482 else
484 OSL_FAIL( "SVGTextWriter::implSetCorrectFontHeight: invalid virtual device." );
488 template< typename SubType >
489 sal_Bool SVGTextWriter::implGetTextPosition( const MetaAction* pAction, Point& raPos, sal_Bool& rbEmpty )
491 const SubType* pA = (const SubType*) pAction;
492 sal_uInt16 nLength = pA->GetLen();
493 rbEmpty = ( nLength == 0 );
494 if( !rbEmpty )
496 raPos = pA->GetPoint();
497 return sal_True;
499 return sal_False;
502 template<>
503 sal_Bool SVGTextWriter::implGetTextPosition<MetaTextRectAction>( const MetaAction* pAction, Point& raPos, sal_Bool& rbEmpty )
505 const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction;
506 sal_uInt16 nLength = pA->GetText().getLength();
507 rbEmpty = ( nLength == 0 );
508 if( !rbEmpty )
510 raPos = pA->GetRect().TopLeft();
511 return sal_True;
513 return sal_False;
516 template< typename SubType >
517 sal_Bool SVGTextWriter::implGetTextPositionFromBitmap( const MetaAction* pAction, Point& raPos, sal_Bool& rbEmpty )
519 const SubType* pA = (const SubType*) pAction;
520 raPos = pA->GetPoint();
521 rbEmpty = sal_False;
522 return sal_True;
525 /** setTextPosition
526 * Set the start position of the next line of text. In case no text is found
527 * the current action index is updated to the index value we reached while
528 * searching for text.
530 * @returns {sal_Int32}
531 * -2 if no text found and end of line is reached
532 * -1 if no text found and end of paragraph is reached
533 * 0 if no text found and end of text shape is reached
534 * 1 if text found!
536 sal_Int32 SVGTextWriter::setTextPosition( const GDIMetaFile& rMtf, sal_uLong& nCurAction )
538 Point aPos;
539 sal_uLong nCount = rMtf.GetActionSize();
540 sal_Bool bEOL = sal_False;
541 sal_Bool bEOP = sal_False;
542 sal_Bool bETS = sal_False;
543 sal_Bool bConfigured = sal_False;
544 sal_Bool bEmpty = sal_True;
546 sal_uLong nActionIndex = nCurAction + 1;
547 for( ; nActionIndex < nCount; ++nActionIndex )
549 const MetaAction* pAction = rMtf.GetAction( nActionIndex );
550 const sal_uInt16 nType = pAction->GetType();
552 switch( nType )
554 case( META_TEXT_ACTION ):
556 bConfigured = implGetTextPosition<MetaTextAction>( pAction, aPos, bEmpty );
558 break;
560 case( META_TEXTRECT_ACTION ):
562 bConfigured = implGetTextPosition<MetaTextRectAction>( pAction, aPos, bEmpty );
564 break;
566 case( META_TEXTARRAY_ACTION ):
568 bConfigured = implGetTextPosition<MetaTextArrayAction>( pAction, aPos, bEmpty );
570 break;
572 case( META_STRETCHTEXT_ACTION ):
574 bConfigured = implGetTextPosition<MetaStretchTextAction>( pAction, aPos, bEmpty );
576 break;
578 case( META_BMPSCALE_ACTION ):
580 bConfigured = implGetTextPositionFromBitmap<MetaBmpScaleAction>( pAction, aPos, bEmpty );
582 break;
584 case( META_BMPEXSCALE_ACTION ):
586 bConfigured = implGetTextPositionFromBitmap<MetaBmpExScaleAction>( pAction, aPos, bEmpty );
588 break;
590 // If we reach the end of the current line, paragraph or text shape
591 // without finding any text we stop searching
592 case( META_COMMENT_ACTION ):
594 const MetaCommentAction* pA = (const MetaCommentAction*) pAction;
595 const OString& rsComment = pA->GetComment();
596 if( rsComment.equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_EOL" ) ) )
598 bEOL = true;
600 else if( rsComment.equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_EOP" ) ) )
602 bEOP = true;
604 OUString sContent;
605 while( nextTextPortion() )
607 sContent = mrCurrentTextPortion->getString();
608 if( sContent.isEmpty() )
610 continue;
612 else
614 if( sContent.equalsAscii( "\n" ) )
615 mbLineBreak = sal_True;
618 if( nextParagraph() )
620 while( nextTextPortion() )
622 sContent = mrCurrentTextPortion->getString();
623 if( sContent.isEmpty() )
625 continue;
627 else
629 if( sContent.equalsAscii( "\n" ) )
630 mbLineBreak = sal_True;
635 else if( rsComment.equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_PAINTSHAPE_END" ) ) )
637 bETS = true;
640 break;
642 if( bConfigured || bEOL || bEOP || bETS ) break;
644 implMap( aPos, maTextPos );
646 if( bEmpty )
648 nCurAction = nActionIndex;
649 return ( (bEOL) ? -2 : ( (bEOP) ? -1 : 0 ) );
651 else
653 return 1;
657 void SVGTextWriter::setTextProperties( const GDIMetaFile& rMtf, sal_uLong nCurAction )
659 sal_uLong nCount = rMtf.GetActionSize();
660 sal_Bool bEOP = sal_False;
661 sal_Bool bConfigured = sal_False;
662 for( sal_uLong nActionIndex = nCurAction + 1; nActionIndex < nCount; ++nActionIndex )
664 const MetaAction* pAction = rMtf.GetAction( nActionIndex );
665 const sal_uInt16 nType = pAction->GetType();
666 switch( nType )
668 case( META_TEXTLINECOLOR_ACTION ):
669 case( META_TEXTFILLCOLOR_ACTION ):
670 case( META_TEXTCOLOR_ACTION ):
671 case( META_TEXTALIGN_ACTION ):
672 case( META_FONT_ACTION ):
673 case( META_LAYOUTMODE_ACTION ):
675 ( (MetaAction*) pAction )->Execute( mpVDev );
677 break;
679 case( META_TEXT_ACTION ):
681 const MetaTextAction* pA = (const MetaTextAction*) pAction;
682 if( pA->GetLen() > 2 )
683 bConfigured = true;
685 break;
686 case( META_TEXTRECT_ACTION ):
688 const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction;
689 if( pA->GetText().getLength() > 2 )
690 bConfigured = true;
692 break;
693 case( META_TEXTARRAY_ACTION ):
695 const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pAction;
696 if( pA->GetLen() > 2 )
697 bConfigured = true;
699 break;
700 case( META_STRETCHTEXT_ACTION ):
702 const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction;
703 if( pA->GetLen() > 2 )
704 bConfigured = true;
706 break;
707 // If we reach the end of the paragraph without finding any text
708 // we stop searching
709 case( META_COMMENT_ACTION ):
711 const MetaCommentAction* pA = (const MetaCommentAction*) pAction;
712 const OString& rsComment = pA->GetComment();
713 if( rsComment.equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_EOP" ) ) )
715 bEOP = true;
718 break;
720 if( bConfigured || bEOP ) break;
724 void SVGTextWriter::addFontAttributes( sal_Bool bIsTextContainer )
726 implSetCurrentFont();
728 if( maCurrentFont != maParentFont )
730 const String& rsCurFontName = maCurrentFont.GetName();
731 long int nCurFontSize = maCurrentFont.GetHeight();
732 FontItalic eCurFontItalic = maCurrentFont.GetItalic();
733 FontWeight eCurFontWeight = maCurrentFont.GetWeight();
735 const String& rsParFontName = maParentFont.GetName();
736 long int nParFontSize = maParentFont.GetHeight();
737 FontItalic eParFontItalic = maParentFont.GetItalic();
738 FontWeight eParFontWeight = maParentFont.GetWeight();
741 // Font Family
742 if( rsCurFontName != rsParFontName )
744 implSetFontFamily();
747 // Font Size
748 if( nCurFontSize != nParFontSize )
750 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontSize,
751 OUString::valueOf( nCurFontSize ) + "px" );
754 // Font Style
755 if( eCurFontItalic != eParFontItalic )
757 OUString sFontStyle;
758 if( eCurFontItalic != ITALIC_NONE )
760 if( eCurFontItalic == ITALIC_OBLIQUE )
761 sFontStyle = "oblique";
762 else
763 sFontStyle = "italic";
765 else
767 sFontStyle = "normal";
769 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontStyle, sFontStyle );
772 // Font Weight
773 if( eCurFontWeight != eParFontWeight )
775 sal_Int32 nFontWeight;
776 switch( eCurFontWeight )
778 case WEIGHT_THIN: nFontWeight = 100; break;
779 case WEIGHT_ULTRALIGHT: nFontWeight = 200; break;
780 case WEIGHT_LIGHT: nFontWeight = 300; break;
781 case WEIGHT_SEMILIGHT: nFontWeight = 400; break;
782 case WEIGHT_NORMAL: nFontWeight = 400; break;
783 case WEIGHT_MEDIUM: nFontWeight = 500; break;
784 case WEIGHT_SEMIBOLD: nFontWeight = 600; break;
785 case WEIGHT_BOLD: nFontWeight = 700; break;
786 case WEIGHT_ULTRABOLD: nFontWeight = 800; break;
787 case WEIGHT_BLACK: nFontWeight = 900; break;
788 default: nFontWeight = 400; break;
790 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontWeight, OUString::valueOf( nFontWeight ) );
793 if( bIsTextContainer )
794 maParentFont = maCurrentFont;
797 if( mrExport.IsUseNativeTextDecoration() )
799 FontUnderline eCurFontUnderline = maCurrentFont.GetUnderline();
800 FontStrikeout eCurFontStrikeout = maCurrentFont.GetStrikeout();
802 FontUnderline eParFontUnderline = maParentFont.GetUnderline();
803 FontStrikeout eParFontStrikeout = maParentFont.GetStrikeout();
805 OUString sTextDecoration;
807 if( eCurFontUnderline != eParFontUnderline )
809 if( eCurFontUnderline != UNDERLINE_NONE )
810 sTextDecoration = "underline ";
812 if( eCurFontStrikeout != eParFontStrikeout )
814 if( eCurFontStrikeout != STRIKEOUT_NONE )
815 sTextDecoration += "line-through ";
817 if( !sTextDecoration.isEmpty() )
818 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTextDecoration, sTextDecoration );
822 void SVGTextWriter::implSetFontFamily()
824 sal_Int32 nNextTokenPos( 0 );
825 const OUString& rsFontName = maCurrentFont.GetName();
826 OUString sFontFamily( rsFontName.getToken( 0, ';', nNextTokenPos ) );
827 FontPitch ePitch = maCurrentFont.GetPitch();
828 if( ePitch == PITCH_FIXED )
830 sFontFamily += ", monospace";
832 else
834 FontFamily eFamily = maCurrentFont.GetFamily();
835 if( eFamily == FAMILY_ROMAN )
836 sFontFamily += ", serif";
837 else if( eFamily == FAMILY_SWISS )
838 sFontFamily += ", sans-serif";
840 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontFamily, sFontFamily );
843 sal_Bool SVGTextWriter::createParagraphEnumeration()
845 if( mrTextShape.is() )
847 Reference< XInterface > xRef( mrTextShape, UNO_QUERY );
848 msShapeId = implGetValidIDFromInterface( xRef );
850 Reference< XEnumerationAccess > xEnumerationAccess( mrTextShape, UNO_QUERY_THROW );
851 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
852 if( xEnumeration.is() )
854 mrParagraphEnumeration.set( xEnumeration );
855 return sal_True;
857 else
859 OSL_FAIL( "SVGTextWriter::createParagraphEnumeration: no valid xEnumeration interface found." );
862 else
864 OSL_FAIL( "SVGTextWriter::createParagraphEnumeration: no valid XText interface found." );
866 return sal_False;
869 sal_Bool SVGTextWriter::nextParagraph()
871 mrTextPortionEnumeration.clear();
872 mrCurrentTextParagraph.clear();
873 mbIsNewListItem = sal_False;
874 mbIsListLevelStyleImage = sal_False;
876 if( mrParagraphEnumeration.is() && mrParagraphEnumeration->hasMoreElements() )
878 Reference < XTextContent > xTextContent( mrParagraphEnumeration->nextElement(), UNO_QUERY_THROW );
879 if( xTextContent.is() )
881 Reference< XServiceInfo > xServiceInfo( xTextContent, UNO_QUERY_THROW );
882 if( xServiceInfo.is() )
884 #if OSL_DEBUG_LEVEL > 0
885 OUString sInfo;
886 #endif
887 if( xServiceInfo->supportsService( "com.sun.star.text.Paragraph" ) )
889 mrCurrentTextParagraph.set( xTextContent );
890 Reference< XPropertySet > xPropSet( xTextContent, UNO_QUERY_THROW );
891 Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
892 if( xPropSetInfo->hasPropertyByName( "NumberingLevel" ) )
894 sal_Int16 nListLevel = 0;
895 if( xPropSet->getPropertyValue( "NumberingLevel" ) >>= nListLevel )
897 mbIsNewListItem = sal_True;
898 #if OSL_DEBUG_LEVEL > 0
899 sInfo = "NumberingLevel: " + OUString::valueOf( (sal_Int32)nListLevel );
900 mrExport.AddAttribute( XML_NAMESPACE_NONE, "style", sInfo );
901 #endif
902 Reference< XIndexReplace > xNumRules;
903 if( xPropSetInfo->hasPropertyByName( "NumberingRules" ) )
905 xPropSet->getPropertyValue( "NumberingRules" ) >>= xNumRules;
907 if( xNumRules.is() && ( nListLevel < xNumRules->getCount() ) )
909 sal_Bool bIsNumbered = sal_True;
910 OUString msNumberingIsNumber("NumberingIsNumber");
911 if( xPropSetInfo->hasPropertyByName( msNumberingIsNumber ) )
913 if( !(xPropSet->getPropertyValue( msNumberingIsNumber ) >>= bIsNumbered ) )
915 OSL_FAIL( "numbered paragraph without number info" );
916 bIsNumbered = sal_False;
918 #if OSL_DEBUG_LEVEL > 0
919 if( bIsNumbered )
921 sInfo = "true";
922 mrExport.AddAttribute( XML_NAMESPACE_NONE, "is-numbered", sInfo );
924 #endif
926 mbIsNewListItem = bIsNumbered;
928 if( bIsNumbered )
930 Sequence<PropertyValue> aProps;
931 if( xNumRules->getByIndex( nListLevel ) >>= aProps )
933 sal_Int16 eType = NumberingType::CHAR_SPECIAL;
934 sal_Unicode cBullet = 0xf095;
935 const sal_Int32 nCount = aProps.getLength();
936 const PropertyValue* pPropArray = aProps.getConstArray();
937 for( sal_Int32 i = 0; i < nCount; ++i )
939 const PropertyValue& rProp = pPropArray[i];
940 if( rProp.Name.equalsAsciiL( XML_UNO_NAME_NRULE_NUMBERINGTYPE, sizeof(XML_UNO_NAME_NRULE_NUMBERINGTYPE)-1 ) )
942 rProp.Value >>= eType;
944 else if( rProp.Name.equalsAsciiL( XML_UNO_NAME_NRULE_BULLET_CHAR, sizeof(XML_UNO_NAME_NRULE_BULLET_CHAR)-1 ) )
946 OUString sValue;
947 rProp.Value >>= sValue;
948 if( !sValue.isEmpty() )
950 cBullet = (sal_Unicode)sValue[0];
954 meNumberingType = eType;
955 mbIsListLevelStyleImage = ( NumberingType::BITMAP == meNumberingType );
956 if( NumberingType::CHAR_SPECIAL == meNumberingType )
958 if( cBullet )
960 if( cBullet < ' ' )
962 cBullet = 0xF000 + 149;
964 mcBulletChar = cBullet;
965 #if OSL_DEBUG_LEVEL > 0
966 sInfo = OUString::valueOf( (sal_Int32) cBullet );
967 mrExport.AddAttribute( XML_NAMESPACE_NONE, "bullet-char", sInfo );
968 #endif
979 Reference< XEnumerationAccess > xEnumerationAccess( xTextContent, UNO_QUERY_THROW );
980 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
981 if( xEnumeration.is() && xEnumeration->hasMoreElements() )
983 mrTextPortionEnumeration.set( xEnumeration );
985 #if OSL_DEBUG_LEVEL > 0
986 sInfo = "Paragraph";
987 #endif
989 else if( xServiceInfo->supportsService( "com.sun.star.text.Table" ) )
991 OSL_FAIL( "SVGTextWriter::nextParagraph: text tables are not handled." );
992 #if OSL_DEBUG_LEVEL > 0
993 sInfo = "Table";
994 #endif
996 else
998 OSL_FAIL( "SVGTextWriter::nextParagraph: Unknown text content." );
999 return sal_False;
1001 #if OSL_DEBUG_LEVEL > 0
1002 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", sInfo );
1003 SvXMLElementExport aParaElem( mrExport, XML_NAMESPACE_NONE, "desc", mbIWS, mbIWS );
1004 #endif
1006 else
1008 OSL_FAIL( "SVGTextWriter::nextParagraph: no XServiceInfo interface available for text content." );
1009 return sal_False;
1012 Reference< XInterface > xRef( xTextContent, UNO_QUERY );
1013 const OUString& rParagraphId = implGetValidIDFromInterface( xRef );
1014 if( !rParagraphId.isEmpty() )
1016 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", rParagraphId );
1018 return sal_True;
1022 return sal_False;
1025 sal_Bool SVGTextWriter::nextTextPortion()
1027 mrCurrentTextPortion.clear();
1028 mbIsURLField = sal_False;
1029 mbIsPlacehlolderShape = sal_False;
1030 if( mrTextPortionEnumeration.is() && mrTextPortionEnumeration->hasMoreElements() )
1032 #if OSL_DEBUG_LEVEL > 0
1033 OUString sInfo;
1034 #endif
1035 Reference< XPropertySet > xPortionPropSet( mrTextPortionEnumeration->nextElement(), UNO_QUERY );
1036 Reference< XPropertySetInfo > xPortionPropInfo( xPortionPropSet->getPropertySetInfo() );
1037 Reference < XTextRange > xPortionTextRange( xPortionPropSet, UNO_QUERY);
1038 if( xPortionPropSet.is() && xPortionPropInfo.is()
1039 && xPortionPropInfo->hasPropertyByName( "TextPortionType" ) )
1041 #if OSL_DEBUG_LEVEL > 0
1042 OUString sPortionType;
1043 if( xPortionPropSet->getPropertyValue( "TextPortionType" ) >>= sPortionType )
1045 sInfo = "type: " + sPortionType + "; ";
1047 #endif
1048 if( xPortionTextRange.is() )
1050 #if OSL_DEBUG_LEVEL > 0
1051 sInfo += "content: " + xPortionTextRange->getString() + "; ";
1052 #endif
1053 mrCurrentTextPortion.set( xPortionTextRange );
1055 Reference < XPropertySet > xRangePropSet( xPortionTextRange, UNO_QUERY );
1056 if( xRangePropSet.is() && xRangePropSet->getPropertySetInfo()->hasPropertyByName( "TextField" ) )
1058 Reference < XTextField > xTextField( xRangePropSet->getPropertyValue( "TextField" ), UNO_QUERY );
1059 if( xTextField.is() )
1061 const OUString sServicePrefix("com.sun.star.text.textfield.");
1062 const OUString sPresentationServicePrefix("com.sun.star.presentation.TextField.");
1064 Reference< XServiceInfo > xService( xTextField, UNO_QUERY );
1065 const Sequence< OUString > aServices = xService->getSupportedServiceNames();
1067 const OUString* pNames = aServices.getConstArray();
1068 sal_Int32 nCount = aServices.getLength();
1070 OUString sFieldName; // service name postfix of current field
1072 // search for TextField service name
1073 while( nCount-- )
1075 if ( pNames->matchIgnoreAsciiCase( sServicePrefix ) )
1077 // TextField found => postfix is field type!
1078 sFieldName = pNames->copy( sServicePrefix.getLength() );
1079 break;
1081 else if( 0 == pNames->compareTo( sPresentationServicePrefix, sPresentationServicePrefix.getLength() ) )
1083 // TextField found => postfix is field type!
1084 sFieldName = pNames->copy( sPresentationServicePrefix.getLength() );
1085 break;
1088 ++pNames;
1091 #if OSL_DEBUG_LEVEL > 0
1092 sInfo += "text field type: " + sFieldName + "; " +
1093 "content: " + xTextField->getPresentation( /* show command: */ sal_False ) + "; ";
1094 #endif
1095 if( sFieldName.equalsAscii( "DateTime" ) || sFieldName.equalsAscii( "Header" )
1096 || sFieldName.equalsAscii( "Footer" ) || sFieldName.equalsAscii( "PageNumber" ) )
1098 mbIsPlacehlolderShape = sal_True;
1100 else
1102 mbIsURLField = sFieldName.equalsAscii( "URL" );
1104 if( mbIsURLField )
1106 Reference<XPropertySet> xTextFieldPropSet(xTextField, UNO_QUERY);
1107 if( xTextFieldPropSet.is() )
1109 OUString sURL;
1110 if( ( xTextFieldPropSet->getPropertyValue( sFieldName ) ) >>= sURL )
1112 #if OSL_DEBUG_LEVEL > 0
1113 sInfo += "url: ";
1114 sInfo += mrExport.GetRelativeReference( sURL );
1115 #endif
1116 msUrl = mrExport.GetRelativeReference( sURL );
1117 if( !msUrl.isEmpty() )
1119 implRegisterInterface( xPortionTextRange );
1121 Reference< XInterface > xRef( xPortionTextRange, UNO_QUERY );
1122 const OUString& rTextPortionId = implGetValidIDFromInterface( xRef );
1123 if( !rTextPortionId.isEmpty() )
1125 msHyperlinkIdList += rTextPortionId;
1126 msHyperlinkIdList += " ";
1136 #if OSL_DEBUG_LEVEL > 0
1137 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "TextPortion" );
1138 SvXMLElementExport aPortionElem( mrExport, XML_NAMESPACE_NONE, "desc", mbIWS, mbIWS );
1139 mrExport.GetDocHandler()->characters( sInfo );
1140 #endif
1141 return sal_True;
1145 return sal_False;
1148 void SVGTextWriter::startTextShape()
1150 if( mpTextShapeElem )
1152 OSL_FAIL( "SVGTextWriter::startTextShape: text shape already defined." );
1156 mbIsTextShapeStarted = sal_True;
1157 maParentFont = Font();
1158 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "TextShape" );
1159 mpTextShapeElem = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, mbIWS );
1160 startTextParagraph();
1164 void SVGTextWriter::endTextShape()
1166 endTextParagraph();
1167 if( mrTextShape.is() )
1168 mrTextShape.clear();
1169 if( mrParagraphEnumeration.is() )
1170 mrParagraphEnumeration.clear();
1171 if( mrCurrentTextParagraph.is() )
1172 mrCurrentTextParagraph.clear();
1173 if( mpTextShapeElem )
1175 delete mpTextShapeElem;
1176 mpTextShapeElem = NULL;
1178 mbIsTextShapeStarted = sal_False;
1179 // these need to be invoked after the <text> element has been closed
1180 implExportHyperlinkIds();
1181 implWriteBulletChars();
1182 implWriteEmbeddedBitmaps();
1186 void SVGTextWriter::startTextParagraph()
1188 endTextParagraph();
1189 nextParagraph();
1190 if( mbIsNewListItem )
1192 OUString sNumberingType;
1193 switch( meNumberingType )
1195 case( NumberingType::CHAR_SPECIAL ):
1196 sNumberingType = "bullet-style";
1197 break;
1198 case( NumberingType::BITMAP ):
1199 sNumberingType = "image-style";
1200 break;
1201 default:
1202 sNumberingType = "number-style";
1203 break;
1205 mrExport.AddAttribute( XML_NAMESPACE_NONE, aOOOAttrNumberingType, sNumberingType );
1206 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "ListItem" );
1208 else
1210 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "TextParagraph" );
1212 maParentFont = Font();
1213 addFontAttributes( /* isTexTContainer: */ true );
1214 mpTextParagraphElem = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1215 if( !mbIsListLevelStyleImage )
1217 startTextPosition();
1221 void SVGTextWriter::endTextParagraph()
1223 mrCurrentTextPortion.clear();
1224 endTextPosition();
1225 mbIsNewListItem = sal_False;
1226 mbIsListLevelStyleImage = sal_False;
1227 mbPositioningNeeded = sal_False;
1229 if( mpTextParagraphElem )
1231 delete mpTextParagraphElem;
1232 mpTextParagraphElem = NULL;
1237 void SVGTextWriter::startTextPosition( sal_Bool bExportX, sal_Bool bExportY )
1239 endTextPosition();
1240 mnTextWidth = 0;
1241 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "TextPosition" );
1242 if( bExportX )
1243 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::valueOf( maTextPos.X() ) );
1244 if( bExportY )
1245 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::valueOf( maTextPos.Y() ) );
1247 // if text is rotated, set transform matrix at new tspan element
1248 const Font& rFont = mpVDev->GetFont();
1249 if( rFont.GetOrientation() )
1251 Point aRot( maTextPos );
1252 OUString aTransform =
1253 OUString("translate(") + OUString::valueOf( aRot.X() ) +
1254 "," + OUString::valueOf( aRot.Y() ) + ")" +
1255 " rotate(" + OUString::valueOf( rFont.GetOrientation() * -0.1 ) +
1256 ")" + " translate(" + OUString::valueOf( -aRot.X() ) +
1257 "," + OUString::valueOf( -aRot.Y() ) + ")";
1259 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform, aTransform );
1262 mpTextPositionElem = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1265 void SVGTextWriter::endTextPosition()
1267 if( mpTextPositionElem )
1269 delete mpTextPositionElem;
1270 mpTextPositionElem = NULL;
1274 void SVGTextWriter::implExportHyperlinkIds()
1276 if( !msHyperlinkIdList.isEmpty() )
1278 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "HyperlinkIdList" );
1279 SvXMLElementExport aDescElem( mrExport, XML_NAMESPACE_NONE, "desc", sal_True, sal_False );
1280 mrExport.GetDocHandler()->characters( msHyperlinkIdList.trim() );
1281 msHyperlinkIdList = OUString();
1285 void SVGTextWriter::implWriteBulletChars()
1287 if( maBulletListItemMap.empty() )
1288 return;
1290 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "BulletChars" );
1291 SvXMLElementExport aGroupElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
1293 BulletListItemInfoMap::const_iterator it = maBulletListItemMap.begin();
1294 BulletListItemInfoMap::const_iterator end = maBulletListItemMap.end();
1295 OUString sId, sPosition, sScaling, sRefId;
1296 for( ; it != end; ++it )
1298 // <g id="?" > (used by animations)
1300 // As id we use the id of the text portion placeholder wrapped
1301 // by bullet-char(*)
1302 sId = "bullet-char(" + it->first+ ")";
1303 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
1304 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "BulletChar" );
1305 SvXMLElementExport aBulletCharElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
1307 // <g transform="translate(x,y)" >
1309 const BulletListItemInfo& rInfo = it->second;
1311 // Add positioning attribute through a translation
1312 sPosition = OUString("translate(") +
1313 OUString::valueOf( rInfo.aPos.X() ) +
1314 "," + OUString::valueOf( rInfo.aPos.Y() ) + ")";
1315 mrExport.AddAttribute( XML_NAMESPACE_NONE, "transform", sPosition );
1317 mpContext->AddPaintAttr( COL_TRANSPARENT, rInfo.aColor );
1319 SvXMLElementExport aPositioningElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
1321 // <use transform="scale(font-size)" xlink:ref="/" >
1323 // Add size attribute through a scaling
1324 sScaling = "scale(" + OUString::valueOf( rInfo.nFontSize ) +
1325 "," + OUString::valueOf( rInfo.nFontSize )+ ")";
1326 mrExport.AddAttribute( XML_NAMESPACE_NONE, "transform", sScaling );
1328 // Add ref attribute
1329 sRefId = "#bullet-char-template(" +
1330 OUString::valueOf( (sal_Int32)( rInfo.cBulletChar ) ) +
1331 ")";
1332 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, sRefId );
1334 SvXMLElementExport aRefElem( mrExport, XML_NAMESPACE_NONE, "use", sal_True, sal_True );
1336 } // close aPositioningElem
1337 } // close aBulletCharElem
1341 // clear the map
1342 maBulletListItemMap.clear();
1345 template< typename MetaBitmapActionType >
1346 void SVGTextWriter::writeBitmapPlaceholder( const MetaBitmapActionType* pAction )
1348 // text position element
1349 const Point& rPos = pAction->GetPoint();
1350 implMap( rPos, maTextPos );
1351 startTextPosition();
1352 mbPositioningNeeded = sal_True;
1353 if( mbIsNewListItem )
1355 mbIsNewListItem = sal_False;
1356 mbIsListLevelStyleImage = sal_False;
1359 // bitmap placeholder element
1360 sal_uLong nId = SVGActionWriter::GetChecksum( pAction );
1361 OUString sId = "bitmap-placeholder(" + msShapeId + "." +
1362 OUString::valueOf( (sal_Int64)nId ) + ")";
1365 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
1366 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "BitmapPlaceholder" );
1367 SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1369 endTextPosition();
1372 void SVGTextWriter::implWriteEmbeddedBitmaps()
1374 if( mpTextEmbeddedBitmapMtf && mpTextEmbeddedBitmapMtf->GetActionSize() )
1376 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "EmbeddedBitmaps" );
1377 SvXMLElementExport aEmbBitmapGroupElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
1379 const GDIMetaFile& rMtf = *mpTextEmbeddedBitmapMtf;
1381 OUString sId, sRefId;
1382 sal_uLong nId, nChecksum = 0;
1383 Point aPt;
1384 Size aSz;
1385 sal_uLong nCount = rMtf.GetActionSize();
1386 for( sal_uLong nCurAction = 0; nCurAction < nCount; nCurAction++ )
1389 const MetaAction* pAction = rMtf.GetAction( nCurAction );
1390 const sal_uInt16 nType = pAction->GetType();
1392 switch( nType )
1394 case( META_BMPSCALE_ACTION ):
1396 const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction;
1397 nChecksum = pA->GetBitmap().GetChecksum();
1398 aPt = pA->GetPoint();
1399 aSz = pA->GetSize();
1401 break;
1402 case( META_BMPEXSCALE_ACTION ):
1404 const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction;
1405 nChecksum = pA->GetBitmapEx().GetChecksum();
1406 aPt = pA->GetPoint();
1407 aSz = pA->GetSize();
1409 break;
1412 // <g id="?" > (used by animations)
1414 // embedded bitmap id
1415 nId = SVGActionWriter::GetChecksum( pAction );
1416 sId = "embedded-bitmap(";
1417 sId += msShapeId;
1418 sId += ".";
1419 sId += OUString::valueOf( (sal_Int64)nId );
1420 sId += ")";
1421 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
1422 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "EmbeddedBitmap" );
1424 SvXMLElementExport aEmbBitmapElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
1426 // <use x="?" y="?" xlink:ref="?" >
1428 // referenced bitmap template
1429 sRefId = "#bitmap(";
1430 sRefId += OUString::valueOf( (sal_Int64)nChecksum );
1431 sRefId += ")";
1433 Point aPoint;
1434 Size aSize;
1435 implMap( aPt, aPoint );
1436 implMap( aSz, aSize );
1438 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::valueOf( aPoint.X() ) );
1439 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::valueOf( aPoint.Y() ) );
1440 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, sRefId );
1442 SvXMLElementExport aRefElem( mrExport, XML_NAMESPACE_NONE, "use", sal_True, sal_True );
1444 } // close aEmbBitmapElem
1449 void SVGTextWriter::writeTextPortion( const Point& rPos,
1450 const String& rText,
1451 sal_Bool bApplyMapping )
1453 if( rText.Len() == 0 )
1454 return;
1456 mbLineBreak = sal_False;
1458 if( !mbIsNewListItem || mbIsListLevelStyleImage )
1460 bool bNotSync = true;
1461 OUString sContent;
1462 sal_Int32 nStartPos;
1463 while( bNotSync )
1465 if( mnLeftTextPortionLength <= 0 || !mrCurrentTextPortion.is() )
1467 if( !nextTextPortion() )
1468 break;
1469 else
1471 sContent = mrCurrentTextPortion->getString();
1472 if( mbIsURLField && sContent.isEmpty() )
1474 Reference < XPropertySet > xPropSet( mrCurrentTextPortion, UNO_QUERY );
1475 Reference < XTextField > xTextField( xPropSet->getPropertyValue( "TextField" ), UNO_QUERY );
1476 sContent = xTextField->getPresentation( /* show command: */ sal_False );
1477 if( sContent.isEmpty() )
1478 OSL_FAIL( "SVGTextWriter::writeTextPortion: content of URL TextField is empty." );
1480 mnLeftTextPortionLength = sContent.getLength();
1483 else
1485 sContent = mrCurrentTextPortion->getString();
1488 nStartPos = sContent.getLength() - mnLeftTextPortionLength;
1489 if( nStartPos < 0 ) nStartPos = 0;
1490 mnLeftTextPortionLength -= rText.Len();
1492 if( sContent.isEmpty() )
1493 continue;
1494 if( sContent.equalsAscii( "\n" ) )
1495 mbLineBreak = sal_True;
1496 if( sContent.match( rText, nStartPos ) )
1497 bNotSync = false;
1501 if( !mpVDev )
1502 OSL_FAIL( "SVGTextWriter::writeTextPortion: invalid virtual device." );
1504 const FontMetric aMetric( mpVDev->GetFontMetric() );
1506 bool bTextSpecial = aMetric.IsShadow() || aMetric.IsOutline() || (aMetric.GetRelief() != RELIEF_NONE);
1508 if( true || !bTextSpecial )
1510 implWriteTextPortion( rPos, rText, mpVDev->GetTextColor(), bApplyMapping );
1512 else
1514 // to be implemented
1519 void SVGTextWriter::implWriteTextPortion( const Point& rPos,
1520 const String& rText,
1521 Color aTextColor,
1522 sal_Bool bApplyMapping )
1524 if( !mpContext )
1525 OSL_FAIL( "SVGTextWriter::implWriteTextPortion: invalid context object." );
1527 Point aPos;
1528 Point aBaseLinePos( rPos );
1529 const FontMetric aMetric( mpVDev->GetFontMetric() );
1530 const Font& rFont = mpVDev->GetFont();
1532 if( rFont.GetAlign() == ALIGN_TOP )
1533 aBaseLinePos.Y() += aMetric.GetAscent();
1534 else if( rFont.GetAlign() == ALIGN_BOTTOM )
1535 aBaseLinePos.Y() -= aMetric.GetDescent();
1537 if( bApplyMapping )
1538 implMap( rPos, aPos );
1539 else
1540 aPos = rPos;
1542 if( mbPositioningNeeded )
1544 mbPositioningNeeded = sal_False;
1545 maTextPos.setX( aPos.X() );
1546 maTextPos.setY( aPos.Y() );
1547 startTextPosition();
1549 else if( maTextPos.Y() != aPos.Y() )
1551 // In case the text position moved backward we could have a line break
1552 // so we end the current line and start a new one.
1553 if( mbLineBreak || ( ( maTextPos.X() + mnTextWidth ) > aPos.X() ) )
1555 mbLineBreak = sal_False;
1556 maTextPos.setX( aPos.X() );
1557 maTextPos.setY( aPos.Y() );
1558 startTextPosition();
1560 else // superscript, subscript, list item numbering
1562 maTextPos.setY( aPos.Y() );
1563 startTextPosition( sal_False /* do not export x attribute */ );
1566 // we are dealing with a bullet, so set up this for the next text portion
1567 if( mbIsNewListItem )
1569 mbIsNewListItem = sal_False;
1570 mbPositioningNeeded = sal_True;
1572 if( meNumberingType == NumberingType::CHAR_SPECIAL )
1574 // Create an id for the current text portion
1575 implRegisterInterface( mrCurrentTextParagraph );
1577 // Add the needed info to the BulletListItemMap
1578 Reference< XInterface > xRef( mrCurrentTextParagraph, UNO_QUERY );
1579 OUString sId = implGetValidIDFromInterface( xRef );
1580 if( !sId.isEmpty() )
1582 sId += ".bp";
1583 BulletListItemInfo& aBulletListItemInfo = maBulletListItemMap[ sId ];
1584 aBulletListItemInfo.nFontSize = rFont.GetHeight();
1585 aBulletListItemInfo.aColor = aTextColor;
1586 aBulletListItemInfo.aPos = maTextPos;
1587 aBulletListItemInfo.cBulletChar = mcBulletChar;
1589 // Make this text portion a bullet placeholder
1590 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
1591 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "BulletPlaceholder" );
1592 SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1593 return;
1598 Reference< XInterface > xRef( mrCurrentTextPortion, UNO_QUERY );
1599 const OUString& rTextPortionId = implGetValidIDFromInterface( xRef );
1600 if( !rTextPortionId.isEmpty() )
1602 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", rTextPortionId );
1605 if( mbIsPlacehlolderShape )
1607 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "PlaceholderText" );
1608 mbIsPlacehlolderShape = sal_False;
1611 addFontAttributes( /* isTexTContainer: */ false );
1612 mpContext->AddPaintAttr( COL_TRANSPARENT, aTextColor );
1614 OUString sTextContent = rText;
1616 // <a> tag for link should be the innermost tag, inside <tspan>
1617 if( !mbIsPlacehlolderShape && mbIsURLField && !msUrl.isEmpty() )
1619 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "UrlField" );
1620 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, msUrl );
1622 SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1623 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, msUrl );
1625 SvXMLElementExport aSVGAElem( mrExport, XML_NAMESPACE_NONE, aXMLElemA, mbIWS, mbIWS );
1626 mrExport.GetDocHandler()->characters( sTextContent );
1629 else
1631 SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1632 mrExport.GetDocHandler()->characters( sTextContent );
1635 mnTextWidth += mpVDev->GetTextWidth( sTextContent );
1638 SVGActionWriter::SVGActionWriter( SVGExport& rExport, SVGFontExport& rFontExport ) :
1639 mnCurGradientId( 1 ),
1640 mnCurMaskId( 1 ),
1641 mnCurPatternId( 1 ),
1642 mrExport( rExport ),
1643 mrFontExport( rFontExport ),
1644 mpContext( NULL ),
1645 maTextWriter( rExport ),
1646 mnInnerMtfCount( 0 ),
1647 mbClipAttrChanged( sal_False )
1649 mpVDev = new VirtualDevice;
1650 mpVDev->EnableOutput( sal_False );
1651 maTargetMapMode = MAP_100TH_MM;
1652 maTextWriter.setVirtualDevice( mpVDev, maTargetMapMode );
1655 SVGActionWriter::~SVGActionWriter()
1657 DBG_ASSERT( !mpContext, "Not all contexts are closed" );
1658 delete mpVDev;
1661 long SVGActionWriter::ImplMap( sal_Int32 nVal ) const
1663 Size aSz( nVal, nVal );
1665 return( ImplMap( aSz, aSz ).Width() );
1668 Point& SVGActionWriter::ImplMap( const Point& rPt, Point& rDstPt ) const
1670 return( rDstPt = mpVDev->LogicToLogic( rPt, mpVDev->GetMapMode(), maTargetMapMode ) );
1673 Size& SVGActionWriter::ImplMap( const Size& rSz, Size& rDstSz ) const
1675 return( rDstSz = mpVDev->LogicToLogic( rSz, mpVDev->GetMapMode(), maTargetMapMode ) );
1678 Rectangle& SVGActionWriter::ImplMap( const Rectangle& rRect, Rectangle& rDstRect ) const
1680 Point aTL( rRect.TopLeft() );
1681 Size aSz( rRect.GetSize() );
1683 return( rDstRect = Rectangle( ImplMap( aTL, aTL ), ImplMap( aSz, aSz ) ) );
1686 Polygon& SVGActionWriter::ImplMap( const Polygon& rPoly, Polygon& rDstPoly ) const
1688 rDstPoly = Polygon( rPoly.GetSize() );
1690 for( sal_uInt16 i = 0, nSize = rPoly.GetSize(); i < nSize; ++i )
1692 ImplMap( rPoly[ i ], rDstPoly[ i ] );
1693 rDstPoly.SetFlags( i, rPoly.GetFlags( i ) );
1696 return( rDstPoly );
1699 PolyPolygon& SVGActionWriter::ImplMap( const PolyPolygon& rPolyPoly, PolyPolygon& rDstPolyPoly ) const
1701 Polygon aPoly;
1703 rDstPolyPoly = PolyPolygon();
1705 for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; ++i )
1707 rDstPolyPoly.Insert( ImplMap( rPolyPoly[ i ], aPoly ) );
1710 return( rDstPolyPoly );
1713 OUString SVGActionWriter::GetPathString( const PolyPolygon& rPolyPoly, sal_Bool bLine )
1715 OUString aPathData;
1716 const OUString aBlank( " " );
1717 const OUString aComma( "," );
1718 Point aPolyPoint;
1720 for( long i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ )
1722 const Polygon& rPoly = rPolyPoly[ (sal_uInt16) i ];
1723 sal_uInt16 n = 1, nSize = rPoly.GetSize();
1725 if( nSize > 1 )
1727 aPathData += "M ";
1728 aPathData += OUString::valueOf( ( aPolyPoint = rPoly[ 0 ] ).X() );
1729 aPathData += aComma;
1730 aPathData += OUString::valueOf( aPolyPoint.Y() );
1732 sal_Char nCurrentMode = 0;
1733 const bool bClose(!bLine || rPoly[0] == rPoly[nSize - 1]);
1734 while( n < nSize )
1736 aPathData += aBlank;
1738 if ( ( rPoly.GetFlags( n ) == POLY_CONTROL ) && ( ( n + 2 ) < nSize ) )
1740 if ( nCurrentMode != 'C' )
1742 nCurrentMode = 'C';
1743 aPathData += "C ";
1745 for ( int j = 0; j < 3; j++ )
1747 if ( j )
1748 aPathData += aBlank;
1749 aPathData += OUString::valueOf( ( aPolyPoint = rPoly[ n++ ] ).X() );
1750 aPathData += aComma;
1751 aPathData += OUString::valueOf( aPolyPoint.Y() );
1754 else
1756 if ( nCurrentMode != 'L' )
1758 nCurrentMode = 'L';
1759 aPathData += "L ";
1761 aPathData += OUString::valueOf( ( aPolyPoint = rPoly[ n++ ] ).X() );
1762 aPathData += aComma;
1763 aPathData += OUString::valueOf( aPolyPoint.Y() );
1767 if(bClose)
1768 aPathData += " Z";
1770 if( i < ( nCount - 1 ) )
1771 aPathData += aBlank;
1775 return aPathData;
1778 sal_uLong SVGActionWriter::GetChecksum( const MetaAction* pAction )
1780 GDIMetaFile aMtf;
1781 MetaAction* pA = (MetaAction*)pAction;
1782 pA->Duplicate();
1783 aMtf.AddAction( pA );
1784 return aMtf.GetChecksum();
1787 void SVGActionWriter::ImplWriteLine( const Point& rPt1, const Point& rPt2,
1788 const Color* pLineColor, sal_Bool bApplyMapping )
1790 Point aPt1, aPt2;
1792 if( bApplyMapping )
1794 ImplMap( rPt1, aPt1 );
1795 ImplMap( rPt2, aPt2 );
1797 else
1799 aPt1 = rPt1;
1800 aPt2 = rPt2;
1803 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, OUString::valueOf( aPt1.X() ) );
1804 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, OUString::valueOf( aPt1.Y() ) );
1805 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, OUString::valueOf( aPt2.X() ) );
1806 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, OUString::valueOf( aPt2.Y() ) );
1808 if( pLineColor )
1810 // !!! mrExport.AddAttribute( XML_NAMESPACE_NONE, ... )
1811 OSL_FAIL( "SVGActionWriter::ImplWriteLine: Line color not implemented" );
1815 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemLine, sal_True, sal_True );
1819 void SVGActionWriter::ImplWriteRect( const Rectangle& rRect, long nRadX, long nRadY,
1820 sal_Bool bApplyMapping )
1822 Rectangle aRect;
1824 if( bApplyMapping )
1825 ImplMap( rRect, aRect );
1826 else
1827 aRect = rRect;
1829 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::valueOf( aRect.Left() ) );
1830 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::valueOf( aRect.Top() ) );
1831 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrWidth, OUString::valueOf( aRect.GetWidth() ) );
1832 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrHeight, OUString::valueOf( aRect.GetHeight() ) );
1834 if( nRadX )
1835 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRX, OUString::valueOf( bApplyMapping ? ImplMap( nRadX ) : nRadX ) );
1837 if( nRadY )
1838 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRY, OUString::valueOf( bApplyMapping ? ImplMap( nRadY ) : nRadY ) );
1841 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemRect, sal_True, sal_True );
1845 void SVGActionWriter::ImplWriteEllipse( const Point& rCenter, long nRadX, long nRadY,
1846 sal_Bool bApplyMapping )
1848 Point aCenter;
1850 if( bApplyMapping )
1851 ImplMap( rCenter, aCenter );
1852 else
1853 aCenter = rCenter;
1855 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCX, OUString::valueOf( aCenter.X() ) );
1856 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCY, OUString::valueOf( aCenter.Y() ) );
1857 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRX, OUString::valueOf( bApplyMapping ? ImplMap( nRadX ) : nRadX ) );
1858 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRY, OUString::valueOf( bApplyMapping ? ImplMap( nRadY ) : nRadY ) );
1861 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemEllipse, sal_True, sal_True );
1865 void SVGActionWriter::ImplAddLineAttr( const LineInfo &rAttrs,
1866 sal_Bool bApplyMapping )
1868 if ( !rAttrs.IsDefault() )
1870 sal_Int32 nStrokeWidth = bApplyMapping ? ImplMap( rAttrs.GetWidth() ) : rAttrs.GetWidth();
1871 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeWidth,
1872 OUString::valueOf( nStrokeWidth ) );
1876 void SVGActionWriter::ImplWritePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bLineOnly,
1877 sal_Bool bApplyMapping )
1879 PolyPolygon aPolyPoly;
1881 if( bApplyMapping )
1882 ImplMap( rPolyPoly, aPolyPoly );
1883 else
1884 aPolyPoly = rPolyPoly;
1886 // add path data attribute
1887 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrD, GetPathString( aPolyPoly, bLineOnly ) );
1890 // write polyline/polygon element
1891 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemPath, sal_True, sal_True );
1895 void SVGActionWriter::ImplWriteShape( const SVGShapeDescriptor& rShape, sal_Bool bApplyMapping )
1897 PolyPolygon aPolyPoly;
1899 if( bApplyMapping )
1900 ImplMap( rShape.maShapePolyPoly, aPolyPoly );
1901 else
1902 aPolyPoly = rShape.maShapePolyPoly;
1904 const sal_Bool bLineOnly = ( rShape.maShapeFillColor == Color( COL_TRANSPARENT ) ) && ( !rShape.mapShapeGradient.get() );
1905 Rectangle aBoundRect( aPolyPoly.GetBoundRect() );
1907 mpContext->AddPaintAttr( rShape.maShapeLineColor, rShape.maShapeFillColor, &aBoundRect, rShape.mapShapeGradient.get() );
1909 if( !rShape.maId.isEmpty() )
1910 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, rShape.maId );
1912 if( rShape.mnStrokeWidth )
1914 sal_Int32 nStrokeWidth = ( bApplyMapping ? ImplMap( rShape.mnStrokeWidth ) : rShape.mnStrokeWidth );
1915 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeWidth, OUString::valueOf( nStrokeWidth ) );
1918 // support for LineJoin
1919 switch(rShape.maLineJoin)
1921 default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE
1922 case basegfx::B2DLINEJOIN_MITER:
1924 // miter is Svg default, so no need to write until the exporter might write styles.
1925 // If this happens, activate here
1926 // mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, OUString::createFromAscii("miter"));
1927 break;
1929 case basegfx::B2DLINEJOIN_BEVEL:
1931 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, OUString::createFromAscii("bevel"));
1932 break;
1934 case basegfx::B2DLINEJOIN_ROUND:
1936 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, OUString::createFromAscii("round"));
1937 break;
1941 // support for LineCap
1942 switch(rShape.maLineCap)
1944 default: /* com::sun::star::drawing::LineCap_BUTT */
1946 // butt is Svg default, so no need to write until the exporter might write styles.
1947 // If this happens, activate here
1948 // mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, OUString::createFromAscii("butt"));
1949 break;
1951 case com::sun::star::drawing::LineCap_ROUND:
1953 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, OUString::createFromAscii("round"));
1954 break;
1956 case com::sun::star::drawing::LineCap_SQUARE:
1958 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, OUString::createFromAscii("square"));
1959 break;
1963 if( rShape.maDashArray.size() )
1965 const OUString aComma( "," );
1966 OUString aDashArrayStr;
1968 for( unsigned int k = 0; k < rShape.maDashArray.size(); ++k )
1970 const sal_Int32 nDash = ( bApplyMapping ?
1971 ImplMap( FRound( rShape.maDashArray[ k ] ) ) :
1972 FRound( rShape.maDashArray[ k ] ) );
1974 if( k )
1975 aDashArrayStr += aComma;
1977 aDashArrayStr += OUString::valueOf( nDash );
1980 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeDashArray, aDashArrayStr );
1983 ImplWritePolyPolygon( aPolyPoly, bLineOnly, sal_False );
1986 void SVGActionWriter::ImplWritePattern( const PolyPolygon& rPolyPoly,
1987 const Hatch* pHatch,
1988 const Gradient* pGradient,
1989 sal_uInt32 nWriteFlags )
1991 if( rPolyPoly.Count() )
1993 SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
1995 OUString aPatternId = "pattern" + OUString::valueOf( mnCurPatternId++ );
1998 SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, sal_True, sal_True );
2000 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aPatternId );
2002 Rectangle aRect;
2003 ImplMap( rPolyPoly.GetBoundRect(), aRect );
2005 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::valueOf( aRect.Left() ) );
2006 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::valueOf( aRect.Top() ) );
2007 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrWidth, OUString::valueOf( aRect.GetWidth() ) );
2008 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrHeight, OUString::valueOf( aRect.GetHeight() ) );
2010 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrPatternUnits, OUString( "userSpaceOnUse") );
2013 SvXMLElementExport aElemPattern( mrExport, XML_NAMESPACE_NONE, aXMLElemPattern, sal_True, sal_True );
2015 // The origin of a pattern is positioned at (aRect.Left(), aRect.Top()).
2016 // So we need to adjust the pattern coordinate.
2017 OUString aTransform = OUString("translate") +
2018 "(" + OUString::valueOf( -aRect.Left() ) +
2019 "," + OUString::valueOf( -aRect.Top() ) +
2020 ")";
2021 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform, aTransform );
2024 SvXMLElementExport aElemG2( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
2026 GDIMetaFile aTmpMtf;
2027 if( pHatch )
2028 mpVDev->AddHatchActions( rPolyPoly, *pHatch, aTmpMtf );
2029 else if ( pGradient )
2030 mpVDev->AddGradientActions( rPolyPoly.GetBoundRect(), *pGradient, aTmpMtf );
2031 ImplWriteActions( aTmpMtf, nWriteFlags, NULL );
2036 OUString aPatternStyle = "fill:url(#" + aPatternId + ")";
2038 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aPatternStyle );
2039 ImplWritePolyPolygon( rPolyPoly, sal_False );
2043 void SVGActionWriter::ImplWriteGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient,
2044 sal_uInt32 nWriteFlags, sal_Bool bApplyMapping )
2046 PolyPolygon aPolyPoly;
2048 if( bApplyMapping )
2049 ImplMap( rPolyPoly, aPolyPoly );
2050 else
2051 aPolyPoly = rPolyPoly;
2053 if ( rGradient.GetStyle() == GradientStyle_LINEAR ||
2054 rGradient.GetStyle() == GradientStyle_AXIAL )
2056 ImplWriteGradientLinear( aPolyPoly, rGradient );
2058 else
2060 ImplWritePattern( aPolyPoly, NULL, &rGradient, nWriteFlags );
2064 void SVGActionWriter::ImplWriteGradientLinear( const PolyPolygon& rPolyPoly,
2065 const Gradient& rGradient )
2067 if( rPolyPoly.Count() )
2069 SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
2071 OUString aGradientId = "gradient" + OUString::valueOf( mnCurGradientId++ );
2074 SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, sal_True, sal_True );
2076 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aGradientId );
2078 Rectangle aTmpRect, aRect;
2079 Point aTmpCenter, aCenter;
2081 rGradient.GetBoundRect( rPolyPoly.GetBoundRect(), aTmpRect, aTmpCenter );
2082 ImplMap( aTmpRect, aRect );
2083 ImplMap( aTmpCenter, aCenter );
2084 const sal_uInt16 nAngle = rGradient.GetAngle() % 3600;
2086 Polygon aPoly( 2 );
2087 // Setting x value of a gradient vector to rotation center to
2088 // place a gradient vector in a target polygon.
2089 // This would help editing it in SVG editors like inkscape.
2090 aPoly[ 0 ].X() = aPoly[ 1 ].X() = aCenter.X();
2091 aPoly[ 0 ].Y() = aRect.Top();
2092 aPoly[ 1 ].Y() = aRect.Bottom();
2093 aPoly.Rotate( aCenter, nAngle );
2095 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, OUString::valueOf( aPoly[ 0 ].X() ) );
2096 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, OUString::valueOf( aPoly[ 0 ].Y() ) );
2097 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, OUString::valueOf( aPoly[ 1 ].X() ) );
2098 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, OUString::valueOf( aPoly[ 1 ].Y() ) );
2100 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits,
2101 OUString( "userSpaceOnUse" ) );
2105 SvXMLElementExport aElemLinearGradient( mrExport, XML_NAMESPACE_NONE, aXMLElemLinearGradient, sal_True, sal_True );
2107 const Color aStartColor = ImplGetColorWithIntensity( rGradient.GetStartColor(), rGradient.GetStartIntensity() );
2108 const Color aEndColor = ImplGetColorWithIntensity( rGradient.GetEndColor(), rGradient.GetEndIntensity() );
2109 double fBorderOffset = rGradient.GetBorder() / 100.0;
2110 const sal_uInt16 nSteps = rGradient.GetSteps();
2111 if( rGradient.GetStyle() == GradientStyle_LINEAR )
2113 // Emulate non-smooth gradient
2114 if( 0 < nSteps && nSteps < 100 )
2116 double fOffsetStep = ( 1.0 - fBorderOffset ) / (double)nSteps;
2117 for( sal_uInt16 i = 0; i < nSteps; i++ ) {
2118 Color aColor = ImplGetGradientColor( aStartColor, aEndColor, i / (double) nSteps );
2119 ImplWriteGradientStop( aColor, fBorderOffset + ( i + 1 ) * fOffsetStep );
2120 aColor = ImplGetGradientColor( aStartColor, aEndColor, ( i + 1 ) / (double) nSteps );
2121 ImplWriteGradientStop( aColor, fBorderOffset + ( i + 1 ) * fOffsetStep );
2124 else
2126 ImplWriteGradientStop( aStartColor, fBorderOffset );
2127 ImplWriteGradientStop( aEndColor, 1.0 );
2130 else
2132 fBorderOffset /= 2;
2133 // Emulate non-smooth gradient
2134 if( 0 < nSteps && nSteps < 100 )
2136 double fOffsetStep = ( 0.5 - fBorderOffset ) / (double)nSteps;
2137 // Upper half
2138 for( sal_uInt16 i = 0; i < nSteps; i++ )
2140 Color aColor = ImplGetGradientColor( aEndColor, aStartColor, i / (double) nSteps );
2141 ImplWriteGradientStop( aColor, fBorderOffset + i * fOffsetStep );
2142 aColor = ImplGetGradientColor( aEndColor, aStartColor, (i + 1 ) / (double) nSteps );
2143 ImplWriteGradientStop( aColor, fBorderOffset + i * fOffsetStep );
2145 // Lower half
2146 for( sal_uInt16 i = 0; i < nSteps; i++ )
2148 Color aColor = ImplGetGradientColor( aStartColor, aEndColor, i / (double) nSteps );
2149 ImplWriteGradientStop( aColor, 0.5 + (i + 1) * fOffsetStep );
2150 aColor = ImplGetGradientColor( aStartColor, aEndColor, (i + 1 ) / (double) nSteps );
2151 ImplWriteGradientStop( aColor, 0.5 + (i + 1) * fOffsetStep );
2154 else
2156 ImplWriteGradientStop( aEndColor, fBorderOffset );
2157 ImplWriteGradientStop( aStartColor, 0.5 );
2158 ImplWriteGradientStop( aEndColor, 1.0 - fBorderOffset );
2164 OUString aGradientStyle = "fill:url(#" + aGradientId + ")";
2166 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aGradientStyle );
2167 ImplWritePolyPolygon( rPolyPoly, sal_False );
2171 void SVGActionWriter::ImplWriteGradientStop( const Color& rColor, double fOffset )
2173 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, OUString::valueOf( fOffset ) );
2175 OUString aStyle, aColor;
2176 aStyle += "stop-color:";
2177 SVGAttributeWriter::ImplGetColorStr ( rColor, aColor );
2178 aStyle += aColor;
2180 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aStyle );
2182 SvXMLElementExport aElemStartStop( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True );
2186 Color SVGActionWriter::ImplGetColorWithIntensity( const Color& rColor,
2187 sal_uInt16 nIntensity )
2189 sal_uInt8 nNewRed = (sal_uInt8)( (long)rColor.GetRed() * nIntensity / 100L );
2190 sal_uInt8 nNewGreen = (sal_uInt8)( (long)rColor.GetGreen() * nIntensity / 100L );
2191 sal_uInt8 nNewBlue = (sal_uInt8)( (long)rColor.GetBlue() * nIntensity / 100L );
2192 return Color( nNewRed, nNewGreen, nNewBlue);
2195 Color SVGActionWriter::ImplGetGradientColor( const Color& rStartColor,
2196 const Color& rEndColor,
2197 double fOffset )
2199 long nRedStep = rEndColor.GetRed() - rStartColor.GetRed();
2200 long nNewRed = rStartColor.GetRed() + (long)( nRedStep * fOffset );
2201 nNewRed = ( nNewRed < 0 ) ? 0 : ( nNewRed > 0xFF) ? 0xFF : nNewRed;
2203 long nGreenStep = rEndColor.GetGreen() - rStartColor.GetGreen();
2204 long nNewGreen = rStartColor.GetGreen() + (long)( nGreenStep * fOffset );
2205 nNewGreen = ( nNewGreen < 0 ) ? 0 : ( nNewGreen > 0xFF) ? 0xFF : nNewGreen;
2207 long nBlueStep = rEndColor.GetBlue() - rStartColor.GetBlue();
2208 long nNewBlue = rStartColor.GetBlue() + (long)( nBlueStep * fOffset );
2209 nNewBlue = ( nNewBlue < 0 ) ? 0 : ( nNewBlue > 0xFF) ? 0xFF : nNewBlue;
2211 return Color( (sal_uInt8)nNewRed, (sal_uInt8)nNewGreen, (sal_uInt8)nNewBlue );
2214 void SVGActionWriter::ImplWriteMask( GDIMetaFile& rMtf,
2215 const Point& rDestPt,
2216 const Size& rDestSize,
2217 const Gradient& rGradient,
2218 sal_uInt32 nWriteFlags )
2220 Point aSrcPt( rMtf.GetPrefMapMode().GetOrigin() );
2221 const Size aSrcSize( rMtf.GetPrefSize() );
2222 const double fScaleX = aSrcSize.Width() ? (double) rDestSize.Width() / aSrcSize.Width() : 1.0;
2223 const double fScaleY = aSrcSize.Height() ? (double) rDestSize.Height() / aSrcSize.Height() : 1.0;
2224 long nMoveX, nMoveY;
2226 if( fScaleX != 1.0 || fScaleY != 1.0 )
2228 rMtf.Scale( fScaleX, fScaleY );
2229 aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
2232 nMoveX = rDestPt.X() - aSrcPt.X(), nMoveY = rDestPt.Y() - aSrcPt.Y();
2234 if( nMoveX || nMoveY )
2235 rMtf.Move( nMoveX, nMoveY );
2237 OUString aMaskId = "mask" + OUString::valueOf( mnCurMaskId++ );
2240 SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, sal_True, sal_True );
2242 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aMaskId );
2244 SvXMLElementExport aElemMask( mrExport, XML_NAMESPACE_NONE, aXMLElemMask, sal_True, sal_True );
2246 const PolyPolygon aPolyPolygon( PolyPolygon( Rectangle( rDestPt, rDestSize ) ) );
2247 Gradient aGradient( rGradient );
2249 // swap gradient stops to adopt SVG mask
2250 Color aTmpColor( aGradient.GetStartColor() );
2251 sal_uInt16 nTmpIntensity( aGradient.GetStartIntensity() );
2252 aGradient.SetStartColor( aGradient.GetEndColor() );
2253 aGradient.SetStartIntensity( aGradient.GetEndIntensity() ) ;
2254 aGradient.SetEndColor( aTmpColor );
2255 aGradient.SetEndIntensity( nTmpIntensity );
2257 ImplWriteGradientEx( aPolyPolygon, aGradient, nWriteFlags );
2261 OUString aMaskStyle = "mask:url(#" + aMaskId + ")";
2262 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aMaskStyle );
2265 SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True );
2267 mpVDev->Push();
2268 ImplWriteActions( rMtf, nWriteFlags, NULL );
2269 mpVDev->Pop();
2273 void SVGActionWriter::ImplWriteText( const Point& rPos, const String& rText,
2274 const sal_Int32* pDXArray, long nWidth,
2275 sal_Bool bApplyMapping )
2277 const FontMetric aMetric( mpVDev->GetFontMetric() );
2279 bool bTextSpecial = aMetric.IsShadow() || aMetric.IsOutline() || (aMetric.GetRelief() != RELIEF_NONE);
2281 if( !bTextSpecial )
2283 ImplWriteText( rPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2285 else
2287 if( aMetric.GetRelief() != RELIEF_NONE )
2289 Color aReliefColor( COL_LIGHTGRAY );
2290 Color aTextColor( mpVDev->GetTextColor() );
2292 if ( aTextColor.GetColor() == COL_BLACK )
2293 aTextColor = Color( COL_WHITE );
2295 if ( aTextColor.GetColor() == COL_WHITE )
2296 aReliefColor = Color( COL_BLACK );
2299 Point aPos( rPos );
2300 Point aOffset( 6, 6 );
2302 if ( aMetric.GetRelief() == RELIEF_ENGRAVED )
2304 aPos -= aOffset;
2306 else
2308 aPos += aOffset;
2311 ImplWriteText( aPos, rText, pDXArray, nWidth, aReliefColor, bApplyMapping );
2312 ImplWriteText( rPos, rText, pDXArray, nWidth, aTextColor, bApplyMapping );
2314 else
2316 if( aMetric.IsShadow() )
2318 long nOff = 1 + ((aMetric.GetLineHeight()-24)/24);
2319 if ( aMetric.IsOutline() )
2320 nOff += 6;
2322 Color aTextColor( mpVDev->GetTextColor() );
2323 Color aShadowColor = Color( COL_BLACK );
2325 if ( (aTextColor.GetColor() == COL_BLACK) || (aTextColor.GetLuminance() < 8) )
2326 aShadowColor = Color( COL_LIGHTGRAY );
2328 Point aPos( rPos );
2329 aPos += Point( nOff, nOff );
2330 ImplWriteText( aPos, rText, pDXArray, nWidth, aShadowColor, bApplyMapping );
2332 if( !aMetric.IsOutline() )
2334 ImplWriteText( rPos, rText, pDXArray, nWidth, aTextColor, bApplyMapping );
2338 if( aMetric.IsOutline() )
2340 Point aPos = rPos + Point( -6, -6 );
2341 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2342 aPos = rPos + Point( +6, +6);
2343 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2344 aPos = rPos + Point( -6, +0);
2345 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2346 aPos = rPos + Point( -6, +6);
2347 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2348 aPos = rPos + Point( +0, +6);
2349 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2350 aPos = rPos + Point( +0, -6);
2351 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2352 aPos = rPos + Point( +6, -1);
2353 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2354 aPos = rPos + Point( +6, +0);
2355 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor(), bApplyMapping );
2357 ImplWriteText( rPos, rText, pDXArray, nWidth, Color( COL_WHITE ), bApplyMapping );
2363 void SVGActionWriter::ImplWriteText( const Point& rPos, const String& rText,
2364 const sal_Int32* pDXArray, long nWidth,
2365 Color aTextColor, sal_Bool bApplyMapping )
2367 sal_Int32 nLen = rText.Len();
2368 Size aNormSize;
2369 Point aPos;
2370 Point aBaseLinePos( rPos );
2371 const FontMetric aMetric( mpVDev->GetFontMetric() );
2372 const Font& rFont = mpVDev->GetFont();
2374 if( rFont.GetAlign() == ALIGN_TOP )
2375 aBaseLinePos.Y() += aMetric.GetAscent();
2376 else if( rFont.GetAlign() == ALIGN_BOTTOM )
2377 aBaseLinePos.Y() -= aMetric.GetDescent();
2379 if( bApplyMapping )
2380 ImplMap( rPos, aPos );
2381 else
2382 aPos = rPos;
2384 boost::shared_array<sal_Int32> xTmpArray(new sal_Int32[nLen]);
2385 // get text sizes
2386 if( pDXArray )
2388 aNormSize = Size( mpVDev->GetTextWidth( rText ), 0 );
2389 memcpy(xTmpArray.get(), pDXArray, nLen * sizeof(sal_Int32));
2391 else
2393 aNormSize = Size( mpVDev->GetTextArray( rText, xTmpArray.get() ), 0 );
2395 sal_Int32* pDX = xTmpArray.get();
2397 // if text is rotated, set transform matrix at new g element
2398 if( rFont.GetOrientation() )
2400 Point aRot( aPos );
2401 OUString aTransform =
2402 OUString("translate") +
2403 "(" + OUString::valueOf( aRot.X() ) +
2404 "," + OUString::valueOf( aRot.Y() ) + ")" +
2405 " rotate" +
2406 "(" + OUString::valueOf( rFont.GetOrientation() * -0.1 ) + ")" +
2407 " translate" +
2408 "(" + OUString::valueOf( -aRot.X() ) +
2409 "," + OUString::valueOf( -aRot.Y() ) + ")";
2411 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform, aTransform );
2415 mpContext->AddPaintAttr( COL_TRANSPARENT, aTextColor );
2417 // for each line of text there should be at least one group element
2418 SvXMLElementExport aSVGGElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_False );
2420 sal_Bool bIsPlaceholderField = sal_False;
2422 if( mbIsPlacehlolderShape )
2424 OUString sTextContent = rText;
2425 bIsPlaceholderField = sTextContent.match( sPlaceholderTag );
2426 // for a placeholder text field we export only one <text> svg element
2427 if( bIsPlaceholderField )
2429 OUString sCleanTextContent;
2430 static const sal_Int32 nFrom = sPlaceholderTag.getLength();
2431 if( sTextContent.getLength() > nFrom )
2433 sCleanTextContent = sTextContent.copy( nFrom );
2435 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "PlaceholderText" );
2436 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::valueOf( aPos.X() ) );
2437 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::valueOf( aPos.Y() ) );
2439 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, sal_False );
2440 // At least for the single slide case we need really to export placeholder text
2441 mrExport.GetDocHandler()->characters( sCleanTextContent );
2446 if( !bIsPlaceholderField )
2448 if( nLen > 1 )
2450 aNormSize.Width() = pDX[ nLen - 2 ] + mpVDev->GetTextWidth( OUString(rText.GetChar(nLen - 1)) );
2452 if( nWidth && aNormSize.Width() && ( nWidth != aNormSize.Width() ) )
2454 long i;
2455 const double fFactor = (double) nWidth / aNormSize.Width();
2457 for( i = 0; i < ( nLen - 1 ); i++ )
2458 pDX[ i ] = FRound( pDX[ i ] * fFactor );
2460 else
2462 ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xBI( ::vcl::unohelper::CreateBreakIterator() );
2463 const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetLanguageTag().getLocale();
2464 sal_Int32 nCurPos = 0, nLastPos = 0, nX = aPos.X();
2466 // write single glyphs at absolute text positions
2467 for( sal_Bool bCont = sal_True; bCont; )
2469 sal_Int32 nCount = 1;
2471 nLastPos = nCurPos;
2472 nCurPos = xBI->nextCharacters( rText, nCurPos, rLocale,
2473 ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL,
2474 nCount, nCount );
2476 nCount = nCurPos - nLastPos;
2477 bCont = ( nCurPos < rText.Len() ) && nCount;
2479 if( nCount )
2481 const OUString aGlyph( rText.Copy( nLastPos, nCount ) );
2483 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::valueOf( nX ) );
2484 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::valueOf( aPos.Y() ) );
2487 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, sal_False );
2488 mrExport.GetDocHandler()->characters( aGlyph );
2491 if( bCont )
2493 // #118796# do NOT access pDXArray, it may be zero (!)
2494 sal_Int32 nDXWidth = pDX[ nCurPos - 1 ];
2495 if ( bApplyMapping )
2496 nDXWidth = ImplMap( nDXWidth );
2497 nX = aPos.X() + nDXWidth;
2503 else
2505 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::valueOf( aPos.X() ) );
2506 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::valueOf( aPos.Y() ) );
2509 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, sal_False );
2510 mrExport.GetDocHandler()->characters( rText );
2516 if( !mrExport.IsUseNativeTextDecoration() )
2518 if( rFont.GetStrikeout() != STRIKEOUT_NONE || rFont.GetUnderline() != UNDERLINE_NONE )
2520 Polygon aPoly( 4 );
2521 const long nLineHeight = std::max( (long) FRound( aMetric.GetLineHeight() * 0.05 ), (long) 1 );
2523 if( rFont.GetStrikeout() )
2525 const long nYLinePos = aBaseLinePos.Y() - FRound( aMetric.GetAscent() * 0.26 );
2527 aPoly[ 0 ].X() = aBaseLinePos.X(); aPoly[ 0 ].Y() = nYLinePos - ( nLineHeight >> 1 );
2528 aPoly[ 1 ].X() = aBaseLinePos.X() + aNormSize.Width() - 1; aPoly[ 1 ].Y() = aPoly[ 0 ].Y();
2529 aPoly[ 2 ].X() = aPoly[ 1 ].X(); aPoly[ 2 ].Y() = aPoly[ 0 ].Y() + nLineHeight - 1;
2530 aPoly[ 3 ].X() = aPoly[ 0 ].X(); aPoly[ 3 ].Y() = aPoly[ 2 ].Y();
2532 ImplWritePolyPolygon( aPoly, sal_False );
2535 if( rFont.GetUnderline() )
2537 const long nYLinePos = aBaseLinePos.Y() + ( nLineHeight << 1 );
2539 aPoly[ 0 ].X() = aBaseLinePos.X(); aPoly[ 0 ].Y() = nYLinePos - ( nLineHeight >> 1 );
2540 aPoly[ 1 ].X() = aBaseLinePos.X() + aNormSize.Width() - 1; aPoly[ 1 ].Y() = aPoly[ 0 ].Y();
2541 aPoly[ 2 ].X() = aPoly[ 1 ].X(); aPoly[ 2 ].Y() = aPoly[ 0 ].Y() + nLineHeight - 1;
2542 aPoly[ 3 ].X() = aPoly[ 0 ].X(); aPoly[ 3 ].Y() = aPoly[ 2 ].Y();
2544 ImplWritePolyPolygon( aPoly, sal_False );
2550 void SVGActionWriter::ImplWriteBmp( const BitmapEx& rBmpEx,
2551 const Point& rPt, const Size& rSz,
2552 const Point& rSrcPt, const Size& rSrcSz,
2553 sal_Bool bApplyMapping )
2555 if( !!rBmpEx )
2557 BitmapEx aBmpEx( rBmpEx );
2558 Point aPoint = Point();
2559 const Rectangle aBmpRect( aPoint, rBmpEx.GetSizePixel() );
2560 const Rectangle aSrcRect( rSrcPt, rSrcSz );
2562 if( aSrcRect != aBmpRect )
2563 aBmpEx.Crop( aSrcRect );
2565 if( !!aBmpEx )
2567 SvMemoryStream aOStm( 65535, 65535 );
2569 if( GraphicConverter::Export( aOStm, rBmpEx, CVT_PNG ) == ERRCODE_NONE )
2571 Point aPt;
2572 Size aSz;
2573 Sequence< sal_Int8 > aSeq( (sal_Int8*) aOStm.GetData(), aOStm.Tell() );
2574 OUStringBuffer aBuffer( "data:image/png;base64," );
2575 ::sax::Converter::encodeBase64( aBuffer, aSeq );
2577 if( bApplyMapping )
2579 ImplMap( rPt, aPt );
2580 ImplMap( rSz, aSz );
2582 else
2584 aPt = rPt;
2585 aSz = rSz;
2588 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::valueOf( aPt.X() ) );
2589 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::valueOf( aPt.Y() ) );
2590 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrWidth, OUString::valueOf( aSz.Width() ) );
2591 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrHeight, OUString::valueOf( aSz.Height() ) );
2592 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, aBuffer.makeStringAndClear() );
2594 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemImage, sal_True, sal_True );
2601 void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
2602 sal_uInt32 nWriteFlags,
2603 const OUString* pElementId,
2604 const Reference< XShape >* pxShape,
2605 const GDIMetaFile* pTextEmbeddedBitmapMtf )
2607 // need a counter fo rthe actions written per shape to avoid double ID
2608 // generation
2609 sal_Int32 nEntryCount(0);
2611 if( mnInnerMtfCount )
2612 nWriteFlags |= SVGWRITER_NO_SHAPE_COMMENTS;
2615 #if OSL_DEBUG_LEVEL > 0
2616 bool bIsTextShape = false;
2617 if( !mrExport.IsUsePositionedCharacters() && pxShape
2618 && Reference< XText >( *pxShape, UNO_QUERY ).is() )
2620 bIsTextShape = true;
2622 #endif
2623 mbIsPlacehlolderShape = false;
2624 if( ( pElementId != NULL ) && ( *pElementId == sPlaceholderTag ) )
2626 mbIsPlacehlolderShape = true;
2627 // since we utilize pElementId in an improper way we reset it to NULL before to go on
2628 pElementId = NULL;
2631 for( sal_uLong nCurAction = 0, nCount = rMtf.GetActionSize(); nCurAction < nCount; nCurAction++ )
2633 const MetaAction* pAction = rMtf.GetAction( nCurAction );
2634 const sal_uInt16 nType = pAction->GetType();
2636 #if OSL_DEBUG_LEVEL > 0
2637 if( bIsTextShape )
2641 SvXMLElementExport aElem( mrExport,
2642 XML_NAMESPACE_NONE, "desc", sal_False, sal_False );
2643 OUStringBuffer sType(OUString::number(nType));
2644 if (pAction && (nType == META_COMMENT_ACTION))
2646 sType.append(": ");
2647 const MetaCommentAction* pA = (const MetaCommentAction*) pAction;
2648 OString sComment = pA->GetComment();
2649 if (!sComment.isEmpty())
2651 sType.append(OStringToOUString(
2652 sComment, RTL_TEXTENCODING_UTF8));
2654 if (sComment.equalsIgnoreAsciiCaseL(
2655 RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_BEGIN")))
2657 sal_uInt8 const*const pData = pA->GetData();
2658 if (pData && (pA->GetDataSize()))
2660 sal_uInt16 sz = (sal_uInt16)((pA->GetDataSize()) / 2);
2661 if (sz)
2663 sType.append("; ");
2664 sType.append(
2665 reinterpret_cast<sal_Unicode const*>(pData),
2666 sz);
2671 if (sType.getLength())
2673 mrExport.GetDocHandler()->characters(
2674 sType.makeStringAndClear());
2677 catch( ... )
2679 const MetaCommentAction* pA = (const MetaCommentAction*) pAction;
2680 OSL_FAIL( pA->GetComment().getStr() );
2684 #endif
2685 switch( nType )
2687 case( META_PIXEL_ACTION ):
2689 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2691 const MetaPixelAction* pA = (const MetaPixelAction*) pAction;
2693 mpContext->AddPaintAttr( pA->GetColor(), pA->GetColor() );
2694 ImplWriteLine( pA->GetPoint(), pA->GetPoint(), &pA->GetColor() );
2697 break;
2699 case( META_POINT_ACTION ):
2701 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2703 const MetaPointAction* pA = (const MetaPointAction*) pAction;
2705 mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetLineColor() );
2706 ImplWriteLine( pA->GetPoint(), pA->GetPoint(), NULL );
2709 break;
2711 case( META_LINE_ACTION ):
2713 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2715 const MetaLineAction* pA = (const MetaLineAction*) pAction;
2717 mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetLineColor() );
2718 ImplWriteLine( pA->GetStartPoint(), pA->GetEndPoint(), NULL );
2721 break;
2723 case( META_RECT_ACTION ):
2725 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2727 mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
2728 ImplWriteRect( ( (const MetaRectAction*) pAction )->GetRect(), 0, 0 );
2731 break;
2733 case( META_ROUNDRECT_ACTION ):
2735 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2737 const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pAction;
2739 mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
2740 ImplWriteRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
2743 break;
2745 case( META_ELLIPSE_ACTION ):
2747 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2749 const MetaEllipseAction* pA = (const MetaEllipseAction*) pAction;
2750 const Rectangle& rRect = pA->GetRect();
2752 mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
2753 ImplWriteEllipse( rRect.Center(), rRect.GetWidth() >> 1, rRect.GetHeight() >> 1 );
2756 break;
2758 case( META_ARC_ACTION ):
2759 case( META_PIE_ACTION ):
2760 case( META_CHORD_ACTION ):
2761 case( META_POLYGON_ACTION ):
2763 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2765 Polygon aPoly;
2767 switch( nType )
2769 case( META_ARC_ACTION ):
2771 const MetaArcAction* pA = (const MetaArcAction*) pAction;
2772 aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC );
2774 break;
2776 case( META_PIE_ACTION ):
2778 const MetaPieAction* pA = (const MetaPieAction*) pAction;
2779 aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE );
2781 break;
2783 case( META_CHORD_ACTION ):
2785 const MetaChordAction* pA = (const MetaChordAction*) pAction;
2786 aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD );
2788 break;
2790 case( META_POLYGON_ACTION ):
2791 aPoly = ( (const MetaPolygonAction*) pAction )->GetPolygon();
2792 break;
2795 if( aPoly.GetSize() )
2797 mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
2798 ImplWritePolyPolygon( aPoly, sal_False );
2802 break;
2804 case( META_POLYLINE_ACTION ):
2806 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2808 const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pAction;
2809 const Polygon& rPoly = pA->GetPolygon();
2811 if( rPoly.GetSize() )
2813 mpContext->AddPaintAttr( mpVDev->GetLineColor(), Color( COL_TRANSPARENT ) );
2814 ImplAddLineAttr( pA->GetLineInfo() );
2815 ImplWritePolyPolygon( rPoly, sal_True );
2819 break;
2821 case( META_POLYPOLYGON_ACTION ):
2823 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2825 const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*) pAction;
2826 const PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
2828 if( rPolyPoly.Count() )
2830 mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
2831 ImplWritePolyPolygon( rPolyPoly, sal_False );
2835 break;
2837 case( META_GRADIENT_ACTION ):
2839 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2841 const MetaGradientAction* pA = (const MetaGradientAction*) pAction;
2842 const Polygon aRectPoly( pA->GetRect() );
2843 const PolyPolygon aRectPolyPoly( aRectPoly );
2845 ImplWriteGradientEx( aRectPolyPoly, pA->GetGradient(), nWriteFlags );
2848 break;
2850 case( META_GRADIENTEX_ACTION ):
2852 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2854 const MetaGradientExAction* pA = (const MetaGradientExAction*) pAction;
2855 ImplWriteGradientEx( pA->GetPolyPolygon(), pA->GetGradient(), nWriteFlags );
2858 break;
2860 case META_HATCH_ACTION:
2862 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2864 const MetaHatchAction* pA = (const MetaHatchAction*) pAction;
2865 ImplWritePattern( pA->GetPolyPolygon(), &pA->GetHatch(), NULL, nWriteFlags );
2868 break;
2870 case( META_TRANSPARENT_ACTION ):
2872 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2874 const MetaTransparentAction* pA = (const MetaTransparentAction*) pAction;
2875 const PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
2877 if( rPolyPoly.Count() )
2879 Color aNewLineColor( mpVDev->GetLineColor() ), aNewFillColor( mpVDev->GetFillColor() );
2881 aNewLineColor.SetTransparency( sal::static_int_cast<sal_uInt8>( FRound( pA->GetTransparence() * 2.55 ) ) );
2882 aNewFillColor.SetTransparency( sal::static_int_cast<sal_uInt8>( FRound( pA->GetTransparence() * 2.55 ) ) );
2884 mpContext->AddPaintAttr( aNewLineColor, aNewFillColor );
2885 ImplWritePolyPolygon( rPolyPoly, sal_False );
2889 break;
2891 case( META_FLOATTRANSPARENT_ACTION ):
2893 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2895 const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pAction;
2896 GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
2897 ImplWriteMask( aTmpMtf, pA->GetPoint(), pA->GetSize(),
2898 pA->GetGradient(), nWriteFlags );
2901 break;
2903 case( META_EPS_ACTION ):
2905 if( nWriteFlags & SVGWRITER_WRITE_FILL )
2907 const MetaEPSAction* pA = (const MetaEPSAction*) pAction;
2908 const GDIMetaFile aGDIMetaFile( pA->GetSubstitute() );
2909 sal_Bool bFound = sal_False;
2911 for( sal_uInt32 k = 0, nCount2 = aGDIMetaFile.GetActionSize(); ( k < nCount2 ) && !bFound; ++k )
2913 const MetaAction* pSubstAct = aGDIMetaFile.GetAction( k );
2915 if( pSubstAct->GetType() == META_BMPSCALE_ACTION )
2917 bFound = sal_True;
2918 const MetaBmpScaleAction* pBmpScaleAction = (const MetaBmpScaleAction*) pSubstAct;
2919 ImplWriteBmp( pBmpScaleAction->GetBitmap(),
2920 pA->GetPoint(), pA->GetSize(),
2921 Point(), pBmpScaleAction->GetBitmap().GetSizePixel() );
2926 break;
2928 case( META_COMMENT_ACTION ):
2930 const MetaCommentAction* pA = (const MetaCommentAction*) pAction;
2932 if( ( pA->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XGRAD_SEQ_BEGIN")) ) &&
2933 ( nWriteFlags & SVGWRITER_WRITE_FILL ) )
2935 const MetaGradientExAction* pGradAction = NULL;
2936 sal_Bool bDone = sal_False;
2938 while( !bDone && ( ++nCurAction < nCount ) )
2940 pAction = rMtf.GetAction( nCurAction );
2942 if( pAction->GetType() == META_GRADIENTEX_ACTION )
2943 pGradAction = (const MetaGradientExAction*) pAction;
2944 else if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
2945 ( ( (const MetaCommentAction*) pAction )->GetComment().
2946 equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XGRAD_SEQ_END")) ) )
2948 bDone = sal_True;
2952 if( pGradAction )
2953 ImplWriteGradientEx( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), nWriteFlags );
2955 else if( ( pA->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHFILL_SEQ_BEGIN")) ) &&
2956 ( nWriteFlags & SVGWRITER_WRITE_FILL ) && !( nWriteFlags & SVGWRITER_NO_SHAPE_COMMENTS ) &&
2957 pA->GetDataSize() )
2959 // write open shape in every case
2960 if( mapCurShape.get() )
2962 ImplWriteShape( *mapCurShape );
2963 mapCurShape.reset();
2966 SvMemoryStream aMemStm( (void*) pA->GetData(), pA->GetDataSize(), STREAM_READ );
2967 SvtGraphicFill aFill;
2969 aMemStm >> aFill;
2971 sal_Bool bGradient = SvtGraphicFill::fillGradient == aFill.getFillType() &&
2972 ( SvtGraphicFill::gradientLinear == aFill.getGradientType() ||
2973 SvtGraphicFill::gradientRadial == aFill.getGradientType() );
2974 sal_Bool bSkip = ( SvtGraphicFill::fillSolid == aFill.getFillType() || bGradient );
2976 if( bSkip )
2978 PolyPolygon aShapePolyPoly;
2980 aFill.getPath( aShapePolyPoly );
2982 if( aShapePolyPoly.Count() )
2984 mapCurShape.reset( new SVGShapeDescriptor );
2986 if( pElementId )
2988 mapCurShape->maId = *pElementId + "_" + OUString::valueOf(nEntryCount++);
2991 mapCurShape->maShapePolyPoly = aShapePolyPoly;
2992 mapCurShape->maShapeFillColor = aFill.getFillColor();
2993 mapCurShape->maShapeFillColor.SetTransparency( (sal_uInt8) FRound( 255.0 * aFill.getTransparency() ) );
2995 if( bGradient )
2997 // step through following actions until the first Gradient/GradientEx action is found
2998 while( !mapCurShape->mapShapeGradient.get() && bSkip && ( ++nCurAction < nCount ) )
3000 pAction = rMtf.GetAction( nCurAction );
3002 if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
3003 ( ( (const MetaCommentAction*) pAction )->GetComment().
3004 equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHFILL_SEQ_END")) ) )
3006 bSkip = sal_False;
3008 else if( pAction->GetType() == META_GRADIENTEX_ACTION )
3010 mapCurShape->mapShapeGradient.reset( new Gradient(
3011 static_cast< const MetaGradientExAction* >( pAction )->GetGradient() ) );
3013 else if( pAction->GetType() == META_GRADIENT_ACTION )
3015 mapCurShape->mapShapeGradient.reset( new Gradient(
3016 static_cast< const MetaGradientAction* >( pAction )->GetGradient() ) );
3021 else
3022 bSkip = sal_False;
3025 // skip rest of comment
3026 while( bSkip && ( ++nCurAction < nCount ) )
3028 pAction = rMtf.GetAction( nCurAction );
3030 if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
3031 ( ( (const MetaCommentAction*) pAction )->GetComment().
3032 equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHFILL_SEQ_END")) ) )
3034 bSkip = sal_False;
3038 else if( ( pA->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHSTROKE_SEQ_BEGIN")) ) &&
3039 ( nWriteFlags & SVGWRITER_WRITE_FILL ) && !( nWriteFlags & SVGWRITER_NO_SHAPE_COMMENTS ) &&
3040 pA->GetDataSize() )
3042 SvMemoryStream aMemStm( (void*) pA->GetData(), pA->GetDataSize(), STREAM_READ );
3043 SvtGraphicStroke aStroke;
3044 PolyPolygon aStartArrow, aEndArrow;
3046 aMemStm >> aStroke;
3047 aStroke.getStartArrow( aStartArrow );
3048 aStroke.getEndArrow( aEndArrow );
3050 // Currently no support for strokes with start/end arrow(s)
3051 sal_Bool bSkip = ( !aStartArrow.Count() && !aEndArrow.Count() );
3053 if( bSkip )
3055 Polygon aPoly;
3057 aStroke.getPath(aPoly);
3059 if(mapCurShape.get())
3061 if(1 != mapCurShape->maShapePolyPoly.Count()
3062 || !mapCurShape->maShapePolyPoly[0].IsEqual(aPoly))
3064 // this path action is not covering the same path than the already existing
3065 // fill polypolygon, so write out the fill polygon
3066 ImplWriteShape( *mapCurShape );
3067 mapCurShape.reset();
3071 if( !mapCurShape.get() )
3073 mapCurShape.reset( new SVGShapeDescriptor );
3075 if( pElementId )
3077 mapCurShape->maId = *pElementId + "_" + OUString::valueOf(nEntryCount++);
3080 aStroke.getPath( aPoly );
3081 mapCurShape->maShapePolyPoly = aPoly;
3084 mapCurShape->maShapeLineColor = mpVDev->GetLineColor();
3085 mapCurShape->maShapeLineColor.SetTransparency( (sal_uInt8) FRound( aStroke.getTransparency() * 255.0 ) );
3086 mapCurShape->mnStrokeWidth = FRound( aStroke.getStrokeWidth() );
3087 aStroke.getDashArray( mapCurShape->maDashArray );
3090 // support for LineJoin
3091 switch(aStroke.getJoinType())
3093 default: /* SvtGraphicStroke::joinMiter, SvtGraphicStroke::joinNone */
3095 mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_MITER;
3096 break;
3098 case SvtGraphicStroke::joinRound:
3100 mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_ROUND;
3101 break;
3103 case SvtGraphicStroke::joinBevel:
3105 mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_BEVEL;
3106 break;
3110 // support for LineCap
3111 switch(aStroke.getCapType())
3113 default: /* SvtGraphicStroke::capButt */
3115 mapCurShape->maLineCap = com::sun::star::drawing::LineCap_BUTT;
3116 break;
3118 case SvtGraphicStroke::capRound:
3120 mapCurShape->maLineCap = com::sun::star::drawing::LineCap_ROUND;
3121 break;
3123 case SvtGraphicStroke::capSquare:
3125 mapCurShape->maLineCap = com::sun::star::drawing::LineCap_SQUARE;
3126 break;
3130 // write open shape in every case
3131 if( mapCurShape.get() )
3133 ImplWriteShape( *mapCurShape );
3134 mapCurShape.reset();
3137 // skip rest of comment
3138 while( bSkip && ( ++nCurAction < nCount ) )
3140 pAction = rMtf.GetAction( nCurAction );
3142 if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
3143 ( ( (const MetaCommentAction*) pAction )->GetComment().
3144 equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHSTROKE_SEQ_END")) ) )
3146 bSkip = sal_False;
3150 else if( !mrExport.IsUsePositionedCharacters() && ( nWriteFlags & SVGWRITER_WRITE_TEXT ) )
3152 if( ( pA->GetComment().equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_PAINTSHAPE_BEGIN" ) ) ) )
3154 if( pxShape )
3156 Reference< XText > xText( *pxShape, UNO_QUERY );
3157 if( xText.is() )
3158 maTextWriter.setTextShape( xText, pTextEmbeddedBitmapMtf );
3160 maTextWriter.createParagraphEnumeration();
3162 // nTextFound == -1 => no text found
3163 // nTextFound == 0 => no text found and end of text shape reached
3164 // nTextFound == 1 => text found!
3165 sal_Int32 nTextFound = -1;
3166 while( ( nTextFound < 0 ) && ( nCurAction < nCount ) )
3168 nTextFound = maTextWriter.setTextPosition( rMtf, nCurAction );
3170 // We found some text in the current text shape.
3171 if( nTextFound > 0 )
3173 maTextWriter.setTextProperties( rMtf, nCurAction );
3174 maTextWriter.startTextShape();
3176 // We reached the end of the current text shape
3177 // without finding any text. So we need to go back
3178 // by one action in order to handle the
3179 // XTEXT_PAINTSHAPE_END action because on the next
3180 // loop the nCurAction is incremented by one.
3181 else
3183 --nCurAction;
3187 else if( ( pA->GetComment().equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_PAINTSHAPE_END" ) ) ) )
3189 maTextWriter.endTextShape();
3191 else if( ( pA->GetComment().equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_EOP" ) ) ) )
3193 const MetaAction* pNextAction = rMtf.GetAction( nCurAction + 1 );
3194 if( !( ( pNextAction->GetType() == META_COMMENT_ACTION ) &&
3195 ( ( (const MetaCommentAction*) pNextAction )->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XTEXT_PAINTSHAPE_END") ) ) ))
3197 // nTextFound == -1 => no text found and end of paragraph reached
3198 // nTextFound == 0 => no text found and end of text shape reached
3199 // nTextFound == 1 => text found!
3200 sal_Int32 nTextFound = -1;
3201 while( ( nTextFound < 0 ) && ( nCurAction < nCount ) )
3203 nTextFound = maTextWriter.setTextPosition( rMtf, nCurAction );
3205 // We found a paragraph with some text in the
3206 // current text shape.
3207 if( nTextFound > 0 )
3209 maTextWriter.setTextProperties( rMtf, nCurAction );
3210 maTextWriter.startTextParagraph();
3212 // We reached the end of the current text shape
3213 // without finding any text. So we need to go back
3214 // by one action in order to handle the
3215 // XTEXT_PAINTSHAPE_END action because on the next
3216 // loop the nCurAction is incremented by one.
3217 else
3219 --nCurAction;
3224 else if( ( pA->GetComment().equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_EOL" ) ) ) )
3226 const MetaAction* pNextAction = rMtf.GetAction( nCurAction + 1 );
3227 if( !( ( pNextAction->GetType() == META_COMMENT_ACTION ) &&
3228 ( ( (const MetaCommentAction*) pNextAction )->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOP") ) ) ) )
3230 // nTextFound == -2 => no text found and end of line reached
3231 // nTextFound == -1 => no text found and end of paragraph reached
3232 // nTextFound == 1 => text found!
3233 sal_Int32 nTextFound = -2;
3234 while( ( nTextFound < -1 ) && ( nCurAction < nCount ) )
3236 nTextFound = maTextWriter.setTextPosition( rMtf, nCurAction );
3238 // We found a line with some text in the current
3239 // paragraph.
3240 if( nTextFound > 0 )
3242 maTextWriter.startTextPosition();
3244 // We reached the end of the current paragraph
3245 // without finding any text. So we need to go back
3246 // by one action in order to handle the XTEXT_EOP
3247 // action because on the next loop the nCurAction is
3248 // incremented by one.
3249 else
3251 --nCurAction;
3257 break;
3259 case( META_BMP_ACTION ):
3261 if( nWriteFlags & SVGWRITER_WRITE_FILL )
3263 const MetaBmpAction* pA = (const MetaBmpAction*) pAction;
3265 ImplWriteBmp( pA->GetBitmap(),
3266 pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmap().GetSizePixel() ),
3267 Point(), pA->GetBitmap().GetSizePixel() );
3270 break;
3272 case( META_BMPSCALE_ACTION ):
3274 if( nWriteFlags & SVGWRITER_WRITE_FILL )
3276 const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction;
3278 // Bitmaps embedded into text shapes are collected and exported elsewhere.
3279 if( maTextWriter.isTextShapeStarted() )
3281 maTextWriter.writeBitmapPlaceholder( pA );
3283 else
3285 ImplWriteBmp( pA->GetBitmap(),
3286 pA->GetPoint(), pA->GetSize(),
3287 Point(), pA->GetBitmap().GetSizePixel() );
3291 break;
3293 case( META_BMPSCALEPART_ACTION ):
3295 if( nWriteFlags & SVGWRITER_WRITE_FILL )
3297 const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pAction;
3299 ImplWriteBmp( pA->GetBitmap(),
3300 pA->GetDestPoint(), pA->GetDestSize(),
3301 pA->GetSrcPoint(), pA->GetSrcSize() );
3304 break;
3306 case( META_BMPEX_ACTION ):
3308 if( nWriteFlags & SVGWRITER_WRITE_FILL )
3310 const MetaBmpExAction* pA = (const MetaBmpExAction*) pAction;
3312 ImplWriteBmp( pA->GetBitmapEx(),
3313 pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmapEx().GetSizePixel() ),
3314 Point(), pA->GetBitmapEx().GetSizePixel() );
3317 break;
3319 case( META_BMPEXSCALE_ACTION ):
3321 if( nWriteFlags & SVGWRITER_WRITE_FILL )
3323 const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction;
3325 // Bitmaps embedded into text shapes are collected and exported elsewhere.
3326 if( maTextWriter.isTextShapeStarted() )
3328 maTextWriter.writeBitmapPlaceholder( pA );
3330 else
3332 ImplWriteBmp( pA->GetBitmapEx(),
3333 pA->GetPoint(), pA->GetSize(),
3334 Point(), pA->GetBitmapEx().GetSizePixel() );
3338 break;
3340 case( META_BMPEXSCALEPART_ACTION ):
3342 if( nWriteFlags & SVGWRITER_WRITE_FILL )
3344 const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pAction;
3346 ImplWriteBmp( pA->GetBitmapEx(),
3347 pA->GetDestPoint(), pA->GetDestSize(),
3348 pA->GetSrcPoint(), pA->GetSrcSize() );
3351 break;
3353 case( META_TEXT_ACTION ):
3355 if( nWriteFlags & SVGWRITER_WRITE_TEXT )
3357 const MetaTextAction* pA = (const MetaTextAction*) pAction;
3358 const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
3360 if( aText.Len() )
3362 if( mrExport.IsUsePositionedCharacters() )
3364 Font aFont = ImplSetCorrectFontHeight();
3365 mpContext->SetFontAttr( aFont );
3366 ImplWriteText( pA->GetPoint(), aText, NULL, 0 );
3368 else
3370 maTextWriter.writeTextPortion( pA->GetPoint(), aText );
3376 break;
3378 case( META_TEXTRECT_ACTION ):
3380 if( nWriteFlags & SVGWRITER_WRITE_TEXT )
3382 const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction;
3384 if (!pA->GetText().isEmpty())
3386 if( mrExport.IsUsePositionedCharacters() )
3388 Font aFont = ImplSetCorrectFontHeight();
3389 mpContext->SetFontAttr( aFont );
3390 ImplWriteText( pA->GetRect().TopLeft(), pA->GetText(), NULL, 0 );
3393 maTextWriter.writeTextPortion( pA->GetRect().TopLeft(), pA->GetText() );
3398 break;
3400 case( META_TEXTARRAY_ACTION ):
3402 if( nWriteFlags & SVGWRITER_WRITE_TEXT )
3404 const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pAction;
3405 const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
3407 if( aText.Len() )
3409 if( mrExport.IsUsePositionedCharacters() )
3411 Font aFont = ImplSetCorrectFontHeight();
3412 mpContext->SetFontAttr( aFont );
3413 ImplWriteText( pA->GetPoint(), aText, pA->GetDXArray(), 0 );
3415 else
3417 maTextWriter.writeTextPortion( pA->GetPoint(), aText );
3422 break;
3424 case( META_STRETCHTEXT_ACTION ):
3426 if( nWriteFlags & SVGWRITER_WRITE_TEXT )
3428 const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction;
3429 const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
3431 if( aText.Len() )
3433 if( mrExport.IsUsePositionedCharacters() )
3435 Font aFont = ImplSetCorrectFontHeight();
3436 mpContext->SetFontAttr( aFont );
3437 ImplWriteText( pA->GetPoint(), aText, NULL, pA->GetWidth() );
3439 else
3441 maTextWriter.writeTextPortion( pA->GetPoint(), aText );
3446 break;
3448 case( META_CLIPREGION_ACTION ):
3449 case( META_ISECTRECTCLIPREGION_ACTION ):
3450 case( META_ISECTREGIONCLIPREGION_ACTION ):
3451 case( META_MOVECLIPREGION_ACTION ):
3453 ( (MetaAction*) pAction )->Execute( mpVDev );
3454 mbClipAttrChanged = sal_True;
3456 break;
3458 case( META_REFPOINT_ACTION ):
3459 case( META_MAPMODE_ACTION ):
3460 case( META_LINECOLOR_ACTION ):
3461 case( META_FILLCOLOR_ACTION ):
3462 case( META_TEXTLINECOLOR_ACTION ):
3463 case( META_TEXTFILLCOLOR_ACTION ):
3464 case( META_TEXTCOLOR_ACTION ):
3465 case( META_TEXTALIGN_ACTION ):
3466 case( META_FONT_ACTION ):
3467 case( META_PUSH_ACTION ):
3468 case( META_POP_ACTION ):
3469 case( META_LAYOUTMODE_ACTION ):
3471 ( (MetaAction*) pAction )->Execute( mpVDev );
3473 break;
3475 case( META_RASTEROP_ACTION ):
3476 case( META_MASK_ACTION ):
3477 case( META_MASKSCALE_ACTION ):
3478 case( META_MASKSCALEPART_ACTION ):
3479 case( META_WALLPAPER_ACTION ):
3480 case( META_TEXTLINE_ACTION ):
3482 // !!! >>> we don't want to support these actions
3484 break;
3486 default:
3487 OSL_FAIL( "SVGActionWriter::ImplWriteActions: unsupported MetaAction #" );
3488 break;
3493 Font SVGActionWriter::ImplSetCorrectFontHeight() const
3495 Font aFont( mpVDev->GetFont() );
3496 Size aSz;
3498 ImplMap( Size( 0, aFont.GetHeight() ), aSz );
3500 aFont.SetHeight( aSz.Height() );
3502 return aFont;
3505 void SVGActionWriter::WriteMetaFile( const Point& rPos100thmm,
3506 const Size& rSize100thmm,
3507 const GDIMetaFile& rMtf,
3508 sal_uInt32 nWriteFlags,
3509 const OUString* pElementId,
3510 const Reference< XShape >* pXShape,
3511 const GDIMetaFile* pTextEmbeddedBitmapMtf )
3513 MapMode aMapMode( rMtf.GetPrefMapMode() );
3514 Size aPrefSize( rMtf.GetPrefSize() );
3515 Fraction aFractionX( aMapMode.GetScaleX() );
3516 Fraction aFractionY( aMapMode.GetScaleY() );
3518 mpVDev->Push();
3520 Size aSize( OutputDevice::LogicToLogic( rSize100thmm, MAP_100TH_MM, aMapMode ) );
3521 aMapMode.SetScaleX( aFractionX *= Fraction( aSize.Width(), aPrefSize.Width() ) );
3522 aMapMode.SetScaleY( aFractionY *= Fraction( aSize.Height(), aPrefSize.Height() ) );
3524 Point aOffset( OutputDevice::LogicToLogic( rPos100thmm, MAP_100TH_MM, aMapMode ) );
3525 aMapMode.SetOrigin( aOffset += aMapMode.GetOrigin() );
3527 mpVDev->SetMapMode( aMapMode );
3528 ImplAcquireContext();
3530 mapCurShape.reset();
3532 ImplWriteActions( rMtf, nWriteFlags, pElementId, pXShape, pTextEmbeddedBitmapMtf );
3533 maTextWriter.endTextParagraph();
3535 // draw open shape that doesn't have a border
3536 if( mapCurShape.get() )
3538 ImplWriteShape( *mapCurShape );
3539 mapCurShape.reset();
3542 ImplReleaseContext();
3543 mpVDev->Pop();
3546 // -------------
3547 // - SVGWriter -
3548 // -------------
3550 SVGWriter::SVGWriter( const Reference< XComponentContext >& rxCtx )
3551 : mxContext(rxCtx)
3555 // -----------------------------------------------------------------------------
3557 SVGWriter::~SVGWriter()
3561 // -----------------------------------------------------------------------------
3563 void SAL_CALL SVGWriter::write( const Reference<XDocumentHandler>& rxDocHandler,
3564 const Sequence<sal_Int8>& rMtfSeq ) throw( RuntimeException )
3566 SvMemoryStream aMemStm( (char*) rMtfSeq.getConstArray(), rMtfSeq.getLength(), STREAM_READ );
3567 GDIMetaFile aMtf;
3569 aMemStm >> aMtf;
3571 const Reference< XDocumentHandler > xDocumentHandler( rxDocHandler );
3572 const Sequence< PropertyValue > aFilterData;
3574 SVGExport* pWriter = new SVGExport( mxContext, xDocumentHandler, aFilterData );
3575 pWriter->writeMtf( aMtf );
3576 delete pWriter;
3579 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */