summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRegina Henschel <rb.henschel@t-online.de>2021-08-12 19:19:19 +0200
committerRegina Henschel <rb.henschel@t-online.de>2021-08-14 17:15:28 +0200
commit925fa608d65a5970f966d45e33cccf04e2318060 (patch)
treee335a2802a4fb0cea8d8e26d235765b0140c7efa
parent768722ea12779e5c533d691c311b63490e2279d0 (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>
-rw-r--r--include/oox/export/drawingml.hxx2
-rw-r--r--oox/qa/unit/data/tdf142605_CurveSize.odpbin0 -> 11220 bytes
-rw-r--r--oox/qa/unit/drawingml.cxx23
-rw-r--r--oox/source/export/drawingml.cxx93
-rw-r--r--oox/source/export/shapes.cxx4
5 files changed, 120 insertions, 2 deletions
diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx
index 77ff77174cc9..4af628a289f9 100644
--- a/include/oox/export/drawingml.hxx
+++ b/include/oox/export/drawingml.hxx
@@ -314,6 +314,8 @@ public:
const SdrObjCustomShape& rSdrObjCustomShape);
void WritePolyPolygon(const css::uno::Reference<css::drawing::XShape>& rXShape,
const tools::PolyPolygon& rPolyPolygon, const bool bClosed);
+ void WritePolyPolygon(const css::uno::Reference<css::drawing::XShape>& rXShape,
+ const bool bClosed);
void WriteFill( const css::uno::Reference< css::beans::XPropertySet >& xPropSet );
void WriteShapeStyle( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet );
void WriteShapeEffects( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet );
diff --git a/oox/qa/unit/data/tdf142605_CurveSize.odp b/oox/qa/unit/data/tdf142605_CurveSize.odp
new file mode 100644
index 000000000000..c797d378f1f3
--- /dev/null
+++ b/oox/qa/unit/data/tdf142605_CurveSize.odp
Binary files differ
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 )