summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRegina Henschel <rb.henschel@t-online.de>2020-06-20 15:08:12 +0200
committerRegina Henschel <rb.henschel@t-online.de>2020-06-22 10:43:08 +0200
commit3f3b50015e4fd9efc3459612a70409fca49cf390 (patch)
treeb9bf5c45f1c8732e74c0852640b666eca78e59af
parent586f106bbec37c81804c63969fd3ad0c1d3da054 (diff)
tdf#134053 tweak dash and space length for ooxml
OOXML does not specify how line caps are applied to dashes. MS Office keeps dash and space length for preset dash styles and for round custom dash styles and add them for square line caps on custom dash styles. ODF specifies, that the linecaps are added to the dashes and the spaces are reduced, so that the dash-space pair keeps its length. This patch changes the dash and space length on import and export so, that they look nearly the same in LibreOffice as in MS Office. For custom dash styles with square line cap the first dash is longer as in MS Office. I have no solution for that. But I consider it as minor problem, because MS Office has not even an UI for that case. It should not hinder the improvement for the usual cases. Change-Id: I3e3e4b7c9d71e440ed301d2be423100440cb688b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96769 Tested-by: Jenkins Reviewed-by: Regina Henschel <rb.henschel@t-online.de>
-rw-r--r--oox/source/drawingml/lineproperties.cxx24
-rw-r--r--oox/source/export/drawingml.cxx49
-rw-r--r--sd/qa/unit/data/pptx/tdf134053_dashdot.pptxbin0 -> 14891 bytes
-rw-r--r--sd/qa/unit/uiimpress.cxx34
4 files changed, 91 insertions, 16 deletions
diff --git a/oox/source/drawingml/lineproperties.cxx b/oox/source/drawingml/lineproperties.cxx
index 3183d5ce4c24..451da4c6aa26 100644
--- a/oox/source/drawingml/lineproperties.cxx
+++ b/oox/source/drawingml/lineproperties.cxx
@@ -443,6 +443,11 @@ void LineProperties::pushToPropMap( ShapePropertyMap& rPropMap,
sal_Int32 nLineWidth = getLineWidth(); // includes conversion from EMUs to 1/100mm
rPropMap.setProperty( ShapeProperty::LineWidth, nLineWidth );
+ // line cap type
+ LineCap eLineCap = moLineCap.has() ? lclGetLineCap( moLineCap.get() ) : LineCap_BUTT;
+ if( moLineCap.has() )
+ rPropMap.setProperty( ShapeProperty::LineCap, eLineCap );
+
// create line dash from preset dash token or dash stop vector (not for invisible line)
if( (eLineStyle != drawing::LineStyle_NONE) && (moPresetDash.differsFrom( XML_solid ) || !maCustomDash.empty()) )
{
@@ -456,12 +461,25 @@ void LineProperties::pushToPropMap( ShapePropertyMap& rPropMap,
lclConvertCustomDash(aLineDash, maCustomDash);
lclRecoverStandardDashStyles(aLineDash, nLineWidth);
}
+
+ // In MS Office (2020) for preset dash style line caps round and square are included in dash length.
+ // For custom dash style round line cap is included, square line cap is added. In ODF line caps are
+ // always added to dash length. Tweak the length accordingly.
+ if (eLineCap == LineCap_ROUND || (eLineCap == LineCap_SQUARE && maCustomDash.empty()))
+ {
+ // Cannot use -100 because that results in 0 length in some cases and
+ // LibreOffice interprets 0 length as 100%.
+ if (aLineDash.DotLen >= 100 || aLineDash.DashLen >= 100)
+ aLineDash.Distance += 99;
+ if (aLineDash.DotLen >= 100)
+ aLineDash.DotLen -= 99;
+ if (aLineDash.DashLen >= 100)
+ aLineDash.DashLen -= 99;
+ }
+
if( rPropMap.setProperty( ShapeProperty::LineDash, aLineDash ) )
eLineStyle = drawing::LineStyle_DASH;
}
- // line cap type
- if( moLineCap.has() )
- rPropMap.setProperty( ShapeProperty::LineCap, lclGetLineCap( moLineCap.get() ) );
// set final line style property
rPropMap.setProperty( ShapeProperty::LineStyle, eLineStyle );
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index f14129d0a2e8..607db7a33ae7 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -733,10 +733,11 @@ void DrawingML::WriteLineArrow( const Reference< XPropertySet >& rXPropSet, bool
void DrawingML::WriteOutline( const Reference<XPropertySet>& rXPropSet, Reference< frame::XModel > const & xModel )
{
drawing::LineStyle aLineStyle( drawing::LineStyle_NONE );
-
if (GetProperty(rXPropSet, "LineStyle"))
mAny >>= aLineStyle;
+ const LineCap aLineCap = GetProperty(rXPropSet, "LineCap") ? mAny.get<drawing::LineCap>() : LineCap_BUTT;
+
sal_uInt32 nLineWidth = 0;
sal_uInt32 nEmuLineWidth = 0;
::Color nColor;
@@ -747,6 +748,7 @@ void DrawingML::WriteOutline( const Reference<XPropertySet>& rXPropSet, Referenc
bool bDashSet = false;
bool bNoFill = false;
+
// get InteropGrabBag and search the relevant attributes
OUString sColorFillScheme;
@@ -846,14 +848,10 @@ void DrawingML::WriteOutline( const Reference<XPropertySet>& rXPropSet, Referenc
{
nColorAlpha = MAX_PERCENT - (mAny.get<sal_Int16>() * PER_PERCENT);
}
- if (GetProperty(rXPropSet, "LineCap"))
- {
- const LineCap aLineCap = mAny.get<drawing::LineCap>();
- if (aLineCap == LineCap_ROUND)
- cap = "rnd";
- else if (aLineCap == LineCap_SQUARE)
- cap = "sq";
- }
+ if (aLineCap == LineCap_ROUND)
+ cap = "rnd";
+ else if (aLineCap == LineCap_SQUARE)
+ cap = "sq";
break;
}
@@ -899,13 +897,25 @@ void DrawingML::WriteOutline( const Reference<XPropertySet>& rXPropSet, Referenc
// start with the longer one. Definitions are in OOXML part 1, 20.1.10.49
// The tests are strict, for to not catch styles from standard.sod (as of Aug 2019).
bool bIsConverted = false;
+
bool bIsRelative(aLineDash.Style == DashStyle_RECTRELATIVE || aLineDash.Style == DashStyle_ROUNDRELATIVE);
if ( bIsRelative && aLineDash.Dots == 1)
- {
+ { // The length were tweaked on import in case of prstDash. Revert it here.
+ sal_uInt32 nDotLen = aLineDash.DotLen;
+ sal_uInt32 nDashLen = aLineDash.DashLen;
+ sal_uInt32 nDistance = aLineDash.Distance;
+ if (aLineCap != LineCap_BUTT && nDistance >= 99)
+ {
+ nDistance -= 99;
+ nDotLen += 99;
+ nDashLen += 99;
+ }
// LO uses length 0 for 100%, if the attribute is missing in ODF.
// Other applications might write 100%. Make is unique for the conditions.
- sal_uInt32 nDotLen = (aLineDash.DotLen == 0) ? 100 : aLineDash.DotLen;
- sal_uInt32 nDashLen = (aLineDash.DashLen == 0 && aLineDash.Dashes > 0) ? 100 : aLineDash.DashLen;
+ if (nDotLen == 0)
+ nDotLen = 100;
+ if (nDashLen == 0 && aLineDash.Dashes > 0)
+ nDashLen = 100;
bIsConverted = true;
if (nDotLen == 100 && aLineDash.Dashes == 0 && nDashLen == 0 && aLineDash.Distance == 300)
{
@@ -964,12 +974,21 @@ void DrawingML::WriteOutline( const Reference<XPropertySet>& rXPropSet, Referenc
// So set 100% explicitly.
if (aLineDash.Distance <= 0)
fSp = 100.0;
- if ( aLineDash.Dots > 0 )
+ // In case of custDash, round caps are included in dash length in MS Office. Square caps are added
+ // to dash length, same as in ODF. Change the length values accordingly.
+ if (aLineCap == LineCap_ROUND && fSp > 99.0)
+ fSp -= 99.0;
+
+ if (aLineDash.Dots > 0)
{
double fD = bIsRelative ? aLineDash.DotLen : aLineDash.DotLen * 100.0 / fLineWidth;
// LO sets length to 0, if attribute is missing in ODF. Then a relative length of 100% is intended.
if (aLineDash.DotLen == 0)
fD = 100.0;
+ // Tweak dash length, see above.
+ if (aLineCap == LineCap_ROUND && fSp > 99.0)
+ fD += 99.0;
+
for( i = 0; i < aLineDash.Dots; i ++ )
{
mpFS->singleElementNS( XML_a, XML_ds,
@@ -983,6 +1002,10 @@ void DrawingML::WriteOutline( const Reference<XPropertySet>& rXPropSet, Referenc
// LO sets length to 0, if attribute is missing in ODF. Then a relative length of 100% is intended.
if (aLineDash.DashLen == 0)
fD = 100.0;
+ // Tweak dash length, see above.
+ if (aLineCap == LineCap_ROUND && fSp > 99.0)
+ fD += 99.0;
+
for( i = 0; i < aLineDash.Dashes; i ++ )
{
mpFS->singleElementNS( XML_a , XML_ds,
diff --git a/sd/qa/unit/data/pptx/tdf134053_dashdot.pptx b/sd/qa/unit/data/pptx/tdf134053_dashdot.pptx
new file mode 100644
index 000000000000..f2d951c570fd
--- /dev/null
+++ b/sd/qa/unit/data/pptx/tdf134053_dashdot.pptx
Binary files differ
diff --git a/sd/qa/unit/uiimpress.cxx b/sd/qa/unit/uiimpress.cxx
index 93a76ac2597d..56d1f8fc789b 100644
--- a/sd/qa/unit/uiimpress.cxx
+++ b/sd/qa/unit/uiimpress.cxx
@@ -345,6 +345,40 @@ CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testPageFillGradient)
CPPUNIT_ASSERT_EQUAL(OUString("ff0000"), aGradient.GetStartColor().AsRGBHexString());
CPPUNIT_ASSERT_EQUAL(OUString("0000ff"), aGradient.GetEndColor().AsRGBHexString());
}
+
+CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf134053)
+{
+ // Error was, that dashes and dots were longer than in MS Office.
+ mxComponent = loadFromDesktop(
+ m_directories.getURLFromSrc("sd/qa/unit/data/pptx/tdf134053_dashdot.pptx"));
+ auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
+ sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
+ SdPage* pActualPage = pViewShell->GetActualPage();
+ SdrObject* pShape = pActualPage->GetObj(0);
+ CPPUNIT_ASSERT_MESSAGE("No Shape", pShape);
+
+ // Break line into single dash and dot objects
+ SdrView* pView = pViewShell->GetView();
+ pView->MarkObj(pShape, pView->GetSdrPageView());
+ dispatchCommand(mxComponent, ".uno:ConvertIntoMetafile", {});
+ dispatchCommand(mxComponent, ".uno:Break", {});
+
+ // Measure the rendered length of dash, dot and distance
+ SdrObject* pDash = pActualPage->GetObj(0);
+ const tools::Rectangle& rBoundDashRect = pDash->GetCurrentBoundRect();
+ const double fDashLength(rBoundDashRect.GetWidth());
+ SdrObject* pDot = pActualPage->GetObj(1);
+ const tools::Rectangle& rBoundDotRect = pDot->GetCurrentBoundRect();
+ const double fDotLength(rBoundDotRect.GetWidth());
+ const double fDistance(rBoundDotRect.Left() - rBoundDashRect.Right());
+
+ // Because 0% is not possible as dash length (as of June 2020) 1% is used in the fix.
+ // For that a larger delta is here allowed to the ideal value than needed for
+ // rounding errors.
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Distance", 2117, fDistance, 12);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Dot length", 706, fDotLength, 12);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Dash length", 2822, fDashLength, 12);
+}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */