2dcfccb
From f940d97bfe93d2c5adc97cde64100f01240f7dfa Mon Sep 17 00:00:00 2001
2dcfccb
From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
2dcfccb
Date: Fri, 20 Nov 2015 11:18:52 +0000
2dcfccb
Subject: [PATCH] Resolves: tdf#92687 implement drawPolyPolygon via cairo
2dcfccb
2dcfccb
modeled on the quartz impl
2dcfccb
2dcfccb
(cherry picked from commit 742da70e6dd2407641835cbcac54b09aeddcb9db)
2dcfccb
2dcfccb
Change-Id: I2f6776c14c7350954932df2bffcca36172f13473
2dcfccb
---
2dcfccb
 vcl/headless/svpgdi.cxx | 173 ++++++++++++++++++++++++++++++++++++++++++------
2dcfccb
 1 file changed, 151 insertions(+), 22 deletions(-)
2dcfccb
2dcfccb
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
2dcfccb
index ed2fe18..effbeda 100644
2dcfccb
--- a/vcl/headless/svpgdi.cxx
2dcfccb
+++ b/vcl/headless/svpgdi.cxx
2dcfccb
@@ -28,6 +28,7 @@
2dcfccb
 #include <basegfx/range/b2drange.hxx>
2dcfccb
 #include <basegfx/range/b2ibox.hxx>
2dcfccb
 #include <basegfx/polygon/b2dpolypolygon.hxx>
2dcfccb
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
2dcfccb
 #include <basegfx/polygon/b2dpolygon.hxx>
2dcfccb
 #include <basegfx/polygon/b2dpolygontools.hxx>
2dcfccb
 #include <basebmp/scanlineformats.hxx>
2dcfccb
@@ -134,6 +135,27 @@ void SvpSalGraphics::clipRegion(cairo_t* cr)
2dcfccb
         cairo_clip(cr);
2dcfccb
     }
2dcfccb
 }
2dcfccb
+namespace
2dcfccb
+{
2dcfccb
+    cairo_rectangle_int_t getFillDamage(cairo_t* cr)
2dcfccb
+    {
2dcfccb
+        cairo_rectangle_int_t extents;
2dcfccb
+        double x1, y1, x2, y2;
2dcfccb
+
2dcfccb
+        cairo_clip_extents(cr, &x1, &y1, &x2, &y2;;
2dcfccb
+        extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1;
2dcfccb
+        cairo_region_t *region = cairo_region_create_rectangle(&extents);
2dcfccb
+
2dcfccb
+        cairo_fill_extents(cr, &x1, &y1, &x2, &y2;;
2dcfccb
+        extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1;
2dcfccb
+        cairo_region_intersect_rectangle(region, &extents);
2dcfccb
+
2dcfccb
+        cairo_region_get_extents(region, &extents);
2dcfccb
+        cairo_region_destroy(region);
2dcfccb
+
2dcfccb
+        return extents;
2dcfccb
+    }
2dcfccb
+}
2dcfccb
 
2dcfccb
 #endif
2dcfccb
 
2dcfccb
@@ -144,7 +166,10 @@ bool SvpSalGraphics::drawAlphaRect(long nX, long nY, long nWidth, long nHeight,
2dcfccb
 #if ENABLE_CAIRO_CANVAS
2dcfccb
 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)
2dcfccb
     if (m_bUseLineColor || !m_bUseFillColor)
2dcfccb
-        return bRet;
2dcfccb
+    {
2dcfccb
+        SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaRect case");
2dcfccb
+        return false;
2dcfccb
+    }
2dcfccb
 
2dcfccb
     cairo_t* cr = createCairoContext(m_aDevice);
2dcfccb
     if (!cr)
2dcfccb
@@ -165,24 +190,10 @@ bool SvpSalGraphics::drawAlphaRect(long nX, long nY, long nWidth, long nHeight,
2dcfccb
                               fTransparency);
2dcfccb
     cairo_rectangle(cr, nX, nY, nWidth, nHeight);
2dcfccb
 
2dcfccb
-
2dcfccb
     cairo_rectangle_int_t extents;
2dcfccb
     basebmp::IBitmapDeviceDamageTrackerSharedPtr xDamageTracker(m_aDevice->getDamageTracker());
2dcfccb
     if (xDamageTracker)
2dcfccb
-    {
2dcfccb
-        double x1, y1, x2, y2;
2dcfccb
-
2dcfccb
-        cairo_clip_extents(cr, &x1, &y1, &x2, &y2;;
2dcfccb
-        extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1;
2dcfccb
-        cairo_region_t *region = cairo_region_create_rectangle(&extents);
2dcfccb
-
2dcfccb
-        cairo_fill_extents(cr, &x1, &y1, &x2, &y2;;
2dcfccb
-        extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1;
2dcfccb
-        cairo_region_intersect_rectangle(region, &extents);
2dcfccb
-
2dcfccb
-        cairo_region_get_extents(region, &extents);
2dcfccb
-        cairo_region_destroy(region);
2dcfccb
-    }
2dcfccb
+        extents = getFillDamage(cr);
2dcfccb
 
2dcfccb
     cairo_fill(cr);
2dcfccb
 
2dcfccb
@@ -644,10 +655,118 @@ bool SvpSalGraphics::drawPolyPolygonBezier( sal_uInt32,
2dcfccb
     return false;
2dcfccb
 }
2dcfccb
 
2dcfccb
-bool SvpSalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon&, double /*fTransparency*/ )
2dcfccb
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)
2dcfccb
+static void AddPolygonToPath(cairo_t* cr, const basegfx::B2DPolygon& rPolygon, bool bClosePath)
2dcfccb
 {
2dcfccb
-    // TODO: maybe BaseBmp can draw B2DPolyPolygons directly
2dcfccb
-    return false;
2dcfccb
+    // short circuit if there is nothing to do
2dcfccb
+    const int nPointCount = rPolygon.count();
2dcfccb
+    if( nPointCount <= 0 )
2dcfccb
+    {
2dcfccb
+        return;
2dcfccb
+    }
2dcfccb
+
2dcfccb
+    const bool bHasCurves = rPolygon.areControlPointsUsed();
2dcfccb
+    for( int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++ )
2dcfccb
+    {
2dcfccb
+        int nClosedIdx = nPointIdx;
2dcfccb
+        if( nPointIdx >= nPointCount )
2dcfccb
+        {
2dcfccb
+            // prepare to close last curve segment if needed
2dcfccb
+            if( bClosePath && (nPointIdx == nPointCount) )
2dcfccb
+            {
2dcfccb
+                nClosedIdx = 0;
2dcfccb
+            }
2dcfccb
+            else
2dcfccb
+            {
2dcfccb
+                break;
2dcfccb
+            }
2dcfccb
+        }
2dcfccb
+
2dcfccb
+        basegfx::B2DPoint aPoint = rPolygon.getB2DPoint( nClosedIdx );
2dcfccb
+
2dcfccb
+        if( !nPointIdx )
2dcfccb
+        {
2dcfccb
+            // first point => just move there
2dcfccb
+            cairo_move_to(cr, aPoint.getX(), aPoint.getY());
2dcfccb
+            continue;
2dcfccb
+        }
2dcfccb
+
2dcfccb
+        bool bPendingCurve = false;
2dcfccb
+        if( bHasCurves )
2dcfccb
+        {
2dcfccb
+            bPendingCurve = rPolygon.isNextControlPointUsed( nPrevIdx );
2dcfccb
+            bPendingCurve |= rPolygon.isPrevControlPointUsed( nClosedIdx );
2dcfccb
+        }
2dcfccb
+
2dcfccb
+        if( !bPendingCurve )    // line segment
2dcfccb
+        {
2dcfccb
+            cairo_line_to(cr, aPoint.getX(), aPoint.getY());
2dcfccb
+        }
2dcfccb
+        else                        // cubic bezier segment
2dcfccb
+        {
2dcfccb
+            basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint( nPrevIdx );
2dcfccb
+            basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint( nClosedIdx );
2dcfccb
+            cairo_curve_to(cr, aCP1.getX(), aCP1.getY(), aCP2.getX(), aCP2.getY(),
2dcfccb
+                               aPoint.getX(), aPoint.getY());
2dcfccb
+        }
2dcfccb
+    }
2dcfccb
+
2dcfccb
+    if( bClosePath )
2dcfccb
+    {
2dcfccb
+        cairo_close_path(cr);
2dcfccb
+    }
2dcfccb
+}
2dcfccb
+#endif
2dcfccb
+
2dcfccb
+bool SvpSalGraphics::drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPoly, double fTransparency)
2dcfccb
+{
2dcfccb
+    bool bRet = false;
2dcfccb
+    (void)rPolyPoly; (void)fTransparency;
2dcfccb
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)
2dcfccb
+    if (m_bUseLineColor || !m_bUseFillColor)
2dcfccb
+    {
2dcfccb
+        SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawPolyPolygon case");
2dcfccb
+        return false;
2dcfccb
+    }
2dcfccb
+
2dcfccb
+    cairo_t* cr = createCairoContext(m_aDevice);
2dcfccb
+    if (!cr)
2dcfccb
+        return false;
2dcfccb
+
2dcfccb
+    if (!m_aDevice->isTopDown())
2dcfccb
+    {
2dcfccb
+        cairo_scale(cr, 1, -1.0);
2dcfccb
+        cairo_translate(cr, 0.0, -m_aDevice->getSize().getY());
2dcfccb
+    }
2dcfccb
+
2dcfccb
+    clipRegion(cr);
2dcfccb
+
2dcfccb
+    cairo_set_source_rgba(cr, m_aFillColor.getRed()/255.0,
2dcfccb
+                              m_aFillColor.getGreen()/255.0,
2dcfccb
+                              m_aFillColor.getBlue()/255.0,
2dcfccb
+                              1.0-fTransparency);
2dcfccb
+
2dcfccb
+    for (const basegfx::B2DPolygon* pPoly = rPolyPoly.begin(); pPoly != rPolyPoly.end(); ++pPoly)
2dcfccb
+        AddPolygonToPath(cr, *pPoly, true);
2dcfccb
+
2dcfccb
+    cairo_rectangle_int_t extents;
2dcfccb
+    basebmp::IBitmapDeviceDamageTrackerSharedPtr xDamageTracker(m_aDevice->getDamageTracker());
2dcfccb
+    if (xDamageTracker)
2dcfccb
+        extents = getFillDamage(cr);
2dcfccb
+
2dcfccb
+    cairo_fill(cr);
2dcfccb
+
2dcfccb
+    cairo_surface_flush(cairo_get_target(cr));
2dcfccb
+    cairo_destroy(cr); // unref
2dcfccb
+
2dcfccb
+    if (xDamageTracker)
2dcfccb
+    {
2dcfccb
+        xDamageTracker->damaged(basegfx::B2IBox(extents.x, extents.y, extents.x + extents.width,
2dcfccb
+                                                extents.y + extents.height));
2dcfccb
+    }
2dcfccb
+    bRet = true;
2dcfccb
+#endif
2dcfccb
+    return bRet;
2dcfccb
 }
2dcfccb
 
2dcfccb
 void SvpSalGraphics::copyArea( long nDestX,
2dcfccb
@@ -883,9 +1002,19 @@ SystemGraphicsData SvpSalGraphics::GetGraphicsData() const
2dcfccb
 bool SvpSalGraphics::supportsOperation(OutDevSupportType eType) const
2dcfccb
 {
2dcfccb
 #if ENABLE_CAIRO_CANVAS
2dcfccb
-    return m_aDrawMode != basebmp::DrawMode_XOR &&
2dcfccb
-           OutDevSupport_TransparentRect == eType &&
2dcfccb
-           isCairoCompatible(m_aDevice);
2dcfccb
+    if (m_aDrawMode == basebmp::DrawMode_XOR)
2dcfccb
+        return false;
2dcfccb
+    if (!isCairoCompatible(m_aDevice))
2dcfccb
+        return false;
2dcfccb
+    switch (eType)
2dcfccb
+    {
2dcfccb
+        case OutDevSupport_TransparentRect:
2dcfccb
+        case OutDevSupport_B2DDraw:
2dcfccb
+            return true;
2dcfccb
+        case OutDevSupport_B2DClip: //what's this one ?
2dcfccb
+            return false;
2dcfccb
+    }
2dcfccb
+    return false;
2dcfccb
 #else
2dcfccb
     (void)eType;
2dcfccb
     return false;
2dcfccb
-- 
2dcfccb
2.5.0
2dcfccb