diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2025-09-24 15:27:06 +0500 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2025-09-24 16:16:00 +0200 |
commit | 202d41e0fb2432ca286953d5f7464289fcb52e30 (patch) | |
tree | 1df506f9362390113ab950b353c6fe2fa30ac75f | |
parent | 9bb3947fadb83712492a156b3477d82f2280a3b3 (diff) |
tdf#168533: make sure to emit frame properties, when they changed
... because of popping state.
In the RTF markup:
\pard\pvpara\phpara\posx3500\posy0\absw3800\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.kaganski@collabora.com>
-rw-r--r-- | sw/qa/extras/rtfexport/data/tdf168533-pard-in-frame.rtf | 12 | ||||
-rw-r--r-- | sw/qa/extras/rtfexport/rtfexport8.cxx | 23 | ||||
-rw-r--r-- | sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx | 3 | ||||
-rw-r--r-- | sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx | 2 |
4 files changed, 40 insertions, 0 deletions
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 @@ +{\rtf1 + +\pard\pvpara\phpara\posx3500\posy0\absw3800\wraparound +Frame 1\par +{\pard Outside frame 1\par} +\pard\par + +\pard\pvpara\phpara\posx3500\posy0\absw3800\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 74ade0ff3614..bd02d10e09cc 100644 --- a/sw/qa/extras/rtfexport/rtfexport8.cxx +++ b/sw/qa/extras/rtfexport/rtfexport8.cxx @@ -1300,6 +1300,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 f4f70d6ed9f9..8ef64f97eea3 100644 --- a/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx +++ b/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx @@ -3866,6 +3866,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 dfd881664d5c..ad2069993504 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. |