oox/source/drawingml/lineproperties.cxx     |   24 ++++++++++++-
 oox/source/export/drawingml.cxx             |   49 ++++++++++++++++++++--------
 sd/qa/unit/data/pptx/tdf134053_dashdot.pptx |binary
 sd/qa/unit/uiimpress.cxx                    |   34 +++++++++++++++++++
 4 files changed, 91 insertions(+), 16 deletions(-)

New commits:
commit 3f3b50015e4fd9efc3459612a70409fca49cf390
Author:     Regina Henschel <[email protected]>
AuthorDate: Sat Jun 20 15:08:12 2020 +0200
Commit:     Regina Henschel <[email protected]>
CommitDate: Mon Jun 22 10:43:08 2020 +0200

    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 <[email protected]>

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
Binary files /dev/null and b/sd/qa/unit/data/pptx/tdf134053_dashdot.pptx 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: */
_______________________________________________
Libreoffice-commits mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to