diff options
author | Regina Henschel <rb.henschel@t-online.de> | 2016-04-09 23:15:09 +0200 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@cib.de> | 2016-04-26 16:42:27 +0000 |
commit | 32cec4ca8bf1e09dd33aa461984e8e8ae34f4a7c (patch) | |
tree | 5591a63de12179505a0e7a4870632754585152d3 | |
parent | early bail out if nGlobalError, tdf#97831 follow-up (diff) | |
download | core-32cec4ca8bf1e09dd33aa461984e8e8ae34f4a7c.tar.gz core-32cec4ca8bf1e09dd33aa461984e8e8ae34f4a7c.zip |
tdf#48066 render stroke-miterlimit correctly in SVG import
The property stroke-miterlimit is transported to the renderers
via a new member mfMiterMinimumAngle in class LineAttribute
Several drawPolyLine methods are adapted. This patch does not
include changes in MetaAction. Presentation mode, printing, and
PDF-export is still wrong.
Corrected LineJoinMiter to LineJoinBevel in canvas, that s closer
to NONE. Removed DrawPolyLine method without MiterMinimumAngle
and adapted calls accordingly.
Change-Id: I6bcd24add5d85c4d9a39e3788e0682091c5fc9c4
Reviewed-on: https://gerrit.libreoffice.org/23946
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Armin Le Grand <Armin.Le.Grand@cib.de>
Reviewed-by: Regina Henschel <rb.henschel@t-online.de>
35 files changed, 214 insertions, 78 deletions
diff --git a/canvas/source/directx/dx_canvashelper.cxx b/canvas/source/directx/dx_canvashelper.cxx index be53b374f291..8ca63ecc4238 100644 --- a/canvas/source/directx/dx_canvashelper.cxx +++ b/canvas/source/directx/dx_canvashelper.cxx @@ -75,10 +75,13 @@ namespace dxcanvas switch( nJoinType ) { case rendering::PathJoinType::NONE: - SAL_WARN( "canvas.directx", "gdiJoinFromJoin(): Join NONE not possible, mapping to MITER" ); - // FALLTHROUGH intended + SAL_WARN( "canvas.directx", "gdiJoinFromJoin(): Join NONE not possible, mapping to BEVEL (closest to NONE)" ); + return Gdiplus::LineJoinBevel; + case rendering::PathJoinType::MITER: - return Gdiplus::LineJoinMiter; + // in GDI+ fallback to Bevel, if miter limit is exceeded, is not done + // by Gdiplus::LineJoinMiter but by Gdiplus::LineJoinMiterClipped + return Gdiplus::LineJoinMiterClipped; case rendering::PathJoinType::ROUND: return Gdiplus::LineJoinRound; diff --git a/canvas/source/vcl/canvashelper.cxx b/canvas/source/vcl/canvashelper.cxx index 82ee7704da22..b294b73503f3 100644 --- a/canvas/source/vcl/canvashelper.cxx +++ b/canvas/source/vcl/canvashelper.cxx @@ -390,8 +390,15 @@ namespace vclcanvas for( sal_uInt32 i=0; i<aPolyPoly.count(); ++i ) { - // TODO(F2): Use MiterLimit from StrokeAttributes, - // need to convert it here to angle. + double fMiterMinimumAngle; + if (strokeAttributes.MiterLimit <= 1.0) + { + fMiterMinimumAngle = F_PI2; + } + else + { + fMiterMinimumAngle = 2.0 * asin(1.0/strokeAttributes.MiterLimit); + } // TODO(F2): Also use Cap settings from // StrokeAttributes, the @@ -403,7 +410,10 @@ namespace vclcanvas aPolyPoly.getB2DPolygon(i), strokeAttributes.StrokeWidth*0.5, b2DJoineFromJoin(strokeAttributes.JoinType), - unoCapeFromCap(strokeAttributes.StartCapType) + unoCapeFromCap(strokeAttributes.StartCapType), + 12.5 * F_PI180 /* default fMaxAllowedAngle*/ , + 0.4 /* default fMaxPartOfEdge*/ , + fMiterMinimumAngle )); //aStrokedPolyPoly.append( // ::basegfx::tools::createAreaGeometryForPolygon( aPolyPoly.getB2DPolygon(i), diff --git a/drawinglayer/source/attribute/lineattribute.cxx b/drawinglayer/source/attribute/lineattribute.cxx index 5e720fbd6969..89ce998924fe 100644 --- a/drawinglayer/source/attribute/lineattribute.cxx +++ b/drawinglayer/source/attribute/lineattribute.cxx @@ -34,16 +34,19 @@ namespace drawinglayer double mfWidth; // absolute line width basegfx::B2DLineJoin meLineJoin; // type of LineJoin css::drawing::LineCap meLineCap; // BUTT, ROUND, or SQUARE + double mfMiterMinimumAngle; // as needed for createAreaGeometry ImpLineAttribute( const basegfx::BColor& rColor, double fWidth, basegfx::B2DLineJoin aB2DLineJoin, - css::drawing::LineCap aLineCap) + css::drawing::LineCap aLineCap, + double fMiterMinimumAngle) : maColor(rColor), mfWidth(fWidth), meLineJoin(aB2DLineJoin), - meLineCap(aLineCap) + meLineCap(aLineCap), + mfMiterMinimumAngle(fMiterMinimumAngle) { } @@ -51,7 +54,8 @@ namespace drawinglayer : maColor(basegfx::BColor()), mfWidth(0.0), meLineJoin(basegfx::B2DLineJoin::Round), - meLineCap(css::drawing::LineCap_BUTT) + meLineCap(css::drawing::LineCap_BUTT), + mfMiterMinimumAngle(15.0 * F_PI180) { } @@ -60,13 +64,15 @@ namespace drawinglayer double getWidth() const { return mfWidth; } basegfx::B2DLineJoin getLineJoin() const { return meLineJoin; } css::drawing::LineCap getLineCap() const { return meLineCap; } + double getMiterMinimumAngle() const { return mfMiterMinimumAngle; } bool operator==(const ImpLineAttribute& rCandidate) const { return (getColor() == rCandidate.getColor() && getWidth() == rCandidate.getWidth() && getLineJoin() == rCandidate.getLineJoin() - && getLineCap() == rCandidate.getLineCap()); + && getLineCap() == rCandidate.getLineCap() + && getMiterMinimumAngle() == rCandidate.getMiterMinimumAngle()); } }; @@ -80,13 +86,15 @@ namespace drawinglayer const basegfx::BColor& rColor, double fWidth, basegfx::B2DLineJoin aB2DLineJoin, - css::drawing::LineCap aLineCap) + css::drawing::LineCap aLineCap, + double fMiterMinimumAngle) : mpLineAttribute( ImpLineAttribute( rColor, fWidth, aB2DLineJoin, - aLineCap)) + aLineCap, + fMiterMinimumAngle)) { } @@ -144,6 +152,11 @@ namespace drawinglayer return mpLineAttribute->getLineCap(); } + double LineAttribute::getMiterMinimumAngle() const + { + return mpLineAttribute->getMiterMinimumAngle(); + } + } // end of namespace attribute } // end of namespace drawinglayer diff --git a/drawinglayer/source/primitive2d/polygonprimitive2d.cxx b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx index ddc83d02d670..76fc498d34d5 100644 --- a/drawinglayer/source/primitive2d/polygonprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx @@ -252,6 +252,7 @@ namespace drawinglayer const basegfx::B2DLineJoin aLineJoin(getLineAttribute().getLineJoin()); const css::drawing::LineCap aLineCap(getLineAttribute().getLineCap()); basegfx::B2DPolyPolygon aAreaPolyPolygon; + const double fMiterMinimumAngle(getLineAttribute().getMiterMinimumAngle()); for(sal_uInt32 a(0L); a < nCount; a++) { @@ -260,7 +261,10 @@ namespace drawinglayer aHairLinePolyPolygon.getB2DPolygon(a), fHalfLineWidth, aLineJoin, - aLineCap)); + aLineCap, + 12.5 * F_PI180 /* default fMaxAllowedAngle*/ , + 0.4 /* default fMaxPartOfEdge*/ , + fMiterMinimumAngle)); } // prepare return value diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index 7b18c5900068..f3b08ec5795b 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -259,7 +259,9 @@ namespace drawinglayer fLineWidth, fTransparency, rSource.getLineAttribute().getLineJoin(), - rSource.getLineAttribute().getLineCap())) + rSource.getLineAttribute().getLineCap(), + rSource.getLineAttribute().getMiterMinimumAngle(), + false /*bBypassAACheck, default*/)) { bTryWorked = true; } diff --git a/drawinglayer/source/processor2d/vclprocessor2d.cxx b/drawinglayer/source/processor2d/vclprocessor2d.cxx index e6ce0f59fc43..f5d24cf001cb 100644 --- a/drawinglayer/source/processor2d/vclprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclprocessor2d.cxx @@ -1301,7 +1301,8 @@ namespace drawinglayer aHairlinePolyPolygon.getB2DPolygon(a), fDiscreteLineWidth, rLineAttribute.getLineJoin(), - rLineAttribute.getLineCap()); + rLineAttribute.getLineCap(), + rLineAttribute.getMiterMinimumAngle()); } bDone = true; diff --git a/include/drawinglayer/attribute/lineattribute.hxx b/include/drawinglayer/attribute/lineattribute.hxx index a405ebce540c..a2ad66d5fe3f 100644 --- a/include/drawinglayer/attribute/lineattribute.hxx +++ b/include/drawinglayer/attribute/lineattribute.hxx @@ -22,6 +22,7 @@ #include <drawinglayer/drawinglayerdllapi.h> +#include <basegfx/numeric/ftools.hxx> // for F_PI180 #include <basegfx/vector/b2enums.hxx> #include <com/sun/star/drawing/LineCap.hpp> #include <o3tl/cow_wrapper.hxx> @@ -56,7 +57,8 @@ namespace drawinglayer const basegfx::BColor& rColor, double fWidth = 0.0, basegfx::B2DLineJoin aB2DLineJoin = basegfx::B2DLineJoin::Round, - css::drawing::LineCap aLineCap = css::drawing::LineCap_BUTT); + css::drawing::LineCap aLineCap = css::drawing::LineCap_BUTT, + double fMiterMinimumAngle = 15.0 * F_PI180); LineAttribute(); LineAttribute(const LineAttribute& rCandidate); LineAttribute& operator=(const LineAttribute& rCandidate); @@ -73,6 +75,7 @@ namespace drawinglayer double getWidth() const; basegfx::B2DLineJoin getLineJoin() const; css::drawing::LineCap getLineCap() const; + double getMiterMinimumAngle() const; }; } // end of namespace attribute } // end of namespace drawinglayer diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx index 9ad1a09ff56e..720c45c651f7 100644 --- a/include/vcl/outdev.hxx +++ b/include/vcl/outdev.hxx @@ -41,6 +41,7 @@ #include <vcl/outdevstate.hxx> #include <vcl/outdevmap.hxx> +#include <basegfx/numeric/ftools.hxx> #include <basegfx/vector/b2enums.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> @@ -826,7 +827,8 @@ public: const basegfx::B2DPolygon&, double fLineWidth = 0.0, basegfx::B2DLineJoin eLineJoin = basegfx::B2DLineJoin::Round, - css::drawing::LineCap eLineCap = css::drawing::LineCap_BUTT); + css::drawing::LineCap eLineCap = css::drawing::LineCap_BUTT, + double fMiterMinimumAngle = 15.0 * F_PI180); /** Render the given polygon as a line stroke @@ -849,7 +851,9 @@ public: double fTransparency = 0.0, basegfx::B2DLineJoin eLineJoin = basegfx::B2DLineJoin::NONE, css::drawing::LineCap eLineCap = css::drawing::LineCap_BUTT, - bool bBypassAACheck = false ); + double fMiterMinimumAngle = 15.0 * F_PI180, + bool bBypassAACheck = false); + private: // #i101491# diff --git a/svgio/inc/svgio/svgreader/svgstyleattributes.hxx b/svgio/inc/svgio/svgreader/svgstyleattributes.hxx index f711feb3af63..141218b3e042 100644 --- a/svgio/inc/svgio/svgreader/svgstyleattributes.hxx +++ b/svgio/inc/svgio/svgreader/svgstyleattributes.hxx @@ -378,7 +378,7 @@ namespace svgio /// StrokeMiterLimit content SvgNumber getStrokeMiterLimit() const; - void setStrokeMiterLimit(const SvgNumber& rStrokeMiterLimit = SvgNumber()) { maStrokeMiterLimit = rStrokeMiterLimit; } + void setStrokeMiterLimit(const SvgNumber& rStrokeMiterLimit = SvgNumber(4.0,Unit_none,false)) { maStrokeMiterLimit = rStrokeMiterLimit; } /// StrokeOpacity content SvgNumber getStrokeOpacity() const; diff --git a/svgio/inc/svgio/svgreader/svgtools.hxx b/svgio/inc/svgio/svgreader/svgtools.hxx index 4c940ee819db..f65cf059e481 100644 --- a/svgio/inc/svgio/svgreader/svgtools.hxx +++ b/svgio/inc/svgio/svgreader/svgtools.hxx @@ -83,7 +83,8 @@ namespace svgio Unit_mm, // 3.543307 px Unit_in, // 90 px - Unit_percent // relative to range + Unit_percent, // relative to range + Unit_none // for stroke-miterlimit, which has no unit }; class SvgNumber diff --git a/svgio/source/svgreader/svgstyleattributes.cxx b/svgio/source/svgreader/svgstyleattributes.cxx index 2d5bc8548495..201ec68422a3 100644 --- a/svgio/source/svgreader/svgstyleattributes.cxx +++ b/svgio/source/svgreader/svgstyleattributes.cxx @@ -676,13 +676,27 @@ namespace svgio // todo: Handle getStrokeDashOffset() + // convert svg:stroke-miterlimit to LineAttrute:mfMiterMinimumAngle + // The default needs to be set explicitely, because svg default <> Draw default + double fMiterMinimumAngle; + if (getStrokeMiterLimit().isSet()) + { + fMiterMinimumAngle = 2.0 * asin(1.0/getStrokeMiterLimit().getNumber()); + } + else + { + fMiterMinimumAngle = 2.0 * asin(0.25); // 1.0/default 4.0 + } + // prepare line attribute drawinglayer::primitive2d::Primitive2DReference aNewLinePrimitive; + const drawinglayer::attribute::LineAttribute aLineAttribute( pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0), fStrokeWidth, aB2DLineJoin, - aLineCap); + aLineCap, + fMiterMinimumAngle); if(aDashArray.empty()) { @@ -1411,9 +1425,9 @@ namespace svgio if(readSingleNumber(aContent, aNum)) { - if(aNum.isPositive()) - { - setStrokeMiterLimit(aNum); + if(basegfx::fTools::moreOrEqual(aNum.getNumber(), 1.0)) + { //readSingleNumber sets Unit_px as default, if unit is missing. Correct it here. + setStrokeMiterLimit(SvgNumber(aNum.getNumber(), Unit_none)); } } break; @@ -2297,7 +2311,7 @@ namespace svgio } // default is 4 - return SvgNumber(4.0); + return SvgNumber(4.0, Unit_none); } SvgNumber SvgStyleAttributes::getStrokeOpacity() const diff --git a/svgio/source/svgreader/svgtools.cxx b/svgio/source/svgreader/svgtools.cxx index 14e5bdaa9553..3bc457344cb4 100644 --- a/svgio/source/svgreader/svgtools.cxx +++ b/svgio/source/svgreader/svgtools.cxx @@ -189,6 +189,13 @@ namespace svgio return fRetval; } + case Unit_none: + { +#ifdef DBG_UTIL + myAssert("Design error, this case should have been handled in the caller"); +#endif + return mfNumber; + } default: { OSL_ENSURE(false, "Do not use with percentage! "); @@ -219,6 +226,7 @@ namespace svgio case Unit_in: case Unit_em: case Unit_ex: + case Unit_none: { return solveNonPercentage( rInfoProvider); } @@ -473,13 +481,13 @@ namespace svgio } else if('t' == aCharB) { - // 'pt' == 1.25 px + // 'pt' == 4/3 px aRetval = Unit_pt; bTwoCharValid = true; } else if('c' == aCharB) { - // 'pc' == 15 px + // 'pc' == 16 px aRetval = Unit_pc; bTwoCharValid = true; } @@ -489,7 +497,7 @@ namespace svgio { if('n' == aCharB) { - // 'in' == 90 px + // 'in' == 96 px, since CSS 2.1 aRetval = Unit_in; bTwoCharValid = true; } @@ -499,7 +507,7 @@ namespace svgio { if('m' == aCharB) { - // 'cm' == 35.43307 px + // 'cm' == 37.79527559 px aRetval = Unit_cm; bTwoCharValid = true; } @@ -509,7 +517,7 @@ namespace svgio { if('m' == aCharB) { - // 'mm' == 3.543307 px + // 'mm' == 3.779528 px aRetval = Unit_mm; bTwoCharValid = true; } diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx index 37e0e17bbbe2..b6c33b709e24 100644 --- a/vcl/headless/svpgdi.cxx +++ b/vcl/headless/svpgdi.cxx @@ -27,6 +27,7 @@ #include <vcl/sysdata.hxx> #include <config_cairo_canvas.h> +#include <basegfx/numeric/ftools.hxx> #include <basegfx/range/b2drange.hxx> #include <basegfx/range/b2ibox.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> @@ -538,7 +539,7 @@ void SvpSalGraphics::drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAry) aPoly.setClosed(false); drawPolyLine(aPoly, 0.0, basegfx::B2DVector(1.0, 1.0), basegfx::B2DLineJoin::Miter, - css::drawing::LineCap_BUTT); + css::drawing::LineCap_BUTT, 15.0 * F_PI180 /*default*/); } void SvpSalGraphics::drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry) @@ -699,7 +700,8 @@ bool SvpSalGraphics::drawPolyLine( double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin eLineJoin, - css::drawing::LineCap eLineCap) + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle) { // short circuit if there is nothing to do const int nPointCount = rPolyLine.count(); @@ -729,6 +731,9 @@ bool SvpSalGraphics::drawPolyLine( break; } + // convert miter minimum angle to miter limit + double fMiterLimit = 1.0 / sin( fMiterMinimumAngle / 2.0); + // setup cap attribute cairo_line_cap_t eCairoLineCap(CAIRO_LINE_CAP_BUTT); @@ -759,7 +764,7 @@ bool SvpSalGraphics::drawPolyLine( cairo_set_line_join(cr, eCairoLineJoin); cairo_set_line_cap(cr, eCairoLineCap); cairo_set_line_width(cr, rLineWidths.getX()); - cairo_set_miter_limit(cr, 15.0); + cairo_set_miter_limit(cr, fMiterLimit); basegfx::B2DRange extents(0, 0, 0, 0); diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx index be9aebe17332..758057500ba2 100644 --- a/vcl/inc/headless/svpgdi.hxx +++ b/vcl/inc/headless/svpgdi.hxx @@ -163,7 +163,8 @@ public: double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin, - css::drawing::LineCap) override; + css::drawing::LineCap, + double fMiterMinimumAngle) override; virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; virtual void drawPolyPolygon( sal_uInt32 nPoly, diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx index ef23328658f1..0f8b605b5fca 100644 --- a/vcl/inc/openglgdiimpl.hxx +++ b/vcl/inc/openglgdiimpl.hxx @@ -133,7 +133,7 @@ public: void DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ); void DrawLineSegment(float x1, float y1, float x2, float y2); void DrawLineCap(float x1, float y1, float x2, float y2, css::drawing::LineCap eLineCap, float fLineWidth); - void DrawPolyLine( const basegfx::B2DPolygon& rPolygon, float fLineWidth, basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap); + void DrawPolyLine( const basegfx::B2DPolygon& rPolygon, float fLineWidth, basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, float fMiterMinimumAngle); void DrawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon, bool blockAA = false ); void DrawRegionBand( const RegionBand& rRegion ); void DrawTextureRect( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted = false ); @@ -257,7 +257,8 @@ public: double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin, - css::drawing::LineCap) override; + css::drawing::LineCap, + double fMiterMinimumAngle) override; virtual bool drawPolyLineBezier( sal_uInt32 nPoints, diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index a4a2608f3399..e4c9ca1a2eeb 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -246,7 +246,8 @@ public: double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin, - css::drawing::LineCap eLineCap) override; + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle) override; virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) override { return false; }; // CopyArea --> No RasterOp, but ClipRegion diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx index 23d0d8164db1..feecc85153fc 100644 --- a/vcl/inc/salgdi.hxx +++ b/vcl/inc/salgdi.hxx @@ -273,6 +273,7 @@ public: const basegfx::B2DVector& i_rLineWidth, basegfx::B2DLineJoin i_eLineJoin, css::drawing::LineCap i_eLineCap, + double i_fMiterMinimumAngle, const OutputDevice* i_pOutDev); bool DrawPolyLineBezier( @@ -470,7 +471,8 @@ protected: double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin, - css::drawing::LineCap) = 0; + css::drawing::LineCap, + double fMiterMinimumAngle) = 0; virtual bool drawPolyLineBezier( sal_uInt32 nPoints, diff --git a/vcl/inc/salgdiimpl.hxx b/vcl/inc/salgdiimpl.hxx index a70fe2c0e437..c5c8e6d42178 100644 --- a/vcl/inc/salgdiimpl.hxx +++ b/vcl/inc/salgdiimpl.hxx @@ -105,7 +105,8 @@ public: double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin, - css::drawing::LineCap) = 0; + css::drawing::LineCap, + double fMiterMinimumAngle) = 0; virtual bool drawPolyLineBezier( sal_uInt32 nPoints, diff --git a/vcl/inc/unx/genpspgraphics.h b/vcl/inc/unx/genpspgraphics.h index 6f6fa6940c9a..e609c124f4d1 100644 --- a/vcl/inc/unx/genpspgraphics.h +++ b/vcl/inc/unx/genpspgraphics.h @@ -148,7 +148,8 @@ public: double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin, - css::drawing::LineCap) override; + css::drawing::LineCap, + double fMiterMinimumAngle) override; virtual bool drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry ) override; diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h index 88db9ce4c94b..29522824ca4a 100644 --- a/vcl/inc/unx/salgdi.h +++ b/vcl/inc/unx/salgdi.h @@ -176,7 +176,8 @@ public: double fTransparency, const basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin, - css::drawing::LineCap ) override; + css::drawing::LineCap, + double fMiterMinimumAngle) override; virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) override; diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index 8866dcfbc289..2c89393d9ed0 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -281,7 +281,8 @@ protected: double fTransparency, const basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin, - css::drawing::LineCap) override; + css::drawing::LineCap, + double fMiterMinimumAngle) override; virtual bool drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry ) override; virtual bool drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry ) override; virtual bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const BYTE* const* pFlgAry ) override; diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx index b8d6fb6d9c73..8bb2c1dbe978 100644 --- a/vcl/opengl/gdiimpl.cxx +++ b/vcl/opengl/gdiimpl.cxx @@ -684,8 +684,6 @@ inline glm::vec2 normalize(const glm::vec2& vector) return vector; } -SAL_CONSTEXPR float constMiterMinimumAngle = 15.0f; - } // end anonymous namespace void OpenGLSalGraphicsImpl::DrawLineCap(float x1, float y1, float x2, float y2, css::drawing::LineCap eLineCap, float fLineWidth) @@ -769,7 +767,7 @@ void OpenGLSalGraphicsImpl::DrawLineSegment(float x1, float y1, float x2, float * - http://artgrammer.blogspot.si/2011/07/drawing-polylines-by-tessellation.html * */ -void OpenGLSalGraphicsImpl::DrawPolyLine(const basegfx::B2DPolygon& rPolygon, float fLineWidth, basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap) +void OpenGLSalGraphicsImpl::DrawPolyLine(const basegfx::B2DPolygon& rPolygon, float fLineWidth, basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, float fMiterMinimumAngle) { sal_uInt32 nPoints = rPolygon.count(); bool bClosed = rPolygon.isClosed(); @@ -871,9 +869,9 @@ void OpenGLSalGraphicsImpl::DrawPolyLine(const basegfx::B2DPolygon& rPolygon, fl float angle = std::atan2(previousLineVector.x * nextLineVector.y - previousLineVector.y * nextLineVector.x, previousLineVector.x * nextLineVector.x + previousLineVector.y * nextLineVector.y); - angle = (F_PI - std::fabs(angle)) / F_PI180; + angle = F_PI - std::fabs(angle); - if (angle < constMiterMinimumAngle) + if (angle < fMiterMinimumAngle) eLineJoin = basegfx::B2DLineJoin::Bevel; } @@ -2060,7 +2058,8 @@ bool OpenGLSalGraphicsImpl::drawPolyLine( double fTransparency, const basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eLineJoin, - css::drawing::LineCap eLineCap) + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle) { VCL_GL_INFO( "::drawPolyLine trans " << fTransparency ); if( mnLineColor == SALCOLOR_NONE ) @@ -2080,7 +2079,7 @@ bool OpenGLSalGraphicsImpl::drawPolyLine( else aPolygon.removeDoublePoints(); - DrawPolyLine(aPolygon, fLineWidth, eLineJoin, eLineCap); + DrawPolyLine(aPolygon, fLineWidth, eLineJoin, eLineCap, fMiterMinimumAngle); } PostDraw(); diff --git a/vcl/quartz/salgdicommon.cxx b/vcl/quartz/salgdicommon.cxx index eaf40deed5e4..e493be1a75fe 100644 --- a/vcl/quartz/salgdicommon.cxx +++ b/vcl/quartz/salgdicommon.cxx @@ -961,7 +961,8 @@ bool AquaSalGraphics::drawPolyLine( const basegfx::B2DPolygon& rPolyLine, double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin eLineJoin, - css::drawing::LineCap eLineCap) + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle) { DBG_DRAW_OPERATION("drawPolyLine", true); @@ -1000,7 +1001,8 @@ bool AquaSalGraphics::drawPolyLine( const basegfx::B2DPolygon& rPolyLine, case basegfx::B2DLineJoin::Miter: aCGLineJoin = kCGLineJoinMiter; break; case basegfx::B2DLineJoin::Round: aCGLineJoin = kCGLineJoinRound; break; } - + // convert miter minimum angle to miter limit + CGFloat fCGMiterLimit = 1.0 / sin(fMiterMinimumAngle / 2.0); // setup cap attribute CGLineCap aCGLineCap(kCGLineCapButt); @@ -1047,6 +1049,7 @@ bool AquaSalGraphics::drawPolyLine( const basegfx::B2DPolygon& rPolyLine, CGContextSetLineJoin( mrContext, aCGLineJoin ); CGContextSetLineCap( mrContext, aCGLineCap ); CGContextSetLineWidth( mrContext, rLineWidths.getX() ); + CGContextSetMiterLimit(mrContext, fCGMiterLimit); SAL_INFO( "vcl.cg", "CGContextDrawPath(" << mrContext << ",kCGPathStroke)" ); CGContextDrawPath( mrContext, kCGPathStroke ); SAL_INFO( "vcl.cg", "CGContextRestoreGState(" << mrContext << ") " << mnContextStackDepth-- ); diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx index 8244e023c4c2..052edc564845 100644 --- a/vcl/source/gdi/salgdilayout.cxx +++ b/vcl/source/gdi/salgdilayout.cxx @@ -23,6 +23,7 @@ #endif #include "salgdi.hxx" #include "salframe.hxx" +#include <basegfx/numeric/ftools.hxx> //for F_PI180 // The only common SalFrame method @@ -481,16 +482,17 @@ bool SalGraphics::DrawPolyLine( const basegfx::B2DPolygon& i_rPolygon, const basegfx::B2DVector& i_rLineWidth, basegfx::B2DLineJoin i_eLineJoin, css::drawing::LineCap i_eLineCap, + double i_fMiterMinimumAngle, const OutputDevice* i_pOutDev ) { bool bRet = false; if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (i_pOutDev && i_pOutDev->IsRTLEnabled()) ) { basegfx::B2DPolygon aMirror( mirror( i_rPolygon, i_pOutDev ) ); - bRet = drawPolyLine( aMirror, i_fTransparency, i_rLineWidth, i_eLineJoin, i_eLineCap ); + bRet = drawPolyLine( aMirror, i_fTransparency, i_rLineWidth, i_eLineJoin, i_eLineCap, i_fMiterMinimumAngle ); } else - bRet = drawPolyLine( i_rPolygon, i_fTransparency, i_rLineWidth, i_eLineJoin, i_eLineCap ); + bRet = drawPolyLine( i_rPolygon, i_fTransparency, i_rLineWidth, i_eLineJoin, i_eLineCap, i_fMiterMinimumAngle ); return bRet; } diff --git a/vcl/source/outdev/line.cxx b/vcl/source/outdev/line.cxx index bf4f2f6a3c8f..a04dd802ee96 100644 --- a/vcl/source/outdev/line.cxx +++ b/vcl/source/outdev/line.cxx @@ -134,7 +134,14 @@ void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt ) aB2DPolyLine = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine); } - if( mpGraphics->DrawPolyLine( aB2DPolyLine, 0.0, aB2DLineWidth, basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, this)) + if( mpGraphics->DrawPolyLine( + aB2DPolyLine, + 0.0, + aB2DLineWidth, + basegfx::B2DLineJoin::NONE, + css::drawing::LineCap_BUTT, + 15.0 * F_PI180, // not used with B2DLineJoin::NONE, but the correct default + this)) { return; } @@ -236,7 +243,14 @@ void OutputDevice::drawLine( basegfx::B2DPolyPolygon aLinePolyPolygon, const Lin if(bTryAA) { - bDone = mpGraphics->DrawPolyLine( aCandidate, 0.0, basegfx::B2DVector(1.0,1.0), basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, this); + bDone = mpGraphics->DrawPolyLine( + aCandidate, + 0.0, + basegfx::B2DVector(1.0,1.0), + basegfx::B2DLineJoin::NONE, + css::drawing::LineCap_BUTT, + 15.0 * F_PI180, // not used with B2DLineJoin::NONE, but the correct default + this); } if(!bDone) diff --git a/vcl/source/outdev/polygon.cxx b/vcl/source/outdev/polygon.cxx index 0f36e30a8e00..612e93716bb1 100644 --- a/vcl/source/outdev/polygon.cxx +++ b/vcl/source/outdev/polygon.cxx @@ -97,6 +97,7 @@ void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon& rPolyPoly ) aB2DLineWidth, basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, + 15.0 * F_PI180, // not used with B2DLineJoin::NONE, but the correct default this); } } @@ -207,6 +208,7 @@ void OutputDevice::DrawPolygon( const tools::Polygon& rPoly ) aB2DLineWidth, basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, + 15.0 * F_PI180, // not used with B2DLineJoin::NONE, but the correct default this); } @@ -311,6 +313,7 @@ void OutputDevice::ImplDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyP aB2DLineWidth, basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, + 15.0 * F_PI180, // not used with B2DLineJoin::NONE, but the correct default this); } } diff --git a/vcl/source/outdev/polyline.cxx b/vcl/source/outdev/polyline.cxx index 6bd72495870f..b2e5b7abbacd 100644 --- a/vcl/source/outdev/polyline.cxx +++ b/vcl/source/outdev/polyline.cxx @@ -72,8 +72,14 @@ void OutputDevice::DrawPolyLine( const tools::Polygon& rPoly ) aB2DPolyLine = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine); } - if(mpGraphics->DrawPolyLine( aB2DPolyLine, 0.0, aB2DLineWidth, - basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, this)) + if(mpGraphics->DrawPolyLine( + aB2DPolyLine, + 0.0, + aB2DLineWidth, + basegfx::B2DLineJoin::NONE, + css::drawing::LineCap_BUTT, + 15.0 * F_PI180 /*default fMiterMinimumAngle, not used*/, + this)) { return; } @@ -117,7 +123,12 @@ void OutputDevice::DrawPolyLine( const tools::Polygon& rPoly, const LineInfo& rL if((mnAntialiasing & AntialiasingFlags::EnableB2dDraw) && LINE_SOLID == rLineInfo.GetStyle()) { - DrawPolyLine( rPoly.getB2DPolygon(), (double)rLineInfo.GetWidth(), rLineInfo.GetLineJoin(), rLineInfo.GetLineCap()); + DrawPolyLine( + rPoly.getB2DPolygon(), + static_cast< double >(rLineInfo.GetWidth()), + rLineInfo.GetLineJoin(), + rLineInfo.GetLineCap(), + 15.0 * F_PI180 /* default fMiterMinimumAngle, value not available in LineInfo */); return; } @@ -130,7 +141,8 @@ void OutputDevice::DrawPolyLine( const tools::Polygon& rPoly, const LineInfo& rL void OutputDevice::DrawPolyLine( const basegfx::B2DPolygon& rB2DPolygon, double fLineWidth, basegfx::B2DLineJoin eLineJoin, - css::drawing::LineCap eLineCap) + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle) { assert(!is_double_buffered_window()); @@ -162,7 +174,7 @@ void OutputDevice::DrawPolyLine( const basegfx::B2DPolygon& rB2DPolygon, InitLineColor(); // use b2dpolygon drawing if possible - if ( DrawPolyLineDirect(rB2DPolygon, fLineWidth, 0.0, eLineJoin, eLineCap) ) + if ( DrawPolyLineDirect(rB2DPolygon, fLineWidth, 0.0, eLineJoin, eLineCap, fMiterMinimumAngle) ) return; // #i101491# @@ -178,7 +190,8 @@ void OutputDevice::DrawPolyLine( const basegfx::B2DPolygon& rB2DPolygon, basegfx::tools::createAreaGeometry( rB2DPolygon, fHalfLineWidth, eLineJoin, - eLineCap)); + eLineCap, + fMiterMinimumAngle)); const Color aOldLineColor(maLineColor); const Color aOldFillColor(maFillColor); @@ -208,7 +221,7 @@ void OutputDevice::DrawPolyLine( const basegfx::B2DPolygon& rB2DPolygon, // to avoid optical gaps for(sal_uInt32 a(0); a < aAreaPolyPolygon.count(); a++) { - DrawPolyLineDirect( aAreaPolyPolygon.getB2DPolygon(a), 0.0, 0.0, basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, bTryAA ); + DrawPolyLineDirect( aAreaPolyPolygon.getB2DPolygon(a), 0.0, 0.0, basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, 15.0 * F_PI180 /*default, not used*/, bTryAA); } } else @@ -276,7 +289,8 @@ bool OutputDevice::DrawPolyLineDirect( const basegfx::B2DPolygon& rB2DPolygon, double fTransparency, basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, - bool bBypassAACheck ) + double fMiterMinimumAngle, + bool bBypassAACheck) { assert(!is_double_buffered_window()); @@ -334,6 +348,7 @@ bool OutputDevice::DrawPolyLineDirect( const basegfx::B2DPolygon& rB2DPolygon, aB2DLineWidth, eLineJoin, eLineCap, + fMiterMinimumAngle, this ); if( bDrawSuccess ) @@ -344,7 +359,10 @@ bool OutputDevice::DrawPolyLineDirect( const basegfx::B2DPolygon& rB2DPolygon, LineInfo aLineInfo; if( fLineWidth != 0.0 ) aLineInfo.SetWidth( static_cast<long>(fLineWidth+0.5) ); - + // Transport known informations, might be needed + aLineInfo.SetLineJoin(eLineJoin); + aLineInfo.SetLineCap(eLineCap); + // MiterMinimumAngle does not exist yet in LineInfo const tools::Polygon aToolsPolygon( rB2DPolygon ); mpMetaFile->AddAction( new MetaPolyLineAction( aToolsPolygon, aLineInfo ) ); } diff --git a/vcl/source/outdev/transparent.cxx b/vcl/source/outdev/transparent.cxx index 6eed4c24c162..addf0d634708 100644 --- a/vcl/source/outdev/transparent.cxx +++ b/vcl/source/outdev/transparent.cxx @@ -256,7 +256,14 @@ void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) { const basegfx::B2DPolygon aOnePoly = aB2DPolyPolygon.getB2DPolygon( nPolyIdx ); - mpGraphics->DrawPolyLine( aOnePoly, fTransparency, aHairlineWidth, basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, this ); + mpGraphics->DrawPolyLine( + aOnePoly, + fTransparency, + aHairlineWidth, + basegfx::B2DLineJoin::NONE, + css::drawing::LineCap_BUTT, + 15.0 * F_PI180, // not used with B2DLineJoin::NONE, but the correct default + this ); } } @@ -352,8 +359,14 @@ bool OutputDevice::DrawTransparentNatively ( const tools::PolyPolygon& rPolyPoly for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) { const basegfx::B2DPolygon& rPolygon = aB2DPolyPolygon.getB2DPolygon( nPolyIdx ); - bDrawn = mpGraphics->DrawPolyLine( rPolygon, fTransparency, aLineWidths, - basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, this ); + bDrawn = mpGraphics->DrawPolyLine( + rPolygon, + fTransparency, + aLineWidths, + basegfx::B2DLineJoin::NONE, + css::drawing::LineCap_BUTT, + 15.0 * F_PI180, // not used with B2DLineJoin::NONE, but the correct default + this ); } // prepare to restore the fill color mbInitFillColor = mbFillColor; diff --git a/vcl/unx/generic/gdi/gdiimpl.cxx b/vcl/unx/generic/gdi/gdiimpl.cxx index df5a77961b15..02f93255e928 100644 --- a/vcl/unx/generic/gdi/gdiimpl.cxx +++ b/vcl/unx/generic/gdi/gdiimpl.cxx @@ -1597,7 +1597,8 @@ bool X11SalGraphicsImpl::drawPolyLine( double fTransparency, const basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eLineJoin, - css::drawing::LineCap eLineCap) + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle) { const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2); @@ -1654,7 +1655,7 @@ bool X11SalGraphicsImpl::drawPolyLine( } // create the area-polygon for the line - const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, fHalfWidth, eLineJoin, eLineCap) ); + const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, fHalfWidth, eLineJoin, eLineCap, fMiterMinimumAngle) ); if( (rLineWidth.getX() != rLineWidth.getY()) && !basegfx::fTools::equalZero( rLineWidth.getX() ) ) diff --git a/vcl/unx/generic/gdi/gdiimpl.hxx b/vcl/unx/generic/gdi/gdiimpl.hxx index d637237d7871..0b58543c71fa 100644 --- a/vcl/unx/generic/gdi/gdiimpl.hxx +++ b/vcl/unx/generic/gdi/gdiimpl.hxx @@ -164,7 +164,8 @@ public: double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin, - css::drawing::LineCap) override; + css::drawing::LineCap, + double fMiterMinimumAngle) override; virtual bool drawPolyLineBezier( sal_uInt32 nPoints, diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx index 6444cc4fe522..5821a38fcaa6 100644 --- a/vcl/unx/generic/gdi/salgdi.cxx +++ b/vcl/unx/generic/gdi/salgdi.cxx @@ -564,10 +564,11 @@ bool X11SalGraphics::drawPolyLine( double fTransparency, const basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eLineJoin, - css::drawing::LineCap eLineCap) + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle) { return mxImpl->drawPolyLine( rPolygon, fTransparency, rLineWidth, - eLineJoin, eLineCap ); + eLineJoin, eLineCap, fMiterMinimumAngle ); } bool X11SalGraphics::drawGradient(const tools::PolyPolygon& rPoly, const Gradient& rGradient) diff --git a/vcl/unx/generic/print/genpspgraphics.cxx b/vcl/unx/generic/print/genpspgraphics.cxx index 85b6f17cfe3b..b018a80dd33f 100644 --- a/vcl/unx/generic/print/genpspgraphics.cxx +++ b/vcl/unx/generic/print/genpspgraphics.cxx @@ -445,7 +445,8 @@ bool GenPspGraphics::drawPolyLine( double /*fTranspareny*/, const basegfx::B2DVector& /*rLineWidths*/, basegfx::B2DLineJoin /*eJoin*/, - css::drawing::LineCap /*eLineCap*/) + css::drawing::LineCap /*eLineCap*/, + double /*fMiterMinimumAngle*/) { // TODO: a PS printer can draw B2DPolyLines almost directly return false; diff --git a/vcl/win/gdi/gdiimpl.cxx b/vcl/win/gdi/gdiimpl.cxx index 0317ca06319a..bd03594292a2 100644 --- a/vcl/win/gdi/gdiimpl.cxx +++ b/vcl/win/gdi/gdiimpl.cxx @@ -2025,7 +2025,8 @@ bool WinSalGraphicsImpl::drawPolyLine( double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin eLineJoin, - css::drawing::LineCap eLineCap) + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle) { const sal_uInt32 nCount(rPolygon.count()); @@ -2055,7 +2056,7 @@ bool WinSalGraphicsImpl::drawPolyLine( } case basegfx::B2DLineJoin::Miter : { - const Gdiplus::REAL aMiterLimit(15.0); + const Gdiplus::REAL aMiterLimit(1.0/sin(fMiterMinimumAngle/2.0)); aPen.SetMiterLimit(aMiterLimit); // tdf#99165 MS's LineJoinMiter creates non standard conform miter additional diff --git a/vcl/win/gdi/gdiimpl.hxx b/vcl/win/gdi/gdiimpl.hxx index b93d1f361292..8f4181c5a2db 100644 --- a/vcl/win/gdi/gdiimpl.hxx +++ b/vcl/win/gdi/gdiimpl.hxx @@ -111,7 +111,8 @@ public: double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin, - css::drawing::LineCap) override; + css::drawing::LineCap, + double fMiterMinimumAngle) override; virtual bool drawPolyLineBezier( sal_uInt32 nPoints, diff --git a/vcl/win/gdi/salgdi_gdiplus.cxx b/vcl/win/gdi/salgdi_gdiplus.cxx index f821e03606ea..45e760ae871b 100644 --- a/vcl/win/gdi/salgdi_gdiplus.cxx +++ b/vcl/win/gdi/salgdi_gdiplus.cxx @@ -36,10 +36,11 @@ bool WinSalGraphics::drawPolyLine( double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin eLineJoin, - css::drawing::LineCap eLineCap) + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle) { return mpImpl->drawPolyLine(rPolygon, fTransparency, rLineWidths, - eLineJoin, eLineCap); + eLineJoin, eLineCap, fMiterMinimumAngle); } bool WinSalGraphics::blendBitmap( |