diff --git a/sw/qa/writerfilter/rtftok/data/shape-in-header-table-row.rtf b/sw/qa/writerfilter/rtftok/data/shape-in-header-table-row.rtf new file mode 100644 index 000000000000..188f6f4015d8 --- /dev/null +++ b/sw/qa/writerfilter/rtftok/data/shape-in-header-table-row.rtf @@ -0,0 +1 @@ +{\rtf1{\header\pard\intbl{\shp{\*\shpinst{\shptxt A{\par}}}}\cell\row}\par} diff --git a/sw/qa/writerfilter/rtftok/rtfdocumentimpl.cxx b/sw/qa/writerfilter/rtftok/rtfdocumentimpl.cxx index d89ffe382206..23c1c8fda9c2 100644 --- a/sw/qa/writerfilter/rtftok/rtfdocumentimpl.cxx +++ b/sw/qa/writerfilter/rtftok/rtfdocumentimpl.cxx @@ -134,6 +134,20 @@ CPPUNIT_TEST_FIXTURE(Test, testImageSizeInShapeText) // i.e. the size of the icon was inherited from the containing shape, losing the own size. CPPUNIT_ASSERT_EQUAL(nExpected, rImageSize.GetWidth()); } + +CPPUNIT_TEST_FIXTURE(Test, testShapeInHeaderTableRow) +{ + // Given a header with a shape in a table row, and a paragraph mark inside the shape text: + // When loading this document: + createSwDoc("shape-in-header-table-row.rtf"); + + // Then make sure the document loads and the shape is there: + // Without the accompanying fix in place, this test would have failed with an assertion + // failure in DomainMapper_Impl::substream(), because the header left the context stack one + // level deeper than it found it. + SwDoc* pDoc = getSwDoc(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), pDoc->GetSpzFrameFormats()->size()); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx b/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx index 32dcd9b58e76..4b067be59182 100644 --- a/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx +++ b/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx @@ -2013,7 +2013,7 @@ void RTFDocumentImpl::replayBuffer(RTFBuffer_t& rBuffer, RTFSprms* const pSprms, uno::Reference xShape; std::get<1>(aTuple)->getAny() >>= xShape; if (xShape.is()) - Mapper().startShape(xShape); + m_pSdrImport->open(xShape); } else if (std::get<0>(aTuple) == RTFBufferTypes::ResolveSubstream) { @@ -3813,7 +3813,9 @@ void RTFDocumentImpl::afterPopState(RTFParserState& rState) && !m_aStates.top().getDrawingObject().getHadShapeText()) { m_aStates.top().setHadShapeText(true); - if (!m_aStates.top().getCurrentBuffer()) + // A replay can send a buffered start before the group ends, and the end + // has to follow it. + if (m_pSdrImport->isOpenInMapper() || !m_aStates.top().getCurrentBuffer()) m_pSdrImport->close(); else m_aStates.top().getCurrentBuffer()->emplace_back(RTFBufferTypes::EndShape, diff --git a/sw/source/writerfilter/rtftok/rtfsdrimport.cxx b/sw/source/writerfilter/rtftok/rtfsdrimport.cxx index 880e5bd9b085..c063fb4c5138 100644 --- a/sw/source/writerfilter/rtftok/rtfsdrimport.cxx +++ b/sw/source/writerfilter/rtftok/rtfsdrimport.cxx @@ -65,6 +65,7 @@ RTFSdrImport::RTFSdrImport(RTFDocumentImpl& rDocument, , m_bTextFrame(false) , m_bTextGraphicObject(false) , m_bFakePict(false) + , m_bOpenInMapper(false) { if (xDstDoc) m_aParents.push(xDstDoc->getDrawPage()); @@ -1165,10 +1166,10 @@ void RTFSdrImport::resolve(RTFShape& rShape, bool bClose, ShapeOrPict const shap // cells exist - resolvePict() defers its own output the same way. if (xShape.is() && !m_rImport.bufferShapeInsertion(xShape, bClose)) { - m_rImport.Mapper().startShape(xShape); + open(xShape); if (bClose) { - m_rImport.Mapper().endShape(); + close(); } } @@ -1186,7 +1187,17 @@ void RTFSdrImport::resolve(RTFShape& rShape, bool bClose, ShapeOrPict const shap m_xShape = std::move(xShape); } -void RTFSdrImport::close() { m_rImport.Mapper().endShape(); } +void RTFSdrImport::open(uno::Reference const& xShape) +{ + m_rImport.Mapper().startShape(xShape); + m_bOpenInMapper = true; +} + +void RTFSdrImport::close() +{ + m_rImport.Mapper().endShape(); + m_bOpenInMapper = false; +} void RTFSdrImport::append(std::u16string_view aKey, std::u16string_view aValue) { diff --git a/sw/source/writerfilter/rtftok/rtfsdrimport.hxx b/sw/source/writerfilter/rtftok/rtfsdrimport.hxx index e9f940f1ac6b..63f0acc7e399 100644 --- a/sw/source/writerfilter/rtftok/rtfsdrimport.hxx +++ b/sw/source/writerfilter/rtftok/rtfsdrimport.hxx @@ -53,6 +53,8 @@ public: PICT }; void resolve(RTFShape& rShape, bool bClose, ShapeOrPict shapeOrPict); + /// Send the start of a shape to the dmapper. It stays open there until its end is sent. + void open(css::uno::Reference const& xShape); void close(); void append(std::u16string_view aKey, std::u16string_view aValue); /// Append property on the current parent. @@ -78,6 +80,7 @@ public: void popParent(); css::uno::Reference const& getCurrentShape() const { return m_xShape; } bool isFakePict() const { return m_bFakePict; } + bool isOpenInMapper() const { return m_bOpenInMapper; } bool isTextGraphicObject() const { return m_bTextGraphicObject; } private: @@ -98,6 +101,8 @@ private: bool m_bTextGraphicObject; /// if inside \pict, but actually it's a shape (not a picture) bool m_bFakePict; + /// If a shape start has gone to the dmapper and its end has not. + bool m_bOpenInMapper; std::stack m_aGraphicZOrderHelpers; }; } // namespace writerfilter::rtftok