Kaydet (Commit) eca8386c authored tarafından Caolán McNamara's avatar Caolán McNamara

Prop_pSegmentInfo is totally misunderstood apparently

digging into the crash on export of kde216114-1.odt
reveals various horrors

Change-Id: I0d24fe303d561a00a08098b306d10fd8273af928
(cherry picked from commit b04e1e79)
üst c0d691b9
...@@ -3258,85 +3258,92 @@ void EscherPropertyContainer::CreateCustomShapeProperties( const MSO_SPT eShapeT ...@@ -3258,85 +3258,92 @@ void EscherPropertyContainer::CreateCustomShapeProperties( const MSO_SPT eShapeT
.WriteUInt16( nElementSize ); .WriteUInt16( nElementSize );
for ( j = 0; j < nElements; j++ ) for ( j = 0; j < nElements; j++ )
{ {
// The segment type is stored in the upper 3 bits
// and segment count is stored in the lower 13
// bits.
//
// If the segment type is msopathEscape, the lower 13 bits
// are divided in a 5 bit escape code and 8 bit
// vertex count (not segment count!)
sal_uInt16 nVal = (sal_uInt16)aSegments[ j ].Count; sal_uInt16 nVal = (sal_uInt16)aSegments[ j ].Count;
switch( aSegments[ j ].Command ) switch( aSegments[ j ].Command )
{ {
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::UNKNOWN : case css::drawing::EnhancedCustomShapeSegmentCommand::UNKNOWN :
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::LINETO : break; case css::drawing::EnhancedCustomShapeSegmentCommand::LINETO :
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::MOVETO : break;
{ case css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO :
nVal = 0x4000; nVal = (msopathMoveTo << 13);
} break;
break;
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::CURVETO : case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::CURVETO :
{ {
nVal |= 0x2000; nVal |= (msopathCurveTo << 13);
} }
break; break;
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH : case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH :
{ {
nVal = 0x6001; nVal = 1;
nVal |= (msopathClose << 13);
} }
break; break;
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH : case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH :
{ {
nVal = 0x8000; nVal = (msopathEnd << 13);
} }
break; break;
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::NOFILL : case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::NOFILL :
{ {
nVal = 0xaa00; nVal = (msopathEscape << 13) | (5 << 8);
} }
break; break;
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE : case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE :
{ {
nVal = 0xab00; nVal = (msopathEscape << 13) | (11 << 8);
} }
break; break;
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO : case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
{ {
nVal *= 3; nVal *= 3;
nVal |= 0xa100; nVal |= (msopathEscape << 13) | (1 << 8);
} }
break; break;
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE : case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
{ {
nVal *= 3; nVal *= 3;
nVal |= 0xa200; nVal |= (msopathEscape << 13) | (2 << 8);
} }
break; break;
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ARCTO : case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ARCTO :
{ {
nVal <<= 2; nVal <<= 2;
nVal |= 0xa300; nVal |= (msopathEscape << 13) | (3 << 8);
} }
break; break;
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ARC : case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ARC :
{ {
nVal <<= 2; nVal <<= 2;
nVal |= 0xa400; nVal |= (msopathEscape << 13) | (4 << 8);
} }
break; break;
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO : case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
{ {
nVal <<= 2; nVal <<= 2;
nVal |= 0xa500; nVal |= (msopathEscape << 13) | (5 << 8);
} }
break; break;
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC : case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
{ {
nVal <<= 2; nVal <<= 2;
nVal |= 0xa600; nVal |= (msopathEscape << 13) | (6 << 8);
} }
break; break;
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX : case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
{ {
nVal |= 0xa700; nVal |= (msopathEscape << 13) | (7 << 8);
} }
break; break;
case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY : case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
{ {
nVal |= 0xa800; nVal |= (msopathEscape << 13) | (8 << 8);
} }
break; break;
} }
......
...@@ -424,6 +424,18 @@ enum ESCHER_LineCap ...@@ -424,6 +424,18 @@ enum ESCHER_LineCap
ESCHER_LineEndCapFlat // Line ends at end point ESCHER_LineEndCapFlat // Line ends at end point
}; };
enum MSOPATHTYPE
{
msopathLineTo, // Draw a straight line (one point)
msopathCurveTo, // Draw a cubic Bezier curve (three points)
msopathMoveTo, // Move to a new point (one point)
msopathClose, // Close a sub - path (no points)
msopathEnd, // End a path (no points)
msopathEscape, // Escape code
msopathClientEscape, // Escape code interpreted by the client
msopathInvalid // Invalid - should never be found
};
// Shape Properties // Shape Properties
// 1pt = 12700 EMU (English Metric Units) // 1pt = 12700 EMU (English Metric Units)
// 1pt = 20 Twip = 20/1440" = 1/72" // 1pt = 20 Twip = 20/1440" = 1/72"
......
...@@ -474,27 +474,56 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect ...@@ -474,27 +474,56 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect
for ( ; nSegments; --nSegments ) for ( ; nSegments; --nSegments )
{ {
sal_uInt16 nSeg = impl_GetUInt16( pSegmentIt ); sal_uInt16 nSeg = impl_GetUInt16( pSegmentIt );
switch ( nSeg )
// The segment type is stored in the upper 3 bits
// and segment count is stored in the lower 13
// bits.
unsigned char nSegmentType = (nSeg & 0xE000) >> 13;
unsigned short nSegmentCount = nSeg & 0x03FF;
switch (nSegmentType)
{ {
case 0x4000: // moveto case msopathMoveTo:
{
sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
if (nX >= 0 && nY >= 0 )
aPath.append( "m" ).append( nX ).append( "," ).append( nY );
break;
}
case msopathClientEscape:
break;
case msopathEscape:
{
// If the segment type is msopathEscape, the lower 13 bits are
// divided in a 5 bit escape code and 8 bit
// vertex count (not segment count!)
unsigned char nEscapeCode = (nSegmentCount & 0x1F00) >> 8;
unsigned char nVertexCount = nSegmentCount & 0x00FF;
pVerticesIt += nVertexCount;
switch (nEscapeCode)
{ {
sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize ); case 0xa: // nofill
sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize ); aPath.append( "nf" );
if (nX >= 0 && nY >= 0 ) break;
aPath.append( "m" ).append( nX ).append( "," ).append( nY ); case 0xb: // nostroke
aPath.append( "ns" );
break;
} }
break; break;
case 0xb300: }
case 0xac00: case msopathLineTo:
break; for (unsigned short i = 0; i < nSegmentCount; ++i)
case 0x0001: // lineto
{ {
sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize ); sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize ); sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
aPath.append( "l" ).append( nX ).append( "," ).append( nY ); aPath.append( "l" ).append( nX ).append( "," ).append( nY );
} }
break; break;
case 0x2001: // curveto case msopathCurveTo:
for (unsigned short i = 0; i < nSegmentCount; ++i)
{ {
sal_Int32 nX1 = impl_GetPointComponent( pVerticesIt, nPointSize ); sal_Int32 nX1 = impl_GetPointComponent( pVerticesIt, nPointSize );
sal_Int32 nY1 = impl_GetPointComponent( pVerticesIt, nPointSize ); sal_Int32 nY1 = impl_GetPointComponent( pVerticesIt, nPointSize );
...@@ -507,35 +536,17 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect ...@@ -507,35 +536,17 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect
.append( nX3 ).append( "," ).append( nY3 ); .append( nX3 ).append( "," ).append( nY3 );
} }
break; break;
case 0xaa00: // nofill case msopathClose:
aPath.append( "nf" );
break;
case 0xab00: // nostroke
aPath.append( "ns" );
break;
case 0x6001: // close
aPath.append( "x" ); aPath.append( "x" );
break; break;
case 0x8000: // end case msopathEnd:
aPath.append( "e" ); aPath.append( "e" );
break; break;
default: default:
// See EscherPropertyContainer::CreateCustomShapeProperties, by default nSeg is simply the number of points. SAL_WARN("oox", "Totally b0rked\n");
// FIXME: we miss out a significant amount of complexity from break;
// the above method here, and do some rather odd things to match. case msopathInvalid:
int nElems = !nPointSize ? 0 : aVertices.nPropSize / (nPointSize * 2); SAL_WARN("oox", "Invalid - should never be found");
if (nSeg > nElems)
{
SAL_WARN("oox", "Busted escher export " << nSeg << "vs . " << nElems << " truncating point stream");
nSeg = nElems;
}
for (int i = 0; i < nSeg; ++i)
{
sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nPointSize);
sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nPointSize);
if (nX >= 0 && nY >= 0 )
aPath.append("l").append(nX).append(",").append(nY);
}
break; break;
} }
} }
......
...@@ -837,11 +837,11 @@ DECLARE_OOXMLEXPORT_TEST(testKDE302504, "kde302504-1.odt") ...@@ -837,11 +837,11 @@ DECLARE_OOXMLEXPORT_TEST(testKDE302504, "kde302504-1.odt")
assertXPath(pXmlDoc, "//v:shape", "ID", "KoPathShape"); assertXPath(pXmlDoc, "//v:shape", "ID", "KoPathShape");
} }
//DECLARE_OOXMLEXPORT_TEST(testKDE216114, "kde216114-1.odt") DECLARE_OOXMLEXPORT_TEST(testKDE216114, "kde216114-1.odt")
//{ {
// if (xmlDocPtr pXmlDoc = parseExport("word/document.xml")) if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
// assertXPath(pXmlDoc, "//w:pict", 1); assertXPath(pXmlDoc, "//w:pict", 1);
//} }
CPPUNIT_PLUGIN_IMPLEMENT(); CPPUNIT_PLUGIN_IMPLEMENT();
......
...@@ -278,48 +278,61 @@ void RtfSdrExport::Commit(EscherPropertyContainer& rProps, const Rectangle& rRec ...@@ -278,48 +278,61 @@ void RtfSdrExport::Commit(EscherPropertyContainer& rProps, const Rectangle& rRec
for (; nSegments; --nSegments) for (; nSegments; --nSegments)
{ {
sal_uInt16 nSeg = impl_GetUInt16(pSegmentIt); sal_uInt16 nSeg = impl_GetUInt16(pSegmentIt);
// The segment type is stored in the upper 3 bits
// and segment count is stored in the lower 13
// bits.
unsigned char nSegmentType = (nSeg & 0xE000) >> 13;
unsigned short nSegmentCount = nSeg & 0x03FF;
aSegmentInfo.append(';').append((sal_Int32)nSeg); aSegmentInfo.append(';').append((sal_Int32)nSeg);
switch (nSeg) switch (nSegmentType)
{
case 0x0001: // lineto
case 0x4000: // moveto
{
sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
aVerticies.append(";(").append(nX).append(",").append(nY).append(")");
nVertices ++;
}
break;
case 0x2001: // curveto
{ {
for (int i = 0; i < 3; i++) case msopathLineTo:
for (unsigned short i = 0; i < nSegmentCount; ++i)
{
sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
aVerticies.append(";(").append(nX).append(",").append(nY).append(")");
nVertices ++;
}
break;
case msopathMoveTo:
{ {
sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize); sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize); sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
aVerticies.append(";(").append(nX).append(",").append(nY).append(")"); aVerticies.append(";(").append(nX).append(",").append(nY).append(")");
nVertices ++; nVertices++;
break;
} }
} case msopathCurveTo:
break; for (unsigned short j = 0; j < nSegmentCount; ++j)
case 0xb300: {
case 0xac00: for (int i = 0; i < 3; i++)
case 0xaa00: // nofill {
case 0xab00: // nostroke sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
case 0x6001: // close sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
case 0x8000: // end aVerticies.append(";(").append(nX).append(",").append(nY).append(")");
break; nVertices ++;
default: }
// See EscherPropertyContainer::CreateCustomShapeProperties, by default nSeg is simply the number of points. }
for (int i = 0; i < nSeg; ++i) break;
case msopathEscape:
{ {
if (nVerticesPos >= aVertices.nPropSize) // If the segment type is msopathEscape, the lower 13 bits are
break; // divided in a 5 bit escape code and 8 bit
sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize); // vertex count (not segment count!)
sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize); unsigned char nVertexCount = nSegmentCount & 0x00FF;
aVerticies.append(";(").append(nX).append(",").append(nY).append(")"); nVerticesPos += nVertexCount;
++nVertices; break;
} }
break; case msopathClientEscape:
case msopathClose:
case msopathEnd:
break;
default:
SAL_WARN("oox", "Totally b0rked\n");
break;
} }
} }
......
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