diff options
-rw-r--r-- | basegfx/source/curve/b2dcubicbezier.cxx | 61 | ||||
-rw-r--r-- | include/basegfx/curve/b2dcubicbezier.hxx | 7 | ||||
-rw-r--r-- | vcl/inc/unx/salgdi.h | 9 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salgdi.cxx | 271 |
4 files changed, 348 insertions, 0 deletions
diff --git a/basegfx/source/curve/b2dcubicbezier.cxx b/basegfx/source/curve/b2dcubicbezier.cxx index 996500a4f6ad..5b320de7d56f 100644 --- a/basegfx/source/curve/b2dcubicbezier.cxx +++ b/basegfx/source/curve/b2dcubicbezier.cxx @@ -20,6 +20,7 @@ #include <basegfx/curve/b2dcubicbezier.hxx> #include <basegfx/vector/b2dvector.hxx> #include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/numeric/ftools.hxx> #include <osl/diagnose.h> @@ -1021,6 +1022,66 @@ namespace basegfx } } + void B2DCubicBezier::transform(const basegfx::B2DHomMatrix& rMatrix) + { + if(!rMatrix.isIdentity()) + { + if(maControlPointA == maStartPoint) + { + maControlPointA = maStartPoint = rMatrix * maStartPoint; + } + else + { + maStartPoint *= rMatrix; + maControlPointA *= rMatrix; + } + + if(maControlPointB == maEndPoint) + { + maControlPointB = maEndPoint = rMatrix * maEndPoint; + } + else + { + maEndPoint *= rMatrix; + maControlPointB *= rMatrix; + } + } + } + + void B2DCubicBezier::fround() + { + if(maControlPointA == maStartPoint) + { + maControlPointA = maStartPoint = basegfx::B2DPoint( + basegfx::fround(maStartPoint.getX()), + basegfx::fround(maStartPoint.getY())); + } + else + { + maStartPoint = basegfx::B2DPoint( + basegfx::fround(maStartPoint.getX()), + basegfx::fround(maStartPoint.getY())); + maControlPointA = basegfx::B2DPoint( + basegfx::fround(maControlPointA.getX()), + basegfx::fround(maControlPointA.getY())); + } + + if(maControlPointB == maEndPoint) + { + maControlPointB = maEndPoint = basegfx::B2DPoint( + basegfx::fround(maEndPoint.getX()), + basegfx::fround(maEndPoint.getY())); + } + else + { + maEndPoint = basegfx::B2DPoint( + basegfx::fround(maEndPoint.getX()), + basegfx::fround(maEndPoint.getY())); + maControlPointB = basegfx::B2DPoint( + basegfx::fround(maControlPointB.getX()), + basegfx::fround(maControlPointB.getY())); + } + } } // end of namespace basegfx /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/curve/b2dcubicbezier.hxx b/include/basegfx/curve/b2dcubicbezier.hxx index f97ac2991306..b8254b4b9a2e 100644 --- a/include/basegfx/curve/b2dcubicbezier.hxx +++ b/include/basegfx/curve/b2dcubicbezier.hxx @@ -33,6 +33,7 @@ namespace basegfx { class BASEGFX_DLLPUBLIC B2DCubicBezier { + private: B2DPoint maStartPoint; B2DPoint maEndPoint; B2DPoint maControlPointA; @@ -187,6 +188,12 @@ namespace basegfx sense to use reserve(4) at the vector as preparation. */ void getAllExtremumPositions(::std::vector< double >& rResults) const; + + /// apply transformation given in matrix form + void transform(const basegfx::B2DHomMatrix& rMatrix); + + /// fround content + void fround(); }; } // end of namespace basegfx diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h index 15f6a49daadf..fb4d8445244f 100644 --- a/vcl/inc/unx/salgdi.h +++ b/vcl/inc/unx/salgdi.h @@ -267,6 +267,10 @@ public: virtual css::uno::Any GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const basegfx::B2ISize& rSize) const override; virtual SystemFontData GetSysFontData( int nFallbackLevel ) const override; +#if ENABLE_CAIRO_CANVAS + void clipRegion(cairo_t* cr); +#endif // ENABLE_CAIRO_CANVAS + bool TryRenderCachedNativeControl(ControlCacheKey& aControlCacheKey, int nX, int nY); @@ -330,6 +334,11 @@ protected: Region pPaintRegion_; Region mpClipRegion; +#if ENABLE_CAIRO_CANVAS + vcl::Region maClipRegion; + SalColor mnPenColor; + SalColor mnFillColor; +#endif // ENABLE_CAIRO_CANVAS GC pFontGC_; // Font attributes Pixel nTextPixel_; diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx index a8106a6c28a1..a1bd2ec9e770 100644 --- a/vcl/unx/generic/gdi/salgdi.cxx +++ b/vcl/unx/generic/gdi/salgdi.cxx @@ -40,6 +40,7 @@ #include "basegfx/matrix/b2dhommatrixtools.hxx" #include "basegfx/polygon/b2dpolypolygoncutter.hxx" #include "basegfx/polygon/b2dtrapezoid.hxx" +#include <basegfx/curve/b2dcubicbezier.hxx> #include <vcl/jobdata.hxx> #include <vcl/virdev.hxx> @@ -79,6 +80,11 @@ X11SalGraphics::X11SalGraphics(): m_aXRenderPicture(0), pPaintRegion_(nullptr), mpClipRegion(nullptr), +#if ENABLE_CAIRO_CANVAS + maClipRegion(), + mnPenColor(SALCOLOR_NONE), + mnFillColor(SALCOLOR_NONE), +#endif // ENABLE_CAIRO_CANVAS pFontGC_(nullptr), nTextPixel_(0), hBrush_(None), @@ -354,26 +360,43 @@ void X11SalGraphics::ResetClipRegion() bool X11SalGraphics::setClipRegion( const vcl::Region& i_rClip ) { + maClipRegion = i_rClip; return mxImpl->setClipRegion( i_rClip ); } void X11SalGraphics::SetLineColor() { +#if ENABLE_CAIRO_CANVAS + mnPenColor = SALCOLOR_NONE; +#endif // ENABLE_CAIRO_CANVAS + mxImpl->SetLineColor(); } void X11SalGraphics::SetLineColor( SalColor nSalColor ) { +#if ENABLE_CAIRO_CANVAS + mnPenColor = nSalColor; +#endif // ENABLE_CAIRO_CANVAS + mxImpl->SetLineColor( nSalColor ); } void X11SalGraphics::SetFillColor() { +#if ENABLE_CAIRO_CANVAS + mnFillColor = SALCOLOR_NONE; +#endif // ENABLE_CAIRO_CANVAS + mxImpl->SetFillColor(); } void X11SalGraphics::SetFillColor( SalColor nSalColor ) { +#if ENABLE_CAIRO_CANVAS + mnFillColor = nSalColor; +#endif // ENABLE_CAIRO_CANVAS + mxImpl->SetFillColor( nSalColor ); } @@ -555,9 +578,134 @@ css::uno::Any X11SalGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rS // draw a poly-polygon bool X11SalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency ) { + if(fTransparency >= 1.0) + { + return true; + } + + const sal_uInt32 nPolyCount(rOrigPolyPoly.count()); + + if(nPolyCount <= 0) + { + return true; + } + + if(SALCOLOR_NONE == mnFillColor && SALCOLOR_NONE == mnPenColor) + { + return true; + } + +#if ENABLE_CAIRO_CANVAS + static bool bUseCairoForPolygons = false; + + if(bUseCairoForPolygons && SupportsCairo()) + { + // snap to raster if requested + basegfx::B2DPolyPolygon aPolyPoly(rOrigPolyPoly); + const bool bSnapPoints(!getAntiAliasB2DDraw()); + + if(bSnapPoints) + { + aPolyPoly = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aPolyPoly); + } + + cairo_t* cr = getCairoContext(); + clipRegion(cr); + + for(sal_uInt32 a(0); a < nPolyCount; ++a) + { + const basegfx::B2DPolygon aPolygon(aPolyPoly.getB2DPolygon(a)); + const sal_uInt32 nPointCount(aPolygon.count()); + + if(nPointCount) + { + const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount : nPointCount - 1); + + if(nEdgeCount) + { + basegfx::B2DCubicBezier aEdge; + + for(sal_uInt32 b = 0; b < nEdgeCount; ++b) + { + aPolygon.getBezierSegment(b, aEdge); + + if(!b) + { + const basegfx::B2DPoint aStart(aEdge.getStartPoint()); + cairo_move_to(cr, aStart.getX(), aStart.getY()); + } + + const basegfx::B2DPoint aEnd(aEdge.getEndPoint()); + + if(aEdge.isBezier()) + { + const basegfx::B2DPoint aCP1(aEdge.getControlPointA()); + const basegfx::B2DPoint aCP2(aEdge.getControlPointB()); + cairo_curve_to(cr, + aCP1.getX(), aCP1.getY(), + aCP2.getX(), aCP2.getY(), + aEnd.getX(), aEnd.getY()); + } + else + { + cairo_line_to(cr, aEnd.getX(), aEnd.getY()); + } + } + + cairo_close_path(cr); + } + } + } + + if(SALCOLOR_NONE != mnFillColor) + { + cairo_set_source_rgba(cr, + SALCOLOR_RED(mnFillColor)/255.0, + SALCOLOR_GREEN(mnFillColor)/255.0, + SALCOLOR_BLUE(mnFillColor)/255.0, + 1.0 - fTransparency); + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_fill_preserve(cr); + } + + if(SALCOLOR_NONE != mnPenColor) + { + cairo_set_source_rgba(cr, + SALCOLOR_RED(mnPenColor)/255.0, + SALCOLOR_GREEN(mnPenColor)/255.0, + SALCOLOR_BLUE(mnPenColor)/255.0, + 1.0 - fTransparency); + cairo_stroke_preserve(cr); + } + + releaseCairoContext(cr); + return true; + } +#endif // ENABLE_CAIRO_CANVAS + return mxImpl->drawPolyPolygon( rOrigPolyPoly, fTransparency ); } +#if ENABLE_CAIRO_CANVAS +void X11SalGraphics::clipRegion(cairo_t* cr) +{ + if(!maClipRegion.IsEmpty()) + { + RectangleVector aRectangles; + maClipRegion.GetRegionRectangles(aRectangles); + + if (!aRectangles.empty()) + { + for (RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter) + { + cairo_rectangle(cr, aRectIter->Left(), aRectIter->Top(), aRectIter->GetWidth(), aRectIter->GetHeight()); + } + cairo_clip(cr); + } + } +} +#endif // ENABLE_CAIRO_CANVAS + bool X11SalGraphics::drawPolyLine( const basegfx::B2DPolygon& rPolygon, double fTransparency, @@ -566,6 +714,129 @@ bool X11SalGraphics::drawPolyLine( css::drawing::LineCap eLineCap, double fMiterMinimumAngle) { + const int nPointCount(rPolygon.count()); + + if(nPointCount <= 0) + { + return true; + } + + if(fTransparency >= 1.0) + { + return true; + } + +#if ENABLE_CAIRO_CANVAS + static bool bUseCairoForFatLines = true; + + if(bUseCairoForFatLines && SupportsCairo()) + { + cairo_t* cr = getCairoContext(); + clipRegion(cr); + cairo_line_join_t eCairoLineJoin(CAIRO_LINE_JOIN_MITER); + bool bNoJoin(false); + + switch(eLineJoin) + { + case basegfx::B2DLineJoin::Bevel: + eCairoLineJoin = CAIRO_LINE_JOIN_BEVEL; + break; + case basegfx::B2DLineJoin::Round: + eCairoLineJoin = CAIRO_LINE_JOIN_ROUND; + break; + case basegfx::B2DLineJoin::NONE: + bNoJoin = true; + SAL_FALLTHROUGH; + case basegfx::B2DLineJoin::Miter: + eCairoLineJoin = CAIRO_LINE_JOIN_MITER; + break; + } + + // setup cap attribute + cairo_line_cap_t eCairoLineCap(CAIRO_LINE_CAP_BUTT); + switch(eLineCap) + { + default: // css::drawing::LineCap_BUTT: + { + eCairoLineCap = CAIRO_LINE_CAP_BUTT; + break; + } + case css::drawing::LineCap_ROUND: + { + eCairoLineCap = CAIRO_LINE_CAP_ROUND; + break; + } + case css::drawing::LineCap_SQUARE: + { + eCairoLineCap = CAIRO_LINE_CAP_SQUARE; + break; + } + } + + cairo_set_source_rgba(cr, + SALCOLOR_RED(mnPenColor)/255.0, + SALCOLOR_GREEN(mnPenColor)/255.0, + SALCOLOR_BLUE(mnPenColor)/255.0, + 1.0 - fTransparency); + cairo_set_line_join(cr, eCairoLineJoin); + cairo_set_line_cap(cr, eCairoLineCap); + cairo_set_line_width(cr, (fabs(rLineWidth.getX()) + fabs(rLineWidth.getY())) * 0.5); + + if(CAIRO_LINE_JOIN_MITER == eCairoLineJoin) + { + cairo_set_miter_limit(cr, 15.0); + } + + const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nPointCount : nPointCount - 1); + + if(nEdgeCount) + { + const bool bSnapPoints(!getAntiAliasB2DDraw()); + static basegfx::B2DHomMatrix aHalfPointTransform(basegfx::tools::createTranslateB2DHomMatrix(0.5, 0.5)); + basegfx::B2DCubicBezier aEdge; + + for(sal_uInt32 i = 0; i < nEdgeCount; ++i) + { + rPolygon.getBezierSegment(i, aEdge); + + aEdge.transform(aHalfPointTransform); + + if(bSnapPoints) + { + aEdge.fround(); + } + + if(!i || bNoJoin) + { + const basegfx::B2DPoint aStart(aEdge.getStartPoint()); + cairo_move_to(cr, aStart.getX(), aStart.getY()); + } + + const basegfx::B2DPoint aEnd(aEdge.getEndPoint()); + + if(aEdge.isBezier()) + { + const basegfx::B2DPoint aCP1(aEdge.getControlPointA()); + const basegfx::B2DPoint aCP2(aEdge.getControlPointB()); + cairo_curve_to(cr, + aCP1.getX(), aCP1.getY(), + aCP2.getX(), aCP2.getY(), + aEnd.getX(), aEnd.getY()); + } + else + { + cairo_line_to(cr, aEnd.getX(), aEnd.getY()); + } + } + + cairo_stroke(cr); + } + + releaseCairoContext(cr); + return true; + } +#endif // ENABLE_CAIRO_CANVAS + return mxImpl->drawPolyLine( rPolygon, fTransparency, rLineWidth, eLineJoin, eLineCap, fMiterMinimumAngle ); } |