diff options
author | Regina Henschel <rb.henschel@t-online.de> | 2021-08-12 19:19:19 +0200 |
---|---|---|
committer | Regina Henschel <rb.henschel@t-online.de> | 2021-08-14 17:15:28 +0200 |
commit | 925fa608d65a5970f966d45e33cccf04e2318060 (patch) | |
tree | e335a2802a4fb0cea8d8e26d235765b0140c7efa /oox | |
parent | 768722ea12779e5c533d691c311b63490e2279d0 (diff) |
tdf#142605 use frame size in oox export of BezierCurve
The export had used the bound rectangle of PolyPolygonBezier. But that
contains control points. Use API position and size instead.
I have not incorporated the changes into existing WritePolyPolygon,
but have made an own version for SdrPathObj, because I find it easier
to read and maintain, than having a lot of case distinctions depending
on the shape type.
Change-Id: I2e646c4f5fa37174c4979855212ca72f2dfa447e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120407
Tested-by: Jenkins
Reviewed-by: Regina Henschel <rb.henschel@t-online.de>
Diffstat (limited to 'oox')
-rw-r--r-- | oox/qa/unit/data/tdf142605_CurveSize.odp | bin | 0 -> 11220 bytes | |||
-rw-r--r-- | oox/qa/unit/drawingml.cxx | 23 | ||||
-rw-r--r-- | oox/source/export/drawingml.cxx | 93 | ||||
-rw-r--r-- | oox/source/export/shapes.cxx | 4 |
4 files changed, 118 insertions, 2 deletions
diff --git a/oox/qa/unit/data/tdf142605_CurveSize.odp b/oox/qa/unit/data/tdf142605_CurveSize.odp Binary files differnew file mode 100644 index 000000000000..c797d378f1f3 --- /dev/null +++ b/oox/qa/unit/data/tdf142605_CurveSize.odp diff --git a/oox/qa/unit/drawingml.cxx b/oox/qa/unit/drawingml.cxx index c8dc0d9cc1fb..c7ba5ac61730 100644 --- a/oox/qa/unit/drawingml.cxx +++ b/oox/qa/unit/drawingml.cxx @@ -11,6 +11,7 @@ #include <unotest/macros_test.hxx> #include <com/sun/star/awt/Gradient.hpp> +#include <com/sun/star/awt/Rectangle.hpp> #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/container/XNamed.hpp> #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> @@ -345,6 +346,28 @@ CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testGroupShapeSmartArt) CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32>(0), xSmartArt->getCount()); } +CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testTdf142605_CurveSize) +{ + // The document contains a Bezier curve, where the control points are outside the bounding + // rectangle of the shape. Error was, that the export uses a path size which included the + // control points. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf142605_CurveSize.odp"; + loadAndReload(aURL, "Impress Office Open XML"); + + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + uno::Reference<container::XEnumerationAccess> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + css::awt::Rectangle aBoundRect; + xShapeProps->getPropertyValue("BoundRect") >>= aBoundRect; + // Without fix, size was 6262 x 3509, and position was 10037|6790. + CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(8601), aBoundRect.Width, 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(4601), aBoundRect.Height, 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(7699), aBoundRect.X, 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(5699), aBoundRect.Y, 1); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index e45c5c52e8c5..91f4a779a984 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -3877,6 +3877,7 @@ sal_Int32 DrawingML::GetCustomGeometryPointValue( return nValue; } +// version for SdrObjCustomShape void DrawingML::WritePolyPolygon(const css::uno::Reference<css::drawing::XShape>& rXShape, const tools::PolyPolygon& rPolyPolygon, const bool bClosed) { @@ -3963,6 +3964,98 @@ void DrawingML::WritePolyPolygon(const css::uno::Reference<css::drawing::XShape> mpFS->endElementNS( XML_a, XML_custGeom ); } +// version for SdrPathObj +void DrawingML::WritePolyPolygon(const css::uno::Reference<css::drawing::XShape>& rXShape, + const bool bClosed) +{ + tools::PolyPolygon aPolyPolygon = EscherPropertyContainer::GetPolyPolygon(rXShape); + // In case of Writer, the parent element is <wps:spPr>, and there the + // <a:custGeom> element is not optional. + if (aPolyPolygon.Count() < 1 && GetDocumentType() != DOCUMENT_DOCX) + return; + + mpFS->startElementNS(XML_a, XML_custGeom); + mpFS->singleElementNS(XML_a, XML_avLst); + mpFS->singleElementNS(XML_a, XML_gdLst); + mpFS->singleElementNS(XML_a, XML_ahLst); + mpFS->singleElementNS(XML_a, XML_rect, XML_l, "0", XML_t, "0", XML_r, "r", XML_b, "b"); + + mpFS->startElementNS(XML_a, XML_pathLst); + + awt::Size aSize = rXShape->getSize(); + awt::Point aPos = rXShape->getPosition(); + Reference<XPropertySet> xPropertySet(rXShape, UNO_QUERY); + uno::Reference<XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo(); + if (xPropertySetInfo->hasPropertyByName("AnchorPosition")) + { + awt::Point aAnchorPosition; + xPropertySet->getPropertyValue("AnchorPosition") >>= aAnchorPosition; + aPos.X += aAnchorPosition.X; + aPos.Y += aAnchorPosition.Y; + } + + // Only closed SdrPathObj can be filled + std::optional<OString> sFill; + if (!bClosed) + sFill = "none"; // for possible values see ST_PathFillMode in OOXML standard + + // Put all polygons of rPolyPolygon in the same path element + // to subtract the overlapped areas. + mpFS->startElementNS(XML_a, XML_path, XML_fill, sFill, XML_w, OString::number(aSize.Width), + XML_h, OString::number(aSize.Height)); + + for (sal_uInt16 i = 0; i < aPolyPolygon.Count(); i++) + { + const tools::Polygon& aPoly = aPolyPolygon[i]; + + if (aPoly.GetSize() > 0) + { + mpFS->startElementNS(XML_a, XML_moveTo); + + mpFS->singleElementNS(XML_a, XML_pt, XML_x, OString::number(aPoly[0].X() - aPos.X), + XML_y, OString::number(aPoly[0].Y() - aPos.Y)); + + mpFS->endElementNS(XML_a, XML_moveTo); + } + + for (sal_uInt16 j = 1; j < aPoly.GetSize(); j++) + { + PolyFlags flags = aPoly.GetFlags(j); + if (flags == PolyFlags::Control) + { + // a:cubicBezTo can only contain 3 a:pt elements, so we need to make sure of this + if (j + 2 < aPoly.GetSize() && aPoly.GetFlags(j + 1) == PolyFlags::Control + && aPoly.GetFlags(j + 2) != PolyFlags::Control) + { + mpFS->startElementNS(XML_a, XML_cubicBezTo); + for (sal_uInt8 k = 0; k <= 2; ++k) + { + mpFS->singleElementNS(XML_a, XML_pt, XML_x, + OString::number(aPoly[j + k].X() - aPos.X), XML_y, + OString::number(aPoly[j + k].Y() - aPos.Y)); + } + mpFS->endElementNS(XML_a, XML_cubicBezTo); + j += 2; + } + } + else if (flags == PolyFlags::Normal) + { + mpFS->startElementNS(XML_a, XML_lnTo); + mpFS->singleElementNS(XML_a, XML_pt, XML_x, OString::number(aPoly[j].X() - aPos.X), + XML_y, OString::number(aPoly[j].Y() - aPos.Y)); + mpFS->endElementNS(XML_a, XML_lnTo); + } + } + } + if (bClosed) + mpFS->singleElementNS(XML_a, XML_close); + mpFS->endElementNS(XML_a, XML_path); + + mpFS->endElementNS(XML_a, XML_pathLst); + + mpFS->endElementNS(XML_a, XML_custGeom); +} + void DrawingML::WriteConnectorConnections( EscherConnectorListEntry& rConnectorEntry, sal_Int32 nStartID, sal_Int32 nEndID ) { if( nStartID != -1 ) diff --git a/oox/source/export/shapes.cxx b/oox/source/export/shapes.cxx index d47acf217ac2..325387f4991d 100644 --- a/oox/source/export/shapes.cxx +++ b/oox/source/export/shapes.cxx @@ -400,7 +400,6 @@ ShapeExport& ShapeExport::WritePolyPolygonShape( const Reference< XShape >& xSha FSHelperPtr pFS = GetFS(); pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp)); - tools::PolyPolygon aPolyPolygon = EscherPropertyContainer::GetPolyPolygon( xShape ); awt::Point aPos = xShape->getPosition(); // Position is relative to group for child elements in Word, but absolute in API. if (GetDocumentType() == DOCUMENT_DOCX && m_xParent.is()) @@ -413,6 +412,7 @@ ShapeExport& ShapeExport::WritePolyPolygonShape( const Reference< XShape >& xSha tools::Rectangle aRect(Point(aPos.X, aPos.Y), Size(aSize.Width, aSize.Height)); #if OSL_DEBUG_LEVEL > 0 + tools::PolyPolygon aPolyPolygon = EscherPropertyContainer::GetPolyPolygon(xShape); awt::Size size = MapSize( awt::Size( aRect.GetWidth(), aRect.GetHeight() ) ); SAL_INFO("oox.shape", "poly count " << aPolyPolygon.Count()); SAL_INFO("oox.shape", "size: " << size.Width << " x " << size.Height); @@ -436,7 +436,7 @@ ShapeExport& ShapeExport::WritePolyPolygonShape( const Reference< XShape >& xSha // visual shape properties pFS->startElementNS(mnXmlNamespace, XML_spPr); WriteTransformation( xShape, aRect, XML_a ); - WritePolyPolygon(xShape, aPolyPolygon, bClosed); + WritePolyPolygon(xShape, bClosed); Reference< XPropertySet > xProps( xShape, UNO_QUERY ); if( xProps.is() ) { if( bClosed ) |