summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drawinglayer/CppunitTest_drawinglayer_border.mk52
-rw-r--r--drawinglayer/Module_drawinglayer.mk4
-rw-r--r--drawinglayer/qa/unit/border.cxx150
-rw-r--r--drawinglayer/source/primitive2d/borderlineprimitive2d.cxx28
-rw-r--r--drawinglayer/source/processor2d/vclpixelprocessor2d.cxx7
-rw-r--r--include/drawinglayer/primitive2d/borderlineprimitive2d.hxx2
6 files changed, 239 insertions, 4 deletions
diff --git a/drawinglayer/CppunitTest_drawinglayer_border.mk b/drawinglayer/CppunitTest_drawinglayer_border.mk
new file mode 100644
index 000000000000..ea72b8cee602
--- /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 52f2482fc714..6d329e95c60a 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 000000000000..65ff03d28fe3
--- /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 30e656d99866..30e7dcbacba6 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 8dcd74e77ac5..8398573ddb4e 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 72e04d5321f1..f152f2d00a64 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;