1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
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
) :
98 mrFontExport( rFontExport
),
104 SVGAttributeWriter::~SVGAttributeWriter()
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 )
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
)
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
);
162 AddColorAttr( aXMLAttrFill
, aXMLAttrFillOpacity
, rFillColor
);
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
;
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
) );
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
)
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
);
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
) );
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
);
286 rGradientId
= OUString();
289 void SVGAttributeWriter::SetFontAttr( const Font
& rFont
)
291 if( rFont
!= maCurFont
)
293 OUString aFontStyle
, aTextDecoration
;
294 sal_Int32 nFontWeight
;
302 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, aXMLAttrFontSize
,
303 OUString::valueOf( rFont
.GetHeight() ) + "px" );
306 if( rFont
.GetItalic() != ITALIC_NONE
)
308 if( rFont
.GetItalic() == ITALIC_OBLIQUE
)
309 aFontStyle
= "oblique";
311 aFontStyle
= "italic";
314 aFontStyle
= "normal";
316 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, aXMLAttrFontStyle
, aFontStyle
);
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 ";
347 aTextDecoration
= "none";
349 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, aXMLAttrTextDecoration
, aTextDecoration
);
356 void SVGAttributeWriter::startFontSettings()
359 if( mrExport
.IsUsePositionedCharacters() )
361 mpElemFont
= new SvXMLElementExport( mrExport
, XML_NAMESPACE_NONE
, aXMLElemG
, sal_True
, sal_True
);
365 mpElemFont
= new SvXMLElementExport( mrExport
, XML_NAMESPACE_NONE
, aXMLElemTspan
, sal_True
, sal_True
);
369 void SVGAttributeWriter::endFontSettings()
378 void SVGAttributeWriter::setFontFamily()
380 if( mrExport
.IsUsePositionedCharacters() )
382 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, aXMLAttrFontFamily
, mrFontExport
.GetMappedFontName( maCurFont
.GetName() ) );
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";
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
),
410 mbIsTextShapeStarted( sal_False
),
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 ),
425 mbPositioningNeeded( sal_False
),
426 mbIsNewListItem( sal_False
),
427 maBulletListItemMap(),
428 mbIsListLevelStyleImage( sal_False
),
429 mbLineBreak( sal_False
),
430 mbIsURLField( sal_False
),
432 mbIsPlacehlolderShape( sal_False
),
439 SVGTextWriter::~SVGTextWriter()
444 void SVGTextWriter::implRegisterInterface( const Reference
< XInterface
>& rxIf
)
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
);
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
);
468 OSL_FAIL( "SVGTextWriter::implMap: invalid virtual device or map mode." );
471 void SVGTextWriter::implSetCurrentFont()
475 maCurrentFont
= mpVDev
->GetFont();
478 implMap( Size( 0, maCurrentFont
.GetHeight() ), aSz
);
480 maCurrentFont
.SetHeight( aSz
.Height() );
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 );
496 raPos
= pA
->GetPoint();
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 );
510 raPos
= pA
->GetRect().TopLeft();
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();
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
536 sal_Int32
SVGTextWriter::setTextPosition( const GDIMetaFile
& rMtf
, sal_uLong
& nCurAction
)
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();
554 case( META_TEXT_ACTION
):
556 bConfigured
= implGetTextPosition
<MetaTextAction
>( pAction
, aPos
, bEmpty
);
560 case( META_TEXTRECT_ACTION
):
562 bConfigured
= implGetTextPosition
<MetaTextRectAction
>( pAction
, aPos
, bEmpty
);
566 case( META_TEXTARRAY_ACTION
):
568 bConfigured
= implGetTextPosition
<MetaTextArrayAction
>( pAction
, aPos
, bEmpty
);
572 case( META_STRETCHTEXT_ACTION
):
574 bConfigured
= implGetTextPosition
<MetaStretchTextAction
>( pAction
, aPos
, bEmpty
);
578 case( META_BMPSCALE_ACTION
):
580 bConfigured
= implGetTextPositionFromBitmap
<MetaBmpScaleAction
>( pAction
, aPos
, bEmpty
);
584 case( META_BMPEXSCALE_ACTION
):
586 bConfigured
= implGetTextPositionFromBitmap
<MetaBmpExScaleAction
>( pAction
, aPos
, bEmpty
);
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" ) ) )
600 else if( rsComment
.equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_EOP" ) ) )
605 while( nextTextPortion() )
607 sContent
= mrCurrentTextPortion
->getString();
608 if( sContent
.isEmpty() )
614 if( sContent
.equalsAscii( "\n" ) )
615 mbLineBreak
= sal_True
;
618 if( nextParagraph() )
620 while( nextTextPortion() )
622 sContent
= mrCurrentTextPortion
->getString();
623 if( sContent
.isEmpty() )
629 if( sContent
.equalsAscii( "\n" ) )
630 mbLineBreak
= sal_True
;
635 else if( rsComment
.equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_PAINTSHAPE_END" ) ) )
642 if( bConfigured
|| bEOL
|| bEOP
|| bETS
) break;
644 implMap( aPos
, maTextPos
);
648 nCurAction
= nActionIndex
;
649 return ( (bEOL
) ? -2 : ( (bEOP
) ? -1 : 0 ) );
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();
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
);
679 case( META_TEXT_ACTION
):
681 const MetaTextAction
* pA
= (const MetaTextAction
*) pAction
;
682 if( pA
->GetLen() > 2 )
686 case( META_TEXTRECT_ACTION
):
688 const MetaTextRectAction
* pA
= (const MetaTextRectAction
*) pAction
;
689 if( pA
->GetText().getLength() > 2 )
693 case( META_TEXTARRAY_ACTION
):
695 const MetaTextArrayAction
* pA
= (const MetaTextArrayAction
*) pAction
;
696 if( pA
->GetLen() > 2 )
700 case( META_STRETCHTEXT_ACTION
):
702 const MetaStretchTextAction
* pA
= (const MetaStretchTextAction
*) pAction
;
703 if( pA
->GetLen() > 2 )
707 // If we reach the end of the paragraph without finding any text
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" ) ) )
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();
742 if( rsCurFontName
!= rsParFontName
)
748 if( nCurFontSize
!= nParFontSize
)
750 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, aXMLAttrFontSize
,
751 OUString::valueOf( nCurFontSize
) + "px" );
755 if( eCurFontItalic
!= eParFontItalic
)
758 if( eCurFontItalic
!= ITALIC_NONE
)
760 if( eCurFontItalic
== ITALIC_OBLIQUE
)
761 sFontStyle
= "oblique";
763 sFontStyle
= "italic";
767 sFontStyle
= "normal";
769 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, aXMLAttrFontStyle
, sFontStyle
);
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";
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
);
859 OSL_FAIL( "SVGTextWriter::createParagraphEnumeration: no valid xEnumeration interface found." );
864 OSL_FAIL( "SVGTextWriter::createParagraphEnumeration: no valid XText interface found." );
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
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
);
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
922 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "is-numbered", sInfo
);
926 mbIsNewListItem
= 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 ) )
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
)
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
);
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
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
998 OSL_FAIL( "SVGTextWriter::nextParagraph: Unknown text content." );
1001 #if OSL_DEBUG_LEVEL > 0
1002 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "class", sInfo
);
1003 SvXMLElementExport
aParaElem( mrExport
, XML_NAMESPACE_NONE
, "desc", mbIWS
, mbIWS
);
1008 OSL_FAIL( "SVGTextWriter::nextParagraph: no XServiceInfo interface available for text content." );
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
);
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
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
+ "; ";
1048 if( xPortionTextRange
.is() )
1050 #if OSL_DEBUG_LEVEL > 0
1051 sInfo
+= "content: " + xPortionTextRange
->getString() + "; ";
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
1075 if ( pNames
->matchIgnoreAsciiCase( sServicePrefix
) )
1077 // TextField found => postfix is field type!
1078 sFieldName
= pNames
->copy( sServicePrefix
.getLength() );
1081 else if( 0 == pNames
->compareTo( sPresentationServicePrefix
, sPresentationServicePrefix
.getLength() ) )
1083 // TextField found => postfix is field type!
1084 sFieldName
= pNames
->copy( sPresentationServicePrefix
.getLength() );
1091 #if OSL_DEBUG_LEVEL > 0
1092 sInfo
+= "text field type: " + sFieldName
+ "; " +
1093 "content: " + xTextField
->getPresentation( /* show command: */ sal_False
) + "; ";
1095 if( sFieldName
.equalsAscii( "DateTime" ) || sFieldName
.equalsAscii( "Header" )
1096 || sFieldName
.equalsAscii( "Footer" ) || sFieldName
.equalsAscii( "PageNumber" ) )
1098 mbIsPlacehlolderShape
= sal_True
;
1102 mbIsURLField
= sFieldName
.equalsAscii( "URL" );
1106 Reference
<XPropertySet
> xTextFieldPropSet(xTextField
, UNO_QUERY
);
1107 if( xTextFieldPropSet
.is() )
1110 if( ( xTextFieldPropSet
->getPropertyValue( sFieldName
) ) >>= sURL
)
1112 #if OSL_DEBUG_LEVEL > 0
1114 sInfo
+= mrExport
.GetRelativeReference( sURL
);
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
);
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()
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()
1190 if( mbIsNewListItem
)
1192 OUString sNumberingType
;
1193 switch( meNumberingType
)
1195 case( NumberingType::CHAR_SPECIAL
):
1196 sNumberingType
= "bullet-style";
1198 case( NumberingType::BITMAP
):
1199 sNumberingType
= "image-style";
1202 sNumberingType
= "number-style";
1205 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, aOOOAttrNumberingType
, sNumberingType
);
1206 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "class", "ListItem" );
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();
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
)
1241 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "class", "TextPosition" );
1243 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, aXMLAttrX
, OUString::valueOf( maTextPos
.X() ) );
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() )
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
) ) +
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
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
);
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;
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();
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();
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();
1412 // <g id="?" > (used by animations)
1414 // embedded bitmap id
1415 nId
= SVGActionWriter::GetChecksum( pAction
);
1416 sId
= "embedded-bitmap(";
1419 sId
+= OUString::valueOf( (sal_Int64
)nId
);
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
);
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 )
1456 mbLineBreak
= sal_False
;
1458 if( !mbIsNewListItem
|| mbIsListLevelStyleImage
)
1460 bool bNotSync
= true;
1462 sal_Int32 nStartPos
;
1465 if( mnLeftTextPortionLength
<= 0 || !mrCurrentTextPortion
.is() )
1467 if( !nextTextPortion() )
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();
1485 sContent
= mrCurrentTextPortion
->getString();
1488 nStartPos
= sContent
.getLength() - mnLeftTextPortionLength
;
1489 if( nStartPos
< 0 ) nStartPos
= 0;
1490 mnLeftTextPortionLength
-= rText
.Len();
1492 if( sContent
.isEmpty() )
1494 if( sContent
.equalsAscii( "\n" ) )
1495 mbLineBreak
= sal_True
;
1496 if( sContent
.match( rText
, nStartPos
) )
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
);
1514 // to be implemented
1519 void SVGTextWriter::implWriteTextPortion( const Point
& rPos
,
1520 const String
& rText
,
1522 sal_Bool bApplyMapping
)
1525 OSL_FAIL( "SVGTextWriter::implWriteTextPortion: invalid context object." );
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();
1538 implMap( rPos
, aPos
);
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() )
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
);
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
);
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 ),
1641 mnCurPatternId( 1 ),
1642 mrExport( rExport
),
1643 mrFontExport( rFontExport
),
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" );
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
) );
1699 PolyPolygon
& SVGActionWriter::ImplMap( const PolyPolygon
& rPolyPoly
, PolyPolygon
& rDstPolyPoly
) const
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
)
1716 const OUString
aBlank( " " );
1717 const OUString
aComma( "," );
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();
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]);
1736 aPathData
+= aBlank
;
1738 if ( ( rPoly
.GetFlags( n
) == POLY_CONTROL
) && ( ( n
+ 2 ) < nSize
) )
1740 if ( nCurrentMode
!= 'C' )
1745 for ( int j
= 0; j
< 3; j
++ )
1748 aPathData
+= aBlank
;
1749 aPathData
+= OUString::valueOf( ( aPolyPoint
= rPoly
[ n
++ ] ).X() );
1750 aPathData
+= aComma
;
1751 aPathData
+= OUString::valueOf( aPolyPoint
.Y() );
1756 if ( nCurrentMode
!= 'L' )
1761 aPathData
+= OUString::valueOf( ( aPolyPoint
= rPoly
[ n
++ ] ).X() );
1762 aPathData
+= aComma
;
1763 aPathData
+= OUString::valueOf( aPolyPoint
.Y() );
1770 if( i
< ( nCount
- 1 ) )
1771 aPathData
+= aBlank
;
1778 sal_uLong
SVGActionWriter::GetChecksum( const MetaAction
* pAction
)
1781 MetaAction
* pA
= (MetaAction
*)pAction
;
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
)
1794 ImplMap( rPt1
, aPt1
);
1795 ImplMap( rPt2
, aPt2
);
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() ) );
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
)
1825 ImplMap( rRect
, aRect
);
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() ) );
1835 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, aXMLAttrRX
, OUString::valueOf( bApplyMapping
? ImplMap( nRadX
) : nRadX
) );
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
)
1851 ImplMap( rCenter
, aCenter
);
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
;
1882 ImplMap( rPolyPoly
, aPolyPoly
);
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
;
1900 ImplMap( rShape
.maShapePolyPoly
, aPolyPoly
);
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"));
1929 case basegfx::B2DLINEJOIN_BEVEL
:
1931 mrExport
.AddAttribute(XML_NAMESPACE_NONE
, aXMLAttrStrokeLinejoin
, OUString::createFromAscii("bevel"));
1934 case basegfx::B2DLINEJOIN_ROUND
:
1936 mrExport
.AddAttribute(XML_NAMESPACE_NONE
, aXMLAttrStrokeLinejoin
, OUString::createFromAscii("round"));
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"));
1951 case com::sun::star::drawing::LineCap_ROUND
:
1953 mrExport
.AddAttribute(XML_NAMESPACE_NONE
, aXMLAttrStrokeLinecap
, OUString::createFromAscii("round"));
1956 case com::sun::star::drawing::LineCap_SQUARE
:
1958 mrExport
.AddAttribute(XML_NAMESPACE_NONE
, aXMLAttrStrokeLinecap
, OUString::createFromAscii("square"));
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
] ) );
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
);
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() ) +
2021 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, aXMLAttrTransform
, aTransform
);
2024 SvXMLElementExport
aElemG2( mrExport
, XML_NAMESPACE_NONE
, aXMLElemG
, sal_True
, sal_True
);
2026 GDIMetaFile aTmpMtf
;
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
;
2049 ImplMap( rPolyPoly
, aPolyPoly
);
2051 aPolyPoly
= rPolyPoly
;
2053 if ( rGradient
.GetStyle() == GradientStyle_LINEAR
||
2054 rGradient
.GetStyle() == GradientStyle_AXIAL
)
2056 ImplWriteGradientLinear( aPolyPoly
, rGradient
);
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;
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
);
2126 ImplWriteGradientStop( aStartColor
, fBorderOffset
);
2127 ImplWriteGradientStop( aEndColor
, 1.0 );
2133 // Emulate non-smooth gradient
2134 if( 0 < nSteps
&& nSteps
< 100 )
2136 double fOffsetStep
= ( 0.5 - fBorderOffset
) / (double)nSteps
;
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
);
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
);
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
);
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
,
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
);
2268 ImplWriteActions( rMtf
, nWriteFlags
, NULL
);
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
);
2283 ImplWriteText( rPos
, rText
, pDXArray
, nWidth
, mpVDev
->GetTextColor(), bApplyMapping
);
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
);
2300 Point
aOffset( 6, 6 );
2302 if ( aMetric
.GetRelief() == RELIEF_ENGRAVED
)
2311 ImplWriteText( aPos
, rText
, pDXArray
, nWidth
, aReliefColor
, bApplyMapping
);
2312 ImplWriteText( rPos
, rText
, pDXArray
, nWidth
, aTextColor
, bApplyMapping
);
2316 if( aMetric
.IsShadow() )
2318 long nOff
= 1 + ((aMetric
.GetLineHeight()-24)/24);
2319 if ( aMetric
.IsOutline() )
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
);
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();
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();
2380 ImplMap( rPos
, aPos
);
2384 boost::shared_array
<sal_Int32
> xTmpArray(new sal_Int32
[nLen
]);
2388 aNormSize
= Size( mpVDev
->GetTextWidth( rText
), 0 );
2389 memcpy(xTmpArray
.get(), pDXArray
, nLen
* sizeof(sal_Int32
));
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() )
2401 OUString aTransform
=
2402 OUString("translate") +
2403 "(" + OUString::valueOf( aRot
.X() ) +
2404 "," + OUString::valueOf( aRot
.Y() ) + ")" +
2406 "(" + OUString::valueOf( rFont
.GetOrientation() * -0.1 ) + ")" +
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
)
2450 aNormSize
.Width() = pDX
[ nLen
- 2 ] + mpVDev
->GetTextWidth( OUString(rText
.GetChar(nLen
- 1)) );
2452 if( nWidth
&& aNormSize
.Width() && ( nWidth
!= aNormSize
.Width() ) )
2455 const double fFactor
= (double) nWidth
/ aNormSize
.Width();
2457 for( i
= 0; i
< ( nLen
- 1 ); i
++ )
2458 pDX
[ i
] = FRound( pDX
[ i
] * fFactor
);
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;
2472 nCurPos
= xBI
->nextCharacters( rText
, nCurPos
, rLocale
,
2473 ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL
,
2476 nCount
= nCurPos
- nLastPos
;
2477 bCont
= ( nCurPos
< rText
.Len() ) && 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
);
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
;
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
)
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
)
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
);
2567 SvMemoryStream
aOStm( 65535, 65535 );
2569 if( GraphicConverter::Export( aOStm
, rBmpEx
, CVT_PNG
) == ERRCODE_NONE
)
2573 Sequence
< sal_Int8
> aSeq( (sal_Int8
*) aOStm
.GetData(), aOStm
.Tell() );
2574 OUStringBuffer
aBuffer( "data:image/png;base64," );
2575 ::sax::Converter::encodeBase64( aBuffer
, aSeq
);
2579 ImplMap( rPt
, aPt
);
2580 ImplMap( rSz
, aSz
);
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
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;
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
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
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
))
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);
2665 reinterpret_cast<sal_Unicode
const*>(pData
),
2671 if (sType
.getLength())
2673 mrExport
.GetDocHandler()->characters(
2674 sType
.makeStringAndClear());
2679 const MetaCommentAction
* pA
= (const MetaCommentAction
*) pAction
;
2680 OSL_FAIL( pA
->GetComment().getStr() );
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() );
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
);
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
);
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 );
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() );
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 );
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
)
2769 case( META_ARC_ACTION
):
2771 const MetaArcAction
* pA
= (const MetaArcAction
*) pAction
;
2772 aPoly
= Polygon( pA
->GetRect(), pA
->GetStartPoint(), pA
->GetEndPoint(), POLY_ARC
);
2776 case( META_PIE_ACTION
):
2778 const MetaPieAction
* pA
= (const MetaPieAction
*) pAction
;
2779 aPoly
= Polygon( pA
->GetRect(), pA
->GetStartPoint(), pA
->GetEndPoint(), POLY_PIE
);
2783 case( META_CHORD_ACTION
):
2785 const MetaChordAction
* pA
= (const MetaChordAction
*) pAction
;
2786 aPoly
= Polygon( pA
->GetRect(), pA
->GetStartPoint(), pA
->GetEndPoint(), POLY_CHORD
);
2790 case( META_POLYGON_ACTION
):
2791 aPoly
= ( (const MetaPolygonAction
*) pAction
)->GetPolygon();
2795 if( aPoly
.GetSize() )
2797 mpContext
->AddPaintAttr( mpVDev
->GetLineColor(), mpVDev
->GetFillColor() );
2798 ImplWritePolyPolygon( aPoly
, sal_False
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
)
2918 const MetaBmpScaleAction
* pBmpScaleAction
= (const MetaBmpScaleAction
*) pSubstAct
;
2919 ImplWriteBmp( pBmpScaleAction
->GetBitmap(),
2920 pA
->GetPoint(), pA
->GetSize(),
2921 Point(), pBmpScaleAction
->GetBitmap().GetSizePixel() );
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")) ) )
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
) &&
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
;
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
);
2978 PolyPolygon aShapePolyPoly
;
2980 aFill
.getPath( aShapePolyPoly
);
2982 if( aShapePolyPoly
.Count() )
2984 mapCurShape
.reset( new SVGShapeDescriptor
);
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() ) );
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")) ) )
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() ) );
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")) ) )
3038 else if( ( pA
->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHSTROKE_SEQ_BEGIN")) ) &&
3039 ( nWriteFlags
& SVGWRITER_WRITE_FILL
) && !( nWriteFlags
& SVGWRITER_NO_SHAPE_COMMENTS
) &&
3042 SvMemoryStream
aMemStm( (void*) pA
->GetData(), pA
->GetDataSize(), STREAM_READ
);
3043 SvtGraphicStroke aStroke
;
3044 PolyPolygon aStartArrow
, aEndArrow
;
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() );
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
);
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
;
3098 case SvtGraphicStroke::joinRound
:
3100 mapCurShape
->maLineJoin
= basegfx::B2DLINEJOIN_ROUND
;
3103 case SvtGraphicStroke::joinBevel
:
3105 mapCurShape
->maLineJoin
= basegfx::B2DLINEJOIN_BEVEL
;
3110 // support for LineCap
3111 switch(aStroke
.getCapType())
3113 default: /* SvtGraphicStroke::capButt */
3115 mapCurShape
->maLineCap
= com::sun::star::drawing::LineCap_BUTT
;
3118 case SvtGraphicStroke::capRound
:
3120 mapCurShape
->maLineCap
= com::sun::star::drawing::LineCap_ROUND
;
3123 case SvtGraphicStroke::capSquare
:
3125 mapCurShape
->maLineCap
= com::sun::star::drawing::LineCap_SQUARE
;
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")) ) )
3150 else if( !mrExport
.IsUsePositionedCharacters() && ( nWriteFlags
& SVGWRITER_WRITE_TEXT
) )
3152 if( ( pA
->GetComment().equalsIgnoreAsciiCaseL( RTL_CONSTASCII_STRINGPARAM( "XTEXT_PAINTSHAPE_BEGIN" ) ) ) )
3156 Reference
< XText
> xText( *pxShape
, UNO_QUERY
);
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.
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.
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
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.
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() );
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
);
3285 ImplWriteBmp( pA
->GetBitmap(),
3286 pA
->GetPoint(), pA
->GetSize(),
3287 Point(), pA
->GetBitmap().GetSizePixel() );
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() );
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() );
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
);
3332 ImplWriteBmp( pA
->GetBitmapEx(),
3333 pA
->GetPoint(), pA
->GetSize(),
3334 Point(), pA
->GetBitmapEx().GetSizePixel() );
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() );
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() );
3362 if( mrExport
.IsUsePositionedCharacters() )
3364 Font aFont
= ImplSetCorrectFontHeight();
3365 mpContext
->SetFontAttr( aFont
);
3366 ImplWriteText( pA
->GetPoint(), aText
, NULL
, 0 );
3370 maTextWriter
.writeTextPortion( pA
->GetPoint(), aText
);
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() );
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() );
3409 if( mrExport
.IsUsePositionedCharacters() )
3411 Font aFont
= ImplSetCorrectFontHeight();
3412 mpContext
->SetFontAttr( aFont
);
3413 ImplWriteText( pA
->GetPoint(), aText
, pA
->GetDXArray(), 0 );
3417 maTextWriter
.writeTextPortion( pA
->GetPoint(), aText
);
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() );
3433 if( mrExport
.IsUsePositionedCharacters() )
3435 Font aFont
= ImplSetCorrectFontHeight();
3436 mpContext
->SetFontAttr( aFont
);
3437 ImplWriteText( pA
->GetPoint(), aText
, NULL
, pA
->GetWidth() );
3441 maTextWriter
.writeTextPortion( pA
->GetPoint(), aText
);
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
;
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
);
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
3487 OSL_FAIL( "SVGActionWriter::ImplWriteActions: unsupported MetaAction #" );
3493 Font
SVGActionWriter::ImplSetCorrectFontHeight() const
3495 Font
aFont( mpVDev
->GetFont() );
3498 ImplMap( Size( 0, aFont
.GetHeight() ), aSz
);
3500 aFont
.SetHeight( aSz
.Height() );
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() );
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();
3550 SVGWriter::SVGWriter( const Reference
< XComponentContext
>& 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
);
3571 const Reference
< XDocumentHandler
> xDocumentHandler( rxDocHandler
);
3572 const Sequence
< PropertyValue
> aFilterData
;
3574 SVGExport
* pWriter
= new SVGExport( mxContext
, xDocumentHandler
, aFilterData
);
3575 pWriter
->writeMtf( aMtf
);
3579 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */