summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2020-05-26 11:03:06 +0200
committerLuboš Luňák <l.lunak@collabora.com>2020-05-26 15:55:37 +0200
commit3a93748c9c4faadeb9ab4eb21706d187677549fa (patch)
treea89371682cb4729a15df1630cf26a19fb6d0e8aa
parent6cd885b46bf168a1fe0d91231a1b6d283f813ed3 (diff)
use Skia to do dashed lines, no need to do it manually (tdf#130431)
Change-Id: Id5efe7227f3c2bcb5ef6f1b990327e72014e8c47 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94857 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
-rw-r--r--vcl/backendtest/VisualBackendTest.cxx9
-rw-r--r--vcl/backendtest/outputdevice/common.cxx5
-rw-r--r--vcl/backendtest/outputdevice/line.cxx87
-rw-r--r--vcl/inc/skia/gdiimpl.hxx6
-rw-r--r--vcl/inc/test/outputdevice.hxx4
-rw-r--r--vcl/qa/cppunit/BackendTest.cxx12
-rw-r--r--vcl/skia/gdiimpl.cxx41
7 files changed, 131 insertions, 33 deletions
diff --git a/vcl/backendtest/VisualBackendTest.cxx b/vcl/backendtest/VisualBackendTest.cxx
index 5daa9a642d55..08efc1d381a3 100644
--- a/vcl/backendtest/VisualBackendTest.cxx
+++ b/vcl/backendtest/VisualBackendTest.cxx
@@ -576,7 +576,7 @@ public:
}
else if (mnTest % gnNumberOfTests == 7)
{
- std::vector<tools::Rectangle> aRegions = setupRegions(3, 1, nWidth, nHeight);
+ std::vector<tools::Rectangle> aRegions = setupRegions(2, 2, nWidth, nHeight);
aRectangle = aRegions[index++];
{
@@ -587,6 +587,13 @@ public:
}
aRectangle = aRegions[index++];
{
+ vcl::test::OutputDeviceTestLine aOutDevTest;
+ Bitmap aBitmap = aOutDevTest.setupDashedLine();
+ assertAndSetBackground(vcl::test::OutputDeviceTestLine::checkDashedLine(aBitmap), aRectangle, rRenderContext);
+ drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext);
+ }
+ aRectangle = aRegions[index++];
+ {
vcl::test::OutputDeviceTestGradient aOutDevTest;
Bitmap aBitmap = aOutDevTest.setupLinearGradient();
drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext);
diff --git a/vcl/backendtest/outputdevice/common.cxx b/vcl/backendtest/outputdevice/common.cxx
index f9052fb77201..a5d032315474 100644
--- a/vcl/backendtest/outputdevice/common.cxx
+++ b/vcl/backendtest/outputdevice/common.cxx
@@ -416,6 +416,11 @@ TestResult OutputDeviceTestCommon::checkRectangles(Bitmap& aBitmap, std::vector<
return aReturnValue;
}
+TestResult OutputDeviceTestCommon::checkRectangle(Bitmap& rBitmap, int aLayerNumber, Color aExpectedColor)
+{
+ return checkRect(rBitmap, aLayerNumber, aExpectedColor);
+}
+
tools::Rectangle OutputDeviceTestCommon::alignToCenter(tools::Rectangle aRect1, tools::Rectangle aRect2)
{
Point aPoint((aRect1.GetWidth() / 2.0) - (aRect2.GetWidth() / 2.0),
diff --git a/vcl/backendtest/outputdevice/line.cxx b/vcl/backendtest/outputdevice/line.cxx
index b9236dcc210d..5b5d73261135 100644
--- a/vcl/backendtest/outputdevice/line.cxx
+++ b/vcl/backendtest/outputdevice/line.cxx
@@ -10,6 +10,11 @@
#include <test/outputdevice.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <vcl/bitmapaccess.hxx>
+
+#include <list>
+
namespace vcl::test {
namespace
@@ -108,6 +113,88 @@ Bitmap OutputDeviceTestLine::setupAALines()
return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize());
}
+Bitmap OutputDeviceTestLine::setupDashedLine()
+{
+ initialSetup(13, 13, constBackgroundColor);
+
+ mpVirtualDevice->SetLineColor(constLineColor);
+ mpVirtualDevice->SetFillColor();
+
+ tools::Rectangle rectangle = maVDRectangle;
+ rectangle.shrink(2);
+
+ std::vector stroke({ 2.0, 1.0 });
+ mpVirtualDevice->DrawPolyLineDirect( basegfx::B2DHomMatrix(),
+ basegfx::B2DPolygon{
+ basegfx::B2DPoint(rectangle.getX(), rectangle.getY()),
+ basegfx::B2DPoint(rectangle.getX(), rectangle.getY() + rectangle.getHeight()),
+ basegfx::B2DPoint(rectangle.getX() + rectangle.getWidth(),
+ rectangle.getY() + rectangle.getHeight()),
+ basegfx::B2DPoint(rectangle.getX() + rectangle.getWidth(), rectangle.getY()),
+ basegfx::B2DPoint(rectangle.getX(), rectangle.getY())},
+ 1, 0, &stroke, basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0), true );
+
+ return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize());
+}
+
+TestResult OutputDeviceTestLine::checkDashedLine(Bitmap& rBitmap)
+{
+ TestResult returnValue = TestResult::Passed;
+ for (int i = 0; i < 7; i++)
+ {
+ TestResult eResult = TestResult::Passed;
+ if( i == 2 )
+ {
+ // Build a sequence of pixels for the drawn rectangle border,
+ // check that they alternate appropriately (there should be
+ // normally 2 line, 1 background).
+ std::list< bool > dash; // true - line color, false - background
+ const int width = rBitmap.GetSizePixel().Width();
+ const int height = rBitmap.GetSizePixel().Height();
+ BitmapReadAccess access(rBitmap);
+ for( int x = 2; x < width - 2; ++x )
+ dash.push_back( access.GetPixel( 2, x ) == constLineColor );
+ for( int y = 3; y < height - 3; ++y )
+ dash.push_back( access.GetPixel( y, width - 3 ) == constLineColor );
+ for( int x = width - 3; x >= 2; --x )
+ dash.push_back( access.GetPixel( height - 3, x ) == constLineColor );
+ for( int y = height - 4; y >= 3; --y )
+ dash.push_back( access.GetPixel( y, 2 ) == constLineColor );
+ for( int x = 2; x < width - 2; ++x ) // repeat, to check also the corner
+ dash.push_back( access.GetPixel( 2, x ) == constLineColor );
+ bool last = false;
+ int lastCount = 0;
+ while( !dash.empty())
+ {
+ if( dash.front() == last )
+ {
+ ++lastCount;
+ if( lastCount > ( last ? 4 : 3 ))
+ eResult = TestResult::Failed;
+ else if( lastCount > ( last ? 3 : 2 ) && eResult != TestResult::Failed)
+ eResult = TestResult::PassedWithQuirks;
+ }
+ else
+ {
+ last = dash.front();
+ lastCount = 1;
+ }
+ dash.pop_front();
+ }
+ }
+ else
+ {
+ eResult = OutputDeviceTestCommon::checkRectangle(rBitmap, i, constBackgroundColor);
+ }
+
+ if (eResult == TestResult::Failed)
+ returnValue = TestResult::Failed;
+ if (eResult == TestResult::PassedWithQuirks && returnValue != TestResult::Failed)
+ returnValue = TestResult::PassedWithQuirks;
+ }
+ return returnValue;
+}
+
} // end namespace vcl::test
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx
index c78845fe6ffa..eb5fbdbdcbf8 100644
--- a/vcl/inc/skia/gdiimpl.hxx
+++ b/vcl/inc/skia/gdiimpl.hxx
@@ -104,9 +104,9 @@ public:
virtual bool drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice,
const basegfx::B2DPolygon&, double fTransparency, double fLineWidth,
- const std::vector<double>* pStroke, // MM01
- basegfx::B2DLineJoin, css::drawing::LineCap,
- double fMiterMinimumAngle, bool bPixelSnapHairline) override;
+ const std::vector<double>* pStroke, basegfx::B2DLineJoin,
+ css::drawing::LineCap, double fMiterMinimumAngle,
+ bool bPixelSnapHairline) override;
virtual bool drawPolyLineBezier(sal_uInt32 nPoints, const SalPoint* pPtAry,
const PolyFlags* pFlgAry) override;
diff --git a/vcl/inc/test/outputdevice.hxx b/vcl/inc/test/outputdevice.hxx
index b6cf70c22bd0..b8ad0b67fc6b 100644
--- a/vcl/inc/test/outputdevice.hxx
+++ b/vcl/inc/test/outputdevice.hxx
@@ -60,6 +60,7 @@ public:
static TestResult checkInvertTrackFrameRectangle(Bitmap& aBitmap);
static TestResult checkRectangles(Bitmap& rBitmap, std::vector<Color>& aExpectedColors);
+ static TestResult checkRectangle(Bitmap& rBitmap, int aLayerNumber, Color aExpectedColor);
static TestResult checkFilled(Bitmap& rBitmap, tools::Rectangle aRectangle, Color aExpectedColor);
static TestResult checkChecker(Bitmap& rBitmap, sal_Int32 nStartX, sal_Int32 nEndX,
@@ -125,6 +126,9 @@ public:
Bitmap setupDiamond();
Bitmap setupLines();
Bitmap setupAALines();
+
+ Bitmap setupDashedLine();
+ static TestResult checkDashedLine(Bitmap& rBitmap);
};
class VCL_DLLPUBLIC OutputDeviceTestPolyLine : public OutputDeviceTestCommon
diff --git a/vcl/qa/cppunit/BackendTest.cxx b/vcl/qa/cppunit/BackendTest.cxx
index b34dda5262ec..ff4ed0d87251 100644
--- a/vcl/qa/cppunit/BackendTest.cxx
+++ b/vcl/qa/cppunit/BackendTest.cxx
@@ -495,6 +495,16 @@ public:
CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
}
+ void testDashedLine()
+ {
+ vcl::test::OutputDeviceTestLine aOutDevTest;
+ Bitmap aBitmap = aOutDevTest.setupDashedLine();
+ auto eResult = vcl::test::OutputDeviceTestLine::checkDashedLine(aBitmap);
+ exportImage("10-01_dashed_line_test.png", aBitmap);
+ if (SHOULD_ASSERT)
+ CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
+ }
+
void testTdf124848()
{
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT);
@@ -575,6 +585,8 @@ public:
CPPUNIT_TEST(testClipPolyPolygon);
CPPUNIT_TEST(testClipB2DPolyPolygon);
+ CPPUNIT_TEST(testDashedLine);
+
CPPUNIT_TEST(testTdf124848);
CPPUNIT_TEST_SUITE_END();
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index a2ccb12d406d..b5b9aad6ae22 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -644,10 +644,8 @@ void SkiaSalGraphicsImpl::drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAr
aPolygon.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY));
aPolygon.setClosed(false);
- drawPolyLine(basegfx::B2DHomMatrix(), aPolygon, 0.0, 1.0,
- nullptr, // MM01
- basegfx::B2DLineJoin::Miter, css::drawing::LineCap_BUTT,
- basegfx::deg2rad(15.0) /*default*/, false);
+ drawPolyLine(basegfx::B2DHomMatrix(), aPolygon, 0.0, 1.0, nullptr, basegfx::B2DLineJoin::Miter,
+ css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0) /*default*/, false);
}
void SkiaSalGraphicsImpl::drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry)
@@ -736,13 +734,11 @@ bool SkiaSalGraphicsImpl::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectTo
bool SkiaSalGraphicsImpl::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice,
const basegfx::B2DPolygon& rPolyLine, double fTransparency,
- double fLineWidth,
- const std::vector<double>* pStroke, // MM01
+ double fLineWidth, const std::vector<double>* pStroke,
basegfx::B2DLineJoin eLineJoin,
css::drawing::LineCap eLineCap, double fMiterMinimumAngle,
bool bPixelSnapHairline)
{
- // MM01 check done for simple reasons
if (!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0
|| mLineColor == SALCOLOR_NONE)
{
@@ -758,29 +754,9 @@ bool SkiaSalGraphicsImpl::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDev
else // Adjust line width for object-to-device scale.
fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength();
- // MM01 need to do line dashing as fallback stuff here now
- const double fDotDashLength(
- nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
- const bool bStrokeUsed(0.0 != fDotDashLength);
- assert(!bStrokeUsed || (bStrokeUsed && pStroke));
- basegfx::B2DPolyPolygon aPolyPolygonLine;
-
- if (bStrokeUsed)
- {
- // apply LineStyle
- basegfx::utils::applyLineDashing(rPolyLine, // source
- *pStroke, // pattern
- &aPolyPolygonLine, // target for lines
- nullptr, // target for gaps
- fDotDashLength); // full length if available
- }
- else
- {
- // no line dashing, just copy
- aPolyPolygonLine.append(rPolyLine);
- }
-
// Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline
+ basegfx::B2DPolyPolygon aPolyPolygonLine;
+ aPolyPolygonLine.append(rPolyLine);
aPolyPolygonLine.transform(rObjectToDevice);
if (bPixelSnapHairline)
{
@@ -831,6 +807,13 @@ bool SkiaSalGraphicsImpl::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDev
aPaint.setStrokeWidth(fLineWidth);
aPaint.setAntiAlias(mParent.getAntiAliasB2DDraw());
+ if (pStroke && std::accumulate(pStroke->begin(), pStroke->end(), 0.0) != 0)
+ {
+ std::vector<SkScalar> intervals;
+ intervals.assign(pStroke->begin(), pStroke->end());
+ aPaint.setPathEffect(SkDashPathEffect::Make(intervals.data(), intervals.size(), 0));
+ }
+
// Skia does not support basegfx::B2DLineJoin::NONE, so in that case batch only if lines
// are not wider than a pixel.
if (eLineJoin != basegfx::B2DLineJoin::NONE || fLineWidth <= 1.0)