summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--basegfx/source/curve/b2dcubicbezier.cxx61
-rw-r--r--include/basegfx/curve/b2dcubicbezier.hxx7
-rw-r--r--vcl/inc/unx/salgdi.h9
-rw-r--r--vcl/unx/generic/gdi/salgdi.cxx271
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 );
}