| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_filter.hxx" |
| |
| #include "svgfontexport.hxx" |
| #include "svgwriter.hxx" |
| #include <vcl/unohelp.hxx> |
| |
| // ----------- |
| // - statics - |
| // ----------- |
| |
| static const char aXMLElemG[] = "g"; |
| static const char aXMLElemDefs[] = "defs"; |
| static const char aXMLElemLine[] = "line"; |
| static const char aXMLElemRect[] = "rect"; |
| static const char aXMLElemEllipse[] = "ellipse"; |
| static const char aXMLElemPath[] = "path"; |
| static const char aXMLElemPolygon[] = "polygon"; |
| static const char aXMLElemPolyLine[] = "polyline"; |
| static const char aXMLElemText[] = "text"; |
| static const char aXMLElemTSpan[] = "tspan"; |
| static const char aXMLElemImage[] = "image"; |
| static const char aXMLElemLinearGradient[] = "linearGradient"; |
| static const char aXMLElemRadialGradient[] = "radialGradient"; |
| static const char aXMLElemStop[] = "stop"; |
| |
| // ----------------------------------------------------------------------------- |
| |
| static const char aXMLAttrTransform[] = "transform"; |
| static const char aXMLAttrStyle[] = "style"; |
| static const char aXMLAttrId[] = "id"; |
| static const char aXMLAttrD[] = "d"; |
| static const char aXMLAttrX[] = "x"; |
| static const char aXMLAttrY[] = "y"; |
| static const char aXMLAttrX1[] = "x1"; |
| static const char aXMLAttrY1[] = "y1"; |
| static const char aXMLAttrX2[] = "x2"; |
| static const char aXMLAttrY2[] = "y2"; |
| static const char aXMLAttrCX[] = "cx"; |
| static const char aXMLAttrCY[] = "cy"; |
| static const char aXMLAttrR[] = "r"; |
| static const char aXMLAttrRX[] = "rx"; |
| static const char aXMLAttrRY[] = "ry"; |
| static const char aXMLAttrWidth[] = "width"; |
| static const char aXMLAttrHeight[] = "height"; |
| static const char aXMLAttrPoints[] = "points"; |
| static const char aXMLAttrStroke[] = "stroke"; |
| static const char aXMLAttrStrokeOpacity[] = "stroke-opacity"; |
| static const char aXMLAttrStrokeWidth[] = "stroke-width"; |
| static const char aXMLAttrStrokeDashArray[] = "stroke-dasharray"; |
| static const char aXMLAttrFill[] = "fill"; |
| static const char aXMLAttrFillOpacity[] = "fill-opacity"; |
| static const char aXMLAttrFontFamily[] = "font-family"; |
| static const char aXMLAttrFontSize[] = "font-size"; |
| static const char aXMLAttrFontStyle[] = "font-style"; |
| static const char aXMLAttrFontWeight[] = "font-weight"; |
| static const char aXMLAttrTextDecoration[] = "text-decoration"; |
| static const char aXMLAttrXLinkHRef[] = "xlink:href"; |
| static const char aXMLAttrGradientUnits[] = "gradientUnits"; |
| static const char aXMLAttrOffset[] = "offset"; |
| static const char aXMLAttrStopColor[] = "stop-color"; |
| |
| // added support for LineJoin and LineCap |
| static const char aXMLAttrStrokeLinejoin[] = "stroke-linejoin"; |
| static const char aXMLAttrStrokeLinecap[] = "stroke-linecap"; |
| |
| // ----------------------------------------------------------------------------- |
| |
| static const sal_Unicode pBase64[] = |
| { |
| //0 1 2 3 4 5 6 7 |
| 'A','B','C','D','E','F','G','H', // 0 |
| 'I','J','K','L','M','N','O','P', // 1 |
| 'Q','R','S','T','U','V','W','X', // 2 |
| 'Y','Z','a','b','c','d','e','f', // 3 |
| 'g','h','i','j','k','l','m','n', // 4 |
| 'o','p','q','r','s','t','u','v', // 5 |
| 'w','x','y','z','0','1','2','3', // 6 |
| '4','5','6','7','8','9','+','/' // 7 |
| }; |
| |
| // ---------------------- |
| // - SVGAttributeWriter - |
| // ---------------------- |
| |
| SVGAttributeWriter::SVGAttributeWriter( SVGExport& rExport, SVGFontExport& rFontExport ) : |
| mrExport( rExport ), |
| mrFontExport( rFontExport ), |
| mpElemFont( NULL ), |
| mpElemPaint( NULL ) |
| { |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| SVGAttributeWriter::~SVGAttributeWriter() |
| { |
| delete mpElemPaint; |
| delete mpElemFont; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| double SVGAttributeWriter::ImplRound( double fValue, sal_Int32 nDecs ) |
| { |
| return( floor( fValue * pow( 10.0, (int)nDecs ) + 0.5 ) / pow( 10.0, (int)nDecs ) ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGAttributeWriter::ImplGetColorStr( const Color& rColor, ::rtl::OUString& rColorStr ) |
| { |
| if( rColor.GetTransparency() == 255 ) |
| rColorStr = B2UCONST( "none" ); |
| else |
| { |
| rColorStr = B2UCONST( "rgb(" ); |
| rColorStr += ::rtl::OUString::valueOf( static_cast< sal_Int32 >( rColor.GetRed() ) ); |
| rColorStr += B2UCONST( "," ); |
| rColorStr += ::rtl::OUString::valueOf( static_cast< sal_Int32 >( rColor.GetGreen() ) ); |
| rColorStr += B2UCONST( "," ); |
| rColorStr += ::rtl::OUString::valueOf( static_cast< sal_Int32 >( rColor.GetBlue() ) ); |
| rColorStr += B2UCONST( ")" ); |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGAttributeWriter::AddColorAttr( const char* pColorAttrName, |
| const char* pColorOpacityAttrName, |
| const Color& rColor ) |
| { |
| ::rtl::OUString aColor, aColorOpacity; |
| |
| ImplGetColorStr( rColor, aColor ); |
| |
| if( rColor.GetTransparency() > 0 && rColor.GetTransparency() < 255 ) |
| aColorOpacity = ::rtl::OUString::valueOf( ImplRound( ( 255.0 - rColor.GetTransparency() ) / 255.0 ) ); |
| |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, pColorAttrName, aColor ); |
| |
| if( aColorOpacity.getLength() && mrExport.IsUseOpacity() ) |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, pColorOpacityAttrName, aColorOpacity ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGAttributeWriter::AddPaintAttr( const Color& rLineColor, const Color& rFillColor, |
| const Rectangle* pObjBoundRect, const Gradient* pFillGradient ) |
| { |
| // Fill |
| if( pObjBoundRect && pFillGradient ) |
| { |
| ::rtl::OUString aGradientId; |
| |
| AddGradientDef( *pObjBoundRect, *pFillGradient, aGradientId ); |
| |
| if( aGradientId.getLength() ) |
| { |
| ::rtl::OUString aGradientURL( B2UCONST( "url(#" ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFill, ( aGradientURL += aGradientId ) += B2UCONST( ")" ) ); |
| } |
| } |
| else |
| AddColorAttr( aXMLAttrFill, aXMLAttrFillOpacity, rFillColor ); |
| |
| // Stroke |
| AddColorAttr( aXMLAttrStroke, aXMLAttrStrokeOpacity, rLineColor ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGAttributeWriter::AddGradientDef( const Rectangle& rObjRect, const Gradient& rGradient, ::rtl::OUString& rGradientId ) |
| { |
| if( rObjRect.GetWidth() && rObjRect.GetHeight() && |
| ( rGradient.GetStyle() == GRADIENT_LINEAR || rGradient.GetStyle() == GRADIENT_AXIAL || |
| rGradient.GetStyle() == GRADIENT_RADIAL || rGradient.GetStyle() == GRADIENT_ELLIPTICAL ) ) |
| { |
| SvXMLElementExport aDesc( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, sal_True, sal_True ); |
| Color aStartColor( rGradient.GetStartColor() ), aEndColor( rGradient.GetEndColor() ); |
| sal_uInt16 nAngle = rGradient.GetAngle() % 3600; |
| Point aObjRectCenter( rObjRect.Center() ); |
| Polygon aPoly( rObjRect ); |
| static sal_Int32 nCurGradientId = 1; |
| |
| aPoly.Rotate( aObjRectCenter, nAngle ); |
| Rectangle aRect( aPoly.GetBoundRect() ); |
| |
| // adjust start/end colors with intensities |
| aStartColor.SetRed( (sal_uInt8)( ( (long) aStartColor.GetRed() * rGradient.GetStartIntensity() ) / 100 ) ); |
| aStartColor.SetGreen( (sal_uInt8)( ( (long) aStartColor.GetGreen() * rGradient.GetStartIntensity() ) / 100 ) ); |
| aStartColor.SetBlue( (sal_uInt8)( ( (long) aStartColor.GetBlue() * rGradient.GetStartIntensity() ) / 100 ) ); |
| |
| aEndColor.SetRed( (sal_uInt8)( ( (long) aEndColor.GetRed() * rGradient.GetEndIntensity() ) / 100 ) ); |
| aEndColor.SetGreen( (sal_uInt8)( ( (long) aEndColor.GetGreen() * rGradient.GetEndIntensity() ) / 100 ) ); |
| aEndColor.SetBlue( (sal_uInt8)( ( (long) aEndColor.GetBlue() * rGradient.GetEndIntensity() ) / 100 ) ); |
| |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, |
| ( rGradientId = B2UCONST( "Gradient_" ) ) += ::rtl::OUString::valueOf( nCurGradientId++ ) ); |
| |
| { |
| ::std::auto_ptr< SvXMLElementExport > apGradient; |
| ::rtl::OUString aColorStr; |
| |
| if( rGradient.GetStyle() == GRADIENT_LINEAR || rGradient.GetStyle() == GRADIENT_AXIAL ) |
| { |
| Polygon aLinePoly( 2 ); |
| |
| aLinePoly[ 0 ] = Point( aObjRectCenter.X(), aRect.Top() ); |
| aLinePoly[ 1 ] = Point( aObjRectCenter.X(), aRect.Bottom() ); |
| |
| aLinePoly.Rotate( aObjRectCenter, nAngle ); |
| |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits, B2UCONST( "userSpaceOnUse" ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, ::rtl::OUString::valueOf( aLinePoly[ 0 ].X() ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, ::rtl::OUString::valueOf( aLinePoly[ 0 ].Y() ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, ::rtl::OUString::valueOf( aLinePoly[ 1 ].X() ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, ::rtl::OUString::valueOf( aLinePoly[ 1 ].Y() ) ); |
| |
| apGradient.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemLinearGradient, sal_True, sal_True ) ); |
| |
| // write stop values |
| double fBorder = static_cast< double >( rGradient.GetBorder() ) * |
| ( ( rGradient.GetStyle() == GRADIENT_AXIAL ) ? 0.005 : 0.01 ); |
| |
| ImplGetColorStr( ( rGradient.GetStyle() == GRADIENT_AXIAL ) ? aEndColor : aStartColor, aColorStr ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, ::rtl::OUString::valueOf( fBorder ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr ); |
| |
| { |
| SvXMLElementExport aDesc2( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True ); |
| } |
| |
| if( rGradient.GetStyle() == GRADIENT_AXIAL ) |
| { |
| ImplGetColorStr( aStartColor, aColorStr ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, ::rtl::OUString::valueOf( 0.5 ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr ); |
| |
| { |
| SvXMLElementExport aDesc3( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True ); |
| } |
| } |
| |
| if( rGradient.GetStyle() != GRADIENT_AXIAL ) |
| fBorder = 0.0; |
| |
| ImplGetColorStr( aEndColor, aColorStr ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, ::rtl::OUString::valueOf( ImplRound( 1.0 - fBorder ) ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr ); |
| |
| { |
| SvXMLElementExport aDesc4( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True ); |
| } |
| } |
| else |
| { |
| const double fCenterX = rObjRect.Left() + rObjRect.GetWidth() * rGradient.GetOfsX() * 0.01; |
| const double fCenterY = rObjRect.Top() + rObjRect.GetHeight() * rGradient.GetOfsY() * 0.01; |
| const double fRadius = sqrt( static_cast< double >( rObjRect.GetWidth() ) * rObjRect.GetWidth() + |
| rObjRect.GetHeight() * rObjRect.GetHeight() ) * 0.5; |
| |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits, B2UCONST( "userSpaceOnUse" ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCX, ::rtl::OUString::valueOf( ImplRound( fCenterX ) ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCY, ::rtl::OUString::valueOf( ImplRound( fCenterY ) ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrR, ::rtl::OUString::valueOf( ImplRound( fRadius ) ) ); |
| |
| apGradient.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemRadialGradient, sal_True, sal_True ) ); |
| |
| // write stop values |
| ImplGetColorStr( aEndColor, aColorStr ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, ::rtl::OUString::valueOf( 0.0 ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr ); |
| |
| { |
| SvXMLElementExport aDesc5( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True ); |
| } |
| |
| ImplGetColorStr( aStartColor, aColorStr ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, |
| ::rtl::OUString::valueOf( ImplRound( 1.0 - rGradient.GetBorder() * 0.01 ) ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr ); |
| |
| { |
| SvXMLElementExport aDesc6( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, sal_True, sal_True ); |
| } |
| } |
| } |
| } |
| else |
| rGradientId = ::rtl::OUString(); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGAttributeWriter::SetFontAttr( const Font& rFont ) |
| { |
| if( !mpElemFont || ( rFont != maCurFont ) ) |
| { |
| ::rtl::OUString aFontStyle, aFontWeight, aTextDecoration; |
| sal_Int32 nFontWeight; |
| |
| delete mpElemPaint, mpElemPaint = NULL; |
| delete mpElemFont; |
| maCurFont = rFont; |
| |
| // Font Family |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontFamily, mrFontExport.GetMappedFontName( rFont.GetName() ) ); |
| |
| // Font Size |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontSize, ::rtl::OUString::valueOf( rFont.GetHeight() ) ); |
| |
| // Font Style |
| if( rFont.GetItalic() != ITALIC_NONE ) |
| { |
| if( rFont.GetItalic() == ITALIC_OBLIQUE ) |
| aFontStyle = B2UCONST( "oblique" ); |
| else |
| aFontStyle = B2UCONST( "italic" ); |
| } |
| else |
| aFontStyle = B2UCONST( "normal" ); |
| |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontStyle, aFontStyle ); |
| |
| // Font Weight |
| switch( rFont.GetWeight() ) |
| { |
| case WEIGHT_THIN: nFontWeight = 100; break; |
| case WEIGHT_ULTRALIGHT: nFontWeight = 200; break; |
| case WEIGHT_LIGHT: nFontWeight = 300; break; |
| case WEIGHT_SEMILIGHT: nFontWeight = 400; break; |
| case WEIGHT_NORMAL: nFontWeight = 400; break; |
| case WEIGHT_MEDIUM: nFontWeight = 500; break; |
| case WEIGHT_SEMIBOLD: nFontWeight = 600; break; |
| case WEIGHT_BOLD: nFontWeight = 700; break; |
| case WEIGHT_ULTRABOLD: nFontWeight = 800; break; |
| case WEIGHT_BLACK: nFontWeight = 900; break; |
| default: nFontWeight = 400; break; |
| } |
| |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontWeight, ::rtl::OUString::valueOf( nFontWeight ) ); |
| |
| if( mrExport.IsUseNativeTextDecoration() ) |
| { |
| if( rFont.GetUnderline() != UNDERLINE_NONE || rFont.GetStrikeout() != STRIKEOUT_NONE ) |
| { |
| if( rFont.GetUnderline() != UNDERLINE_NONE ) |
| aTextDecoration = B2UCONST( "underline " ); |
| |
| if( rFont.GetStrikeout() != STRIKEOUT_NONE ) |
| aTextDecoration += B2UCONST( "line-through " ); |
| } |
| else |
| aTextDecoration = B2UCONST( "none" ); |
| |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTextDecoration, aTextDecoration ); |
| } |
| |
| mpElemFont = new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True ); |
| } |
| } |
| |
| // ------------------- |
| // - SVGActionWriter - |
| // ------------------- |
| |
| SVGActionWriter::SVGActionWriter( SVGExport& rExport, SVGFontExport& rFontExport ) : |
| mrExport( rExport ), |
| mrFontExport( rFontExport ), |
| mpContext( NULL ), |
| mnInnerMtfCount( 0 ), |
| mbClipAttrChanged( sal_False ) |
| { |
| mpVDev = new VirtualDevice; |
| mpVDev->EnableOutput( sal_False ); |
| maTargetMapMode = MAP_100TH_MM; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| SVGActionWriter::~SVGActionWriter() |
| { |
| DBG_ASSERT( !mpContext, "Not all contexts are closed" ); |
| delete mpVDev; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| long SVGActionWriter::ImplMap( sal_Int32 nVal ) const |
| { |
| Size aSz( nVal, nVal ); |
| |
| return( ImplMap( aSz, aSz ).Width() ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| Point& SVGActionWriter::ImplMap( const Point& rPt, Point& rDstPt ) const |
| { |
| return( rDstPt = mpVDev->LogicToLogic( rPt, mpVDev->GetMapMode(), maTargetMapMode ) ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| Size& SVGActionWriter::ImplMap( const Size& rSz, Size& rDstSz ) const |
| { |
| return( rDstSz = mpVDev->LogicToLogic( rSz, mpVDev->GetMapMode(), maTargetMapMode ) ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| Rectangle& SVGActionWriter::ImplMap( const Rectangle& rRect, Rectangle& rDstRect ) const |
| { |
| Point aTL( rRect.TopLeft() ); |
| Size aSz( rRect.GetSize() ); |
| |
| return( rDstRect = Rectangle( ImplMap( aTL, aTL ), ImplMap( aSz, aSz ) ) ); |
| } |
| |
| |
| // ----------------------------------------------------------------------------- |
| |
| Polygon& SVGActionWriter::ImplMap( const Polygon& rPoly, Polygon& rDstPoly ) const |
| { |
| rDstPoly = Polygon( rPoly.GetSize() ); |
| |
| for( sal_uInt16 i = 0, nSize = rPoly.GetSize(); i < nSize; ++i ) |
| { |
| ImplMap( rPoly[ i ], rDstPoly[ i ] ); |
| rDstPoly.SetFlags( i, rPoly.GetFlags( i ) ); |
| } |
| |
| return( rDstPoly ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| PolyPolygon& SVGActionWriter::ImplMap( const PolyPolygon& rPolyPoly, PolyPolygon& rDstPolyPoly ) const |
| { |
| Polygon aPoly; |
| |
| rDstPolyPoly = PolyPolygon(); |
| |
| for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; ++i ) |
| { |
| rDstPolyPoly.Insert( ImplMap( rPolyPoly[ i ], aPoly ) ); |
| } |
| |
| return( rDstPolyPoly ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| ::rtl::OUString SVGActionWriter::GetPathString( const PolyPolygon& rPolyPoly, sal_Bool bLine ) |
| { |
| ::rtl::OUString aPathData; |
| const ::rtl::OUString aBlank( B2UCONST( " " ) ); |
| const ::rtl::OUString aComma( B2UCONST( "," ) ); |
| Point aPolyPoint; |
| |
| for( long i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ ) |
| { |
| const Polygon& rPoly = rPolyPoly[ (sal_uInt16) i ]; |
| sal_uInt16 n = 1, nSize = rPoly.GetSize(); |
| |
| if( nSize > 1 ) |
| { |
| aPathData += B2UCONST( "M " ); |
| aPathData += ::rtl::OUString::valueOf( ( aPolyPoint = rPoly[ 0 ] ).X() ); |
| aPathData += aComma; |
| aPathData += ::rtl::OUString::valueOf( aPolyPoint.Y() ); |
| sal_Char nCurrentMode = 0; |
| const bool bClose(!bLine || rPoly[0] == rPoly[nSize - 1]); |
| |
| while( n < nSize ) |
| { |
| aPathData += aBlank; |
| |
| if ( ( rPoly.GetFlags( n ) == POLY_CONTROL ) && ( ( n + 2 ) < nSize ) ) |
| { |
| if ( nCurrentMode != 'C' ) |
| { |
| nCurrentMode = 'C'; |
| aPathData += B2UCONST( "C " ); |
| } |
| for ( int j = 0; j < 3; j++ ) |
| { |
| if ( j ) |
| aPathData += aBlank; |
| aPathData += ::rtl::OUString::valueOf( ( aPolyPoint = rPoly[ n++ ] ).X() ); |
| aPathData += aComma; |
| aPathData += ::rtl::OUString::valueOf( aPolyPoint.Y() ); |
| } |
| } |
| else |
| { |
| if ( nCurrentMode != 'L' ) |
| { |
| nCurrentMode = 'L'; |
| aPathData += B2UCONST( "L " ); |
| } |
| aPathData += ::rtl::OUString::valueOf( ( aPolyPoint = rPoly[ n++ ] ).X() ); |
| aPathData += aComma; |
| aPathData += ::rtl::OUString::valueOf( aPolyPoint.Y() ); |
| } |
| } |
| |
| if(bClose) |
| aPathData += B2UCONST( " Z" ); |
| |
| if( i < ( nCount - 1 ) ) |
| aPathData += aBlank; |
| } |
| } |
| |
| return aPathData; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGActionWriter::ImplWriteLine( const Point& rPt1, const Point& rPt2, |
| const Color* pLineColor, sal_Bool bApplyMapping ) |
| { |
| Point aPt1, aPt2; |
| |
| if( bApplyMapping ) |
| { |
| ImplMap( rPt1, aPt1 ); |
| ImplMap( rPt2, aPt2 ); |
| } |
| else |
| { |
| aPt1 = rPt1; |
| aPt2 = rPt2; |
| } |
| |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, ::rtl::OUString::valueOf( aPt1.X() ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, ::rtl::OUString::valueOf( aPt1.Y() ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, ::rtl::OUString::valueOf( aPt2.X() ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, ::rtl::OUString::valueOf( aPt2.Y() ) ); |
| |
| if( pLineColor ) |
| { |
| // !!! mrExport.AddAttribute( XML_NAMESPACE_NONE, ... ) |
| DBG_ERROR( "SVGActionWriter::ImplWriteLine: Line color not implemented" ); |
| } |
| |
| { |
| SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemLine, sal_True, sal_True ); |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGActionWriter::ImplWriteRect( const Rectangle& rRect, long nRadX, long nRadY, |
| sal_Bool bApplyMapping ) |
| { |
| Rectangle aRect; |
| |
| if( bApplyMapping ) |
| ImplMap( rRect, aRect ); |
| else |
| aRect = rRect; |
| |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, ::rtl::OUString::valueOf( aRect.Left() ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( aRect.Top() ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrWidth, ::rtl::OUString::valueOf( aRect.GetWidth() ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrHeight, ::rtl::OUString::valueOf( aRect.GetHeight() ) ); |
| |
| if( nRadX ) |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRX, ::rtl::OUString::valueOf( bApplyMapping ? ImplMap( nRadX ) : nRadX ) ); |
| |
| if( nRadY ) |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRY, ::rtl::OUString::valueOf( bApplyMapping ? ImplMap( nRadY ) : nRadY ) ); |
| |
| { |
| SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemRect, sal_True, sal_True ); |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGActionWriter::ImplWriteEllipse( const Point& rCenter, long nRadX, long nRadY, |
| sal_Bool bApplyMapping ) |
| { |
| Point aCenter; |
| |
| if( bApplyMapping ) |
| ImplMap( rCenter, aCenter ); |
| else |
| aCenter = rCenter; |
| |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCX, ::rtl::OUString::valueOf( aCenter.X() ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCY, ::rtl::OUString::valueOf( aCenter.Y() ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRX, ::rtl::OUString::valueOf( bApplyMapping ? ImplMap( nRadX ) : nRadX ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRY, ::rtl::OUString::valueOf( bApplyMapping ? ImplMap( nRadY ) : nRadY ) ); |
| |
| { |
| SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemEllipse, sal_True, sal_True ); |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGActionWriter::ImplWritePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bLineOnly, |
| sal_Bool bApplyMapping ) |
| { |
| PolyPolygon aPolyPoly; |
| |
| if( bApplyMapping ) |
| ImplMap( rPolyPoly, aPolyPoly ); |
| else |
| aPolyPoly = rPolyPoly; |
| |
| if( mrExport.hasClip() ) |
| { |
| const ::basegfx::B2DPolyPolygon aB2DPolyPoly( ::basegfx::tools::correctOrientations( aPolyPoly.getB2DPolyPolygon() ) ); |
| |
| aPolyPoly = PolyPolygon( ::basegfx::tools::clipPolyPolygonOnPolyPolygon( |
| *mrExport.getCurClip(), aB2DPolyPoly, sal_False, sal_False ) ); |
| } |
| |
| // add path data attribute |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrD, GetPathString( aPolyPoly, bLineOnly ) ); |
| |
| { |
| // write polyline/polygon element |
| SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemPath, sal_True, sal_True ); |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGActionWriter::ImplWriteShape( const SVGShapeDescriptor& rShape, sal_Bool bApplyMapping ) |
| { |
| PolyPolygon aPolyPoly; |
| |
| if( bApplyMapping ) |
| ImplMap( rShape.maShapePolyPoly, aPolyPoly ); |
| else |
| aPolyPoly = rShape.maShapePolyPoly; |
| |
| const sal_Bool bLineOnly = ( rShape.maShapeFillColor == Color( COL_TRANSPARENT ) ) && ( !rShape.mapShapeGradient.get() ); |
| Rectangle aBoundRect( aPolyPoly.GetBoundRect() ); |
| |
| mpContext->AddPaintAttr( rShape.maShapeLineColor, rShape.maShapeFillColor, &aBoundRect, rShape.mapShapeGradient.get() ); |
| |
| if( rShape.maId.getLength() ) |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, rShape.maId ); |
| |
| if( rShape.mnStrokeWidth ) |
| { |
| sal_Int32 nStrokeWidth = ( bApplyMapping ? ImplMap( rShape.mnStrokeWidth ) : rShape.mnStrokeWidth ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeWidth, ::rtl::OUString::valueOf( nStrokeWidth ) ); |
| } |
| |
| // support for LineJoin |
| switch(rShape.maLineJoin) |
| { |
| default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE |
| case basegfx::B2DLINEJOIN_MITER: |
| { |
| // miter is Svg default, so no need to write until the exporter might write styles. |
| // If this happens, activate here |
| // mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, ::rtl::OUString::createFromAscii("miter")); |
| break; |
| } |
| case basegfx::B2DLINEJOIN_BEVEL: |
| { |
| mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, ::rtl::OUString::createFromAscii("bevel")); |
| break; |
| } |
| case basegfx::B2DLINEJOIN_ROUND: |
| { |
| mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, ::rtl::OUString::createFromAscii("round")); |
| break; |
| } |
| } |
| |
| // support for LineCap |
| switch(rShape.maLineCap) |
| { |
| default: /* com::sun::star::drawing::LineCap_BUTT */ |
| { |
| // butt is Svg default, so no need to write until the exporter might write styles. |
| // If this happens, activate here |
| // mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, ::rtl::OUString::createFromAscii("butt")); |
| break; |
| } |
| case com::sun::star::drawing::LineCap_ROUND: |
| { |
| mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, ::rtl::OUString::createFromAscii("round")); |
| break; |
| } |
| case com::sun::star::drawing::LineCap_SQUARE: |
| { |
| mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, ::rtl::OUString::createFromAscii("square")); |
| break; |
| } |
| } |
| |
| if( rShape.maDashArray.size() ) |
| { |
| const ::rtl::OUString aComma( B2UCONST( "," ) ); |
| ::rtl::OUString aDashArrayStr; |
| |
| for( unsigned int k = 0; k < rShape.maDashArray.size(); ++k ) |
| { |
| const sal_Int32 nDash = ( bApplyMapping ? |
| ImplMap( FRound( rShape.maDashArray[ k ] ) ) : |
| FRound( rShape.maDashArray[ k ] ) ); |
| |
| if( k ) |
| aDashArrayStr += aComma; |
| |
| aDashArrayStr += ::rtl::OUString::valueOf( nDash ); |
| } |
| |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeDashArray, aDashArrayStr ); |
| } |
| |
| ImplWritePolyPolygon( aPolyPoly, bLineOnly, sal_False ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGActionWriter::ImplWriteGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient, |
| sal_uInt32 nWriteFlags, sal_Bool bApplyMapping ) |
| { |
| PolyPolygon aPolyPoly; |
| |
| if( bApplyMapping ) |
| ImplMap( rPolyPoly, aPolyPoly ); |
| else |
| aPolyPoly = rPolyPoly; |
| |
| if( rGradient.GetStyle() == GRADIENT_LINEAR || rGradient.GetStyle() == GRADIENT_AXIAL || |
| rGradient.GetStyle() == GRADIENT_RADIAL || rGradient.GetStyle() == GRADIENT_ELLIPTICAL ) |
| { |
| SVGShapeDescriptor aShapeDesc; |
| |
| aShapeDesc.maShapePolyPoly = aPolyPoly; |
| aShapeDesc.mapShapeGradient.reset( new Gradient( rGradient ) ); |
| |
| ImplWriteShape( aShapeDesc, sal_False ); |
| } |
| else |
| { |
| GDIMetaFile aTmpMtf; |
| |
| mrExport.pushClip( aPolyPoly.getB2DPolyPolygon() ); |
| mpVDev->AddGradientActions( rPolyPoly.GetBoundRect(), rGradient, aTmpMtf ); |
| ++mnInnerMtfCount; |
| |
| ImplWriteActions( aTmpMtf, nWriteFlags, NULL ); |
| |
| --mnInnerMtfCount; |
| mrExport.popClip(); |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGActionWriter::ImplWriteText( const Point& rPos, const String& rText, |
| const sal_Int32* pDXArray, long nWidth, |
| sal_Bool bApplyMapping ) |
| { |
| sal_Int32 nLen = rText.Len(), i; |
| Size aNormSize; |
| ::std::auto_ptr< sal_Int32 > apTmpArray; |
| ::std::auto_ptr< SvXMLElementExport > apTransform; |
| sal_Int32* pDX; |
| Point aPos; |
| Point aBaseLinePos( rPos ); |
| const FontMetric aMetric( mpVDev->GetFontMetric() ); |
| const Font& rFont = mpVDev->GetFont(); |
| |
| if( rFont.GetAlign() == ALIGN_TOP ) |
| aBaseLinePos.Y() += aMetric.GetAscent(); |
| else if( rFont.GetAlign() == ALIGN_BOTTOM ) |
| aBaseLinePos.Y() -= aMetric.GetDescent(); |
| |
| if( bApplyMapping ) |
| ImplMap( rPos, aPos ); |
| else |
| aPos = rPos; |
| |
| // get text sizes |
| if( pDXArray ) |
| { |
| aNormSize = Size( mpVDev->GetTextWidth( rText ), 0 ); |
| pDX = const_cast< sal_Int32* >( pDXArray ); |
| } |
| else |
| { |
| apTmpArray.reset( new sal_Int32[ nLen ] ); |
| aNormSize = Size( mpVDev->GetTextArray( rText, apTmpArray.get() ), 0 ); |
| pDX = apTmpArray.get(); |
| } |
| |
| // if text is rotated, set transform matrix at new g element |
| if( rFont.GetOrientation() ) |
| { |
| Point aRot( aPos ); |
| String aTransform; |
| |
| aTransform = String( ::rtl::OUString::createFromAscii( "translate" ) ); |
| aTransform += '('; |
| aTransform += String( ::rtl::OUString::valueOf( aRot.X() ) ); |
| aTransform += ','; |
| aTransform += String( ::rtl::OUString::valueOf( aRot.Y() ) ); |
| aTransform += ')'; |
| |
| aTransform += String( ::rtl::OUString::createFromAscii( " rotate" ) ); |
| aTransform += '('; |
| aTransform += String( ::rtl::OUString::valueOf( rFont.GetOrientation() * -0.1 ) ); |
| aTransform += ')'; |
| |
| aTransform += String( ::rtl::OUString::createFromAscii( " translate" ) ); |
| aTransform += '('; |
| aTransform += String( ::rtl::OUString::valueOf( -aRot.X() ) ); |
| aTransform += ','; |
| aTransform += String( ::rtl::OUString::valueOf( -aRot.Y() ) ); |
| aTransform += ')'; |
| |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform, aTransform ); |
| apTransform.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemG, sal_True, sal_True ) ); |
| } |
| |
| if( nLen > 1 ) |
| { |
| ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xBI( ::vcl::unohelper::CreateBreakIterator() ); |
| const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetLocale(); |
| sal_Int32 nCurPos = 0, nLastPos = 0, nX = aPos.X(); |
| |
| if ( mrExport.IsUseTSpans() ) |
| { |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, ::rtl::OUString::valueOf( aPos.X() ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( aPos.Y() ) ); |
| SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, sal_False ); |
| { |
| rtl::OUString aString; |
| for( sal_Bool bCont = sal_True; bCont; ) |
| { |
| sal_Int32 nCount = 1; |
| const ::rtl::OUString aSpace( ' ' ); |
| |
| nLastPos = nCurPos; |
| nCurPos = xBI->nextCharacters( rText, nCurPos, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount ); |
| nCount = nCurPos - nLastPos; |
| bCont = ( nCurPos < rText.Len() ) && nCount; |
| |
| if( nCount ) |
| { |
| aString += rtl::OUString::valueOf( nX ); |
| if( bCont ) |
| { |
| sal_Int32 nWidth = pDX[ nCurPos - 1 ]; |
| if ( bApplyMapping ) |
| nWidth = ImplMap( nWidth ); |
| nX = aPos.X() + nWidth; |
| aString += aSpace; |
| } |
| } |
| } |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, aString ); |
| SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTSpan, sal_True, sal_False ); |
| mrExport.GetDocHandler()->characters( rText ); |
| } |
| } |
| else |
| { |
| aNormSize.Width() = pDX[ nLen - 2 ] + mpVDev->GetTextWidth( rText.GetChar( nLen - 1 ) ); |
| |
| if( nWidth && aNormSize.Width() && ( nWidth != aNormSize.Width() ) ) |
| { |
| const double fFactor = (double) nWidth / aNormSize.Width(); |
| |
| for( i = 0; i < ( nLen - 1 ); i++ ) |
| pDX[ i ] = FRound( pDX[ i ] * fFactor ); |
| } |
| else |
| { |
| // write single glyphs at absolute text positions |
| for( sal_Bool bCont = sal_True; bCont; ) |
| { |
| sal_Int32 nCount = 1; |
| |
| nLastPos = nCurPos; |
| nCurPos = xBI->nextCharacters( rText, nCurPos, rLocale, |
| ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, |
| nCount, nCount ); |
| |
| nCount = nCurPos - nLastPos; |
| bCont = ( nCurPos < rText.Len() ) && nCount; |
| |
| if( nCount ) |
| { |
| const ::rtl::OUString aGlyph( rText.Copy( nLastPos, nCount ) ); |
| |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, ::rtl::OUString::valueOf( nX ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( aPos.Y() ) ); |
| |
| { |
| SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, sal_False ); |
| mrExport.GetDocHandler()->characters( aGlyph ); |
| } |
| |
| if( bCont ) |
| { |
| // #118796# do NOT access pDXArray, it may be zero (!) |
| sal_Int32 nWidth = pDX[ nCurPos - 1 ]; |
| if ( bApplyMapping ) |
| nWidth = ImplMap( nWidth ); |
| nX = aPos.X() + nWidth; |
| } |
| } |
| } |
| } |
| } |
| } |
| else |
| { |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, ::rtl::OUString::valueOf( aPos.X() ) ); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, ::rtl::OUString::valueOf( aPos.Y() ) ); |
| |
| { |
| SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, sal_True, sal_False ); |
| mrExport.GetDocHandler()->characters( rText ); |
| } |
| } |
| |
| if( !mrExport.IsUseNativeTextDecoration() ) |
| { |
| if( rFont.GetStrikeout() != STRIKEOUT_NONE || rFont.GetUnderline() != UNDERLINE_NONE ) |
| { |
| Polygon aPoly( 4 ); |
| const long nLineHeight = Max( (long) FRound( aMetric.GetLineHeight() * 0.05 ), (long) 1 ); |
| |
| if( rFont.GetStrikeout() ) |
| { |
| const long nYLinePos = aBaseLinePos.Y() - FRound( aMetric.GetAscent() * 0.26 ); |
| |
| aPoly[ 0 ].X() = aBaseLinePos.X(); aPoly[ 0 ].Y() = nYLinePos - ( nLineHeight >> 1 ); |
| aPoly[ 1 ].X() = aBaseLinePos.X() + aNormSize.Width() - 1; aPoly[ 1 ].Y() = aPoly[ 0 ].Y(); |
| aPoly[ 2 ].X() = aPoly[ 1 ].X(); aPoly[ 2 ].Y() = aPoly[ 0 ].Y() + nLineHeight - 1; |
| aPoly[ 3 ].X() = aPoly[ 0 ].X(); aPoly[ 3 ].Y() = aPoly[ 2 ].Y(); |
| |
| ImplWritePolyPolygon( aPoly, sal_False ); |
| } |
| |
| if( rFont.GetUnderline() ) |
| { |
| const long nYLinePos = aBaseLinePos.Y() + ( nLineHeight << 1 ); |
| |
| aPoly[ 0 ].X() = aBaseLinePos.X(); aPoly[ 0 ].Y() = nYLinePos - ( nLineHeight >> 1 ); |
| aPoly[ 1 ].X() = aBaseLinePos.X() + aNormSize.Width() - 1; aPoly[ 1 ].Y() = aPoly[ 0 ].Y(); |
| aPoly[ 2 ].X() = aPoly[ 1 ].X(); aPoly[ 2 ].Y() = aPoly[ 0 ].Y() + nLineHeight - 1; |
| aPoly[ 3 ].X() = aPoly[ 0 ].X(); aPoly[ 3 ].Y() = aPoly[ 2 ].Y(); |
| |
| ImplWritePolyPolygon( aPoly, sal_False ); |
| } |
| } |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGActionWriter::ImplWriteBmp( const BitmapEx& rBmpEx, |
| const Point& rPt, const Size& rSz, |
| const Point& rSrcPt, const Size& rSrcSz, |
| sal_Bool bApplyMapping ) |
| { |
| if( !!rBmpEx ) |
| { |
| BitmapEx aBmpEx( rBmpEx ); |
| Point aPoint = Point(); |
| const Rectangle aBmpRect( aPoint, rBmpEx.GetSizePixel() ); |
| const Rectangle aSrcRect( rSrcPt, rSrcSz ); |
| |
| if( aSrcRect != aBmpRect ) |
| aBmpEx.Crop( aSrcRect ); |
| |
| if( !!aBmpEx ) |
| { |
| SvMemoryStream aOStm( 65535, 65535 ); |
| |
| if( GraphicConverter::Export( aOStm, rBmpEx, CVT_PNG ) == ERRCODE_NONE ) |
| { |
| Point aPt; |
| Size aSz; |
| |
| // #119735# Do not copy the stream data to a ::rtl::OUString any longer, this is not needed and |
| // (of course) throws many exceptions with the used RTL_TEXTENCODING_ASCII_US. Keeping that line |
| // to show what I'm talking about |
| // ::rtl::OUString aImageData( (sal_Char*) aOStm.GetData(), aOStm.Tell(), RTL_TEXTENCODING_ASCII_US ); |
| const sal_Char* pImageData = (sal_Char*)aOStm.GetData(); |
| const sal_uInt32 nImageDataLength = aOStm.Tell(); |
| REF( NMSP_SAX::XExtendedDocumentHandler ) xExtDocHandler( mrExport.GetDocHandler(), NMSP_UNO::UNO_QUERY ); |
| |
| if( bApplyMapping ) |
| { |
| ImplMap( rPt, aPt ); |
| ImplMap( rSz, aSz ); |
| } |
| else |
| { |
| aPt = rPt; |
| aSz = rSz; |
| } |
| const Rectangle aRect( aPt, aSz ); |
| if( mrExport.IsVisible( aRect ) && xExtDocHandler.is() ) |
| { |
| static const sal_uInt32 nPartLen = 64; |
| const ::rtl::OUString aSpace( ' ' ); |
| const ::rtl::OUString aLineFeed( ::rtl::OUString::valueOf( (sal_Unicode) 0x0a ) ); |
| ::rtl::OUString aString; |
| |
| aString = aLineFeed; |
| aString += B2UCONST( "<" ); |
| aString += ::rtl::OUString::createFromAscii( aXMLElemImage ); |
| aString += aSpace; |
| |
| aString += ::rtl::OUString::createFromAscii( aXMLAttrX ); |
| aString += B2UCONST( "=\"" ); |
| aString += ::rtl::OUString::valueOf( aPt.X() ); |
| aString += B2UCONST( "\" " ); |
| |
| aString += ::rtl::OUString::createFromAscii( aXMLAttrY ); |
| aString += B2UCONST( "=\"" ); |
| aString += ::rtl::OUString::valueOf( aPt.Y() ); |
| aString += B2UCONST( "\" " ); |
| |
| aString += ::rtl::OUString::createFromAscii( aXMLAttrWidth ); |
| aString += B2UCONST( "=\"" ); |
| aString += ::rtl::OUString::valueOf( aSz.Width() ); |
| aString += B2UCONST( "\" " ); |
| |
| aString += ::rtl::OUString::createFromAscii( aXMLAttrHeight ); |
| aString += B2UCONST( "=\"" ); |
| aString += ::rtl::OUString::valueOf( aSz.Height() ); |
| aString += B2UCONST( "\" " ); |
| |
| aString += ::rtl::OUString::createFromAscii( aXMLAttrXLinkHRef ); |
| aString += B2UCONST( "=\"data:image/png;base64," ); |
| |
| xExtDocHandler->unknown( aString ); |
| |
| // #119735# |
| const sal_uInt32 nQuadCount = nImageDataLength / 3; |
| const sal_uInt32 nRest = nImageDataLength % 3; |
| |
| if( nQuadCount || nRest ) |
| { |
| sal_Int32 nBufLen = ( ( nQuadCount + ( nRest ? 1 : 0 ) ) << 2 ); |
| const sal_Char* pSrc = pImageData; |
| |
| sal_Unicode* pBuffer = new sal_Unicode[ nBufLen * sizeof( sal_Unicode ) ]; |
| sal_Unicode* pTmpDst = pBuffer; |
| |
| for( sal_uInt32 i = 0; i < nQuadCount; ++i ) |
| { |
| const sal_Int32 nA = *pSrc++; |
| const sal_Int32 nB = *pSrc++; |
| const sal_Int32 nC = *pSrc++; |
| |
| *pTmpDst++ = pBase64[ ( nA >> 2 ) & 0x3f ]; |
| *pTmpDst++ = pBase64[ ( ( nA << 4 ) & 0x30 ) + ( ( nB >> 4 ) & 0xf ) ]; |
| *pTmpDst++ = pBase64[ ( ( nB << 2 ) & 0x3c ) + ( ( nC >> 6 ) & 0x3 ) ]; |
| *pTmpDst++ = pBase64[ nC & 0x3f ]; |
| } |
| |
| if( nRest ) |
| { |
| const sal_Int32 nA = *pSrc++; |
| |
| *pTmpDst++ = pBase64[ ( nA >> 2 ) & 0x3f ]; |
| |
| if( 2 == nRest ) |
| { |
| const sal_Int32 nB = *pSrc; |
| |
| *pTmpDst++ = pBase64[ ( ( nA << 4 ) & 0x30 ) + ( ( nB >> 4 ) & 0xf ) ]; |
| *pTmpDst++ = pBase64[ ( nB << 2 ) & 0x3c ]; |
| } |
| else |
| { |
| *pTmpDst++ = pBase64[ ( nA << 4 ) & 0x30 ]; |
| *pTmpDst++ = '='; |
| } |
| |
| *pTmpDst = '='; |
| } |
| |
| for( sal_Int32 nCurPos = 0; nCurPos < nBufLen; nCurPos += nPartLen ) |
| { |
| const ::rtl::OUString aPart( pBuffer + nCurPos, ::std::min< sal_Int32 >( nPartLen, nBufLen - nCurPos ) ); |
| |
| xExtDocHandler->unknown( aLineFeed ); |
| xExtDocHandler->unknown( aPart ); |
| } |
| |
| delete[] pBuffer; |
| } |
| |
| xExtDocHandler->unknown( B2UCONST( "\"/>" ) ); |
| } |
| } |
| } |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf, |
| sal_uInt32 nWriteFlags, |
| const ::rtl::OUString* pElementId ) |
| { |
| // need a counter fo rthe actions written per shape to avoid double ID |
| // generation |
| sal_Int32 nEntryCount(0); |
| |
| if( mnInnerMtfCount ) |
| nWriteFlags |= SVGWRITER_NO_SHAPE_COMMENTS; |
| |
| for( sal_uLong nCurAction = 0, nCount = rMtf.GetActionCount(); nCurAction < nCount; nCurAction++ ) |
| { |
| const MetaAction* pAction = rMtf.GetAction( nCurAction ); |
| const sal_uInt16 nType = pAction->GetType(); |
| |
| switch( nType ) |
| { |
| case( META_PIXEL_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaPixelAction* pA = (const MetaPixelAction*) pAction; |
| |
| mpContext->AddPaintAttr( pA->GetColor(), pA->GetColor() ); |
| ImplWriteLine( pA->GetPoint(), pA->GetPoint(), &pA->GetColor() ); |
| } |
| } |
| break; |
| |
| case( META_POINT_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaPointAction* pA = (const MetaPointAction*) pAction; |
| |
| mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetLineColor() ); |
| ImplWriteLine( pA->GetPoint(), pA->GetPoint(), NULL ); |
| } |
| } |
| break; |
| |
| case( META_LINE_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaLineAction* pA = (const MetaLineAction*) pAction; |
| |
| mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetLineColor() ); |
| ImplWriteLine( pA->GetStartPoint(), pA->GetEndPoint(), NULL ); |
| } |
| } |
| break; |
| |
| case( META_RECT_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() ); |
| ImplWriteRect( ( (const MetaRectAction*) pAction )->GetRect(), 0, 0 ); |
| } |
| } |
| break; |
| |
| case( META_ROUNDRECT_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pAction; |
| |
| mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() ); |
| ImplWriteRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() ); |
| } |
| } |
| break; |
| |
| case( META_ELLIPSE_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaEllipseAction* pA = (const MetaEllipseAction*) pAction; |
| const Rectangle& rRect = pA->GetRect(); |
| |
| mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() ); |
| ImplWriteEllipse( rRect.Center(), rRect.GetWidth() >> 1, rRect.GetHeight() >> 1 ); |
| } |
| } |
| break; |
| |
| case( META_ARC_ACTION ): |
| case( META_PIE_ACTION ): |
| case( META_CHORD_ACTION ): |
| case( META_POLYGON_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| Polygon aPoly; |
| |
| switch( nType ) |
| { |
| case( META_ARC_ACTION ): |
| { |
| const MetaArcAction* pA = (const MetaArcAction*) pAction; |
| aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC ); |
| } |
| break; |
| |
| case( META_PIE_ACTION ): |
| { |
| const MetaPieAction* pA = (const MetaPieAction*) pAction; |
| aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE ); |
| } |
| break; |
| |
| case( META_CHORD_ACTION ): |
| { |
| const MetaChordAction* pA = (const MetaChordAction*) pAction; |
| aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD ); |
| } |
| break; |
| |
| case( META_POLYGON_ACTION ): |
| aPoly = ( (const MetaPolygonAction*) pAction )->GetPolygon(); |
| break; |
| } |
| |
| if( aPoly.GetSize() ) |
| { |
| mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() ); |
| ImplWritePolyPolygon( aPoly, sal_False ); |
| } |
| } |
| } |
| break; |
| |
| case( META_POLYLINE_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pAction; |
| const Polygon& rPoly = pA->GetPolygon(); |
| |
| if( rPoly.GetSize() ) |
| { |
| const LineInfo& rLineInfo = pA->GetLineInfo(); |
| |
| if(rLineInfo.GetWidth()) |
| { |
| sal_Int32 nStrokeWidth = ImplMap(rLineInfo.GetWidth()); |
| mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeWidth, ::rtl::OUString::valueOf( nStrokeWidth ) ); |
| } |
| |
| mpContext->AddPaintAttr( mpVDev->GetLineColor(), Color( COL_TRANSPARENT ) ); |
| ImplWritePolyPolygon( rPoly, sal_True ); |
| } |
| } |
| } |
| break; |
| |
| case( META_POLYPOLYGON_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*) pAction; |
| const PolyPolygon& rPolyPoly = pA->GetPolyPolygon(); |
| |
| if( rPolyPoly.Count() ) |
| { |
| mpContext->AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() ); |
| ImplWritePolyPolygon( rPolyPoly, sal_False ); |
| } |
| } |
| } |
| break; |
| |
| case( META_GRADIENT_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaGradientAction* pA = (const MetaGradientAction*) pAction; |
| const Polygon aRectPoly( pA->GetRect() ); |
| const PolyPolygon aRectPolyPoly( aRectPoly ); |
| |
| ImplWriteGradientEx( aRectPolyPoly, pA->GetGradient(), nWriteFlags ); |
| } |
| } |
| break; |
| |
| case( META_GRADIENTEX_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaGradientExAction* pA = (const MetaGradientExAction*) pAction; |
| ImplWriteGradientEx( pA->GetPolyPolygon(), pA->GetGradient(), nWriteFlags ); |
| } |
| } |
| break; |
| |
| case META_HATCH_ACTION: |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaHatchAction* pA = (const MetaHatchAction*) pAction; |
| GDIMetaFile aTmpMtf; |
| |
| mpVDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf ); |
| |
| ++mnInnerMtfCount; |
| |
| ImplWriteActions( aTmpMtf, nWriteFlags, NULL ); |
| |
| --mnInnerMtfCount; |
| } |
| } |
| break; |
| |
| case( META_TRANSPARENT_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaTransparentAction* pA = (const MetaTransparentAction*) pAction; |
| const PolyPolygon& rPolyPoly = pA->GetPolyPolygon(); |
| |
| if( rPolyPoly.Count() ) |
| { |
| Color aNewLineColor( mpVDev->GetLineColor() ), aNewFillColor( mpVDev->GetFillColor() ); |
| |
| aNewLineColor.SetTransparency( sal::static_int_cast<sal_uInt8>( FRound( pA->GetTransparence() * 2.55 ) ) ); |
| aNewFillColor.SetTransparency( sal::static_int_cast<sal_uInt8>( FRound( pA->GetTransparence() * 2.55 ) ) ); |
| |
| mpContext->AddPaintAttr( aNewLineColor, aNewFillColor ); |
| ImplWritePolyPolygon( rPolyPoly, sal_False ); |
| } |
| } |
| } |
| break; |
| |
| case( META_FLOATTRANSPARENT_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pAction; |
| GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() ); |
| Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() ); |
| const Size aSrcSize( aTmpMtf.GetPrefSize() ); |
| const Point aDestPt( pA->GetPoint() ); |
| const Size aDestSize( pA->GetSize() ); |
| const double fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0; |
| const double fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0; |
| long nMoveX, nMoveY; |
| |
| if( fScaleX != 1.0 || fScaleY != 1.0 ) |
| { |
| aTmpMtf.Scale( fScaleX, fScaleY ); |
| aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY ); |
| } |
| |
| nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y(); |
| |
| if( nMoveX || nMoveY ) |
| aTmpMtf.Move( nMoveX, nMoveY ); |
| |
| mpVDev->Push(); |
| ++mnInnerMtfCount; |
| |
| ImplWriteActions( aTmpMtf, nWriteFlags, NULL ); |
| |
| --mnInnerMtfCount; |
| mpVDev->Pop(); |
| } |
| } |
| break; |
| |
| case( META_EPS_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaEPSAction* pA = (const MetaEPSAction*) pAction; |
| const GDIMetaFile aGDIMetaFile( pA->GetSubstitute() ); |
| sal_Bool bFound = sal_False; |
| |
| for( sal_uInt32 k = 0, nCount2 = aGDIMetaFile.GetActionCount(); ( k < nCount2 ) && !bFound; ++k ) |
| { |
| const MetaAction* pSubstAct = aGDIMetaFile.GetAction( k ); |
| |
| if( pSubstAct->GetType() == META_BMPSCALE_ACTION ) |
| { |
| bFound = sal_True; |
| const MetaBmpScaleAction* pBmpScaleAction = (const MetaBmpScaleAction*) pSubstAct; |
| ImplWriteBmp( pBmpScaleAction->GetBitmap(), |
| pA->GetPoint(), pA->GetSize(), |
| Point(), pBmpScaleAction->GetBitmap().GetSizePixel() ); |
| } |
| } |
| } |
| } |
| break; |
| |
| case( META_COMMENT_ACTION ): |
| { |
| const MetaCommentAction* pA = (const MetaCommentAction*) pAction; |
| String aSkipComment; |
| |
| if( ( pA->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL ) && |
| ( nWriteFlags & SVGWRITER_WRITE_FILL ) ) |
| { |
| const MetaGradientExAction* pGradAction = NULL; |
| sal_Bool bDone = sal_False; |
| |
| while( !bDone && ( ++nCurAction < nCount ) ) |
| { |
| pAction = rMtf.GetAction( nCurAction ); |
| |
| if( pAction->GetType() == META_GRADIENTEX_ACTION ) |
| pGradAction = (const MetaGradientExAction*) pAction; |
| else if( ( pAction->GetType() == META_COMMENT_ACTION ) && |
| ( ( (const MetaCommentAction*) pAction )->GetComment(). |
| CompareIgnoreCaseToAscii( "XGRAD_SEQ_END" ) == COMPARE_EQUAL ) ) |
| { |
| bDone = sal_True; |
| } |
| } |
| |
| if( pGradAction ) |
| ImplWriteGradientEx( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), nWriteFlags ); |
| } |
| else if( ( pA->GetComment().CompareIgnoreCaseToAscii( "XPATHFILL_SEQ_BEGIN" ) == COMPARE_EQUAL ) && |
| ( nWriteFlags & SVGWRITER_WRITE_FILL ) && !( nWriteFlags & SVGWRITER_NO_SHAPE_COMMENTS ) && |
| pA->GetDataSize() ) |
| { |
| // write open shape in every case |
| if( mapCurShape.get() ) |
| { |
| ImplWriteShape( *mapCurShape ); |
| mapCurShape.reset(); |
| } |
| |
| SvMemoryStream aMemStm( (void*) pA->GetData(), pA->GetDataSize(), STREAM_READ ); |
| SvtGraphicFill aFill; |
| |
| aMemStm >> aFill; |
| |
| sal_Bool bGradient = SvtGraphicFill::fillGradient == aFill.getFillType() && |
| ( SvtGraphicFill::gradientLinear == aFill.getGradientType() || |
| SvtGraphicFill::gradientRadial == aFill.getGradientType() ); |
| sal_Bool bSkip = ( SvtGraphicFill::fillSolid == aFill.getFillType() || bGradient ); |
| |
| if( bSkip ) |
| { |
| PolyPolygon aShapePolyPoly; |
| |
| aFill.getPath( aShapePolyPoly ); |
| |
| if( aShapePolyPoly.Count() ) |
| { |
| mapCurShape.reset( new SVGShapeDescriptor ); |
| |
| if( pElementId ) |
| { |
| mapCurShape->maId = *pElementId + B2UCONST("_") + ::rtl::OUString::valueOf(nEntryCount++); |
| } |
| |
| mapCurShape->maShapePolyPoly = aShapePolyPoly; |
| mapCurShape->maShapeFillColor = aFill.getFillColor(); |
| mapCurShape->maShapeFillColor.SetTransparency( (sal_uInt8) FRound( 255.0 * aFill.getTransparency() ) ); |
| |
| if( bGradient ) |
| { |
| // step through following actions until the first Gradient/GradientEx action is found |
| while( !mapCurShape->mapShapeGradient.get() && bSkip && ( ++nCurAction < nCount ) ) |
| { |
| pAction = rMtf.GetAction( nCurAction ); |
| |
| if( ( pAction->GetType() == META_COMMENT_ACTION ) && |
| ( ( (const MetaCommentAction*) pAction )->GetComment(). |
| CompareIgnoreCaseToAscii( "XPATHFILL_SEQ_END" ) == COMPARE_EQUAL ) ) |
| { |
| bSkip = sal_False; |
| } |
| else if( pAction->GetType() == META_GRADIENTEX_ACTION ) |
| { |
| mapCurShape->mapShapeGradient.reset( new Gradient( |
| static_cast< const MetaGradientExAction* >( pAction )->GetGradient() ) ); |
| } |
| else if( pAction->GetType() == META_GRADIENT_ACTION ) |
| { |
| mapCurShape->mapShapeGradient.reset( new Gradient( |
| static_cast< const MetaGradientAction* >( pAction )->GetGradient() ) ); |
| } |
| } |
| } |
| } |
| else |
| bSkip = sal_False; |
| } |
| |
| // skip rest of comment |
| while( bSkip && ( ++nCurAction < nCount ) ) |
| { |
| pAction = rMtf.GetAction( nCurAction ); |
| |
| if( ( pAction->GetType() == META_COMMENT_ACTION ) && |
| ( ( (const MetaCommentAction*) pAction )->GetComment(). |
| CompareIgnoreCaseToAscii( "XPATHFILL_SEQ_END" ) == COMPARE_EQUAL ) ) |
| { |
| bSkip = sal_False; |
| } |
| } |
| } |
| else if( ( pA->GetComment().CompareIgnoreCaseToAscii( "XPATHSTROKE_SEQ_BEGIN" ) == COMPARE_EQUAL ) && |
| ( nWriteFlags & SVGWRITER_WRITE_FILL ) && !( nWriteFlags & SVGWRITER_NO_SHAPE_COMMENTS ) && |
| pA->GetDataSize() ) |
| { |
| SvMemoryStream aMemStm( (void*) pA->GetData(), pA->GetDataSize(), STREAM_READ ); |
| SvtGraphicStroke aStroke; |
| PolyPolygon aStartArrow, aEndArrow; |
| |
| aMemStm >> aStroke; |
| aStroke.getStartArrow( aStartArrow ); |
| aStroke.getEndArrow( aEndArrow ); |
| |
| // Currently no support for strokes with start/end arrow(s) |
| // added that support |
| Polygon aPoly; |
| |
| aStroke.getPath(aPoly); |
| |
| if(mapCurShape.get()) |
| { |
| if(1 != mapCurShape->maShapePolyPoly.Count() |
| || !mapCurShape->maShapePolyPoly[0].IsEqual(aPoly)) |
| { |
| // this path action is not covering the same path than the already existing |
| // fill polypolygon, so write out the fill polygon |
| ImplWriteShape( *mapCurShape ); |
| mapCurShape.reset(); |
| } |
| } |
| |
| if( !mapCurShape.get() ) |
| { |
| |
| mapCurShape.reset( new SVGShapeDescriptor ); |
| |
| if( pElementId ) |
| { |
| mapCurShape->maId = *pElementId + B2UCONST("_") + ::rtl::OUString::valueOf(nEntryCount++); |
| } |
| |
| mapCurShape->maShapePolyPoly = aPoly; |
| } |
| |
| mapCurShape->maShapeLineColor = mpVDev->GetLineColor(); |
| mapCurShape->maShapeLineColor.SetTransparency( (sal_uInt8) FRound( aStroke.getTransparency() * 255.0 ) ); |
| mapCurShape->mnStrokeWidth = FRound( aStroke.getStrokeWidth() ); |
| aStroke.getDashArray( mapCurShape->maDashArray ); |
| |
| // added support for LineJoin |
| switch(aStroke.getJoinType()) |
| { |
| default: /* SvtGraphicStroke::joinMiter, SvtGraphicStroke::joinNone */ |
| { |
| mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_MITER; |
| break; |
| } |
| case SvtGraphicStroke::joinRound: |
| { |
| mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_ROUND; |
| break; |
| } |
| case SvtGraphicStroke::joinBevel: |
| { |
| mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_BEVEL; |
| break; |
| } |
| } |
| |
| // added support for LineCap |
| switch(aStroke.getCapType()) |
| { |
| default: /* SvtGraphicStroke::capButt */ |
| { |
| mapCurShape->maLineCap = com::sun::star::drawing::LineCap_BUTT; |
| break; |
| } |
| case SvtGraphicStroke::capRound: |
| { |
| mapCurShape->maLineCap = com::sun::star::drawing::LineCap_ROUND; |
| break; |
| } |
| case SvtGraphicStroke::capSquare: |
| { |
| mapCurShape->maLineCap = com::sun::star::drawing::LineCap_SQUARE; |
| break; |
| } |
| } |
| |
| if(mapCurShape.get() &&(aStartArrow.Count() || aEndArrow.Count())) |
| { |
| ImplWriteShape( *mapCurShape ); |
| |
| mapCurShape->maShapeFillColor = mapCurShape->maShapeLineColor; |
| mapCurShape->maShapeLineColor = Color(COL_TRANSPARENT); |
| mapCurShape->mnStrokeWidth = 0; |
| mapCurShape->maDashArray.clear(); |
| mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_MITER; |
| mapCurShape->maLineCap = com::sun::star::drawing::LineCap_BUTT; |
| |
| if(aStartArrow.Count()) |
| { |
| mapCurShape->maShapePolyPoly = aStartArrow; |
| |
| if( pElementId ) // #i124825# pElementId is optinal, may be zero |
| { |
| mapCurShape->maId = *pElementId + B2UCONST("_") + ::rtl::OUString::valueOf(nEntryCount++); |
| } |
| |
| ImplWriteShape( *mapCurShape ); |
| } |
| |
| if(aEndArrow.Count()) |
| { |
| mapCurShape->maShapePolyPoly = aEndArrow; |
| |
| if( pElementId ) // #i124825# pElementId is optinal, may be zero |
| { |
| mapCurShape->maId = *pElementId + B2UCONST("_") + ::rtl::OUString::valueOf(nEntryCount++); |
| } |
| |
| ImplWriteShape( *mapCurShape ); |
| } |
| |
| mapCurShape.reset(); |
| } |
| |
| // write open shape in every case |
| if( mapCurShape.get() ) |
| { |
| ImplWriteShape( *mapCurShape ); |
| mapCurShape.reset(); |
| } |
| |
| // skip rest of comment |
| sal_Bool bSkip = true; |
| |
| while( bSkip && ( ++nCurAction < nCount ) ) |
| { |
| pAction = rMtf.GetAction( nCurAction ); |
| |
| if( ( pAction->GetType() == META_COMMENT_ACTION ) && |
| ( ( (const MetaCommentAction*) pAction )->GetComment(). |
| CompareIgnoreCaseToAscii( "XPATHSTROKE_SEQ_END" ) == COMPARE_EQUAL ) ) |
| { |
| bSkip = sal_False; |
| } |
| } |
| } |
| } |
| break; |
| |
| case( META_BMP_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaBmpAction* pA = (const MetaBmpAction*) pAction; |
| |
| ImplWriteBmp( pA->GetBitmap(), |
| pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmap().GetSizePixel() ), |
| Point(), pA->GetBitmap().GetSizePixel() ); |
| } |
| } |
| break; |
| |
| case( META_BMPSCALE_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction; |
| |
| ImplWriteBmp( pA->GetBitmap(), |
| pA->GetPoint(), pA->GetSize(), |
| Point(), pA->GetBitmap().GetSizePixel() ); |
| } |
| } |
| break; |
| |
| case( META_BMPSCALEPART_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pAction; |
| |
| ImplWriteBmp( pA->GetBitmap(), |
| pA->GetDestPoint(), pA->GetDestSize(), |
| pA->GetSrcPoint(), pA->GetSrcSize() ); |
| } |
| } |
| break; |
| |
| case( META_BMPEX_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaBmpExAction* pA = (const MetaBmpExAction*) pAction; |
| |
| ImplWriteBmp( pA->GetBitmapEx(), |
| pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmapEx().GetSizePixel() ), |
| Point(), pA->GetBitmapEx().GetSizePixel() ); |
| } |
| } |
| break; |
| |
| case( META_BMPEXSCALE_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction; |
| |
| ImplWriteBmp( pA->GetBitmapEx(), |
| pA->GetPoint(), pA->GetSize(), |
| Point(), pA->GetBitmapEx().GetSizePixel() ); |
| } |
| } |
| break; |
| |
| case( META_BMPEXSCALEPART_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_FILL ) |
| { |
| const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pAction; |
| |
| ImplWriteBmp( pA->GetBitmapEx(), |
| pA->GetDestPoint(), pA->GetDestSize(), |
| pA->GetSrcPoint(), pA->GetSrcSize() ); |
| } |
| } |
| break; |
| |
| case( META_TEXT_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_TEXT ) |
| { |
| const MetaTextAction* pA = (const MetaTextAction*) pAction; |
| const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() ); |
| |
| if( aText.Len() ) |
| { |
| Font aFont( mpVDev->GetFont() ); |
| Size aSz; |
| |
| ImplMap( Size( 0, aFont.GetHeight() ), aSz ); |
| |
| aFont.SetHeight( aSz.Height() ); |
| mpContext->AddPaintAttr( COL_TRANSPARENT, mpVDev->GetTextColor() ); |
| mpContext->SetFontAttr( aFont ); |
| ImplWriteText( pA->GetPoint(), aText, NULL, 0 ); |
| } |
| } |
| } |
| break; |
| |
| case( META_TEXTRECT_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_TEXT ) |
| { |
| const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction; |
| |
| if( pA->GetText().Len() ) |
| { |
| Font aFont( mpVDev->GetFont() ); |
| Size aSz; |
| |
| ImplMap( Size( 0, aFont.GetHeight() ), aSz ); |
| |
| aFont.SetHeight( aSz.Height() ); |
| mpContext->AddPaintAttr( COL_TRANSPARENT, mpVDev->GetTextColor() ); |
| mpContext->SetFontAttr( aFont ); |
| ImplWriteText( pA->GetRect().TopLeft(), pA->GetText(), NULL, 0 ); |
| } |
| } |
| } |
| break; |
| |
| case( META_TEXTARRAY_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_TEXT ) |
| { |
| const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pAction; |
| const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() ); |
| |
| if( aText.Len() ) |
| { |
| Font aFont( mpVDev->GetFont() ); |
| Size aSz; |
| |
| ImplMap( Size( 0, aFont.GetHeight() ), aSz ); |
| |
| aFont.SetHeight( aSz.Height() ); |
| mpContext->AddPaintAttr( COL_TRANSPARENT, mpVDev->GetTextColor() ); |
| mpContext->SetFontAttr( aFont ); |
| ImplWriteText( pA->GetPoint(), aText, pA->GetDXArray(), 0 ); |
| } |
| } |
| } |
| break; |
| |
| case( META_STRETCHTEXT_ACTION ): |
| { |
| if( nWriteFlags & SVGWRITER_WRITE_TEXT ) |
| { |
| const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction; |
| const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() ); |
| |
| if( aText.Len() ) |
| { |
| Font aFont( mpVDev->GetFont() ); |
| Size aSz; |
| |
| ImplMap( Size( 0, aFont.GetHeight() ), aSz ); |
| |
| aFont.SetHeight( aSz.Height() ); |
| mpContext->AddPaintAttr( COL_TRANSPARENT, mpVDev->GetTextColor() ); |
| mpContext->SetFontAttr( aFont ); |
| ImplWriteText( pA->GetPoint(), aText, NULL, pA->GetWidth() ); |
| } |
| } |
| } |
| break; |
| |
| case( META_CLIPREGION_ACTION ): |
| case( META_ISECTRECTCLIPREGION_ACTION ): |
| case( META_ISECTREGIONCLIPREGION_ACTION ): |
| case( META_MOVECLIPREGION_ACTION ): |
| { |
| ( (MetaAction*) pAction )->Execute( mpVDev ); |
| mbClipAttrChanged = sal_True; |
| } |
| break; |
| |
| case( META_REFPOINT_ACTION ): |
| case( META_MAPMODE_ACTION ): |
| case( META_LINECOLOR_ACTION ): |
| case( META_FILLCOLOR_ACTION ): |
| case( META_TEXTLINECOLOR_ACTION ): |
| case( META_TEXTFILLCOLOR_ACTION ): |
| case( META_TEXTCOLOR_ACTION ): |
| case( META_TEXTALIGN_ACTION ): |
| case( META_FONT_ACTION ): |
| case( META_PUSH_ACTION ): |
| case( META_POP_ACTION ): |
| case( META_LAYOUTMODE_ACTION ): |
| { |
| ( (MetaAction*) pAction )->Execute( mpVDev ); |
| } |
| break; |
| |
| case( META_RASTEROP_ACTION ): |
| case( META_MASK_ACTION ): |
| case( META_MASKSCALE_ACTION ): |
| case( META_MASKSCALEPART_ACTION ): |
| case( META_WALLPAPER_ACTION ): |
| case( META_TEXTLINE_ACTION ): |
| { |
| // !!! >>> we don't want to support these actions |
| } |
| break; |
| |
| default: |
| DBG_ERROR( "SVGActionWriter::ImplWriteActions: unsupported MetaAction #" ); |
| break; |
| } |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGActionWriter::WriteMetaFile( const Point& rPos100thmm, |
| const Size& rSize100thmm, |
| const GDIMetaFile& rMtf, |
| sal_uInt32 nWriteFlags, |
| const ::rtl::OUString* pElementId ) |
| { |
| MapMode aMapMode( rMtf.GetPrefMapMode() ); |
| Size aPrefSize( rMtf.GetPrefSize() ); |
| Fraction aFractionX( aMapMode.GetScaleX() ); |
| Fraction aFractionY( aMapMode.GetScaleY() ); |
| |
| mpVDev->Push(); |
| |
| Size aSize( OutputDevice::LogicToLogic( rSize100thmm, MAP_100TH_MM, aMapMode ) ); |
| aMapMode.SetScaleX( aFractionX *= Fraction( aSize.Width(), aPrefSize.Width() ) ); |
| aMapMode.SetScaleY( aFractionY *= Fraction( aSize.Height(), aPrefSize.Height() ) ); |
| |
| Point aOffset( OutputDevice::LogicToLogic( rPos100thmm, MAP_100TH_MM, aMapMode ) ); |
| aMapMode.SetOrigin( aOffset += aMapMode.GetOrigin() ); |
| |
| mpVDev->SetMapMode( aMapMode ); |
| ImplAcquireContext(); |
| |
| mapCurShape.reset(); |
| |
| ImplWriteActions( rMtf, nWriteFlags, pElementId ); |
| |
| // draw open shape that doesn't have a border |
| if( mapCurShape.get() ) |
| { |
| ImplWriteShape( *mapCurShape ); |
| mapCurShape.reset(); |
| } |
| |
| ImplReleaseContext(); |
| mpVDev->Pop(); |
| } |
| |
| // ------------- |
| // - SVGWriter - |
| // ------------- |
| |
| SVGWriter::SVGWriter( const REF( NMSP_LANG::XMultiServiceFactory )& rxMgr ) : |
| mxFact( rxMgr ) |
| { |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| SVGWriter::~SVGWriter() |
| { |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| |
| ANY SAL_CALL SVGWriter::queryInterface( const NMSP_UNO::Type & rType ) throw( NMSP_UNO::RuntimeException ) |
| { |
| const ANY aRet( NMSP_CPPU::queryInterface( rType, |
| static_cast< NMSP_SVG::XSVGWriter* >( this ), |
| static_cast< NMSP_LANG::XInitialization* >( this ) ) ); |
| return( aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ) ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SAL_CALL SVGWriter::acquire() throw() |
| { |
| OWeakObject::acquire(); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SAL_CALL SVGWriter::release() throw() |
| { |
| OWeakObject::release(); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SAL_CALL SVGWriter::write( const REF( NMSP_SAX::XDocumentHandler )& rxDocHandler, |
| const SEQ( sal_Int8 )& rMtfSeq ) throw( NMSP_UNO::RuntimeException ) |
| { |
| SvMemoryStream aMemStm( (char*) rMtfSeq.getConstArray(), rMtfSeq.getLength(), STREAM_READ ); |
| GDIMetaFile aMtf; |
| |
| aMemStm.SetCompressMode( COMPRESSMODE_FULL ); |
| aMemStm >> aMtf; |
| |
| const REF( NMSP_SAX::XDocumentHandler ) xDocumentHandler( rxDocHandler ); |
| SVGExport* pWriter = new SVGExport( mxFact, xDocumentHandler, maFilterData ); |
| |
| pWriter->writeMtf( aMtf ); |
| delete pWriter; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void SVGWriter::initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) |
| throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException) |
| { |
| if ( aArguments.getLength() == 1 ) |
| { |
| ::com::sun::star::uno::Any aArg = aArguments.getConstArray()[0]; |
| aArg >>= maFilterData; |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| #define SVG_WRITER_SERVICE_NAME "com.sun.star.svg.SVGWriter" |
| #define SVG_WRITER_IMPLEMENTATION_NAME "com.sun.star.comp.Draw.SVGWriter" |
| |
| rtl::OUString SVGWriter_getImplementationName() |
| throw (RuntimeException) |
| { |
| return rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM( SVG_WRITER_IMPLEMENTATION_NAME ) ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| Sequence< sal_Int8 > SAL_CALL SVGWriter_getImplementationId() |
| throw(RuntimeException) |
| { |
| static const ::cppu::OImplementationId aId; |
| |
| return( aId.getImplementationId() ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| Sequence< rtl::OUString > SAL_CALL SVGWriter_getSupportedServiceNames() |
| throw (RuntimeException) |
| { |
| Sequence< rtl::OUString > aRet( 1 ); |
| |
| aRet.getArray()[ 0 ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SVG_WRITER_SERVICE_NAME ) ); |
| |
| return aRet; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| Reference< XInterface > SAL_CALL SVGWriter_createInstance( const Reference< XMultiServiceFactory > & rSMgr ) |
| throw( Exception ) |
| { |
| return( static_cast< cppu::OWeakObject* >( new SVGWriter( rSMgr ) ) ); |
| } |