summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2025-09-24 15:27:06 +0500
committerMike Kaganski <mike.kaganski@collabora.com>2025-09-24 16:16:00 +0200
commit202d41e0fb2432ca286953d5f7464289fcb52e30 (patch)
tree1df506f9362390113ab950b353c6fe2fa30ac75f
parent9bb3947fadb83712492a156b3477d82f2280a3b3 (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.rtf12
-rw-r--r--sw/qa/extras/rtfexport/rtfexport8.cxx23
-rw-r--r--sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx3
-rw-r--r--sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx2
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.