[Libreoffice-commits] core.git: filter/source include/oox oox/source sd/qa sw/qa

Regina Henschel (via logerrit) logerrit at kemper.freedesktop.org
Thu Sep 5 10:37:51 UTC 2019


 dev/null                                                  |binary
 filter/source/msfilter/escherex.cxx                       |  102 +++++--
 filter/source/msfilter/msdffimp.cxx                       |   88 ++++--
 include/oox/export/utils.hxx                              |    2 
 oox/source/drawingml/lineproperties.cxx                   |  168 ++++++++----
 oox/source/export/drawingml.cxx                           |  191 ++++++--------
 sd/qa/unit/data/odp/LineStylesOwn.odp                     |binary
 sd/qa/unit/data/odp/tdf127267DashOnHairline.odp           |binary
 sd/qa/unit/data/pptx/presetDashDot.pptx                   |binary
 sd/qa/unit/export-tests-ooxml1.cxx                        |  113 ++++++++
 sd/qa/unit/export-tests-ooxml2.cxx                        |    8 
 sw/qa/extras/ooxmlexport/ooxmlexport11.cxx                |   13 
 sw/qa/extras/ww8export/data/tdf127166_prstDash_Word97.doc |binary
 sw/qa/extras/ww8export/ww8export3.cxx                     |   36 ++
 14 files changed, 496 insertions(+), 225 deletions(-)

New commits:
commit 57c9bdab377a00649299d1a4c9ed2f9e5e03b84e
Author:     Regina Henschel <rb.henschel at t-online.de>
AuthorDate: Sun Sep 1 19:26:40 2019 +0200
Commit:     Regina Henschel <rb.henschel at t-online.de>
CommitDate: Thu Sep 5 12:36:56 2019 +0200

    tdf#127166, tdf#123903 improve import/export of line styles
    
    I have added import and export of prstDash line styles, for OOXML
    and for binary MS Office formats. This includes:
    Corrected Dot <--> Dash confusion, corrected some wrong defaults,
    added support for hairlines tdf#127267, take care of treating
    length 0 as 100%.
    
    tdf#108064 has introduced some mapping from our standard line styles
    to OOXML prstDash. I have removed that and implemented to export
    our styles as custDash and recover them back on import. That way the
    dashing looks initially the same in MS Office. I have removed the now
    wrong test.
    
    Binary MS Office formats have no custom dash styles AFAIK, therefore
    I have not changed the export of our styles there, but only added
    support for prstDash styles.
    
    Change-Id: Ia8cc8f90df6fdbe42adfc0236cc52becc670b333
    Reviewed-on: https://gerrit.libreoffice.org/78372
    Tested-by: Jenkins
    Reviewed-by: Regina Henschel <rb.henschel at t-online.de>

diff --git a/filter/source/msfilter/escherex.cxx b/filter/source/msfilter/escherex.cxx
index 1324a23979cd..69bb2b92f257 100644
--- a/filter/source/msfilter/escherex.cxx
+++ b/filter/source/msfilter/escherex.cxx
@@ -1028,6 +1028,11 @@ void EscherPropertyContainer::CreateLineProperties(
         }
     }
 
+    sal_uInt32 nLineWidth = ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineWidth" ) )
+        ? *o3tl::doAccess<sal_uInt32>(aAny) : 0;
+    if ( nLineWidth > 1 )
+        AddOpt( ESCHER_Prop_lineWidth, nLineWidth * 360 );       // 100TH MM -> PT , 1PT = 12700 EMU
+
     if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineStyle" ) )
     {
         drawing::LineStyle eLS;
@@ -1045,7 +1050,6 @@ void EscherPropertyContainer::CreateLineProperties(
                     {
                         ESCHER_LineDashing eDash = ESCHER_LineSolid;
                         auto pLineDash = o3tl::doAccess<drawing::LineDash>(aAny);
-                        sal_Int32 nDistance = pLineDash->Distance << 1;
                         switch ( pLineDash->Style )
                         {
                             case drawing::DashStyle_ROUND :
@@ -1054,35 +1058,86 @@ void EscherPropertyContainer::CreateLineProperties(
                             break;
                             default : break;
                         }
-                        if ( ((!(pLineDash->Dots )) || (!(pLineDash->Dashes )) ) || ( pLineDash->DotLen == pLineDash->DashLen ) )
+                        // Try to detect exact prstDash styles. Use a similar method as in oox export.
+                        // Map it to a roughly fitting prstDash in outher cases.
+                        bool bIsConverted = false;
+                        bool bIsRelative = pLineDash->Style == drawing::DashStyle_RECTRELATIVE
+                                            || pLineDash->Style == drawing::DashStyle_ROUNDRELATIVE;
+                        sal_Int16 nDashes = pLineDash->Dashes;
+                        sal_Int16 nDots = pLineDash->Dots;
+                        sal_Int32 nDashLen = pLineDash->DashLen;
+                        sal_Int32 nDotLen = pLineDash->DotLen;
+                        sal_Int32 nDistance = pLineDash->Distance;
+
+                        // Caution! The names are misleading. "dot" is always the first dash and "dash"
+                        // the second one, regardless of the actual length. All prstDash
+                        // definitions start with the longer dash and have exact one longer dash.
+                        // Preset line style definitions for binary format are the same as for OOXML.
+                        if (bIsRelative && nDots == 1)
                         {
-                            sal_Int32 nLen = pLineDash->DotLen;
-                            if ( pLineDash->Dashes )
-                                nLen = pLineDash->DashLen;
-
-                            if ( nLen >= nDistance )
+                            // I'm not sure that LO always uses 100%, because in case of absolute values, LO
+                            // sets length to 0 but treats it as 100%, if the attribute is missing in ODF.
+                            // So to be sure set 100% explicitly in case of relative too.
+                            if (nDashes > 0 && nDashLen == 0)
+                                nDashLen = 100;
+                            if (nDotLen == 0)
+                                nDotLen = 100;
+                            bIsConverted = true;
+                            if (nDotLen == 100 && nDashes == 0 && nDashLen == 0 && nDistance == 300)
+                                eDash = ESCHER_LineDotGEL;
+                            else if (nDotLen == 400 && nDashes == 0 && nDashLen == 0 && nDistance == 300)
+                                eDash = ESCHER_LineDashGEL;
+                            else if (nDotLen == 400 && nDashes == 1 && nDashLen == 100 && nDistance == 300)
+                                eDash = ESCHER_LineDashDotGEL;
+                            else if (nDotLen == 800 && nDashes == 0 && nDashLen == 0 && nDistance == 300)
                                 eDash = ESCHER_LineLongDashGEL;
-                            else if ( pLineDash->Dots )
+                            else if (nDotLen == 800 && nDashes == 1 && nDashLen == 100 && nDistance == 300)
+                                eDash = ESCHER_LineLongDashDotGEL;
+                            else if (nDotLen == 800 && nDashes == 2 && nDashLen == 100 && nDistance == 300)
+                                eDash = ESCHER_LineLongDashDotDotGEL;
+                            else if (nDotLen == 100 && nDashes == 0 && nDashLen == 0 && nDistance == 100)
                                 eDash = ESCHER_LineDotSys;
+                            else if (nDotLen == 300 && nDashes == 0 && nDashLen == 0 && nDistance == 100)
+                                eDash = ESCHER_LineDashSys;
+                            else if (nDotLen == 300 && nDashes == 1 && nDashLen == 100 && nDistance == 100)
+                                eDash = ESCHER_LineDashDotSys;
+                            else if (nDotLen == 300 && nDashes == 2 && nDashLen == 100 && nDistance == 100)
+                                eDash = ESCHER_LineDashDotDotSys;
                             else
-                                eDash = ESCHER_LineDashGEL;
+                                bIsConverted = false;
                         }
-                        else                                                            // X Y
-                        {
-                            if ( pLineDash->Dots != pLineDash->Dashes )
+
+                        if (!bIsConverted)
+                        {   // Map the style roughly to preset line styles.
+                            if (((!(pLineDash->Dots)) || (!(pLineDash->Dashes)))
+                                || (pLineDash->DotLen == pLineDash->DashLen))
                             {
-                                if ( ( pLineDash->DashLen > nDistance ) || ( pLineDash->DotLen > nDistance ) )
-                                    eDash = ESCHER_LineLongDashDotDotGEL;
+                                sal_Int32 nLen = pLineDash->DotLen;
+                                if (pLineDash->Dashes)
+                                    nLen = pLineDash->DashLen;
+                                if (nLen >= nDistance)
+                                    eDash = ESCHER_LineLongDashGEL;
+                                else if (pLineDash->Dots)
+                                    eDash = ESCHER_LineDotSys;
                                 else
-                                    eDash = ESCHER_LineDashDotDotSys;
+                                 eDash = ESCHER_LineDashGEL;
                             }
-                            else                                                        // X Y Y
+                            else                                                            // X Y
                             {
-                                if ( ( pLineDash->DashLen > nDistance ) || ( pLineDash->DotLen > nDistance ) )
-                                    eDash = ESCHER_LineLongDashDotGEL;
-                                else
-                                    eDash = ESCHER_LineDashDotGEL;
-
+                                if (pLineDash->Dots != pLineDash->Dashes)
+                                {
+                                    if ((pLineDash->DashLen > nDistance) || (pLineDash->DotLen > nDistance))
+                                        eDash = ESCHER_LineLongDashDotDotGEL;
+                                    else
+                                        eDash = ESCHER_LineDashDotDotSys;
+                                }
+                                else                                                        // X Y Y
+                                {
+                                    if ((pLineDash->DashLen > nDistance) || (pLineDash->DotLen > nDistance))
+                                        eDash = ESCHER_LineLongDashDotGEL;
+                                    else
+                                        eDash = ESCHER_LineDashDotGEL;
+                                }
                             }
                         }
                         AddOpt( ESCHER_Prop_lineDashing, eDash );
@@ -1105,11 +1160,6 @@ void EscherPropertyContainer::CreateLineProperties(
         }
     }
 
-    sal_uInt32 nLineSize = ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineWidth" ) )
-        ? *o3tl::doAccess<sal_uInt32>(aAny) : 0;
-    if ( nLineSize > 1 )
-        AddOpt( ESCHER_Prop_lineWidth, nLineSize * 360 );       // 100TH MM -> PT , 1PT = 12700 EMU
-
     ESCHER_LineJoin eLineJoin = ESCHER_LineJoinMiter;
     if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineJoint", true ) )
     {
diff --git a/filter/source/msfilter/msdffimp.cxx b/filter/source/msfilter/msdffimp.cxx
index 17be716f50c8..3dc792e7674f 100644
--- a/filter/source/msfilter/msdffimp.cxx
+++ b/filter/source/msfilter/msdffimp.cxx
@@ -934,7 +934,7 @@ void DffPropertyReader::ApplyLineAttributes( SfxItemSet& rSet, const MSO_SPT eSh
         sal_Int32 nLineWidth = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_lineWidth, 9525 ));
 
         // support LineCap
-        const MSO_LineCap eLineCap(static_cast<MSO_LineCap>(GetPropertyValue(DFF_Prop_lineEndCapStyle, mso_lineEndCapSquare)));
+        const MSO_LineCap eLineCap(static_cast<MSO_LineCap>(GetPropertyValue(DFF_Prop_lineEndCapStyle, mso_lineEndCapFlat)));
 
         switch(eLineCap)
         {
@@ -961,63 +961,97 @@ void DffPropertyReader::ApplyLineAttributes( SfxItemSet& rSet, const MSO_SPT eSh
             rSet.Put(XLineStyleItem( drawing::LineStyle_SOLID ) );
         else
         {
-            sal_uInt16  nDots = 1;
-            sal_uInt32  nDotLen = nLineWidth / 360;
+            // Despite of naming "dot" and "dash", that are all dashes and a "dot" can be longer
+            // than a "dash". The naming indicates the order, "dot" is always the first dash and
+            // "dash" is always the second dash. MS Office always starts with the longer dash, so
+            // set it here accordingly.
+            // The preset from binary is essentially the same as from OOXML. So here the same
+            // setting is used as in oox import. The comment corrensponds to
+            // "dots, dotLen, dashes, dashLen, distance" there.
+            // MS Office uses always relative length, so no need to consider nLineWidth
+            // here. Values are of kind 300 for 300% in css::drawing::DashStyle, for example.
+
+            sal_uInt16  nDots = 1; // in all cases, "solid" is treated above
+            // initalize, will be changened if necessary
+            sal_uInt32  nDotLen = 300;
             sal_uInt16  nDashes = 0;
-            const bool bHugeWidth = static_cast<sal_uInt32>(nLineWidth) >= SAL_MAX_UINT32/8U; //then rougher approx is fine
-            sal_uInt32  nDashLen = bHugeWidth ? (nDotLen * 8U) : ((8U * nLineWidth) / 360);
-            sal_uInt32  nDistance = bHugeWidth ? (nDotLen * 3U) : ((3U * nLineWidth) / 360);
-
+            sal_uInt32  nDashLen = 0;
+            sal_uInt32  nDistance = 300;
             switch ( eLineDashing )
             {
                 default:
-                case mso_lineDotSys :
+                case mso_lineDotSys : // 1 1 0 0 1
                 {
-                    nDots = 1;
-                    nDashes = 0;
-                    nDistance = nDotLen;
+                    nDotLen =100;
+                    nDistance = 100;
                 }
                 break;
 
-                case mso_lineDashGEL :
+                case mso_lineDashGEL : // 1 4 0 0 3
                 {
-                    nDots = 0;
-                    nDashes = 1;
-                    nDashLen = bHugeWidth ? (nDotLen * 4U) : ((4U * nLineWidth) / 360);
+                    nDotLen = 400;
                 }
                 break;
 
-                case mso_lineDashDotGEL :
+                case mso_lineDashDotGEL : // 1 4 1 1 3
                 {
-                    nDots = 1;
+                    nDotLen = 400;
                     nDashes = 1;
-                    nDashLen = bHugeWidth ? (nDotLen * 4U) : ((4U * nLineWidth) / 360);
+                    nDashLen = 100;
                 }
                 break;
 
-                case mso_lineLongDashGEL :
+                case mso_lineLongDashGEL : // 1 8 0 0 3
                 {
-                    nDots = 0;
-                    nDashes = 1;
+                    nDotLen = 800;
                 }
                 break;
 
-                case mso_lineLongDashDotGEL :
+                case mso_lineLongDashDotGEL : // 1 8 1 1 3
                 {
-                    nDots = 1;
+                    nDotLen = 800;
                     nDashes = 1;
+                    nDashLen = 100;
+                }
+                break;
+
+                case mso_lineLongDashDotDotGEL: // 1 8 2 1 3
+                {
+                    nDotLen = 800;
+                    nDashes = 2;
+                    nDashLen = 100;
+                }
+                break;
+
+                case mso_lineDotGEL: // 1 1 0 0 3
+                {
+                    nDotLen = 100;
+                }
+                break;
+
+                case mso_lineDashSys: // 1 3 0 0 1
+                {
+                    nDistance = 100;
                 }
                 break;
 
-                case mso_lineLongDashDotDotGEL:
+                case mso_lineDashDotSys: // 1 3 1 1 1
                 {
-                    nDots = 2;
                     nDashes = 1;
+                    nDashLen = 100;
+                    nDistance = 100;
                 }
                 break;
-            }
 
-            rSet.Put( XLineDashItem( OUString(), XDash( css::drawing::DashStyle_RECT, nDots, nDotLen, nDashes, nDashLen, nDistance ) ) );
+                case mso_lineDashDotDotSys: // 1 3 2 1 1
+                {
+                    nDashes = 2;
+                    nDashLen = 100;
+                    nDistance = 100;
+                }
+                break;
+            }
+            rSet.Put( XLineDashItem( OUString(), XDash( css::drawing::DashStyle_RECTRELATIVE, nDots, nDotLen, nDashes, nDashLen, nDistance ) ) );
             rSet.Put( XLineStyleItem( drawing::LineStyle_DASH ) );
         }
         rSet.Put( XLineColorItem( OUString(), rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_lineColor, 0 ) ) ) );
diff --git a/include/oox/export/utils.hxx b/include/oox/export/utils.hxx
index e75a3f83a120..e28b01c1d95d 100644
--- a/include/oox/export/utils.hxx
+++ b/include/oox/export/utils.hxx
@@ -63,7 +63,7 @@ static constexpr sal_Int64 TwipsToEMU( sal_Int32 nTwips )
 template <typename T>
 OString write1000thOfAPercent(T number)
 {
-    return OString::number( number * 1000 );
+    return OString::number( lround(number * 1000.0) );
 }
 
 namespace oox { namespace drawingml {
diff --git a/oox/source/drawingml/lineproperties.cxx b/oox/source/drawingml/lineproperties.cxx
index 1139273a1831..d9a441d8f52d 100644
--- a/oox/source/drawingml/lineproperties.cxx
+++ b/oox/source/drawingml/lineproperties.cxx
@@ -57,74 +57,143 @@ void lclSetDashData( LineDash& orLineDash, sal_Int16 nDots, sal_Int32 nDotLen,
 
 /** Converts the specified preset dash to API dash.
  */
-void lclConvertPresetDash(LineDash& orLineDash, sal_Int32 nPresetDash, sal_Int32 nLineWidth)
+void lclConvertPresetDash(LineDash& orLineDash, sal_Int32 nPresetDash)
 {
     switch( nPresetDash )
     {
         case XML_dot:           lclSetDashData( orLineDash, 1, 1, 0, 0, 3 );    break;
-        case XML_dash:          lclSetDashData( orLineDash, 0, 0, 1, 4, 3 );    break;
-        case XML_dashDot:       lclSetDashData( orLineDash, 1, 1, 1, 4, 3 );    break;
+        case XML_dash:          lclSetDashData( orLineDash, 1, 4, 0, 0, 3 );    break;
+        case XML_dashDot:       lclSetDashData( orLineDash, 1, 4, 1, 1, 3 );    break;
 
-        case XML_lgDash:        lclSetDashData( orLineDash, 0, 0, 1, 8, 3 );    break;
-        case XML_lgDashDot:     lclSetDashData( orLineDash, 1, 1, 1, 8, 3 );    break;
+        case XML_lgDash:        lclSetDashData( orLineDash, 1, 8, 0, 0, 3 );    break;
+        case XML_lgDashDot:     lclSetDashData( orLineDash, 1, 8, 1, 1, 3 );    break;
         case XML_lgDashDotDot:  lclSetDashData( orLineDash, 1, 8, 2, 1, 3 );    break;
 
         case XML_sysDot:        lclSetDashData( orLineDash, 1, 1, 0, 0, 1 );    break;
-        case XML_sysDash:       lclSetDashData( orLineDash, 0, 0, 1, 3, 1 );    break;
-        case XML_sysDashDot:    lclSetDashData( orLineDash, 1, 1, 1, 3, 1 );    break;
-        case XML_sysDashDotDot: lclSetDashData( orLineDash, 2, 1, 1, 3, 1 );    break;
+        case XML_sysDash:       lclSetDashData( orLineDash, 1, 3, 0, 0, 1 );    break;
+        case XML_sysDashDot:    lclSetDashData( orLineDash, 1, 3, 1, 1, 1 );    break;
+        case XML_sysDashDotDot: lclSetDashData( orLineDash, 1, 3, 2, 1, 1 );    break;
 
         default:
             OSL_FAIL( "lclConvertPresetDash - unsupported preset dash" );
-            lclSetDashData( orLineDash, 0, 0, 1, 4, 3 );
+            lclSetDashData( orLineDash, 1, 4, 0, 0, 3 );
     }
-    // convert relative dash/dot length to absolute length
-    orLineDash.DotLen *= nLineWidth;
-    orLineDash.DashLen *= nLineWidth;
-    orLineDash.Distance *= nLineWidth;
+    orLineDash.DotLen *= 100;
+    orLineDash.DashLen *= 100;
+    orLineDash.Distance *= 100;
 }
 
 /** Converts the passed custom dash to API dash. rCustomDash should not be empty.
+ * We assume, that there exist only two lenght values and the distance is the same
+ * for all dashes. Other kind of dash stop sequences cannot be represented, neither
+ * in model nor in ODF.
  */
-void lclConvertCustomDash(LineDash& orLineDash, const LineProperties::DashStopVector& rCustomDash, sal_Int32 nLineWidth)
+void lclConvertCustomDash(LineDash& orLineDash, const LineProperties::DashStopVector& rCustomDash)
 {
     OSL_ASSERT(!rCustomDash.empty());
-    orLineDash.Dashes = 0;
-    // Follow the order we export custDash: dashes first.
-    orLineDash.DashLen = rCustomDash[0].first;
-    // Also assume dash and dot have the same sp values.
+    // Assume all dash stops have the same sp values.
     orLineDash.Distance = rCustomDash[0].second;
-    orLineDash.DotLen = 0;
-
+    // First kind of dashes go to "Dots"
+    orLineDash.DotLen = rCustomDash[0].first;
+    orLineDash.Dots = 0;
     for(const auto& rIt : rCustomDash)
     {
-        sal_Int32 nLen = rIt.first;
-        if (nLen != orLineDash.DashLen)
-        {
-            orLineDash.DotLen = nLen;
+        if (rIt.first != orLineDash.DotLen)
             break;
-        }
-        ++orLineDash.Dashes;
+        ++orLineDash.Dots;
     }
-    // TODO: verify the assumption and approximate complex line patterns.
+    // All others go to "Dashes", we cannot handle more than two kinds.
+    orLineDash.Dashes = rCustomDash.size() - orLineDash.Dots;
+    if (orLineDash.Dashes > 0)
+        orLineDash.DashLen = rCustomDash[orLineDash.Dots].first;
+    else
+        orLineDash.DashLen = 0;
+
+    // convert to API, e.g. 123% is 123000 in MS Office and 123 in our API
+    orLineDash.DotLen = orLineDash.DotLen / 1000;
+    orLineDash.DashLen = orLineDash.DashLen / 1000;
+    orLineDash.Distance = orLineDash.Distance / 1000;
+}
 
-    // Assume we only have two types of dash stops, the rest are all dots.
-    orLineDash.Dots = rCustomDash.size() - orLineDash.Dashes;
-    orLineDash.DashLen = orLineDash.DashLen / 100000.0 * nLineWidth;
-    orLineDash.DotLen = orLineDash.DotLen / 100000.0 * nLineWidth;
-    orLineDash.Distance = orLineDash.Distance / 100000.0 * nLineWidth;
+/** LibreOffice uses value 0, if a length attribute is missing in the
+ * style definition, but treats it as 100%.
+ * LibreOffice uses absolute values in some style definitions. Try to
+ * reconstruct them from the imported relative values.
+ */
+void lclRecoverStandardDashStyles(LineDash& orLineDash, sal_Int32 nLineWidth)
+{
+    sal_uInt16 nDots = orLineDash.Dots;
+    sal_uInt16 nDashes = orLineDash.Dashes;
+    sal_uInt32 nDotLen = orLineDash.DotLen;
+    sal_uInt32 nDashLen = orLineDash.DashLen;
+    sal_uInt32 nDistance = orLineDash.Distance;
+    // Use same ersatz for hairline as in export.
+    double fWidthHelp = nLineWidth == 0 ? 26.95/100.0 : nLineWidth / 100.0;
+    // start with (var) cases, because they have no rounding problems
+    // "Fine Dashed", "Line Style 9" and "Dashed (var)" need no recover
+    if (nDots == 3 && nDotLen == 197 &&nDashes == 3 && nDashLen == 100 && nDistance == 100)
+    {   // "3 Dashes 3 Dots (var)"
+        orLineDash.DashLen = 0;
+    }
+    else if (nDots == 1 && nDotLen == 100 && nDashes == 0 && nDistance == 50)
+    {   // "Ultrafine Dotted (var)"
+        orLineDash.DotLen = 0;
+    }
+    else if (nDots == 2 && nDashes == 0 && nDotLen == nDistance
+        && std::abs(nDistance * fWidthHelp - 51.0) < fWidthHelp)
+    {   // "Ultrafine Dashed"
+        orLineDash.Dots = 1;
+        orLineDash.DotLen = 51;
+        orLineDash.Dashes = 1;
+        orLineDash.DashLen = 51;
+        orLineDash.Distance = 51;
+        orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
+    }
+    else if (nDots == 2 && nDashes == 3 && std::abs(nDotLen * fWidthHelp - 51.0) < fWidthHelp
+        && std::abs(nDashLen * fWidthHelp - 254.0) < fWidthHelp
+        && std::abs(nDistance * fWidthHelp - 127.0) < fWidthHelp)
+    {   // "Ultrafine 2 Dots 3 Dashes"
+        orLineDash.DotLen = 51;
+        orLineDash.DashLen = 254;
+        orLineDash.Distance = 127;
+        orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
+    }
+    else if (nDots == 1 && nDotLen == 100 && nDashes == 0
+        && std::abs(nDistance * fWidthHelp - 457.0) < fWidthHelp)
+    {    // "Fine Dotted"
+        orLineDash.DotLen = 0;
+        orLineDash.Distance = 457;
+        orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
+    }
+    else if (nDots == 1 && nDashes == 10 && nDashLen == 100
+        && std::abs(nDistance * fWidthHelp - 152.0) < fWidthHelp)
+    {   // "Line with Fine Dots"
+        orLineDash.DotLen = 2007;
+        orLineDash.DashLen = 0;
+        orLineDash.Distance = 152;
+        orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
+    }
+    else if (nDots == 2 && nDotLen == 100 && nDashes == 1 && nDashLen == nDistance
+        && std::abs(nDistance * fWidthHelp - 203.0) < fWidthHelp)
+    {   // "2 Dots 1 Dash"
+        orLineDash.DotLen = 0;
+        orLineDash.DashLen = 203;
+        orLineDash.Distance = 203;
+        orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
+    }
 }
 
 DashStyle lclGetDashStyle( sal_Int32 nToken )
 {
     OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
+    // MS Office dashing is always relative to line width
     switch( nToken )
     {
         case XML_rnd:   return DashStyle_ROUNDRELATIVE;
-        case XML_sq:    return DashStyle_RECTRELATIVE;
-        case XML_flat:  return DashStyle_RECT;
+        case XML_sq:    return DashStyle_RECTRELATIVE; // default in OOXML
+        case XML_flat:  return DashStyle_RECTRELATIVE; // default in MS Office
     }
-    return DashStyle_ROUNDRELATIVE;
+    return DashStyle_RECTRELATIVE;
 }
 
 LineCap lclGetLineCap( sal_Int32 nToken )
@@ -133,8 +202,8 @@ LineCap lclGetLineCap( sal_Int32 nToken )
     switch( nToken )
     {
         case XML_rnd:   return LineCap_ROUND;
-        case XML_sq:    return LineCap_SQUARE;
-        case XML_flat:  return LineCap_BUTT;
+        case XML_sq:    return LineCap_SQUARE; // default in OOXML
+        case XML_flat:  return LineCap_BUTT; // default in MS Office
     }
     return LineCap_BUTT;
 }
@@ -373,25 +442,23 @@ void LineProperties::pushToPropMap( ShapePropertyMap& rPropMap,
         // line style (our core only supports none and solid)
         drawing::LineStyle eLineStyle = (maLineFill.moFillType.get() == XML_noFill) ? drawing::LineStyle_NONE : drawing::LineStyle_SOLID;
 
-        // convert line width from EMUs to 1/100mm
-        sal_Int32 nLineWidth = getLineWidth();
+        // line width in 1/100mm
+        sal_Int32 nLineWidth = getLineWidth(); // includes convertion from EMUs to 1/100mm
+        rPropMap.setProperty( ShapeProperty::LineWidth, nLineWidth );
 
-        // create line dash from preset dash token (not for invisible line)
+        // 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()) )
         {
             LineDash aLineDash;
-            aLineDash.Style = lclGetDashStyle( moLineCap.get( XML_rnd ) );
+            aLineDash.Style = lclGetDashStyle( moLineCap.get( XML_flat ) );
 
-            // convert preset dash or custom dash
-            if(moPresetDash.differsFrom(XML_solid) || maCustomDash.empty())
+            if(moPresetDash.differsFrom(XML_solid))
+                lclConvertPresetDash(aLineDash, moPresetDash.get(XML_dash));
+            else // !maCustomDash.empty()
             {
-                sal_Int32 nBaseLineWidth = ::std::max<sal_Int32>(nLineWidth, 35);
-                lclConvertPresetDash(aLineDash, moPresetDash.get(XML_dash), nBaseLineWidth);
+                lclConvertCustomDash(aLineDash, maCustomDash);
+                lclRecoverStandardDashStyles(aLineDash, nLineWidth);
             }
-            else
-                lclConvertCustomDash(aLineDash, maCustomDash, nLineWidth);
-
-
             if( rPropMap.setProperty( ShapeProperty::LineDash, aLineDash ) )
                 eLineStyle = drawing::LineStyle_DASH;
         }
@@ -406,9 +473,6 @@ void LineProperties::pushToPropMap( ShapePropertyMap& rPropMap,
         if( moLineJoint.has() )
             rPropMap.setProperty( ShapeProperty::LineJoint, lclGetLineJoint( moLineJoint.get() ) );
 
-        // line width in 1/100mm
-        rPropMap.setProperty( ShapeProperty::LineWidth, nLineWidth );
-
         // line color and transparence
         Color aLineColor = maLineFill.getBestSolidColor();
         if( aLineColor.isUsed() )
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index 24aa6fde79b5..2eafc6f32e24 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -859,116 +859,101 @@ void DrawingML::WriteOutline( const Reference<XPropertySet>& rXPropSet, Referenc
 
     if( bDashSet && aStyleLineStyle != drawing::LineStyle_DASH )
     {
-        // convert absolute dash/dot length to relative length
-        int relDotLen = nLineWidth ? aLineDash.DotLen / nLineWidth : 0;
-        int relDashLen = nLineWidth ? aLineDash.DashLen / nLineWidth : 0;
-        int relDistance = nLineWidth ? aLineDash.Distance / nLineWidth : 0;
-        // fixing relative values in the case of linewidths smaller than 1 pt
-        if (0 < nLineWidth && nLineWidth < 35) //35 HMM == 1 pt
-        {
-            relDotLen = relDotLen ? (relDotLen + 1) * (nLineWidth * 360.0 / 12700) : 0;
-            relDashLen = relDashLen ? (relDashLen + 1) * (nLineWidth * 360.0 / 12700) : 0;
-            relDistance = relDistance ? (relDistance + 1) * (nLineWidth * 360.0 / 12700) : 0;
-        }
-        // keep default mso preset linestyles (instead of custdash)
-        if (aLineDash.Dots == 1 && relDotLen == 1 && aLineDash.Dashes == 0 && relDashLen == 0 && relDistance == 3)
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "dot");
-        }
-        else if (aLineDash.Dots == 0 && relDotLen == 0 && aLineDash.Dashes == 1 && relDashLen == 4 && relDistance == 3)
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "dash");
-        }
-        else if (aLineDash.Dots == 1 && relDotLen == 1 && aLineDash.Dashes == 1 && relDashLen == 4 && relDistance == 3)
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "dashDot");
-        }
-        else if (aLineDash.Dots == 0 && relDotLen == 0 && aLineDash.Dashes == 1 && relDashLen == 8 && relDistance == 3)
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "lgDash");
-        }
-        else if (aLineDash.Dots == 1 && relDotLen == 1 && aLineDash.Dashes == 1 && relDashLen == 8 && relDistance == 3)
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "lgDashDot");
-        }
-        else if (aLineDash.Dots == 1 && relDotLen == 8 && aLineDash.Dashes == 2 && relDashLen == 1 && relDistance == 3)
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "lgDashDotDot");
-        }
-        else if (aLineDash.Dots == 1 && relDotLen == 1 && aLineDash.Dashes == 0 && relDashLen == 0 && relDistance == 1)
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "sysDot");
-        }
-        else if (aLineDash.Dots == 0 && relDotLen == 0 && aLineDash.Dashes == 1 && relDashLen == 3 && relDistance == 1)
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "sysDash");
-        }
-        else if (aLineDash.Dots == 1 && relDotLen == 1 && aLineDash.Dashes == 1 && relDashLen == 3 && relDistance == 1)
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "sysDashDot");
-        }
-        else if (aLineDash.Dots == 2 && relDotLen == 1 && aLineDash.Dashes == 1 && relDashLen == 3 && relDistance == 1)
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "sysDashDotDot");
-        }
-        /*convert some LO preset dashes to MSO preset dashes for oox interoperability
-        LO preset dashes which don't have equivalent in MSO preset dashes: 2 Dots 3 Dashes, Line with Fine Dots, 3 Dashes 3 Dots*/
-        //ultrafine Dashed, Ultrafine Dotted -> sysDot
-        else if ((aLineDash.Dots == 1 && aLineDash.DotLen == 51 && aLineDash.Dashes == 1 && aLineDash.DashLen == 51 && aLineDash.Distance == 51) ||
-                 (aLineDash.Dots == 1 && aLineDash.DotLen == 0 && aLineDash.Dashes == 0 && aLineDash.DashLen == 0 && aLineDash.Distance == 50))
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "sysDot");
-        }
-        //Fine Dashed -> dash
-        else if (aLineDash.Dots == 1 && aLineDash.DotLen == 197 && aLineDash.Dashes == 0 && aLineDash.DashLen == 0 && aLineDash.Distance == 197)
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "dash");
-        }
-        //Fine Dotted -> dot
-        else if (aLineDash.Dots == 1 && aLineDash.DotLen == 0 && aLineDash.Dashes == 0 && aLineDash.DashLen == 0 && aLineDash.Distance == 457)
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "dot");
-        }
-        //Line Style 9, Dashed -> sysDash
-        else if ((aLineDash.Dots == 1 && aLineDash.DotLen == 197 && aLineDash.Dashes == 0 && aLineDash.DashLen == 0 && aLineDash.Distance == 120) ||
-                 (aLineDash.Dots == 1 && aLineDash.DotLen == 197 && aLineDash.Dashes == 0 && aLineDash.DashLen == 0  && aLineDash.Distance == 127))
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "sysDash");
-        }
-        //2 Dots 1 Dash -> sysDashDotDot
-        else if (aLineDash.Dots == 2 && aLineDash.DotLen == 0 && aLineDash.Dashes == 1 && aLineDash.DashLen == 203 && aLineDash.Distance == 203)
-        {
-            mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "sysDashDotDot");
+        // Try to detect if it might come from ms preset line style import.
+        // MS Office styles are always relative, both binary and OOXML.
+        // "dot" is always the first dash and "dash" the second one. All OOXML presets linestyles
+        // 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)
+        {
+            // 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;
+            bIsConverted = true;
+            if (nDotLen == 100 && aLineDash.Dashes == 0 && nDashLen == 0 && aLineDash.Distance == 300)
+            {
+                mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "dot");
+            }
+            else if (nDotLen == 400 && aLineDash.Dashes == 0 && nDashLen == 0 && aLineDash.Distance == 300)
+            {
+                mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "dash");
+            }
+            else if (nDotLen == 400 && aLineDash.Dashes == 1 && nDashLen == 100 && aLineDash.Distance == 300)
+            {
+                mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "dashDot");
+            }
+            else if (nDotLen == 800 && aLineDash.Dashes == 0 && nDashLen == 0 && aLineDash.Distance == 300)
+            {
+                mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "lgDash");
+            }
+            else if (nDotLen == 800 && aLineDash.Dashes == 1 && nDashLen == 100 && aLineDash.Distance == 300)
+            {
+                mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "lgDashDot");
+            }
+            else if (nDotLen == 800 && aLineDash.Dashes == 2 && nDashLen == 100 && aLineDash.Distance == 300)
+            {
+                mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "lgDashDotDot");
+            }
+            else if (nDotLen == 100 && aLineDash.Dashes == 0 && nDashLen == 0 && aLineDash.Distance == 100)
+            {
+                mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "sysDot");
+            }
+            else if (nDotLen == 300 && aLineDash.Dashes == 0 && nDashLen == 0 && aLineDash.Distance == 100)
+            {
+                mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "sysDash");
+            }
+            else if (nDotLen == 300 && aLineDash.Dashes == 1 && nDashLen == 100 && aLineDash.Distance == 100)
+            {
+                mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "sysDashDot");
+            }
+            else if (nDotLen == 300 && aLineDash.Dashes == 2 && nDashLen == 100 && aLineDash.Distance == 100)
+            {
+                mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, "sysDashDotDot");
+            }
+            else
+                bIsConverted = false;
         }
-        else
+        // Do not map our own line styles to OOXML prstDash values, because custDash gives better results.
+        if (!bIsConverted)
         {
             mpFS->startElementNS(XML_a, XML_custDash);
-
-            // Check that line-width is positive and distance between dashes\dots is positive
-            if ( nLineWidth > 0 && aLineDash.Distance > 0 )
+            // In case of hairline we would need the current pixel size. Instead use a reasonable
+            // ersatz for it. The value is the same as SMALLEST_DASH_WIDTH in xattr.cxx.
+            // (And it makes sure fLineWidth is not zero in below division.)
+            double fLineWidth = nLineWidth > 0 ? nLineWidth : 26.95;
+            int i;
+            double fSp = bIsRelative ? aLineDash.Distance : aLineDash.Distance * 100.0 / fLineWidth;
+            // LO uses line width, in case Distance is zero. MS Office would use a space of zero length.
+            // So set 100% explicitly.
+            if (aLineDash.Distance <= 0)
+                    fSp = 100.0;
+            if ( aLineDash.Dots > 0 )
             {
-                // Write 'dashes' first, and then 'dots'
-                int i;
-                sal_Int32 nSp = aLineDash.Distance * 100 / nLineWidth;
-                if ( aLineDash.Dashes > 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;
+                for( i = 0; i < aLineDash.Dots; i ++ )
                 {
-                    sal_Int32 nD = aLineDash.DashLen * 100 / nLineWidth;
-                    for( i = 0; i < aLineDash.Dashes; i ++ )
-                    {
-                        mpFS->singleElementNS( XML_a , XML_ds,
-                                               XML_d , write1000thOfAPercent(nD),
-                                               XML_sp, write1000thOfAPercent(nSp) );
-                    }
+                    mpFS->singleElementNS( XML_a, XML_ds,
+                                           XML_d , write1000thOfAPercent(fD),
+                                           XML_sp, write1000thOfAPercent(fSp) );
                 }
-                if ( aLineDash.Dots > 0 )
+            }
+            if ( aLineDash.Dashes > 0 )
+            {
+                double fD = bIsRelative ? aLineDash.DashLen : aLineDash.DashLen * 100.0 / fLineWidth;
+                // LO sets length to 0, if attribute is missing in ODF. Then a relataive length of 100% is intended.
+                if (aLineDash.DashLen == 0)
+                    fD = 100.0;
+                for( i = 0; i < aLineDash.Dashes; i ++ )
                 {
-                    sal_Int32 nD = aLineDash.DotLen * 100 / nLineWidth;
-                    for( i = 0; i < aLineDash.Dots; i ++ )
-                    {
-                        mpFS->singleElementNS( XML_a, XML_ds,
-                                               XML_d , write1000thOfAPercent(nD),
-                                               XML_sp, write1000thOfAPercent(nSp) );
-                    }
+                    mpFS->singleElementNS( XML_a , XML_ds,
+                                           XML_d , write1000thOfAPercent(fD),
+                                           XML_sp, write1000thOfAPercent(fSp) );
                 }
             }
 
diff --git a/sd/qa/unit/data/odp/LineStylesOwn.odp b/sd/qa/unit/data/odp/LineStylesOwn.odp
new file mode 100644
index 000000000000..8a145bb9ff11
Binary files /dev/null and b/sd/qa/unit/data/odp/LineStylesOwn.odp differ
diff --git a/sd/qa/unit/data/odp/tdf127267DashOnHairline.odp b/sd/qa/unit/data/odp/tdf127267DashOnHairline.odp
new file mode 100644
index 000000000000..08aed1758b1f
Binary files /dev/null and b/sd/qa/unit/data/odp/tdf127267DashOnHairline.odp differ
diff --git a/sd/qa/unit/data/pptx/presetDashDot.pptx b/sd/qa/unit/data/pptx/presetDashDot.pptx
new file mode 100644
index 000000000000..ae1525c97b14
Binary files /dev/null and b/sd/qa/unit/data/pptx/presetDashDot.pptx differ
diff --git a/sd/qa/unit/export-tests-ooxml1.cxx b/sd/qa/unit/export-tests-ooxml1.cxx
index dde6fa42781f..05d7d3aff31b 100644
--- a/sd/qa/unit/export-tests-ooxml1.cxx
+++ b/sd/qa/unit/export-tests-ooxml1.cxx
@@ -40,6 +40,7 @@
 #include <com/sun/star/awt/FontDescriptor.hpp>
 #include <com/sun/star/frame/XStorable.hpp>
 #include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/LineDash.hpp>
 #include <com/sun/star/text/WritingMode2.hpp>
 #include <com/sun/star/table/BorderLine2.hpp>
 #include <com/sun/star/table/XTable.hpp>
@@ -83,6 +84,9 @@ public:
     void testTdf94238();
     void testPictureTransparency();
     void testTdf125554();
+    void testRoundtripOwnLineStyles();
+    void testRoundtripPrstDash();
+    void testDashOnHairline();
 
     CPPUNIT_TEST_SUITE(SdOOXMLExportTest1);
 
@@ -116,6 +120,9 @@ public:
     CPPUNIT_TEST(testTdf94238);
     CPPUNIT_TEST(testTdf125554);
     CPPUNIT_TEST(testPictureTransparency);
+    CPPUNIT_TEST(testRoundtripOwnLineStyles);
+    CPPUNIT_TEST(testRoundtripPrstDash);
+    CPPUNIT_TEST(testDashOnHairline);
 
     CPPUNIT_TEST_SUITE_END();
 
@@ -905,6 +912,112 @@ void SdOOXMLExportTest1::testTdf125554()
     xDocShRef->DoClose();
 }
 
+void SdOOXMLExportTest1::testRoundtripOwnLineStyles()
+{
+    // Load odp document and read the LineDash values.
+    ::sd::DrawDocShellRef xDocShRef
+        = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/odp/LineStylesOwn.odp"), ODP);
+    uno::Reference<drawing::XDrawPagesSupplier> xDocodp(xDocShRef->GetDoc()->getUnoModel(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xDocodp.is());
+    uno::Reference<drawing::XDrawPage> xPageodp(xDocodp->getDrawPages()->getByIndex(0), uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xPageodp.is());
+    drawing::LineDash aLineDashodp[10];
+    for (sal_uInt16 i= 0; i < 10; i++)
+    {
+        uno::Reference<beans::XPropertySet> xShapeodp(getShape(i, xPageodp));
+        CPPUNIT_ASSERT(xShapeodp.is());
+        xShapeodp->getPropertyValue("LineDash") >>= aLineDashodp[i];
+    }
+
+    // Save to pptx, reload and compare the LineDash values
+    utl::TempFile tempFile;
+    xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
+    uno::Reference<drawing::XDrawPagesSupplier> xDocpptx(xDocShRef->GetDoc()->getUnoModel(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xDocpptx.is());
+    uno::Reference<drawing::XDrawPage> xPagepptx(xDocpptx->getDrawPages()->getByIndex(0), uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xPagepptx.is());
+
+    for (sal_uInt16 i = 0; i < 10; i++)
+    {
+        drawing::LineDash aLineDashpptx;
+        uno::Reference<beans::XPropertySet> xShapepptx(getShape(i, xPagepptx));
+        CPPUNIT_ASSERT(xShapepptx.is());
+        xShapepptx->getPropertyValue("LineDash") >>= aLineDashpptx;
+        bool bIsSameLineDash = (aLineDashodp[i].Style == aLineDashpptx.Style
+                                && aLineDashodp[i].Dots == aLineDashpptx.Dots
+                                && aLineDashodp[i].DotLen == aLineDashpptx.DotLen
+                                && aLineDashodp[i].Dashes == aLineDashpptx.Dashes
+                                && aLineDashodp[i].DashLen == aLineDashpptx.DashLen
+                                && aLineDashodp[i].Distance == aLineDashpptx.Distance);
+        CPPUNIT_ASSERT_MESSAGE("LineDash differ", bIsSameLineDash);
+    }
+    xDocShRef->DoClose();
+}
+
+void SdOOXMLExportTest1::testRoundtripPrstDash()
+{
+    // load and save document, compare prstDash values in saved document with original.
+    ::sd::DrawDocShellRef xDocShRef
+        = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/pptx/presetDashDot.pptx"), PPTX);
+    utl::TempFile tempFile;
+    xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
+
+    const OUString sOriginal[] = {
+        "dash",
+        "dashDot",
+        "dot",
+        "lgDash",
+        "lgDashDot",
+        "lgDashDotDot",
+        "sysDash",
+        "sysDashDot",
+        "sysDashDotDot",
+        "sysDot"
+    };
+    xmlDocPtr pXmlDoc = parseExport(tempFile, "ppt/slides/slide1.xml");
+    const OString sStart = "/p:sld/p:cSld/p:spTree/p:sp[";
+    const OString sEnd = "]/p:spPr/a:ln/a:prstDash";
+    for (sal_uInt16 i = 0; i < 10; i++)
+    {
+        OString sXmlPath = sStart + OString::number(i+1) + sEnd;
+        OUString sResaved = getXPath(pXmlDoc, sXmlPath, "val");
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong prstDash", sOriginal[i], sResaved);
+    }
+
+    // tdf#126746: Make sure that dash-dot pattern starts with the longer dash, as defined in OOXML
+    // Make sure Style is drawing::DashStyle_RECTRELATIVE
+    uno::Reference<drawing::XDrawPagesSupplier> xDoc(xDocShRef->GetDoc()->getUnoModel(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xDoc.is());
+    uno::Reference<drawing::XDrawPage> xPage(xDoc->getDrawPages()->getByIndex(0), uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xPage.is());
+    for (sal_uInt16 i = 0; i < 10; i++)
+    {
+        drawing::LineDash aLineDash;
+        uno::Reference<beans::XPropertySet> xShape(getShape(i, xPage));
+        CPPUNIT_ASSERT(xShape.is());
+        xShape->getPropertyValue("LineDash") >>= aLineDash;
+        CPPUNIT_ASSERT_MESSAGE("First dash is short", aLineDash.DotLen >= aLineDash.DashLen);
+        bool bIsRectRelative = aLineDash.Style == drawing::DashStyle_RECTRELATIVE;
+        CPPUNIT_ASSERT_MESSAGE("not RECTRELATIVE", bIsRectRelative);
+    }
+
+    xDocShRef->DoClose();
+}
+
+void SdOOXMLExportTest1::testDashOnHairline()
+{
+    // load and save document, make sure the custDash has 11 child elements.
+    ::sd::DrawDocShellRef xDocShRef
+        = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/odp/tdf127267DashOnHairline.odp"), ODP);
+    utl::TempFile tempFile;
+    xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
+    xDocShRef->DoClose();
+
+    xmlDocPtr pXmlDoc = parseExport(tempFile, "ppt/slides/slide1.xml");
+    const OString sXmlPath = "/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:ln/a:custDash/a:ds";
+    assertXPath(pXmlDoc, sXmlPath, 11);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SdOOXMLExportTest1);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sd/qa/unit/export-tests-ooxml2.cxx b/sd/qa/unit/export-tests-ooxml2.cxx
index e2f82aa9d0c0..e9eeee5b8405 100644
--- a/sd/qa/unit/export-tests-ooxml2.cxx
+++ b/sd/qa/unit/export-tests-ooxml2.cxx
@@ -2478,6 +2478,8 @@ void SdOOXMLExportTest2::testTdf126741()
     xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
 
     // dash dot dot line style import fix
+    // The original fixed values are replaced with the percent values, because
+    // with fix for tdf#127166 the MS Office preset styles are correctly detected.
     const SdrPage *pPage = GetPage( 1, xDocShRef );
     SdrObject *const pObj = pPage->GetObj(0);
     CPPUNIT_ASSERT(pObj);
@@ -2489,10 +2491,10 @@ void SdOOXMLExportTest2::testTdf126741()
 
     CPPUNIT_ASSERT_EQUAL(drawing::LineStyle_DASH, rStyleItem.GetValue());
     CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), rDashItem.GetDashValue().GetDots());
-    CPPUNIT_ASSERT_EQUAL(sal_uInt32(280), rDashItem.GetDashValue().GetDotLen());
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(800), rDashItem.GetDashValue().GetDotLen());
     CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), rDashItem.GetDashValue().GetDashes());
-    CPPUNIT_ASSERT_EQUAL(sal_uInt32(35), rDashItem.GetDashValue().GetDashLen());
-    CPPUNIT_ASSERT_EQUAL(sal_uInt32(105), rDashItem.GetDashValue().GetDistance());
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(100), rDashItem.GetDashValue().GetDashLen());
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(300), rDashItem.GetDashValue().GetDistance());
 
     xDocShRef->DoClose();
 }
diff --git a/sw/qa/extras/ooxmlexport/data/lo_preset_dashes.odt b/sw/qa/extras/ooxmlexport/data/lo_preset_dashes.odt
deleted file mode 100644
index b9b8a79d46da..000000000000
Binary files a/sw/qa/extras/ooxmlexport/data/lo_preset_dashes.odt and /dev/null differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
index 54e2002bd12d..70ee26bbd2f4 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
@@ -944,19 +944,6 @@ DECLARE_OOXMLEXPORT_TEST(testTdf64264, "tdf64264.docx")
                          parseDump("/root/page[2]/body/tab/row[2]/cell[1]/txt/text()"));
 }
 
-DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testLOPresetDashesConvert, "lo_preset_dashes.odt")
-{
-    // File asserting while saving in LO.
-    xmlDocPtr pXmlDoc = parseExport("word/document.xml");
-    assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent[1]/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:ln/a:prstDash", "val", "sysDot");
-    assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent[2]/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:ln/a:prstDash", "val", "sysDash");
-    assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent[3]/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:ln/a:prstDash", "val", "sysDot");
-    assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent[6]/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:ln/a:prstDash", "val", "dot");
-    assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent[8]/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:ln/a:prstDash", "val", "dash");
-    assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent[9]/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:ln/a:prstDash", "val", "sysDashDotDot");
-    assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent[10]/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:ln/a:prstDash", "val", "sysDash");
-}
-
 DECLARE_OOXMLEXPORT_TEST(testTdf58944RepeatingTableHeader, "tdf58944-repeating-table-header.docx")
 {
     // DOCX tables with more than 10 repeating header lines imported without repeating header lines
diff --git a/sw/qa/extras/ww8export/data/tdf127166_prstDash_Word97.doc b/sw/qa/extras/ww8export/data/tdf127166_prstDash_Word97.doc
new file mode 100644
index 000000000000..21cd47a4ced0
Binary files /dev/null and b/sw/qa/extras/ww8export/data/tdf127166_prstDash_Word97.doc differ
diff --git a/sw/qa/extras/ww8export/ww8export3.cxx b/sw/qa/extras/ww8export/ww8export3.cxx
index b8a6d4056d13..36d525f22d15 100644
--- a/sw/qa/extras/ww8export/ww8export3.cxx
+++ b/sw/qa/extras/ww8export/ww8export3.cxx
@@ -13,6 +13,7 @@
 #include <com/sun/star/beans/XPropertySet.hpp>
 #include <com/sun/star/container/XIndexAccess.hpp>
 #include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/LineDash.hpp>
 #include <com/sun/star/graphic/XGraphic.hpp>
 #include <com/sun/star/text/XFormField.hpp>
 #include <com/sun/star/text/XTextTable.hpp>
@@ -308,6 +309,41 @@ DECLARE_WW8EXPORT_TEST(testBtlrFrame, "btlr-frame.odt")
     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(9000), getProperty<sal_Int32>(xFrame, "RotateAngle"));
 }
 
+DECLARE_WW8EXPORT_TEST(testPresetDash, "tdf127166_prstDash_Word97.doc")
+{
+    // Error was, that the 'sys' preset dash styles were neither imported not
+    // exported, the mixed styles had wrong dash-dot order, they were imported
+    // with absolute values.
+    const drawing::LineDash dashParams[] =
+    {
+        {drawing::DashStyle_RECTRELATIVE, 1, 400, 0, 0, 300}, // dash
+        {drawing::DashStyle_RECTRELATIVE, 1, 400, 1, 100, 300}, // dashDot
+        {drawing::DashStyle_RECTRELATIVE, 1, 100, 0, 0, 300}, // dot
+        {drawing::DashStyle_RECTRELATIVE, 1, 800, 0, 0, 300}, // lgDash
+        {drawing::DashStyle_RECTRELATIVE, 1, 800, 1, 100, 300}, // lgDashDot
+        {drawing::DashStyle_RECTRELATIVE, 1, 800, 2, 100, 300}, // lgDashDotDot
+        {drawing::DashStyle_RECTRELATIVE, 1, 300, 0, 0, 100}, // sysDash
+        {drawing::DashStyle_RECTRELATIVE, 1, 300, 1, 100, 100}, // sysDashDot
+        {drawing::DashStyle_RECTRELATIVE, 1, 300, 2, 100, 100}, // sysDashDotDot
+        {drawing::DashStyle_RECTRELATIVE, 1, 100, 0, 0, 100} // sysDot
+    };
+    drawing::LineDash aPresetLineDash;
+    drawing::LineDash aShapeLineDash;
+    for (sal_uInt16 i = 0; i < 10; i++)
+    {
+        aPresetLineDash = dashParams[i];
+        uno::Reference<drawing::XShape> xShape = getShape(i+1);
+        aShapeLineDash = getProperty<drawing::LineDash>(xShape, "LineDash");
+        bool bIsEqual = aPresetLineDash.Style == aShapeLineDash.Style
+                        && aPresetLineDash.Dots == aShapeLineDash.Dots
+                        && aPresetLineDash.DotLen == aShapeLineDash.DotLen
+                        && aPresetLineDash.Dashes == aShapeLineDash.Dashes
+                        && aPresetLineDash.DashLen == aShapeLineDash.DashLen
+                        && aPresetLineDash.Distance == aShapeLineDash.Distance;
+        CPPUNIT_ASSERT_MESSAGE("LineDash differ", bIsEqual);
+    }
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list