summaryrefslogtreecommitdiff
path: root/oox
diff options
context:
space:
mode:
authorRegina Henschel <rb.henschel@t-online.de>2019-09-01 19:26:40 +0200
committerRegina Henschel <rb.henschel@t-online.de>2019-09-05 12:36:56 +0200
commit57c9bdab377a00649299d1a4c9ed2f9e5e03b84e (patch)
tree680bb89ff0c2d11745702e1fdca149fe0ea3f20f /oox
parent8590de9d8c3f155f23155d7500fd805c0e21a26b (diff)
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@t-online.de>
Diffstat (limited to 'oox')
-rw-r--r--oox/source/drawingml/lineproperties.cxx168
-rw-r--r--oox/source/export/drawingml.cxx191
2 files changed, 204 insertions, 155 deletions
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) );
}
}