diff options
author | Regényi Balázs <regenyi.balazs@nisz.hu> | 2020-12-01 12:16:12 +0100 |
---|---|---|
committer | László Németh <nemeth@numbertext.org> | 2020-12-10 10:27:33 +0100 |
commit | bda05ba17362222b74727872579b65b3fa14e3d8 (patch) | |
tree | 60d9448754f1a992e7e9695c8f458b55cfb62d69 | |
parent | 7720f8cf22718415adb3db2304916581f864f884 (diff) |
tdf#41466 DOCX import: fix VML v:shape/v:textbox
VML v:shape/v:textbox element was imported only as
a text frame, losing (otherwise recognized) preset
shape geometry, i.e. replacing a callout bubble
(wedgeRectCallout) and other special shapes with a
plain rectangle.
Thanks to Attila Bakos for the initial help.
Change-Id: I03a608822ed54a20ed07406a08c3539e72958f5b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/105299
Tested-by: Jenkins
Reviewed-by: László Németh <nemeth@numbertext.org>
-rw-r--r-- | include/oox/export/drawingml.hxx | 4 | ||||
-rw-r--r-- | include/oox/vml/vmlshape.hxx | 10 | ||||
-rw-r--r-- | oox/qa/unit/vml.cxx | 19 | ||||
-rw-r--r-- | oox/source/export/drawingml.cxx | 34 | ||||
-rw-r--r-- | oox/source/export/vmlexport.cxx | 50 | ||||
-rw-r--r-- | oox/source/vml/vmlshape.cxx | 32 | ||||
-rw-r--r-- | oox/source/vml/vmlshapecontext.cxx | 20 | ||||
-rw-r--r-- | sw/inc/textboxhelper.hxx | 7 | ||||
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/layout-flow-alt-alone.docx (renamed from oox/qa/unit/data/layout-flow-alt-alone.docx) | bin | 7669 -> 7669 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/tdf41466_testVmlShapeWithTextbox.docx | bin | 0 -> 21651 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport9.cxx | 24 | ||||
-rw-r--r-- | sw/source/core/doc/textboxhelper.cxx | 23 | ||||
-rw-r--r-- | sw/source/core/unocore/unodraw.cxx | 9 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 6 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.hxx | 2 |
15 files changed, 207 insertions, 33 deletions
diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx index 31eeb727760f..9f87e54c1361 100644 --- a/include/oox/export/drawingml.hxx +++ b/include/oox/export/drawingml.hxx @@ -70,6 +70,7 @@ namespace style { namespace text { class XTextContent; class XTextRange; + class XTextFrame; } namespace io { class XOutputStream; @@ -125,6 +126,9 @@ public: virtual OUString FindRelId(BitmapChecksum nChecksum) = 0; /// Store the RelId of a graphic based on its checksum. virtual void CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId) = 0; + /// Get textbox which belongs to the shape. + virtual css::uno::Reference<css::text::XTextFrame> GetUnoTextFrame( + css::uno::Reference<css::drawing::XShape> xShape) = 0; protected: DMLTextExport() {} virtual ~DMLTextExport() {} diff --git a/include/oox/vml/vmlshape.hxx b/include/oox/vml/vmlshape.hxx index 7703b311c757..0e50e5b6ee1f 100644 --- a/include/oox/vml/vmlshape.hxx +++ b/include/oox/vml/vmlshape.hxx @@ -216,6 +216,7 @@ struct ShapeModel OUString maSignatureLineSigningInstructions; bool mbSignatureLineShowSignDate; bool mbSignatureLineCanAddComment; + bool mbInGroup; explicit ShapeModel(); ~ShapeModel(); @@ -275,6 +276,13 @@ protected: const css::uno::Reference< css::drawing::XShapes >& rxShapes, const css::awt::Rectangle& rShapeRect ) const = 0; + /** Always called after implConvertAndInsert for the same task.*/ + virtual css::uno::Reference<css::drawing::XShape> finalImplConvertAndInsert( + const css::uno::Reference<css::drawing::XShape>& rxShape) const + { + return rxShape; + }; + /** Calculates the final shape rectangle according to the passed anchor, if present, otherwise according to the own anchor settings. */ css::awt::Rectangle calcShapeRectangle( @@ -304,6 +312,8 @@ protected: implConvertAndInsert( const css::uno::Reference< css::drawing::XShapes >& rxShapes, const css::awt::Rectangle& rShapeRect ) const override; + virtual css::uno::Reference<css::drawing::XShape> finalImplConvertAndInsert( + const css::uno::Reference<css::drawing::XShape>& rxShape) const override; /** Used by both RectangleShape and ComplexShape. */ css::uno::Reference<css::drawing::XShape>createEmbeddedPictureObject( const css::uno::Reference< css::drawing::XShapes >& rxShapes, diff --git a/oox/qa/unit/vml.cxx b/oox/qa/unit/vml.cxx index d43d2d5645ae..ec64a08c3fcf 100644 --- a/oox/qa/unit/vml.cxx +++ b/oox/qa/unit/vml.cxx @@ -55,25 +55,6 @@ void OoxVmlTest::load(const OUString& rFileName) mxComponent = loadFromDesktop(aURL); } -CPPUNIT_TEST_FIXTURE(OoxVmlTest, testLayoutFlowAltAlone) -{ - // mso-layout-flow-alt:bottom-to-top without a matching layout-flow:vertical. - load("layout-flow-alt-alone.docx"); - - uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY); - uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), - uno::UNO_QUERY); - uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); - sal_Int16 nWritingMode = 0; - xShape->getPropertyValue("WritingMode") >>= nWritingMode; - - // Without the accompanying fix in place, this test would have failed with: - // - Expected: 5 [ BTLR ] - // - Actual : 4 [ PAGE ] - // i.e. in case layout-flow:vertical was missing, the text was not vertical. - CPPUNIT_ASSERT_EQUAL(text::WritingMode2::BT_LR, nWritingMode); -} - CPPUNIT_TEST_FIXTURE(OoxVmlTest, testSpt202ShapeType) { // Load a document with a groupshape, 2nd child is a <v:shape>, its type has o:spt set to 202 diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index f309e1541409..5374812fa094 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -88,6 +88,7 @@ #include <com/sun/star/text/XTextContent.hpp> #include <com/sun/star/text/XTextField.hpp> #include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/text/XTextFrame.hpp> #include <com/sun/star/style/CaseMap.hpp> #include <com/sun/star/xml/dom/XNodeList.hpp> #include <com/sun/star/xml/sax/Writer.hpp> @@ -2942,6 +2943,39 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo } } } + else + { + if (mpTextExport) + { + uno::Reference<drawing::XShape> xShape(rXIface, uno::UNO_QUERY); + if (xShape) + { + auto xTextFrame = mpTextExport->GetUnoTextFrame(xShape); + if (xTextFrame) + { + uno::Reference<beans::XPropertySet> xPropSet(xTextFrame, uno::UNO_QUERY); + auto aAny = xPropSet->getPropertyValue("WritingMode"); + sal_Int16 nWritingMode; + if (aAny >>= nWritingMode) + { + switch (nWritingMode) + { + case WritingMode2::TB_RL: + sWritingMode = "vert"; + bVertical = true; + break; + case WritingMode2::BT_LR: + sWritingMode = "vert270"; + bVertical = true; + break; + default: + break; + } + } + } + } + } + } OUString sPresetWarp(PresetGeometryTypeNames::GetMsoName(sShapeType)); // ODF may have user defined TextPath, use "textPlain" as ersatz. if (sPresetWarp.isEmpty()) diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx index 430ade878bf2..5ef5ed096b2e 100644 --- a/oox/source/export/vmlexport.cxx +++ b/oox/source/export/vmlexport.cxx @@ -46,6 +46,8 @@ #include <com/sun/star/text/HoriOrientation.hpp> #include <com/sun/star/text/VertOrientation.hpp> #include <com/sun/star/text/RelOrientation.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/text/XTextFrame.hpp> #include <cstdio> @@ -1470,15 +1472,49 @@ void VMLExport::EndShape( sal_Int32 nShapeElement ) if (m_pTextExport && lcl_isTextBox(m_pSdrObject)) { - uno::Reference<beans::XPropertySet> xPropertySet(const_cast<SdrObject*>(m_pSdrObject)->getUnoShape(), uno::UNO_QUERY); - comphelper::SequenceAsHashMap aCustomShapeProperties(xPropertySet->getPropertyValue("CustomShapeGeometry")); - sax_fastparser::FastAttributeList* pTextboxAttrList = FastSerializerHelper::createAttrList(); - if (aCustomShapeProperties.find("TextPreRotateAngle") != aCustomShapeProperties.end()) + uno::Reference<drawing::XShape> xShape {const_cast<SdrObject*>(m_pSdrObject)->getUnoShape(), uno::UNO_QUERY}; + uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY); + uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo(); + bool bBottomToTop = false; + if (xPropertySetInfo->hasPropertyByName("CustomShapeGeometry")) { - sal_Int32 nTextRotateAngle = aCustomShapeProperties["TextPreRotateAngle"].get<sal_Int32>(); - if (nTextRotateAngle == -270) - pTextboxAttrList->add(XML_style, "mso-layout-flow-alt:bottom-to-top"); + // In this case a DrawingML DOCX was imported. + comphelper::SequenceAsHashMap aCustomShapeProperties( + xPropertySet->getPropertyValue("CustomShapeGeometry")); + if (aCustomShapeProperties.find("TextPreRotateAngle") != aCustomShapeProperties.end()) + { + sal_Int32 nTextRotateAngle = aCustomShapeProperties["TextPreRotateAngle"].get<sal_Int32>(); + if (nTextRotateAngle == -270) + bBottomToTop = true; + } } + else + { + // In this case a pure VML DOCX was imported, so there is no CustomShapeGeometry. + auto pTextExport = m_pTextExport->GetDrawingML().GetTextExport(); + // FIXME: somewhy pTextExport is always nullptr, we should find its reason + if (pTextExport) + { + auto xTextFrame = pTextExport->GetUnoTextFrame(xShape); + uno::Reference<beans::XPropertySet> xPropSet(xTextFrame, uno::UNO_QUERY); + auto aAny = xPropSet->getPropertyValue("WritingMode"); + sal_Int16 nWritingMode; + if (aAny >>= nWritingMode) + { + switch (nWritingMode) + { + case text::WritingMode2::BT_LR: + bBottomToTop = true; + break; + default: + break; + } + } + } + } + sax_fastparser::FastAttributeList* pTextboxAttrList = FastSerializerHelper::createAttrList(); + if (bBottomToTop) + pTextboxAttrList->add(XML_style, "mso-layout-flow-alt:bottom-to-top"); sax_fastparser::XFastAttributeListRef xTextboxAttrList(pTextboxAttrList); pTextboxAttrList = nullptr; m_pSerializer->startElementNS(XML_v, XML_textbox, xTextboxAttrList); diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx index 1e3e1f72e64d..7ee10203341e 100644 --- a/oox/source/vml/vmlshape.cxx +++ b/oox/source/vml/vmlshape.cxx @@ -69,6 +69,7 @@ #include <comphelper/processfactory.hxx> #include <comphelper/propertyvalue.hxx> #include <comphelper/storagehelper.hxx> +#include <comphelper/sequenceashashmap.hxx> using ::com::sun::star::beans::XPropertySet; using ::com::sun::star::uno::Any; @@ -259,6 +260,7 @@ ShapeModel::ShapeModel() : mbIsSignatureLine(false) , mbSignatureLineShowSignDate(true) , mbSignatureLineCanAddComment(false) + , mbInGroup(false) { } @@ -459,6 +461,8 @@ Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxS PropertySet aControlShapeProp( xControlShape->getControl() ); aControlShapeProp.setProperty( PROP_EnableVisible, uno::makeAny( false ) ); } + + xShape = finalImplConvertAndInsert(xShape); /* Notify the drawing that a new shape has been inserted. For convenience, pass the rectangle that contains position and size of the shape. */ @@ -887,6 +891,34 @@ Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes return xShape; } +Reference<XShape> SimpleShape::finalImplConvertAndInsert(const css::uno::Reference<css::drawing::XShape>& rxShape) const +{ + // tdf#41466 This setting must be done here, because the position of textbox will be set as an + // effect of the PROP_TextBox property setting, and if we do this setting earlier (setting of + // properties of position and size) then the position of textbox will be set with wrong data. + // TODO: TextShape is set if we have rect shape in group; we should use the shape-with-textbox + // mechanism to handle this situation + if (getTextBox() && maService != "com.sun.star.text.TextFrame" && maService != "com.sun.star.drawing.TextShape" + && !maShapeModel.mbInGroup) + { + const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper(); + const auto& nLeft = ConversionHelper::decodeMeasureToHmm( + rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true); + PropertySet aPropertySet(rxShape); + aPropertySet.setProperty(PROP_HoriOrientPosition, nLeft); + const auto& nTop = ConversionHelper::decodeMeasureToHmm( + rGraphicHelper, maTypeModel.maMarginTop, 0, true, true); + aPropertySet.setProperty(PROP_VertOrientPosition, nTop); + aPropertySet.setProperty(PROP_TextBox, true); + + // And these properties must be set after textbox creation (set PROP_Textbox property). + // Note: if you set a new property then you have to handle it in the proper + // SwTextBoxHelper::syncProperty function. + if (maTypeModel.maLayoutFlowAlt == "bottom-to-top") + aPropertySet.setAnyProperty(PROP_TextWritingMode, uno::makeAny(text::WritingMode2::BT_LR)); + } + return ShapeBase::finalImplConvertAndInsert(rxShape); +} Reference< XShape > SimpleShape::createEmbeddedPictureObject( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect, OUString const & rGraphicPath ) const { Reference<XGraphic> xGraphic = mrDrawing.getFilter().getGraphicHelper().importEmbeddedGraphic(rGraphicPath); diff --git a/oox/source/vml/vmlshapecontext.cxx b/oox/source/vml/vmlshapecontext.cxx index f1ba9e32340c..e8f1b0b1910e 100644 --- a/oox/source/vml/vmlshapecontext.cxx +++ b/oox/source/vml/vmlshapecontext.cxx @@ -499,20 +499,26 @@ ContextHandlerRef ShapeContext::onCreateContext( sal_Int32 nElement, const Attri nShapeType = pShapeType->getTypeModel().moShapeType.get(); } } + mrShapeModel.mbInGroup = (getParentElement() == VML_TOKEN(group)); - if (getParentElement() != VML_TOKEN( group )) + // FIXME: the shape with textbox should be used for the next cases + if (getCurrentElement() == VML_TOKEN(rect) || nShapeType == ESCHER_ShpInst_TextBox) { - // Custom shape in Writer with a textbox are transformed into a frame - dynamic_cast<SimpleShape&>( mrShape ).setService( - "com.sun.star.text.TextFrame"); + if (mrShapeModel.mbInGroup) + // FIXME: without this a text will be added into the group-shape instead of its + // parent shape + dynamic_cast<SimpleShape&>(mrShape).setService("com.sun.star.drawing.TextShape"); + else + // FIXME: without this we does not handle some properties like shadow + dynamic_cast<SimpleShape&>(mrShape).setService("com.sun.star.text.TextFrame"); } - else if (getCurrentElement() == VML_TOKEN(rect) || nShapeType == ESCHER_ShpInst_TextBox) - // Transform only rectangles into a TextShape inside a groupshape. - dynamic_cast<SimpleShape&>(mrShape).setService("com.sun.star.drawing.TextShape"); return new TextBoxContext( *this, mrShapeModel.createTextBox(mrShape.getTypeModel()), rAttribs, mrShape.getDrawing().getFilter().getGraphicHelper()); } case VMLX_TOKEN( ClientData ): + // tdf#41466 ActiveX control shapes with a textbox are transformed into a frame + // (see unit test testActiveXOptionButtonGroup) + dynamic_cast<SimpleShape&>(mrShape).setService("com.sun.star.text.TextFrame"); return new ClientDataContext( *this, mrShapeModel.createClientData(), rAttribs ); case VMLPPT_TOKEN( textdata ): // Force RectangleShape, this is ugly :( diff --git a/sw/inc/textboxhelper.hxx b/sw/inc/textboxhelper.hxx index a0cd4c593082..6d209d2c7140 100644 --- a/sw/inc/textboxhelper.hxx +++ b/sw/inc/textboxhelper.hxx @@ -35,6 +35,10 @@ namespace com::sun::star::drawing { class XShape; } +namespace com::sun::star::text +{ +class XTextFrame; +} /** * A TextBox is a TextFrame, that is tied to a drawinglayer shape. @@ -85,6 +89,9 @@ public: /// If we have an associated TextFrame, then return that. static SwFrameFormat* getOtherTextBoxFormat(css::uno::Reference<css::drawing::XShape> const& xShape); + /// If we have an associated TextFrame, then return its XTextFrame. + static css::uno::Reference<css::text::XTextFrame> + getUnoTextFrame(css::uno::Reference<css::drawing::XShape> const& xShape); /// Return the textbox rectangle of a draw shape (in twips). static tools::Rectangle getTextRectangle(SwFrameFormat* pShape, bool bAbsolute = true); diff --git a/oox/qa/unit/data/layout-flow-alt-alone.docx b/sw/qa/extras/ooxmlexport/data/layout-flow-alt-alone.docx Binary files differindex 59c2db23d588..59c2db23d588 100644 --- a/oox/qa/unit/data/layout-flow-alt-alone.docx +++ b/sw/qa/extras/ooxmlexport/data/layout-flow-alt-alone.docx diff --git a/sw/qa/extras/ooxmlexport/data/tdf41466_testVmlShapeWithTextbox.docx b/sw/qa/extras/ooxmlexport/data/tdf41466_testVmlShapeWithTextbox.docx Binary files differnew file mode 100644 index 000000000000..2dfeb909cf9d --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf41466_testVmlShapeWithTextbox.docx diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx index 251bc2dcb952..47ee7a99b351 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx @@ -1622,6 +1622,30 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testAlignmentRelativeFromTopMarginVML, "tdf1 "center"); } +DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testVmlShapeWithTextbox, "tdf41466_testVmlShapeWithTextbox.docx") +{ + // Import as VML. + // tdf#41466: check whether VML DOCX shape with text is imported as shape with a text frame + // (text box). These kind of shapes were imported only as text frames previously, losing the + // preset shape geometry, in this case "wedgeRectCallout". + xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); + + // the wrong value was "rect" instead of "wedgeRectCallout" + assertXPath(pXmlDoc, + "/w:document/w:body/w:p/w:r/" + "mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:prstGeom", + "prst", "wedgeRectCallout"); +} + +DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testLayoutFlowAltAlone, "layout-flow-alt-alone.docx") +{ + // moved from oox/qa/unit/vml.cxx + // FIXME: now the DML part is checked, but we should check VML part in Fallback (too) + xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); + assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/" + "a:graphic/a:graphicData/wps:wsp/wps:bodyPr", "vert", "vert270"); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/doc/textboxhelper.cxx b/sw/source/core/doc/textboxhelper.cxx index 0d66639baf83..f569cb4ff595 100644 --- a/sw/source/core/doc/textboxhelper.cxx +++ b/sw/source/core/doc/textboxhelper.cxx @@ -44,6 +44,7 @@ #include <com/sun/star/text/TextContentAnchorType.hpp> #include <com/sun/star/text/WrapTextMode.hpp> #include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/text/XTextFrame.hpp> #include <com/sun/star/table/BorderLine2.hpp> #include <com/sun/star/text/WritingMode.hpp> #include <com/sun/star/text/WritingMode2.hpp> @@ -357,6 +358,25 @@ SwFrameFormat* SwTextBoxHelper::getOtherTextBoxFormat(uno::Reference<drawing::XS return getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT); } +uno::Reference<text::XTextFrame> +SwTextBoxHelper::getUnoTextFrame(uno::Reference<drawing::XShape> const& xShape) +{ + if (xShape) + { + auto pFrameFormat = SwTextBoxHelper::getOtherTextBoxFormat(xShape); + if (pFrameFormat) + { + auto pSdrObj = pFrameFormat->FindSdrObject(); + if (pSdrObj && pSdrObj->IsTextBox()) + { + return uno::Reference<css::text::XTextFrame>(pSdrObj->getUnoShape(), + uno::UNO_QUERY); + } + } + } + return uno::Reference<css::text::XTextFrame>(); +} + template <typename T> static void lcl_queryInterface(const SwFrameFormat* pShape, uno::Any& rAny) { if (SwFrameFormat* pFormat = SwTextBoxHelper::getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT)) @@ -537,8 +557,11 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, std::u16string_view rP else if (rPropertyName == UNO_NAME_TEXT_WRITINGMODE) { text::WritingMode eMode; + sal_Int16 eMode2; if (rValue >>= eMode) syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(sal_Int16(eMode))); + else if (rValue >>= eMode2) + syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(eMode2)); } } diff --git a/sw/source/core/unocore/unodraw.cxx b/sw/source/core/unocore/unodraw.cxx index fa2fdfb24944..087949787d89 100644 --- a/sw/source/core/unocore/unodraw.cxx +++ b/sw/source/core/unocore/unodraw.cxx @@ -737,6 +737,15 @@ void SwXDrawPage::remove(const uno::Reference< drawing::XShape > & xShape) SolarMutexGuard aGuard; if(!m_pDoc) throw uno::RuntimeException(); + // tdf#41466 remove TextFrame too which is belonged to the actual shape + auto xTextFrame = SwTextBoxHelper::getUnoTextFrame(xShape); + if (xTextFrame) + { + uno::Reference<lang::XComponent> xComp(xTextFrame, uno::UNO_QUERY); + if (xComp) + xComp->dispose(); + } + // remove shape uno::Reference<lang::XComponent> xComp(xShape, uno::UNO_QUERY); xComp->dispose(); } diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 5b246d999254..bf25b3111379 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -4904,6 +4904,12 @@ void DocxAttributeOutput::CacheRelId(BitmapChecksum nChecksum, const OUString& r m_aSdrRelIdCache.top()[nChecksum] = rRelId; } +uno::Reference<css::text::XTextFrame> DocxAttributeOutput::GetUnoTextFrame( + css::uno::Reference<css::drawing::XShape> xShape) +{ + return SwTextBoxHelper::getUnoTextFrame(xShape); +} + OString DocxAttributeOutput::getExistingGraphicRelId(BitmapChecksum nChecksum) { OString aResult; diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index b9278e7f771c..349cab0cb310 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -1025,6 +1025,8 @@ public: virtual void WriteTextBox(css::uno::Reference<css::drawing::XShape> xShape) override; virtual OUString FindRelId(BitmapChecksum nChecksum) override; virtual void CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId) override; + virtual css::uno::Reference<css::text::XTextFrame> GetUnoTextFrame( + css::uno::Reference<css::drawing::XShape> xShape) override; virtual oox::drawingml::DrawingML& GetDrawingML() override; virtual void MaybeOutputBrushItem(SfxItemSet const&) override; |