diff options
-rw-r--r-- | filter/source/msfilter/escherex.cxx | 102 | ||||
-rw-r--r-- | filter/source/msfilter/msdffimp.cxx | 88 | ||||
-rw-r--r-- | include/oox/export/utils.hxx | 2 | ||||
-rw-r--r-- | oox/source/drawingml/lineproperties.cxx | 168 | ||||
-rw-r--r-- | oox/source/export/drawingml.cxx | 191 | ||||
-rw-r--r-- | sd/qa/unit/data/odp/LineStylesOwn.odp | bin | 0 -> 15253 bytes | |||
-rw-r--r-- | sd/qa/unit/data/odp/tdf127267DashOnHairline.odp | bin | 0 -> 11874 bytes | |||
-rw-r--r-- | sd/qa/unit/data/pptx/presetDashDot.pptx | bin | 0 -> 11273 bytes | |||
-rw-r--r-- | sd/qa/unit/export-tests-ooxml1.cxx | 113 | ||||
-rw-r--r-- | sd/qa/unit/export-tests-ooxml2.cxx | 8 | ||||
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/lo_preset_dashes.odt | bin | 11876 -> 0 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport11.cxx | 13 | ||||
-rw-r--r-- | sw/qa/extras/ww8export/data/tdf127166_prstDash_Word97.doc | bin | 0 -> 26624 bytes | |||
-rw-r--r-- | sw/qa/extras/ww8export/ww8export3.cxx | 36 |
14 files changed, 496 insertions, 225 deletions
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 Binary files differnew file mode 100644 index 000000000000..8a145bb9ff11 --- /dev/null +++ b/sd/qa/unit/data/odp/LineStylesOwn.odp diff --git a/sd/qa/unit/data/odp/tdf127267DashOnHairline.odp b/sd/qa/unit/data/odp/tdf127267DashOnHairline.odp Binary files differnew file mode 100644 index 000000000000..08aed1758b1f --- /dev/null +++ b/sd/qa/unit/data/odp/tdf127267DashOnHairline.odp diff --git a/sd/qa/unit/data/pptx/presetDashDot.pptx b/sd/qa/unit/data/pptx/presetDashDot.pptx Binary files differnew file mode 100644 index 000000000000..ae1525c97b14 --- /dev/null +++ b/sd/qa/unit/data/pptx/presetDashDot.pptx 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 Binary files differdeleted file mode 100644 index b9b8a79d46da..000000000000 --- a/sw/qa/extras/ooxmlexport/data/lo_preset_dashes.odt +++ /dev/null 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 Binary files differnew file mode 100644 index 000000000000..21cd47a4ced0 --- /dev/null +++ b/sw/qa/extras/ww8export/data/tdf127166_prstDash_Word97.doc 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: */ |