diff options
author | Balazs Varga <balazs.varga991@gmail.com> | 2020-12-11 20:31:28 +0100 |
---|---|---|
committer | László Németh <nemeth@numbertext.org> | 2020-12-16 16:11:40 +0100 |
commit | 3184cfc493c6931725dce1de19ac958067b1fd25 (patch) | |
tree | 26913d99fb8f7368132b24d42027d09d662401f4 /oox/source | |
parent | fbe77e5d61ca63a688c12be721e760935d78e780 (diff) |
tdf#128621 OOXML Chart: export embedded shapes in chart
Use ShapeExport to export additional shapes (userShapes)
in Chart.
Change-Id: Ic70a7f84c4ac028b6f09a69bec2cf4949944b16c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/107605
Tested-by: Jenkins
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
Diffstat (limited to 'oox/source')
-rw-r--r-- | oox/source/export/chartexport.cxx | 108 | ||||
-rw-r--r-- | oox/source/export/drawingml.cxx | 69 | ||||
-rw-r--r-- | oox/source/token/relationship.inc | 1 | ||||
-rw-r--r-- | oox/source/token/tokens.txt | 1 |
4 files changed, 179 insertions, 0 deletions
diff --git a/oox/source/export/chartexport.cxx b/oox/source/export/chartexport.cxx index e87fba060646..24fc7dc88aad 100644 --- a/oox/source/export/chartexport.cxx +++ b/oox/source/export/chartexport.cxx @@ -74,6 +74,7 @@ #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/container/XNameAccess.hpp> #include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/drawing/XShapes.hpp> #include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/drawing/LineStyle.hpp> #include <com/sun/star/awt/XBitmap.hpp> @@ -927,6 +928,9 @@ void ChartExport::exportChartSpace( const Reference< css::chart::XChartDocument //XML_externalData exportExternalData(xChartDoc); + // export additional shapes in chart + exportAdditionalShapes(xChartDoc); + pFS->endElement( FSNS( XML_c, XML_chartSpace ) ); } @@ -977,6 +981,110 @@ void ChartExport::exportExternalData( const Reference< css::chart::XChartDocumen pFS->singleElementNS(XML_c, XML_externalData, FSNS(XML_r, XML_id), sRelId); } +void ChartExport::exportAdditionalShapes( const Reference< css::chart::XChartDocument >& xChartDoc ) +{ + Reference< beans::XPropertySet > xDocPropSet(xChartDoc, uno::UNO_QUERY); + if (xDocPropSet.is()) + { + css::uno::Reference< css::drawing::XShapes > mxAdditionalShapes; + // get a sequence of non-chart shapes + try + { + Any aShapesAny = xDocPropSet->getPropertyValue("AdditionalShapes"); + if( (aShapesAny >>= mxAdditionalShapes) && mxAdditionalShapes.is() ) + { + OUString sId; + const char* sFullPath = nullptr; + const char* sRelativePath = nullptr; + sal_Int32 nDrawing = getNewDrawingUniqueId(); + + switch (GetDocumentType()) + { + case DOCUMENT_DOCX: + { + sFullPath = "word/drawings/drawing"; + sRelativePath = "../drawings/drawing"; + break; + } + case DOCUMENT_PPTX: + { + sFullPath = "ppt/drawings/drawing"; + sRelativePath = "../drawings/drawing"; + break; + } + case DOCUMENT_XLSX: + { + sFullPath = "xl/drawings/drawing"; + sRelativePath = "../drawings/drawing"; + break; + } + default: + { + sFullPath = "drawings/drawing"; + sRelativePath = "drawings/drawing"; + break; + } + } + OUString sFullStream = OUStringBuffer() + .appendAscii(sFullPath) + .append(nDrawing) + .append(".xml") + .makeStringAndClear(); + OUString sRelativeStream = OUStringBuffer() + .appendAscii(sRelativePath) + .append(nDrawing) + .append(".xml") + .makeStringAndClear(); + + sax_fastparser::FSHelperPtr pDrawing = CreateOutputStream( + sFullStream, + sRelativeStream, + GetFS()->getOutputStream(), + "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml", + OUStringToOString(oox::getRelationship(Relationship::CHARTUSERSHAPES), RTL_TEXTENCODING_UTF8).getStr(), + &sId); + + GetFS()->singleElementNS(XML_c, XML_userShapes, FSNS(XML_r, XML_id), sId); + + XmlFilterBase* pFB = GetFB(); + pDrawing->startElement(FSNS(XML_c, XML_userShapes), + FSNS(XML_xmlns, XML_cdr), pFB->getNamespaceURL(OOX_NS(dmlChartDr)), + FSNS(XML_xmlns, XML_a), pFB->getNamespaceURL(OOX_NS(dml)), + FSNS(XML_xmlns, XML_c), pFB->getNamespaceURL(OOX_NS(dmlChart))); + + const sal_Int32 nShapeCount(mxAdditionalShapes->getCount()); + for (sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++) + { + Reference< drawing::XShape > xShape; + mxAdditionalShapes->getByIndex(nShapeId) >>= xShape; + SAL_WARN_IF(!xShape.is(), "xmloff.chart", "Shape without an XShape?"); + if (!xShape.is()) + continue; + + // TODO: absSizeAnchor: we import both (absSizeAnchor and relSizeAnchor), but there is no essential difference between them. + pDrawing->startElement(FSNS(XML_cdr, XML_relSizeAnchor)); + uno::Reference< beans::XPropertySet > xShapeProperties(xShape, uno::UNO_QUERY); + if( xShapeProperties.is() ) + { + Reference<embed::XVisualObject> xVisObject(mxChartModel, uno::UNO_QUERY); + awt::Size aPageSize = xVisObject->getVisualAreaSize(embed::Aspects::MSOLE_CONTENT); + WriteFromTo( xShape, aPageSize, pDrawing ); + + ShapeExport aExport(XML_cdr, pDrawing, nullptr, GetFB(), GetDocumentType()); + aExport.WriteShape(xShape); + } + pDrawing->endElement(FSNS(XML_cdr, XML_relSizeAnchor)); + } + pDrawing->endElement(FSNS(XML_c, XML_userShapes)); + } + } + catch (const uno::Exception&) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "AdditionalShapes not found"); + } + } +} + void ChartExport::exportChart( const Reference< css::chart::XChartDocument >& xChartDoc ) { Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY ); diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 5374812fa094..f291de8662ef 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -209,6 +209,8 @@ void WriteGradientPath(const awt::Gradient& rGradient, const FSHelperPtr& pFS, c int DrawingML::mnImageCounter = 1; int DrawingML::mnWdpImageCounter = 1; std::map<OUString, OUString> DrawingML::maWdpCache; +sal_Int32 DrawingML::mnDrawingMLCount = 0; +sal_Int32 DrawingML::mnVmlCount = 0; sal_Int16 DrawingML::GetScriptType(const OUString& rStr) { @@ -241,6 +243,12 @@ void DrawingML::ResetCounters() maWdpCache.clear(); } +void DrawingML::ResetMlCounters() +{ + mnDrawingMLCount = 0; + mnVmlCount = 0; +} + bool DrawingML::GetProperty( const Reference< XPropertySet >& rXPropertySet, const OUString& aName ) { try @@ -4952,6 +4960,67 @@ void DrawingML::writeDiagramRels(const uno::Sequence<uno::Sequence<uno::Any>>& x } } +void DrawingML::WriteFromTo(const uno::Reference<css::drawing::XShape>& rXShape, const awt::Size& aPageSize, + const FSHelperPtr& pDrawing) +{ + awt::Point aTopLeft = rXShape->getPosition(); + awt::Size aSize = rXShape->getSize(); + + SdrObject* pObj = SdrObject::getSdrObjectFromXShape(rXShape.get()); + if (pObj) + { + sal_Int32 nRotation = pObj->GetRotateAngle(); + if (nRotation != 0) + { + sal_Int16 nHalfWidth = aSize.Width / 2; + sal_Int16 nHalfHeight = aSize.Height / 2; + // aTopLeft needs correction for rotated customshapes + if (pObj->GetObjIdentifier() == OBJ_CUSTOMSHAPE) + { + const tools::Rectangle& aSnapRect(pObj->GetSnapRect()); // bounding box of the rotated shape + aTopLeft.X = aSnapRect.getX() + (aSnapRect.GetWidth() / 2) - nHalfWidth; + aTopLeft.Y = aSnapRect.getY() + (aSnapRect.GetHeight() / 2) - nHalfHeight; + } + + // MSO changes the anchor positions at these angles and that does an extra 90 degrees + // rotation on our shapes, so we output it in such position that MSO + // can draw this shape correctly. + if ((nRotation >= 45 * 100 && nRotation < 135 * 100) || (nRotation >= 225 * 100 && nRotation < 315 * 100)) + { + aTopLeft.X = aTopLeft.X - nHalfHeight + nHalfWidth; + aTopLeft.Y = aTopLeft.Y - nHalfWidth + nHalfHeight; + + std::swap(aSize.Width, aSize.Height); + } + } + } + + tools::Rectangle aLocation(aTopLeft.X, aTopLeft.Y, aTopLeft.X + aSize.Width, aTopLeft.Y + aSize.Height); + double nXpos = static_cast<double>(aLocation.TopLeft().getX()) / static_cast<double>(aPageSize.Width); + double nYpos = static_cast<double>(aLocation.TopLeft().getY()) / static_cast<double>(aPageSize.Height); + + pDrawing->startElement(FSNS(XML_cdr, XML_from)); + pDrawing->startElement(FSNS(XML_cdr, XML_x)); + pDrawing->write(nXpos); + pDrawing->endElement(FSNS(XML_cdr, XML_x)); + pDrawing->startElement(FSNS(XML_cdr, XML_y)); + pDrawing->write(nYpos); + pDrawing->endElement(FSNS(XML_cdr, XML_y)); + pDrawing->endElement(FSNS(XML_cdr, XML_from)); + + nXpos = static_cast<double>(aLocation.BottomRight().getX()) / static_cast<double>(aPageSize.Width); + nYpos = static_cast<double>(aLocation.BottomRight().getY()) / static_cast<double>(aPageSize.Height); + + pDrawing->startElement(FSNS(XML_cdr, XML_to)); + pDrawing->startElement(FSNS(XML_cdr, XML_x)); + pDrawing->write(nXpos); + pDrawing->endElement(FSNS(XML_cdr, XML_x)); + pDrawing->startElement(FSNS(XML_cdr, XML_y)); + pDrawing->write(nYpos); + pDrawing->endElement(FSNS(XML_cdr, XML_y)); + pDrawing->endElement(FSNS(XML_cdr, XML_to)); +} + } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/token/relationship.inc b/oox/source/token/relationship.inc index 2b973ded1653..e0b282c94848 100644 --- a/oox/source/token/relationship.inc +++ b/oox/source/token/relationship.inc @@ -1,5 +1,6 @@ {Relationship::ACTIVEXCONTROLBINARY, "http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary"}, {Relationship::CHART, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"}, +{Relationship::CHARTUSERSHAPES, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartUserShapes"}, {Relationship::COMMENTS, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"}, {Relationship::COMMENTAUTHORS, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/commentAuthors"}, {Relationship::CONTROL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/control"}, diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt index 27396f5b8dfa..e81ff50a217c 100644 --- a/oox/source/token/tokens.txt +++ b/oox/source/token/tokens.txt @@ -1024,6 +1024,7 @@ byte c c15 cBhvr +cdr cGp cGpRule cMediaNode |