sw/qa/extras/rtfexport/data/tdf168533-pard-in-frame.rtf | 12 ++++++++ sw/qa/extras/rtfexport/rtfexport8.cxx | 23 ++++++++++++++++ sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx | 3 ++ sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx | 2 + 4 files changed, 40 insertions(+)
New commits: commit 8566b6167c5f788bf5849a461e4a52f66b6e3682 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Wed Sep 24 15:27:06 2025 +0500 Commit: Thorsten Behrens <thorsten.behr...@collabora.com> CommitDate: Thu Sep 25 11:20:10 2025 +0200 tdf#168533: make sure to emit frame properties, when they changed ... because of popping state. In the RTF markup: \pard\pvpara\phpara\posx3500\posy0bsw3800\wraparound Frame 2\par {\pard Still frame 2}\par the frame is created first: the frame properties are collected, m_bNeedPap is set to true, and the frame settings are pushed in checkNeedPap, called from RTFDocumentImpl::text() when "Frame 2" text arrives; that resets m_bNeedPap. When checkNeedPap is called from \par handler code, m_bNeedPap is false, and it bails out. Then opening brace creates a new state on the stack; \pard resets all the paragraph properties to default, including frame properties; then text "Still frame 2" arrives, calling checkNeedPap, which doesn't send frame properties, because there's none at this moment; it resets m_bNeedPap. Then closing brace pops the state from stack, returning to the state with the frame properties; and \par handler in RTFDocumentImpl::dispatchSymbol calls checkNeedPap. But at this point, m_bNeedPap was still false, so it bailed out, and didn't send the frame properties - so in the end, the current paragraph never obtained frame properties, and got imported into the main text flow. This change makes sure, that whenever popping the state changes the frame properties, m_bNeedPap is set, to ensure emitting it when time comes. Change-Id: I61b95e2818a66f54d7026db3cbb85e92135807c9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191439 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> (cherry picked from commit 202d41e0fb2432ca286953d5f7464289fcb52e30) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191453 Reviewed-by: Thorsten Behrens <thorsten.behr...@collabora.com> diff --git a/sw/qa/extras/rtfexport/data/tdf168533-pard-in-frame.rtf b/sw/qa/extras/rtfexport/data/tdf168533-pard-in-frame.rtf new file mode 100644 index 000000000000..44ef618ca6fe --- /dev/null +++ b/sw/qa/extras/rtfexport/data/tdf168533-pard-in-frame.rtf @@ -0,0 +1,12 @@ +{ tf1 + +\pard\pvpara\phpara\posx3500\posy0bsw3800\wraparound +Frame 1\par +{\pard Outside frame 1\par} +\pard\par + +\pard\pvpara\phpara\posx3500\posy0bsw3800\wraparound +Frame 2\par +{\pard Still frame 2}\par +\pard\par +} \ No newline at end of file diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx b/sw/qa/extras/rtfexport/rtfexport8.cxx index a02e6e04886f..d267ad765f94 100644 --- a/sw/qa/extras/rtfexport/rtfexport8.cxx +++ b/sw/qa/extras/rtfexport/rtfexport8.cxx @@ -1305,6 +1305,29 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf168181) getProperty<OUString>(getRun(getParagraph(1), 1), u"HyperLinkURL"_ustr)); } +CPPUNIT_TEST_FIXTURE(Test, testTdf168533) +{ + // Given an RTF with frame definitions, followed by braces with \pard inside, and then \par + // inside and outside the braces: + createSwDoc("tdf168533-pard-in-frame.rtf"); + CPPUNIT_ASSERT_EQUAL(2, getShapes()); + + // 1. {\pard Outside frame 1\par} + // \par sees the \pard, which reset frame properties, and so the paragraph is outside any frame + CPPUNIT_ASSERT_EQUAL(u"Frame 1"_ustr, getShape(1).queryThrow<text::XText>()->getString()); + CPPUNIT_ASSERT_EQUAL(u"Outside frame 1"_ustr, getParagraph(1)->getString()); + + // 2. {\pard Still frame 2}\par + // \pard has reset the frame properties; but it goes out of scope with the closing brace, and + // \par sees the parent-in-stack state's frame properties, so the text is kept in frame + // Without the fix, it failed with + // - Expected: Frame 2 + // Still frame 2 + // - Actual : Frame 2 + CPPUNIT_ASSERT_EQUAL(u"Frame 2" SAL_NEWLINE_STRING "Still frame 2"_ustr, + getShape(2).queryThrow<text::XText>()->getString()); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx b/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx index c9dc19203670..6044e427ee79 100644 --- a/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx +++ b/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx @@ -3860,6 +3860,9 @@ RTFError RTFDocumentImpl::popState() afterPopState(aState); + if (!m_aStates.empty() && aState.getFrame() != m_aStates.top().getFrame()) + m_bNeedPap = true; + if (aState.getCurrentBuffer() == &m_aSuperBuffer) { OSL_ASSERT(!m_aStates.empty() && m_aStates.top().getCurrentBuffer() == nullptr); diff --git a/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx b/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx index 12e4aa64d151..931ee12df8bf 100644 --- a/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx +++ b/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx @@ -386,6 +386,8 @@ public: void setSprm(Id nId, Id nValue); /// If we got tokens indicating we're in a frame. bool hasProperties() const; + + bool operator==(const RTFFrame&) const = default; }; /// State of the parser, which gets saved / restored when changing groups.