tdf#152997 - Duplicate an odd length dash array to meet the spec

An odd-length array will be drawn as one dash spanning the entire path.
The specifications under
https://www.w3.org/TR/svg-strokes/#StrokeDashing state: "If the list has
an odd number of values, then it is repeated to yield an even number of
values. Thus, the rendering behaviour of stroke-array: 5,4,2 is
equivalent to stroke-dasharray: 5,4,2,5,4,2."

Change-Id: I8f233c4cec5c85f5ab1096b032cbb8743715f14d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/211062
Reviewed-by: Andreas Heinisch <andreas.heinisch@yahoo.de>
Tested-by: Jenkins
This commit is contained in:
Andreas Heinisch
2026-09-21 12:28:00 +02:00
parent dec8cca513
commit e1fe3c74f9
3 changed files with 94 additions and 0 deletions
@@ -37,6 +37,7 @@ $(eval $(call gb_CppunitTest_use_externals,drawinglayer_processors,\
))
$(eval $(call gb_CppunitTest_add_exception_objects,drawinglayer_processors, \
drawinglayer/qa/unit/strokeattribute \
drawinglayer/qa/unit/vclmetafileprocessor2d \
drawinglayer/qa/unit/vclpixelprocessor2d \
))
+78
View File
@@ -0,0 +1,78 @@
/* -*- 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 <test/bootstrapfixture.hxx>
#include <drawinglayer/attribute/strokeattribute.hxx>
using namespace drawinglayer::attribute;
namespace
{
class StrokeAttributeTest : public test::BootstrapFixture
{
};
CPPUNIT_TEST_FIXTURE(StrokeAttributeTest, tdf152997_odd_length_dash_array)
{
std::vector<double> aDashArray{ 6.0 };
StrokeAttribute aStroke(std::move(aDashArray));
// Without the fix in place, this test would have failed with
// - Expected: 2
// - Actual : 1
// i.e. the odd-length array was not duplicated
const std::vector<double> aExpected{ 6.0, 6.0 };
CPPUNIT_ASSERT_EQUAL(aExpected.size(), aStroke.getDotDashArray().size());
CPPUNIT_ASSERT_EQUAL(12.0, aStroke.getFullDotDashLen());
for (size_t i = 0; i < aExpected.size(); ++i)
CPPUNIT_ASSERT_DOUBLES_EQUAL(aExpected[i], aStroke.getDotDashArray()[i], 1E-12);
}
CPPUNIT_TEST_FIXTURE(StrokeAttributeTest, tdf152997_odd_length_dash_array_multiple_values)
{
std::vector<double> aDashArray{ 5.0, 3.0, 2.0 };
StrokeAttribute aStroke(std::move(aDashArray));
// Without the fix in place, this test would have failed with
// - Expected: 6
// - Actual : 3
// i.e. the odd-length array was not duplicated
const std::vector<double> aExpected{ 5.0, 3.0, 2.0, 5.0, 3.0, 2.0 };
CPPUNIT_ASSERT_EQUAL(aExpected.size(), aStroke.getDotDashArray().size());
for (size_t i = 0; i < aExpected.size(); ++i)
CPPUNIT_ASSERT_DOUBLES_EQUAL(aExpected[i], aStroke.getDotDashArray()[i], 1E-12);
}
CPPUNIT_TEST_FIXTURE(StrokeAttributeTest, tdf152997_even_length_dash_array)
{
std::vector<double> aDashArray{ 4.0, 2.0 };
StrokeAttribute aStroke(std::move(aDashArray), 6.0);
// An even-length dash array should not be changed
const std::vector<double> aExpected{ 4.0, 2.0 };
CPPUNIT_ASSERT_EQUAL(aExpected.size(), aStroke.getDotDashArray().size());
CPPUNIT_ASSERT_EQUAL(6.0, aStroke.getFullDotDashLen());
for (size_t i = 0; i < aExpected.size(); ++i)
CPPUNIT_ASSERT_DOUBLES_EQUAL(aExpected[i], aStroke.getDotDashArray()[i], 1E-12);
}
CPPUNIT_TEST_FIXTURE(StrokeAttributeTest, tdf152997_empty_dash_array)
{
std::vector<double> aDashArray;
StrokeAttribute aStroke(std::move(aDashArray));
// An empty dash array should not be changed
CPPUNIT_ASSERT(aStroke.getDotDashArray().empty());
}
} // namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
@@ -36,6 +36,21 @@ namespace drawinglayer::attribute
: maDotDashArray(std::move(rDotDashArray)),
mfFullDotDashLen(fFullDotDashLen)
{
// tdf#152997 - duplicate an odd length dash array in order to meet the spec.
// An odd-length array will be drawn as one dash spanning the entire path. The
// specifications under https://www.w3.org/TR/svg-strokes/#StrokeDashing state:
// "If the list has an odd number of values, then it is repeated to yield an
// even number of values. Thus, the rendering behavior of stroke-dasharray: 5,3,2
// is equivalent to stroke-dasharray: 5,3,2,5,3,2."
if (maDotDashArray.size() % 2 == 1)
{
const std::vector<double> aOriginal(maDotDashArray);
maDotDashArray.insert(maDotDashArray.end(), aOriginal.begin(), aOriginal.end());
// Increase the length accordingly
if (0.0 != mfFullDotDashLen)
mfFullDotDashLen *= 2.0;
}
}
ImpStrokeAttribute()