[Libreoffice-commits] core.git: Branch 'libreoffice-5-1' - drawinglayer/CppunitTest_drawinglayer_border.mk drawinglayer/Module_drawinglayer.mk drawinglayer/qa drawinglayer/source include/drawinglayer

Miklos Vajna vmiklos at collabora.co.uk
Wed Apr 20 12:09:23 UTC 2016


 drawinglayer/CppunitTest_drawinglayer_border.mk            |   52 ++++
 drawinglayer/Module_drawinglayer.mk                        |    4 
 drawinglayer/qa/unit/border.cxx                            |  150 +++++++++++++
 drawinglayer/source/primitive2d/borderlineprimitive2d.cxx  |   28 ++
 drawinglayer/source/processor2d/vclpixelprocessor2d.cxx    |    7 
 include/drawinglayer/primitive2d/borderlineprimitive2d.hxx |    2 
 6 files changed, 239 insertions(+), 4 deletions(-)

New commits:
commit a5928a57a53df84cacd2975e227f9e03d50456a6
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Apr 15 15:46:06 2016 +0200

    tdf#99315 VclPixelProcessor2D: fix double border line width
    
    Regression from commit 2c91cb08d65cd35fa8ef6eaca3677aa82fb58cbe (better
    drawing support for borders of different width, fdo#33634, 2012-04-04),
    the problem is that previously the width of inner/outer double border
    lines got rounded to integer values quite early, but after the commit
    they are kept at a double precision for much longer, which needs pixel
    correction in VclPixelProcessor2D.
    
    Example: if the border with is 1.47, and the line gets moved by 0.2
    pixels, then the inner and outer edge of the line will be 0.2 and 1.67,
    which gets rounded to 0 -> 2 in the pixel processor. Previously the
    input was rounded to 1, so moving by 0.2 resulted in 0.2 -> 1.2, which
    got rounded to 0 -> 1. The result is that sometimes the line width is 1
    pixel wider than expected.
    
    Fix the problem by allowing VclPixelProcessor2D to request pixel
    correction from BorderLinePrimitive2D. It wouldn't be possible to do
    pixel correction only in VclPixelProcessor2D, as it has no idea what to
    correct: it only gets polygons, so it has no idea if e.g. the top of a
    polygon is the outer edge of a top border line or an inner edge of a
    bottom border line.
    
    Conflicts:
    	drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
    
    (cherry picked from commits 1ee570a4e625719f8bf270d372926c0d829ae6f0,
    555c9add26e06030402c73f885de98f4b96826f0,
    304f50684d3ac08e973fd27e6acf3e821394d164,
    422f10c5d7ebe6f4b778636c9c1eb6dbdf708a27,
    ce12a5021a080cc1781e0e0256af5e0085e11ef2 and
    cac70559013e575009657aa3c5168b88b1f14691)
    
    Change-Id: I1971f3a952fbcdc598ab46c659e12d976c13cbe6
    Reviewed-on: https://gerrit.libreoffice.org/24238
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Eike Rathke <erack at redhat.com>

diff --git a/drawinglayer/CppunitTest_drawinglayer_border.mk b/drawinglayer/CppunitTest_drawinglayer_border.mk
new file mode 100644
index 0000000..ea72b8c
--- /dev/null
+++ b/drawinglayer/CppunitTest_drawinglayer_border.mk
@@ -0,0 +1,52 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,drawinglayer_border))
+
+$(eval $(call gb_CppunitTest_use_api,drawinglayer_border,\
+	offapi \
+	udkapi \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,drawinglayer_border, \
+	basegfx \
+	cppu \
+	cppuhelper \
+	sal \
+	salhelper \
+	drawinglayer \
+	vcl \
+	test \
+	tl \
+	$(gb_UWINAPI) \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,drawinglayer_border,\
+	boost_headers \
+	libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,drawinglayer_border, \
+	drawinglayer/qa/unit/border \
+))
+
+$(eval $(call gb_CppunitTest_use_ure,drawinglayer_border))
+
+$(eval $(call gb_CppunitTest_use_vcl,drawinglayer_border))
+
+$(eval $(call gb_CppunitTest_use_components,drawinglayer_border,\
+    configmgr/source/configmgr \
+    i18npool/util/i18npool \
+    ucb/source/core/ucb1 \
+    ucb/source/ucp/file/ucpfile1 \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,drawinglayer_border))
+
+# vim: set noet sw=4 ts=4:
diff --git a/drawinglayer/Module_drawinglayer.mk b/drawinglayer/Module_drawinglayer.mk
index 52f2482..6d329e9 100644
--- a/drawinglayer/Module_drawinglayer.mk
+++ b/drawinglayer/Module_drawinglayer.mk
@@ -13,4 +13,8 @@ $(eval $(call gb_Module_add_targets,drawinglayer,\
     Library_drawinglayer \
 ))
 
+$(eval $(call gb_Module_add_slowcheck_targets,drawinglayer,\
+    CppunitTest_drawinglayer_border \
+))
+
 # vim: set noet sw=4 ts=4:
diff --git a/drawinglayer/qa/unit/border.cxx b/drawinglayer/qa/unit/border.cxx
new file mode 100644
index 0000000..65ff03d
--- /dev/null
+++ b/drawinglayer/qa/unit/border.cxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+#include <com/sun/star/table/BorderLineStyle.hpp>
+
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
+#include <rtl/ref.hxx>
+#include <test/bootstrapfixture.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/virdev.hxx>
+
+using namespace com::sun::star;
+
+namespace
+{
+
+class DrawinglayerBorderTest : public test::BootstrapFixture
+{
+public:
+    void testDoubleDecompositionSolid();
+    void testDoublePixelProcessing();
+
+    CPPUNIT_TEST_SUITE(DrawinglayerBorderTest);
+    CPPUNIT_TEST(testDoubleDecompositionSolid);
+    CPPUNIT_TEST(testDoublePixelProcessing);
+    CPPUNIT_TEST_SUITE_END();
+};
+
+void DrawinglayerBorderTest::testDoubleDecompositionSolid()
+{
+    // Create a border line primitive that's similar to the one from the bugdoc:
+    // 1.47 pixels is 0.03cm at 130% zoom and 96 DPI.
+    basegfx::B2DPoint aStart(0, 20);
+    basegfx::B2DPoint aEnd(100, 20);
+    double fLeftWidth = 1.47;
+    double fDistance = 1.47;
+    double fRightWidth = 1.47;
+    double fExtendLeftStart = 0;
+    double fExtendLeftEnd = 0;
+    double fExtendRightStart = 0;
+    double fExtendRightEnd = 0;
+    basegfx::BColor aColorRight;
+    basegfx::BColor aColorLeft;
+    basegfx::BColor aColorGap;
+    bool bHasGapColor = false;
+    sal_Int16 nStyle = table::BorderLineStyle::DOUBLE;
+    rtl::Reference<drawinglayer::primitive2d::BorderLinePrimitive2D> aBorder(new drawinglayer::primitive2d::BorderLinePrimitive2D(aStart, aEnd, fLeftWidth, fDistance, fRightWidth, fExtendLeftStart, fExtendLeftEnd, fExtendRightStart, fExtendRightEnd, aColorRight, aColorLeft, aColorGap, bHasGapColor, nStyle));
+
+    // Decompose it into polygons.
+    drawinglayer::geometry::ViewInformation2D aView;
+    drawinglayer::primitive2d::Primitive2DSequence aContainer = aBorder->get2DDecomposition(aView);
+
+    // Make sure it results in two borders as it's a double one.
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), aContainer.getLength());
+
+    // Get the inside line.
+    auto pInside = dynamic_cast<const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D*>(aContainer[0].get());
+    CPPUNIT_ASSERT(pInside);
+
+    // Make sure the inside line's height is fLeftWidth.
+    const basegfx::B2DPolyPolygon& rPolyPolygon = pInside->getB2DPolyPolygon();
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(1), rPolyPolygon.count());
+    const basegfx::B2DPolygon& rPolygon = rPolyPolygon.getB2DPolygon(0);
+    const basegfx::B2DRange& rRange = rPolygon.getB2DRange();
+    // This was 2.47, i.e. the width of the inner line was 1 unit (in the bugdoc's case: 1 pixel) wider than expected.
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(fLeftWidth, rRange.getHeight(), basegfx::fTools::getSmallValue());
+}
+
+void DrawinglayerBorderTest::testDoublePixelProcessing()
+{
+    // Create a pixel processor.
+    ScopedVclPtrInstance<VirtualDevice> pDev;
+    drawinglayer::geometry::ViewInformation2D aView;
+    std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(*pDev, aView));
+    CPPUNIT_ASSERT(pProcessor);
+    GDIMetaFile aMetaFile;
+    // Start recording after the processor is created, so we can test the pixel processor.
+    aMetaFile.Record(pDev);
+
+    // Create a border line primitive that's similar to the one from the bugdoc:
+    // 1.47 pixels is 0.03cm at 130% zoom and 96 DPI.
+    basegfx::B2DPoint aStart(0, 20);
+    basegfx::B2DPoint aEnd(100, 20);
+    double fLeftWidth = 1.47;
+    double fDistance = 1.47;
+    double fRightWidth = 1.47;
+    double fExtendLeftStart = 0;
+    double fExtendLeftEnd = 0;
+    double fExtendRightStart = 0;
+    double fExtendRightEnd = 0;
+    basegfx::BColor aColorRight;
+    basegfx::BColor aColorLeft;
+    basegfx::BColor aColorGap;
+    bool bHasGapColor = false;
+    sal_Int16 nStyle = table::BorderLineStyle::DOUBLE;
+    rtl::Reference<drawinglayer::primitive2d::BorderLinePrimitive2D> xBorder(new drawinglayer::primitive2d::BorderLinePrimitive2D(aStart, aEnd, fLeftWidth, fDistance, fRightWidth, fExtendLeftStart, fExtendLeftEnd, fExtendRightStart, fExtendRightEnd, aColorRight, aColorLeft, aColorGap, bHasGapColor, nStyle));
+    drawinglayer::primitive2d::Primitive2DSequence aPrimitives(1);
+    aPrimitives[0] = drawinglayer::primitive2d::Primitive2DReference(xBorder.get());
+
+    // Process the primitives.
+    pProcessor->process(aPrimitives);
+
+    // Now assert the height of the outer (second) border polygon.
+    aMetaFile.Stop();
+    aMetaFile.WindStart();
+    bool bFirst = true;
+    sal_Int32 nHeight = 0;
+    for(std::size_t nAction = 0; nAction < aMetaFile.GetActionSize(); ++nAction)
+    {
+        MetaAction* pAction = aMetaFile.GetAction(nAction);
+        if (pAction->GetType() == MetaActionType::POLYPOLYGON)
+        {
+            if (bFirst)
+            {
+                bFirst = false;
+                continue;
+            }
+
+            auto pMPPAction = static_cast<MetaPolyPolygonAction*>(pAction);
+            const tools::PolyPolygon& rPolyPolygon = pMPPAction->GetPolyPolygon();
+            nHeight = rPolyPolygon.GetBoundRect().getHeight();
+        }
+    }
+    sal_Int32 nExpectedHeight = std::round(fRightWidth);
+    // This was 2, and should be 1: if the logical requested width is 1.47,
+    // then that must be 1 px on the screen, not 2.
+    CPPUNIT_ASSERT_EQUAL(nExpectedHeight, nHeight);
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(DrawinglayerBorderTest);
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
index 30e656d..30e7dcb 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -28,6 +28,17 @@
 #include <numeric>
 #include <algorithm>
 
+#if defined(ANDROID)
+namespace std
+{
+template<typename T>
+T round(T x)
+{
+    return ::round(x);
+}
+}
+#endif
+
 namespace drawinglayer {
 
 namespace {
@@ -63,7 +74,7 @@ primitive2d::Primitive2DReference makeSolidLinePrimitive(
     const basegfx::B2DVector& rVector, const basegfx::BColor& rColor, double fLineWidth, double fGap)
 {
     const basegfx::B2DVector aPerpendicular = basegfx::getPerpendicular(rVector);
-    const basegfx::B2DVector aLineWidthOffset = ((fLineWidth + 1.0) * 0.5) * aPerpendicular;
+    const basegfx::B2DVector aLineWidthOffset = (fLineWidth * 0.5) * aPerpendicular;
 
     basegfx::B2DPolygon aPolygon;
     aPolygon.append(rStart + aLineWidthOffset);
@@ -163,6 +174,11 @@ primitive2d::Primitive2DReference makeSolidLinePrimitive(
 
         Primitive2DSequence BorderLinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
         {
+            return createDecomposition(rViewInformation, false);
+        }
+
+        Primitive2DSequence BorderLinePrimitive2D::createDecomposition(const geometry::ViewInformation2D& rViewInformation, bool bPixelCorrection) const
+        {
             Primitive2DSequence xRetval;
 
             if(!getStart().equal(getEnd()) && ( isInsideUsed() || isOutsideUsed() ) )
@@ -199,8 +215,11 @@ primitive2d::Primitive2DReference makeSolidLinePrimitive(
                         xRetval[0] = makeHairLinePrimitive(
                             getStart(), getEnd(), aVector, getRGBColorLeft(), 0.0);
                     else
+                    {
+                        double fWidth = bPixelCorrection ? std::round(fLeftWidth) : fLeftWidth;
                         xRetval[0] = makeSolidLinePrimitive(
-                            aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorLeft(), fLeftWidth, -fLeftWidth/2.0);
+                            aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorLeft(), fWidth, -fLeftWidth/2.0);
+                    }
 
                     // "outside" line
 
@@ -208,8 +227,11 @@ primitive2d::Primitive2DReference makeSolidLinePrimitive(
                         xRetval[1] = makeHairLinePrimitive(
                             getStart(), getEnd(), aVector, getRGBColorRight(), fLeftWidth+mfDistance);
                     else
+                    {
+                        double fWidth = bPixelCorrection ? std::round(fRightWidth) : fRightWidth;
                         xRetval[1] = makeSolidLinePrimitive(
-                            aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorRight(), fRightWidth, mfDistance+fRightWidth/2.0);
+                            aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorRight(), fWidth, mfDistance+fRightWidth/2.0);
+                    }
                 }
                 else
                 {
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index 8dcd74e..8398573 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -1232,7 +1232,12 @@ namespace drawinglayer
                         static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate);
 
                     if (!tryDrawBorderLinePrimitive2DDirect(rBorder))
-                        process(rCandidate.get2DDecomposition(getViewInformation2D()));
+                    {
+                        if (rBorder.getStyle() == table::BorderLineStyle::DOUBLE)
+                            process(rBorder.createDecomposition(getViewInformation2D(), true));
+                        else
+                            process(rCandidate.get2DDecomposition(getViewInformation2D()));
+                    }
 
                     mpOutputDevice->SetAntialiasing(nAntiAliasing);
                     break;
diff --git a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
index 72e04d5..f152f2d 100644
--- a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
@@ -132,6 +132,8 @@ namespace drawinglayer
             bool hasGapColor( ) const { return mbHasGapColor; }
             short getStyle () const { return mnStyle; }
             double getPatternScale() const { return mfPatternScale; }
+            /// Same as create2DDecomposition(), but can do pixel correction if requested.
+            Primitive2DSequence createDecomposition(const geometry::ViewInformation2D& rViewInformation, bool bPixelCorrection) const;
 
             /// compare operator
             virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;


More information about the Libreoffice-commits mailing list