summaryrefslogtreecommitdiff
path: root/xmloff
diff options
context:
space:
mode:
authorRegina Henschel <rb.henschel@t-online.de>2023-11-19 00:26:16 +0100
committerMiklos Vajna <vmiklos@collabora.com>2023-12-01 08:44:01 +0100
commit44ee19c99bfb3bf0f550d9656e87bca3e20e5ca0 (patch)
tree3c937a4c86ec15400a12fb1e69ae893fc8541d39 /xmloff
parenta83088b05f177fb938c2e4ffb06cd19362a5a1ca (diff)
[API CHANGE] Add OOXML way of curved connector routing
The paths generated for curved connectors are basically incompatible between LibreOffice and OOXML. Thus it was not possible to render curved connectors the same way as MS Office. The patch adds an OOXML compatible method for calculating the path. The new method results in a different svg:d attribute when saved in ODF, but needs no change to ODF. The patch introduces the boolean connector property 'EdgeOOXMLCurve' to switch between the two methods. The property value is determined from the svg:d attribute in case of import from ODF. In case of missing svg:d attribute the property value is set to 'true', because Word currently does not write a svg:d attribute when it exports to ODF. The property value is set to 'true' for import of connectors on a drawing canvas in docx. Default value for new connectors is 'false'. The new property has no UI, but can be used via macro. Currently the new method is used for import of curved connectors on drawing canvas in docx documents. Change-Id: I53d99f44febe4d74c2b611f5fdb9de86628c4519 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159708 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Diffstat (limited to 'xmloff')
-rw-r--r--xmloff/source/draw/ximpshap.cxx54
-rw-r--r--xmloff/source/draw/ximpshap.hxx5
2 files changed, 57 insertions, 2 deletions
diff --git a/xmloff/source/draw/ximpshap.cxx b/xmloff/source/draw/ximpshap.cxx
index d228b729521c..6cf226274115 100644
--- a/xmloff/source/draw/ximpshap.cxx
+++ b/xmloff/source/draw/ximpshap.cxx
@@ -1749,7 +1749,8 @@ SdXMLConnectorShapeContext::SdXMLConnectorShapeContext(
mnEndGlueId(-1),
mnDelta1(0),
mnDelta2(0),
- mnDelta3(0)
+ mnDelta3(0),
+ mbLikelyOOXMLCurve(true)
{
}
@@ -1774,6 +1775,50 @@ bool SvXMLImport::needFixPositionAfterZ() const
return bWrongPositionAfterZ;
}
+namespace
+{
+bool lcl_IsLikelyOOXMLCurve(const basegfx::B2DPolygon& rPolygon)
+{
+ sal_uInt32 nCount = rPolygon.count();
+ if (!rPolygon.areControlPointsUsed() or nCount < 2)
+ return false; // no curve at all
+
+ basegfx::B2DVector aStartVec(rPolygon.getNextControlPoint(0) - rPolygon.getB2DPoint(0));
+ basegfx::B2DVector aEndVec(rPolygon.getPrevControlPoint(nCount-1) - rPolygon.getB2DPoint(nCount - 1));
+ // LibreOffice uses one point less than OOXML for the same underlaying bentConnector or
+ // STANDARD connector, respectively. A deeper inspection is only needed in case of 2 resulting
+ // points. Those connector paths look like a quarter ellipse.
+ switch (nCount)
+ {
+ case 2:
+ {
+ // In case start and end direction are parallel, it cannot be OOXML because that case
+ // introduces a handle on the path and the curve has three points then.
+ if (basegfx::areParallel(aStartVec, aEndVec))
+ return false;
+ // OOXML sets the control point at 1/2, LibreOffice at 2/3 of width or height.
+ // A tolerance is used because +-1 deviations due to integer arithmetic in many places.
+ basegfx::B2DRange aRect(rPolygon.getB2DPoint(0), rPolygon.getB2DPoint(1));
+ if ((basegfx::fTools::equalZero(aStartVec.getX())
+ && basegfx::fTools::equal(aStartVec.getLength() * 2.0, aRect.getHeight(), 2.0))
+ || (basegfx::fTools::equalZero(aStartVec.getY())
+ && basegfx::fTools::equal(aStartVec.getLength() * 2.0, aRect.getWidth(), 2.0)))
+ return true;
+ }
+ break;
+ case 3:
+ case 5:
+ return basegfx::areParallel(aStartVec, aEndVec);
+ break;
+ case 4: // start and end direction are orthogonal
+ return basegfx::fTools::equalZero(aStartVec.scalar( aEndVec));
+ break;
+ default:
+ return false;
+ }
+ return false;
+}
+} // end namespace
// this is called from the parent group for each unparsed attribute in the attribute list
bool SdXMLConnectorShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter )
@@ -1859,6 +1904,8 @@ bool SdXMLConnectorShapeContext::processAttribute( const sax_fastparser::FastAtt
aPolyPolygon,
aSourcePolyPolygon);
maPath <<= aSourcePolyPolygon;
+
+ mbLikelyOOXMLCurve = lcl_IsLikelyOOXMLCurve(aPolyPolygon.getB2DPolygon(0));
}
}
break;
@@ -1921,13 +1968,16 @@ void SdXMLConnectorShapeContext::startFastElement (sal_Int32 nElement,
}
}
+ uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY );
+ if (xProps.is())
+ xProps->setPropertyValue("EdgeOOXMLCurve", Any(mbLikelyOOXMLCurve));
+
// add connection ids
if( !maStartShapeId.isEmpty() )
GetImport().GetShapeImport()->addShapeConnection( mxShape, true, maStartShapeId, mnStartGlueId );
if( !maEndShapeId.isEmpty() )
GetImport().GetShapeImport()->addShapeConnection( mxShape, false, maEndShapeId, mnEndGlueId );
- uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY );
if( xProps.is() )
{
xProps->setPropertyValue("StartPosition", Any(maStart));
diff --git a/xmloff/source/draw/ximpshap.hxx b/xmloff/source/draw/ximpshap.hxx
index 64b28df579a0..3450a16e5780 100644
--- a/xmloff/source/draw/ximpshap.hxx
+++ b/xmloff/source/draw/ximpshap.hxx
@@ -296,6 +296,11 @@ private:
css::uno::Any maPath;
+ // Guess from the svg:d attribute whether the shape was rendered using OOXML definition. The
+ // default value is true to cover files exported to ODF by MS Office, which does not write a
+ // svg:d attribute. LibreOffice has always written a svg:d attribute.
+ bool mbLikelyOOXMLCurve;
+
public:
SdXMLConnectorShapeContext( SvXMLImport& rImport,