Kaydet (Commit) 2211a67c authored tarafından Adam Co's avatar Adam Co Kaydeden (comit) Miklos Vajna

Rewrite import and export of custom dashes in ooxml filter (fix)

The import mechanism of custom-dash (a:custDash) was wrong, and imported
wrong values, which causes that if you would import-export-import-export -
you would get inflated values, which might cause a corruption.

The attributes for custom-dash nodes (a:ds) are of type 'PositivePercentage'.
Office will read percentages formatted with a trailing percent sign or
formatted as 1000th of a percent without a trailing percent sign, but only
write percentages as 1000th's of a percent without a trailing percent sign.

During import - LO did not check if it was in '%' format or in
'1000th of a percent' format. So that was fixed. Also - when exporting -
it always exports now in '1000th of a percent' format.

Change-Id: I6bd74df26951974f85173227c832386c70034afb
Reviewed-on: https://gerrit.libreoffice.org/9681Reviewed-by: 's avatarMiklos Vajna <vmiklos@collabora.co.uk>
Tested-by: 's avatarMiklos Vajna <vmiklos@collabora.co.uk>
üst 93152e26
......@@ -49,9 +49,9 @@ static inline sal_Int64 TwipsToEMU( sal_Int32 nTwips )
}
template <typename T>
OString writePercentage(T number)
OString write1000thOfAPercent(T number)
{
return OString::number(number) + "%";
return OString::number( number * 1000 );
}
#endif
......
......@@ -107,19 +107,26 @@ void lclConvertCustomDash( LineDash& orLineDash, const LineProperties::DashStopV
sal_Int16 nDashes = 0;
sal_Int32 nDashLen = 0;
sal_Int32 nDistance = 0;
sal_Int32 nConvertedLen = 0;
sal_Int32 nConvertedDistance = 0;
for( LineProperties::DashStopVector::const_iterator aIt = rCustomDash.begin(), aEnd = rCustomDash.end(); aIt != aEnd; ++aIt )
{
if( aIt->first <= 2 )
// Get from "1000th of percent" ==> percent ==> multiplier
nConvertedLen = aIt->first / 1000 / 100;
nConvertedDistance = aIt->second / 1000 / 100;
// Check if it is a dot (100% = dot)
if( nConvertedLen == 1 )
{
++nDots;
nDotLen += aIt->first;
nDotLen += nConvertedLen;
}
else
{
++nDashes;
nDashLen += aIt->first;
nDashLen += nConvertedLen;
}
nDistance += aIt->second;
nDistance += nConvertedDistance;
}
orLineDash.DotLen = (nDots > 0) ? ::std::max< sal_Int32 >( nDotLen / nDots, 1 ) : 0;
orLineDash.Dots = nDots;
......
......@@ -66,8 +66,50 @@ ContextHandlerRef LinePropertiesContext::onCreateContext( sal_Int32 nElement, co
return this;
break;
case A_TOKEN( ds ):
mrLineProperties.maCustomDash.push_back( LineProperties::DashStop(
rAttribs.getInteger( XML_d, 0 ), rAttribs.getInteger( XML_sp, 0 ) ) );
{
// 'a:ds' has 2 attributes : 'd' and 'sp'
// both are of type 'a:ST_PositivePercentage'
// according to the specs Office will read percentages formatted with a trailing percent sign
// or formatted as 1000th of a percent without a trailing percent sign, but only write percentages
// as 1000th's of a percent without a trailing percent sign.
// The code below takes care of both scenarios by converting to '1000th of a percent' always
OUString aStr;
sal_Int32 nDash = 0;
aStr = rAttribs.getString( XML_d, "" );
if ( aStr.endsWith("%") )
{
// Ends with a '%'
aStr = aStr.copy(0, aStr.getLength() - 1);
aStr = aStr.trim();
nDash = aStr.toInt32();
// Convert to 1000th of a percent
nDash *= 1000;
}
else
{
nDash = rAttribs.getInteger( XML_d, 0 );
}
sal_Int32 nSp = 0;
aStr = rAttribs.getString( XML_sp, "" );
if ( aStr.endsWith("%") )
{
// Ends with a '%'
aStr = aStr.copy(0, aStr.getLength() - 1);
aStr = aStr.trim();
nSp = aStr.toInt32();
// Convert to 1000th of a percent
nSp *= 1000;
}
else
{
nSp = rAttribs.getInteger( XML_sp, 0 );
}
mrLineProperties.maCustomDash.push_back( LineProperties::DashStop( nDash, nSp ) );
}
break;
// LineJoinPropertiesGroup
......
......@@ -626,24 +626,45 @@ void DrawingML::WriteOutline( Reference< XPropertySet > rXPropSet )
if( bDashSet && aStyleLineStyle != drawing::LineStyle_DASH ) {
// line style is a dash and it was not set by the shape style
// TODO: the XML_d and XML_sp values seem insane
mpFS->startElementNS( XML_a, XML_custDash, FSEND );
aLineDash.DotLen = aLineDash.DotLen / nLineWidth;
aLineDash.DashLen = aLineDash.DashLen / nLineWidth;
aLineDash.Distance = aLineDash.Distance / nLineWidth;
// Check that line-width is positive and distance between dashes\dots is positive
if ( nLineWidth > 0 && aLineDash.Distance > 0 )
{
// Write 'dashes' first, and then 'dots'
int i;
if ( aLineDash.Dashes > 0 )
{
for( i = 0; i < aLineDash.Dashes; i ++ )
mpFS->singleElementNS( XML_a , XML_ds,
XML_d , write1000thOfAPercent( aLineDash.DashLen > 0 ? aLineDash.DashLen / nLineWidth * 100 : 100 ),
XML_sp, write1000thOfAPercent( aLineDash.Distance > 0 ? aLineDash.Distance / nLineWidth * 100 : 100 ),
FSEND );
}
if ( aLineDash.Dots > 0 )
{
for( i = 0; i < aLineDash.Dots; i ++ )
mpFS->singleElementNS( XML_a, XML_ds,
XML_d , write1000thOfAPercent( aLineDash.DotLen > 0 ? aLineDash.DotLen / nLineWidth * 100 : 100 ),
XML_sp, write1000thOfAPercent( aLineDash.Distance > 0 ? aLineDash.Distance / nLineWidth * 100 : 100 ),
FSEND );
}
}
if ( nLineWidth <= 0 )
SAL_WARN("oox", "while writing outline - custom dash - line width was < 0 : " << nLineWidth);
if ( aLineDash.Dashes < 0 )
SAL_WARN("oox", "while writing outline - custom dash - number of dashes was < 0 : " << aLineDash.Dashes);
if ( aLineDash.Dashes > 0 && aLineDash.DashLen <= 0 )
SAL_WARN("oox", "while writing outline - custom dash - dash length was < 0 : " << aLineDash.DashLen);
if ( aLineDash.Dots < 0 )
SAL_WARN("oox", "while writing outline - custom dash - number of dots was < 0 : " << aLineDash.Dots);
if ( aLineDash.Dots > 0 && aLineDash.DotLen <= 0 )
SAL_WARN("oox", "while writing outline - custom dash - dot length was < 0 : " << aLineDash.DotLen);
if ( aLineDash.Distance <= 0 )
SAL_WARN("oox", "while writing outline - custom dash - distance was < 0 : " << aLineDash.Distance);
int i;
for( i = 0; i < aLineDash.Dots; i ++ )
mpFS->singleElementNS( XML_a, XML_ds,
XML_d, aLineDash.DotLen ? writePercentage( aLineDash.DotLen*1000 ) : "100000%",
XML_sp, writePercentage( aLineDash.Distance*1000 ),
FSEND );
for( i = 0; i < aLineDash.Dashes; i ++ )
mpFS->singleElementNS( XML_a, XML_ds,
XML_d, aLineDash.DashLen ? writePercentage( aLineDash.DashLen*1000 ) : "100000%",
XML_sp, writePercentage( aLineDash.Distance*1000 ),
FSEND );
mpFS->endElementNS( XML_a, XML_custDash );
}
......
......@@ -1642,6 +1642,68 @@ DECLARE_OOXMLEXPORT_TEST(testfdo79256, "fdo79256.docx")
CPPUNIT_ASSERT(d <= maxLimit );
}
DECLARE_OOXMLEXPORT_TEST(testDashedLinePreset, "dashed_line_preset.docx")
{
/* Make sure that preset line is exported correctly as "1000th of a percent".
* This test-file has a PRESET dash-line which will be converted by LO import
* to a custom-dash (dash-dot-dot). This test-case makes sure that the exporter
* outputs the correct values.
*/
xmlDocPtr pXmlDoc = parseExport("word/document.xml");
if (!pXmlDoc)
return;
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[1]", "d" , "800000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[1]", "sp", "300000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[2]", "d" , "100000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[2]", "sp", "300000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[3]", "d" , "100000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[3]", "sp", "300000");
}
DECLARE_OOXMLEXPORT_TEST(testDashedLine_CustDash1000thOfPercent, "dashed_line_custdash_1000th_of_percent.docx")
{
/* Make sure that preset line is exported correctly as "1000th of a percent".
* This test-file has a CUSTOM dash-line that is defined as '1000th of a percent'.
* This should be imported by LO as-is, and exported back with the same values.
*/
xmlDocPtr pXmlDoc = parseExport("word/document.xml");
if (!pXmlDoc)
return;
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[1]", "d" , "800000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[1]", "sp", "300000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[2]", "d" , "100000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[2]", "sp", "300000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[3]", "d" , "100000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[3]", "sp", "300000");
}
DECLARE_OOXMLEXPORT_TEST(testDashedLine_CustDashPercentage, "dashed_line_custdash_percentage.docx")
{
/* Make sure that preset line is exported correctly as "1000th of a percent".
* This test-file has a CUSTOM dash-line that is defined as percentages.
* This should be imported by LO as '1000th of a percent', and exported back
* as '1000th of a percent'.
*/
xmlDocPtr pXmlDoc = parseExport("word/document.xml");
if (!pXmlDoc)
return;
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[1]", "d" , "800000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[1]", "sp", "300000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[2]", "d" , "100000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[2]", "sp", "300000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[3]", "d" , "100000");
assertXPath(pXmlDoc,"/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:spPr[1]/a:ln[1]/a:custDash[1]/a:ds[3]", "sp", "300000");
}
#endif
CPPUNIT_PLUGIN_IMPLEMENT();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment