diff options
Diffstat (limited to 'sw')
85 files changed, 1951 insertions, 660 deletions
diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx index 20636648c7..03afe5006a 100644 --- a/sw/inc/crsrsh.hxx +++ b/sw/inc/crsrsh.hxx @@ -267,7 +267,7 @@ private: SAL_DLLPRIVATE bool LRMargin( bool, bool bAPI = false ); SAL_DLLPRIVATE bool IsAtLRMargin( bool, bool bAPI = false ) const; - SAL_DLLPRIVATE bool isInHiddenTextFrame(SwShellCursor* pShellCursor); + SAL_DLLPRIVATE bool isInHiddenFrame(SwShellCursor* pShellCursor); SAL_DLLPRIVATE bool GoStartWordImpl(); SAL_DLLPRIVATE bool GoEndWordImpl(); @@ -334,7 +334,7 @@ public: void ExtendedSelectAll(bool bFootnotes = true); /// If ExtendedSelectAll() was called and selection didn't change since then. ::std::optional<::std::pair<SwNode const*, ::std::vector<SwTableNode*>>> ExtendedSelectedAll() const; - enum class StartsWith { None, Table, HiddenPara }; + enum class StartsWith { None, Table, HiddenPara, HiddenSection }; /// If document body starts with a table or starts/ends with hidden paragraph. StartsWith StartsWith_(); diff --git a/sw/inc/ndarr.hxx b/sw/inc/ndarr.hxx index 7afe8d2bce..7383c253a2 100644 --- a/sw/inc/ndarr.hxx +++ b/sw/inc/ndarr.hxx @@ -131,6 +131,11 @@ class SW_DLLPUBLIC SwNodes final SwNodes(SwDoc& rDoc); + // Returns start of the document section (PostIts/Inserts/Autotext/Redlines/Content), + // or of a specific fly / header / footer / footnote, where this node is, which must not + // be crossed when moving backwards + SwNodeOffset StartOfGlobalSection(const SwNode& node) const; + public: ~SwNodes(); @@ -188,8 +193,8 @@ public: SwContentNode* GoNext(SwNodeIndex *) const; SwContentNode* GoNext(SwPosition *) const; - static SwContentNode* GoPrevious(SwNodeIndex *); - static SwContentNode* GoPrevious(SwPosition *); + static SwContentNode* GoPrevious(SwNodeIndex *, bool canCrossBoundary = false); + static SwContentNode* GoPrevious(SwPosition *, bool canCrossBoundary = false); /** Go to next content-node that is not protected or hidden (Both set FALSE ==> GoNext/GoPrevious!!!). */ diff --git a/sw/inc/node.hxx b/sw/inc/node.hxx index de7e24a0b1..b1e3309d59 100644 --- a/sw/inc/node.hxx +++ b/sw/inc/node.hxx @@ -590,7 +590,7 @@ public: const SwSection& GetSection() const { return *m_pSection; } SwSection& GetSection() { return *m_pSection; } - SwFrame *MakeFrame( SwFrame* ); + SwFrame* MakeFrame(SwFrame* pSib, bool bHidden); /** Creates the frms for the SectionNode (i.e. the SectionFrames). On default the frames are created until the end of the range. diff --git a/sw/inc/pagedesc.hxx b/sw/inc/pagedesc.hxx index 11bb347aa1..ddc7e659a5 100644 --- a/sw/inc/pagedesc.hxx +++ b/sw/inc/pagedesc.hxx @@ -151,9 +151,9 @@ class SW_DLLPUBLIC SwPageDesc final struct StashedPageDesc { - std::shared_ptr<SwFrameFormat> m_pStashedFirst; - std::shared_ptr<SwFrameFormat> m_pStashedLeft; - std::shared_ptr<SwFrameFormat> m_pStashedFirstLeft; + std::optional<SwFrameFormat> m_oStashedFirst; + std::optional<SwFrameFormat> m_oStashedLeft; + std::optional<SwFrameFormat> m_oStashedFirstLeft; }; mutable StashedPageDesc m_aStashedHeader; diff --git a/sw/qa/core/layout/data/floattable-wrapped-by-table-nested.docx b/sw/qa/core/layout/data/floattable-wrapped-by-table-nested.docx Binary files differnew file mode 100644 index 0000000000..d6950a6c8e --- /dev/null +++ b/sw/qa/core/layout/data/floattable-wrapped-by-table-nested.docx diff --git a/sw/qa/core/layout/tabfrm.cxx b/sw/qa/core/layout/tabfrm.cxx index 61b1a25109..e0d099c771 100644 --- a/sw/qa/core/layout/tabfrm.cxx +++ b/sw/qa/core/layout/tabfrm.cxx @@ -221,6 +221,20 @@ CPPUNIT_TEST_FIXTURE(Test, testInlineTableThenSplitFly) // large positive one. CPPUNIT_ASSERT_LESS(static_cast<SwTwips>(0), nInlineLeft); } + +CPPUNIT_TEST_FIXTURE(Test, testSplitFlyWrappedByTableNested) +{ + // Given a document with 3 tables, one inline toplevel and two inner ones (one inline, one + // floating): + // When laying out that document: + // Without the accompanying fix in place, this test would have failed here with a layout loop. + createSwDoc("floattable-wrapped-by-table-nested.docx"); + + // Than make sure we have 3 tables, but only one of them is floating: + SwDoc* pDoc = getSwDoc(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pDoc->GetTableFrameFormats()->GetFormatCount()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDoc->GetSpzFrameFormats()->GetFormatCount()); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/core/unocore/unocore.cxx b/sw/qa/core/unocore/unocore.cxx index 381fe0dab3..3e52b12a36 100644 --- a/sw/qa/core/unocore/unocore.cxx +++ b/sw/qa/core/unocore/unocore.cxx @@ -78,6 +78,33 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testTdf119081) CPPUNIT_ASSERT_EQUAL(OUString("x"), pWrtShell->GetCurrentShellCursor().GetText()); } +CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, selectTextRange) +{ + createSwDoc(); + uno::Reference<text::XTextDocument> const xTD(mxComponent, uno::UNO_QUERY_THROW); + uno::Reference<text::XText> const xText(xTD->getText()); + uno::Reference<text::XTextCursor> const xCursor(xText->createTextCursor()); + xText->insertString(xCursor, "test", /*bAbsorb=*/false); + xCursor->gotoStart(false); + xCursor->gotoEnd(true); + CPPUNIT_ASSERT_EQUAL(OUString("test"), xCursor->getString()); + uno::Reference<lang::XMultiServiceFactory> const xMSF(mxComponent, uno::UNO_QUERY_THROW); + uno::Reference<text::XTextSection> const xSection( + xMSF->createInstance("com.sun.star.text.TextSection"), uno::UNO_QUERY_THROW); + xText->insertTextContent(xCursor, xSection, true); + uno::Reference<text::XTextRange> const xAnchor(xSection->getAnchor()); + uno::Reference<view::XSelectionSupplier> const xView(xTD->getCurrentController(), + uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("test"), xAnchor->getString()); + CPPUNIT_ASSERT(xView->select(uno::Any(xAnchor))); + uno::Reference<container::XIndexAccess> xSel; + CPPUNIT_ASSERT(xView->getSelection() >>= xSel); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSel->getCount()); + uno::Reference<text::XTextRange> xSelRange; + CPPUNIT_ASSERT(xSel->getByIndex(0) >>= xSelRange); + CPPUNIT_ASSERT_EQUAL(OUString("test"), xSelRange->getString()); +} + CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, flyAtParaAnchor) { createSwDoc(); diff --git a/sw/qa/extras/accessibility/dialogs.cxx b/sw/qa/extras/accessibility/dialogs.cxx index 091e6729c9..665e76c9bc 100644 --- a/sw/qa/extras/accessibility/dialogs.cxx +++ b/sw/qa/extras/accessibility/dialogs.cxx @@ -89,6 +89,7 @@ CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, TestSpecialCharactersDialogFocu CPPUNIT_ASSERT_EQUAL(u"<PARAGRAPH>!</PARAGRAPH>"_ustr, collectText()); } +#if !defined(_WIN32) CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestHyperlinkDialog) { load(u"private:factory/swriter"_ustr); @@ -112,6 +113,7 @@ CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestHyperlinkDialog) CPPUNIT_ASSERT_EQUAL(rtl::OUString("<PARAGRAPH>https://libreoffice.org/</PARAGRAPH>"), collectText()); } +#endif //defined(_WIN32) CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestBookmarkDialog) { diff --git a/sw/qa/extras/fodfexport/fodfexport.cxx b/sw/qa/extras/fodfexport/fodfexport.cxx index 2cf5bf42a7..840b5d47ba 100644 --- a/sw/qa/extras/fodfexport/fodfexport.cxx +++ b/sw/qa/extras/fodfexport/fodfexport.cxx @@ -20,34 +20,38 @@ public: } }; -DECLARE_FODFEXPORT_TEST(testTdf113696, "tdf113696.odt") +CPPUNIT_TEST_FIXTURE(Test, testTdf113696) { + loadFromFile(u"tdf113696.odt"); + CPPUNIT_ASSERT_EQUAL(1, getShapes()); CPPUNIT_ASSERT_EQUAL(1, getPages()); + + save("OpenDocument Text Flat XML"); // Test that an image which is written in svm format (image/x-vclgraphic) // is accompanied by a png fallback graphic. - if (xmlDocUniquePtr pXmlDoc = parseExportedFile()) - { - assertXPath(pXmlDoc, "/office:document/office:body/office:text/text:p/draw:frame/" - "draw:image[@draw:mime-type='image/x-vclgraphic']"_ostr); - assertXPath(pXmlDoc, "/office:document/office:body/office:text/text:p/draw:frame/" - "draw:image[@draw:mime-type='image/png']"_ostr); - } + xmlDocUniquePtr pXmlDoc = parseExportedFile(); + assertXPath(pXmlDoc, "/office:document/office:body/office:text/text:p/draw:frame/" + "draw:image[@draw:mime-type='image/x-vclgraphic']"_ostr); + assertXPath(pXmlDoc, "/office:document/office:body/office:text/text:p/draw:frame/" + "draw:image[@draw:mime-type='image/png']"_ostr); } -DECLARE_FODFEXPORT_TEST(testTdf113696WriterImage, "tdf113696-writerimage.odt") +CPPUNIT_TEST_FIXTURE(Test, testTdf113696WriterImage) { + loadFromFile(u"tdf113696-writerimage.odt"); + CPPUNIT_ASSERT_EQUAL(1, getShapes()); CPPUNIT_ASSERT_EQUAL(1, getPages()); + + save("OpenDocument Text Flat XML"); // Same as testTdf113696, but with a writer image instead of a draw image // (they use different code paths). - if (xmlDocUniquePtr pXmlDoc = parseExportedFile()) - { - assertXPath(pXmlDoc, "/office:document/office:body/office:text/text:p/draw:frame/" - "draw:image[@draw:mime-type='image/x-vclgraphic']"_ostr); - assertXPath(pXmlDoc, "/office:document/office:body/office:text/text:p/draw:frame/" - "draw:image[@draw:mime-type='image/png']"_ostr); - } + xmlDocUniquePtr pXmlDoc = parseExportedFile(); + assertXPath(pXmlDoc, "/office:document/office:body/office:text/text:p/draw:frame/" + "draw:image[@draw:mime-type='image/x-vclgraphic']"_ostr); + assertXPath(pXmlDoc, "/office:document/office:body/office:text/text:p/draw:frame/" + "draw:image[@draw:mime-type='image/png']"_ostr); } DECLARE_FODFEXPORT_TEST(testSvgImageRoundtrip, "SvgImageTest.fodt") diff --git a/sw/qa/extras/htmlexport/data/char_border_and_font_color.fodt b/sw/qa/extras/htmlexport/data/char_border_and_font_color.fodt new file mode 100644 index 0000000000..bda2ec6313 --- /dev/null +++ b/sw/qa/extras/htmlexport/data/char_border_and_font_color.fodt @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph"> + <style:text-properties fo:color="#000000" loext:border="none"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <text:p text:style-name="P1">foo</text:p> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index 1bd883be11..de2e9da4c6 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -3032,6 +3032,27 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_NoBrClearForImageWrap) 0); } +CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_Tdf160017_spanClosingOrder) +{ + // Given a document with a paragraph having explicit font color and character border properties: + createSwDoc("char_border_and_font_color.fodt"); + // When exporting to reqif: + ExportToReqif(); + // Without the fix, this would fail, because there was an extra closing </reqif-xhtml:span> + WrapReqifFromTempFile(); +} + +CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testHTML_Tdf160017_spanClosingOrder) +{ + // Given a document with a paragraph having explicit font color and character border properties: + createSwDoc("char_border_and_font_color.fodt"); + // When exporting to HTML: + ExportToHTML(); + // Parse it as XML (strict!) + // Without the fix, this would fail, because span and font elements closed in wrong order + CPPUNIT_ASSERT(parseXml(maTempFile)); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/layout/data/largeTopMarginAndHiddenFirstSection.fodt b/sw/qa/extras/layout/data/largeTopMarginAndHiddenFirstSection.fodt new file mode 100644 index 0000000000..fbefc5c480 --- /dev/null +++ b/sw/qa/extras/layout/data/largeTopMarginAndHiddenFirstSection.fodt @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:styles> + <style:style style:name="Standard" style:family="paragraph" style:class="text"> + <style:paragraph-properties fo:margin-top="1in" fo:margin-bottom="0" style:contextual-spacing="false" fo:line-height="12pt"/> + </style:style> + </office:styles> + <office:body> + <office:text> + <text:section text:name="Hidden" text:display="none"/> + <text:section text:name="Shown"/> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/qa/extras/layout/data/pageBreakInHiddenSection.fodt b/sw/qa/extras/layout/data/pageBreakInHiddenSection.fodt new file mode 100644 index 0000000000..5fae6a4917 --- /dev/null +++ b/sw/qa/extras/layout/data/pageBreakInHiddenSection.fodt @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph" style:master-page-name="Landscape"> + <style:paragraph-properties style:page-number="1"/> + </style:style> + <style:style style:name="P2" style:family="paragraph" style:master-page-name="Landscape"> + <style:paragraph-properties style:page-number="1"/> + <style:text-properties text:display="none"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <text:p>First line</text:p> + <text:section text:name="Hidden" text:display="none"> + <text:p text:style-name="P1"/> + </text:section> + <text:section text:name="Shown"> + <text:p>Before break (still first page)</text:p> + </text:section> + <text:section text:name="HiddenText"> + <text:p text:style-name="P2"/> + </text:section> + <text:p>After break</text:p> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p/> + <text:p>Should be together with next</text:p> + <text:section text:name="Hidden2" text:display="none"> + <text:p text:style-name="P2"/> + </text:section> + <text:p>Should be together with previous</text:p> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/qa/extras/layout/layout3.cxx b/sw/qa/extras/layout/layout3.cxx index 9c46d8395a..a074a35dc6 100644 --- a/sw/qa/extras/layout/layout3.cxx +++ b/sw/qa/extras/layout/layout3.cxx @@ -94,15 +94,25 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf119875) { createSwDoc("tdf119875.odt"); xmlDocUniquePtr pXmlDoc = parseLayoutDump(); - sal_Int32 nFirstTop - = getXPath(pXmlDoc, "/root/page[2]/body/section[1]/infos/bounds"_ostr, "top"_ostr) - .toInt32(); - sal_Int32 nSecondTop - = getXPath(pXmlDoc, "/root/page[2]/body/section[2]/infos/bounds"_ostr, "top"_ostr) - .toInt32(); - // The first section had the same top value as the second one, so they - // overlapped. - CPPUNIT_ASSERT_LESS(nSecondTop, nFirstTop); + + assertXPath(pXmlDoc, "//page[2]/body/section[1]"_ostr, "formatName"_ostr, u"S10"_ustr); + assertXPath(pXmlDoc, "//page[2]/body/section[2]"_ostr, "formatName"_ostr, u"S11"_ustr); + assertXPath(pXmlDoc, "//page[2]/body/section[3]"_ostr, "formatName"_ostr, u"S13"_ustr); + assertXPath(pXmlDoc, "//page[2]/body/section[4]"_ostr, "formatName"_ostr, u"S14"_ustr); + // Sections "S10" and "S13" are hidden -> their frames are zero-height + assertXPath(pXmlDoc, "//page[2]/body/section[1]/infos/bounds"_ostr, "height"_ostr, u"0"_ustr); + assertXPath(pXmlDoc, "//page[2]/body/section[3]/infos/bounds"_ostr, "height"_ostr, u"0"_ustr); + + OUString S10Top = getXPath(pXmlDoc, "//page[2]/body/section[1]/infos/bounds"_ostr, "top"_ostr); + OUString S11Top = getXPath(pXmlDoc, "//page[2]/body/section[2]/infos/bounds"_ostr, "top"_ostr); + OUString S13Top = getXPath(pXmlDoc, "//page[2]/body/section[3]/infos/bounds"_ostr, "top"_ostr); + OUString S14Top = getXPath(pXmlDoc, "//page[2]/body/section[4]/infos/bounds"_ostr, "top"_ostr); + + CPPUNIT_ASSERT_EQUAL(S10Top, S11Top); + CPPUNIT_ASSERT_EQUAL(S13Top, S14Top); + + // Section "S11" had the same top value as section "S14", so they overlapped. + CPPUNIT_ASSERT_LESS(S14Top.toInt32(), S11Top.toInt32()); } CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf137523) @@ -2303,6 +2313,46 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf159259) CPPUNIT_ASSERT_EQUAL(paraHeight, flyHeight); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testLargeTopParaMarginAfterHiddenSection) +{ + // Given a large top margin in Standard paragraph style, and the first section hidden + createSwDoc("largeTopMarginAndHiddenFirstSection.fodt"); + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + // Make sure there is only one page and two sections, first hidden (zero-height) + assertXPath(pXmlDoc, "//page"_ostr, 1); + assertXPath(pXmlDoc, "//page/body/section"_ostr, 2); + assertXPath(pXmlDoc, "//page/body/section[1]/infos/bounds"_ostr, "height"_ostr, u"0"_ustr); + // Check that the top margin (1 in = 1440 twip) is added to line height (12 pt = 240 twip) + assertXPath(pXmlDoc, "//page/body/section[2]/infos/bounds"_ostr, "height"_ostr, u"1680"_ustr); +} + +CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testPageBreakInHiddenSection) +{ + // Given a paragraph with page-break-before with page style and page number + createSwDoc("pageBreakInHiddenSection.fodt"); + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page"_ostr, 4); + assertXPath(pXmlDoc, "//section"_ostr, 4); + assertXPath(pXmlDoc, "//page[1]/body/txt"_ostr, 1); + // The page break inside the hidden section is ignored (otherwise, there would be one section + // on the first page) + assertXPath(pXmlDoc, "//page[1]/body/section"_ostr, 2); + // The first section is hidden + assertXPath(pXmlDoc, "//page[1]/body/section[1]/infos/bounds"_ostr, "height"_ostr, u"0"_ustr); + + // Page 2 is empty even page (generated by the next page's section with page-break-before) + assertXPath(pXmlDoc, "//page[2]/body"_ostr, 0); + + // The section on page 3 is not hidden, only text in it is, therefore its page break works + assertXPath(pXmlDoc, "//page[3]/body/section"_ostr, 1); + assertXPath(pXmlDoc, "//page[3]/body/section/infos/bounds"_ostr, "height"_ostr, u"0"_ustr); + + // The section on page 4 is hidden, thus page break in it is ignored (no further pages, where + // the section would be moved to otherwise) + assertXPath(pXmlDoc, "//page[4]/body/section"_ostr, 1); + assertXPath(pXmlDoc, "//page[4]/body/section/infos/bounds"_ostr, "height"_ostr, u"0"_ustr); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/odfexport/data/bookmark_order.fodt b/sw/qa/extras/odfexport/data/bookmark_order.fodt new file mode 100644 index 0000000000..c7eac58758 --- /dev/null +++ b/sw/qa/extras/odfexport/data/bookmark_order.fodt @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:body> + <office:text> + <text:p><text:bookmark-start text:name="bookmark1"/>foo<text:bookmark-end text:name="bookmark1"/><text:bookmark text:name="bookmark2"/><text:bookmark-start text:name="bookmark3"/>bar<text:bookmark-end text:name="bookmark3"/></text:p> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/qa/extras/odfexport/odfexport2.cxx b/sw/qa/extras/odfexport/odfexport2.cxx index 37e744e9c8..4983608290 100644 --- a/sw/qa/extras/odfexport/odfexport2.cxx +++ b/sw/qa/extras/odfexport/odfexport2.cxx @@ -1247,6 +1247,102 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf159382) } } +CPPUNIT_TEST_FIXTURE(Test, testTdf159438) +{ + // Given a text with bookmarks, where an end of one bookmark is the position of another, + // and the start of a third + loadAndReload("bookmark_order.fodt"); + auto xPara = getParagraph(1); + + // Check that the order of runs is correct (bookmarks don't overlap) + + { + auto run = getRun(xPara, 1); + CPPUNIT_ASSERT_EQUAL(u"Bookmark"_ustr, getProperty<OUString>(run, "TextPortionType")); + CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(run, "IsStart")); + CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(run, "IsCollapsed")); + auto named = getProperty<uno::Reference<container::XNamed>>(run, "Bookmark"); + CPPUNIT_ASSERT_EQUAL(u"bookmark1"_ustr, named->getName()); + } + + { + auto run = getRun(xPara, 2); + CPPUNIT_ASSERT_EQUAL(u"Text"_ustr, getProperty<OUString>(run, "TextPortionType")); + CPPUNIT_ASSERT_EQUAL(u"foo"_ustr, run->getString()); + } + + { + auto run = getRun(xPara, 3); + CPPUNIT_ASSERT_EQUAL(u"Bookmark"_ustr, getProperty<OUString>(run, "TextPortionType")); + CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(run, "IsStart")); + CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(run, "IsCollapsed")); + auto named = getProperty<uno::Reference<container::XNamed>>(run, "Bookmark"); + CPPUNIT_ASSERT_EQUAL(u"bookmark1"_ustr, named->getName()); + } + + { + auto run = getRun(xPara, 4); + CPPUNIT_ASSERT_EQUAL(u"Bookmark"_ustr, getProperty<OUString>(run, "TextPortionType")); + CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(run, "IsStart")); + CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(run, "IsCollapsed")); + auto named = getProperty<uno::Reference<container::XNamed>>(run, "Bookmark"); + CPPUNIT_ASSERT_EQUAL(u"bookmark2"_ustr, named->getName()); + } + + { + auto run = getRun(xPara, 5); + CPPUNIT_ASSERT_EQUAL(u"Bookmark"_ustr, getProperty<OUString>(run, "TextPortionType")); + CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(run, "IsStart")); + CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(run, "IsCollapsed")); + auto named = getProperty<uno::Reference<container::XNamed>>(run, "Bookmark"); + CPPUNIT_ASSERT_EQUAL(u"bookmark3"_ustr, named->getName()); + } + + { + auto run = getRun(xPara, 6); + CPPUNIT_ASSERT_EQUAL(u"Text"_ustr, getProperty<OUString>(run, "TextPortionType")); + CPPUNIT_ASSERT_EQUAL(u"bar"_ustr, run->getString()); + } + + { + auto run = getRun(xPara, 7); + CPPUNIT_ASSERT_EQUAL(u"Bookmark"_ustr, getProperty<OUString>(run, "TextPortionType")); + CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(run, "IsStart")); + CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(run, "IsCollapsed")); + auto named = getProperty<uno::Reference<container::XNamed>>(run, "Bookmark"); + CPPUNIT_ASSERT_EQUAL(u"bookmark3"_ustr, named->getName()); + } + + // Test that the markup stays at save-and-reload + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + + assertXPathNodeName(pXmlDoc, "//office:body/office:text/text:p/*[1]"_ostr, + "bookmark-start"_ostr); + assertXPath(pXmlDoc, "//office:body/office:text/text:p/*[1]"_ostr, "name"_ostr, + u"bookmark1"_ustr); + + // Without the fix in place, this would fail with + // - Expected: bookmark-end + // - Actual : bookmark-start + // - In XPath '//office:body/office:text/text:p/*[2]' name of node is incorrect + assertXPathNodeName(pXmlDoc, "//office:body/office:text/text:p/*[2]"_ostr, "bookmark-end"_ostr); + assertXPath(pXmlDoc, "//office:body/office:text/text:p/*[2]"_ostr, "name"_ostr, + u"bookmark1"_ustr); + + assertXPathNodeName(pXmlDoc, "//office:body/office:text/text:p/*[3]"_ostr, "bookmark"_ostr); + assertXPath(pXmlDoc, "//office:body/office:text/text:p/*[3]"_ostr, "name"_ostr, + u"bookmark2"_ustr); + + assertXPathNodeName(pXmlDoc, "//office:body/office:text/text:p/*[4]"_ostr, + "bookmark-start"_ostr); + assertXPath(pXmlDoc, "//office:body/office:text/text:p/*[4]"_ostr, "name"_ostr, + u"bookmark3"_ustr); + + assertXPathNodeName(pXmlDoc, "//office:body/office:text/text:p/*[5]"_ostr, "bookmark-end"_ostr); + assertXPath(pXmlDoc, "//office:body/office:text/text:p/*[5]"_ostr, "name"_ostr, + u"bookmark3"_ustr); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/ooxmlexport/data/tdf158597.docx b/sw/qa/extras/ooxmlexport/data/tdf158597.docx Binary files differnew file mode 100644 index 0000000000..ad7924ce71 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf158597.docx diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx index cdcdfe7785..e902f7a7b8 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx @@ -9,12 +9,15 @@ #include <swmodeltestbase.hxx> +#include <com/sun/star/awt/FontSlant.hpp> #include <com/sun/star/beans/XPropertyState.hpp> #include <com/sun/star/text/XDocumentIndex.hpp> #include <com/sun/star/text/XTextTable.hpp> #include <com/sun/star/style/LineSpacing.hpp> #include <com/sun/star/style/LineSpacingMode.hpp> +#include <comphelper/sequenceashashmap.hxx> + #include <pam.hxx> #include <unotxdoc.hxx> #include <docsh.hxx> @@ -30,6 +33,261 @@ public: } }; +DECLARE_OOXMLEXPORT_TEST(testTdf158597, "tdf158597.docx") +{ + // test with 2 properties: font size, italic (toggle) + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(1)); + CPPUNIT_ASSERT_EQUAL(OUString("No style"), xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(11.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE, getProperty<awt::FontSlant>(xRun, "CharPosture")); + CPPUNIT_ASSERT(!xProps->getPropertyValue("ListAutoFormat").hasValue()); + } + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(2)); + CPPUNIT_ASSERT_EQUAL(OUString("Char style mark"), xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(11.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE, getProperty<awt::FontSlant>(xRun, "CharPosture")); + comphelper::SequenceAsHashMap listAutoFormat(xProps->getPropertyValue("ListAutoFormat")); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), listAutoFormat["CharStyleName"].get<OUString>()); + CPPUNIT_ASSERT(!listAutoFormat["CharHeight"].hasValue()); + CPPUNIT_ASSERT(!listAutoFormat["CharPosture"].hasValue()); + } + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(3)); + CPPUNIT_ASSERT_EQUAL(OUString("Char style mark and text"), xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(16.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + getProperty<awt::FontSlant>(xRun, "CharPosture")); + comphelper::SequenceAsHashMap listAutoFormat(xProps->getPropertyValue("ListAutoFormat")); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), listAutoFormat["CharStyleName"].get<OUString>()); + CPPUNIT_ASSERT(!listAutoFormat["CharHeight"].hasValue()); + CPPUNIT_ASSERT(!listAutoFormat["CharPosture"].hasValue()); + } + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(4)); + CPPUNIT_ASSERT_EQUAL(OUString("Char style text"), xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(16.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + getProperty<awt::FontSlant>(xRun, "CharPosture")); + CPPUNIT_ASSERT(!xProps->getPropertyValue("ListAutoFormat").hasValue()); + } + + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(5)); + CPPUNIT_ASSERT_EQUAL(OUString("Para style"), xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph E"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(16.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + getProperty<awt::FontSlant>(xRun, "CharPosture")); + CPPUNIT_ASSERT(!xProps->getPropertyValue("ListAutoFormat").hasValue()); + } + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(6)); + CPPUNIT_ASSERT_EQUAL(OUString("Para style + Char style mark"), xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph E"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(16.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + getProperty<awt::FontSlant>(xRun, "CharPosture")); + comphelper::SequenceAsHashMap listAutoFormat(xProps->getPropertyValue("ListAutoFormat")); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), listAutoFormat["CharStyleName"].get<OUString>()); + CPPUNIT_ASSERT(!listAutoFormat["CharHeight"].hasValue()); + // bug was that here the toggle property was not overwritten + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE, + listAutoFormat["CharPosture"].get<awt::FontSlant>()); + } + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(7)); + CPPUNIT_ASSERT_EQUAL(OUString("Para style + Char style mark and text"), + xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph E"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(16.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE, getProperty<awt::FontSlant>(xRun, "CharPosture")); + comphelper::SequenceAsHashMap listAutoFormat(xProps->getPropertyValue("ListAutoFormat")); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), listAutoFormat["CharStyleName"].get<OUString>()); + CPPUNIT_ASSERT(!listAutoFormat["CharHeight"].hasValue()); + // bug was that here the toggle property was not overwritten + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE, + listAutoFormat["CharPosture"].get<awt::FontSlant>()); + } + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(8)); + CPPUNIT_ASSERT_EQUAL(OUString("Para style + Char style text"), xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph E"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(16.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE, getProperty<awt::FontSlant>(xRun, "CharPosture")); + CPPUNIT_ASSERT(!xProps->getPropertyValue("ListAutoFormat").hasValue()); + } + + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(9)); + CPPUNIT_ASSERT_EQUAL(OUString("No style + direct mark"), xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(11.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE, getProperty<awt::FontSlant>(xRun, "CharPosture")); + comphelper::SequenceAsHashMap listAutoFormat(xProps->getPropertyValue("ListAutoFormat")); + CPPUNIT_ASSERT(!listAutoFormat["CharStyleName"].hasValue()); + CPPUNIT_ASSERT_EQUAL(16.f, listAutoFormat["CharHeight"].get<float>()); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + listAutoFormat["CharPosture"].get<awt::FontSlant>()); + } + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(10)); + CPPUNIT_ASSERT_EQUAL(OUString("Char style + direct mark"), xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(11.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE, getProperty<awt::FontSlant>(xRun, "CharPosture")); + comphelper::SequenceAsHashMap listAutoFormat(xProps->getPropertyValue("ListAutoFormat")); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), listAutoFormat["CharStyleName"].get<OUString>()); + CPPUNIT_ASSERT_EQUAL(16.f, listAutoFormat["CharHeight"].get<float>()); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + listAutoFormat["CharPosture"].get<awt::FontSlant>()); + } + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(11)); + CPPUNIT_ASSERT_EQUAL(OUString("Char style + direct mark and text"), + xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(16.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + getProperty<awt::FontSlant>(xRun, "CharPosture")); + comphelper::SequenceAsHashMap listAutoFormat(xProps->getPropertyValue("ListAutoFormat")); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), listAutoFormat["CharStyleName"].get<OUString>()); + CPPUNIT_ASSERT_EQUAL(16.f, listAutoFormat["CharHeight"].get<float>()); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + listAutoFormat["CharPosture"].get<awt::FontSlant>()); + } + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(12)); + CPPUNIT_ASSERT_EQUAL(OUString("Char style + direct text"), xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(16.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + getProperty<awt::FontSlant>(xRun, "CharPosture")); + CPPUNIT_ASSERT(!xProps->getPropertyValue("ListAutoFormat").hasValue()); + } + + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(13)); + CPPUNIT_ASSERT_EQUAL(OUString("Para style + direct mark"), xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph E"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(16.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + getProperty<awt::FontSlant>(xRun, "CharPosture")); + comphelper::SequenceAsHashMap listAutoFormat(xProps->getPropertyValue("ListAutoFormat")); + CPPUNIT_ASSERT(!listAutoFormat["CharStyleName"].hasValue()); + CPPUNIT_ASSERT_EQUAL(16.f, listAutoFormat["CharHeight"].get<float>()); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + listAutoFormat["CharPosture"].get<awt::FontSlant>()); + } + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(14)); + CPPUNIT_ASSERT_EQUAL(OUString("Para style + Char style + direct mark"), + xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph E"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(16.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + getProperty<awt::FontSlant>(xRun, "CharPosture")); + comphelper::SequenceAsHashMap listAutoFormat(xProps->getPropertyValue("ListAutoFormat")); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), listAutoFormat["CharStyleName"].get<OUString>()); + CPPUNIT_ASSERT_EQUAL(16.f, listAutoFormat["CharHeight"].get<float>()); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + listAutoFormat["CharPosture"].get<awt::FontSlant>()); + } + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(15)); + CPPUNIT_ASSERT_EQUAL(OUString("Para style + Char style + direct mark and text"), + xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph E"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(16.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + getProperty<awt::FontSlant>(xRun, "CharPosture")); + comphelper::SequenceAsHashMap listAutoFormat(xProps->getPropertyValue("ListAutoFormat")); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), listAutoFormat["CharStyleName"].get<OUString>()); + CPPUNIT_ASSERT_EQUAL(16.f, listAutoFormat["CharHeight"].get<float>()); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + listAutoFormat["CharPosture"].get<awt::FontSlant>()); + } + { + uno::Reference<text::XTextRange> xParagraph(getParagraph(16)); + CPPUNIT_ASSERT_EQUAL(OUString("Para style + Char style + direct text"), + xParagraph->getString()); + uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("List Paragraph E"), + getProperty<OUString>(xProps, "ParaStyleName")); + uno::Reference<text::XTextRange> xRun(getRun(xParagraph, 1)); + CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), getProperty<OUString>(xRun, "CharStyleName")); + CPPUNIT_ASSERT_EQUAL(16.f, getProperty<float>(xRun, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, + getProperty<awt::FontSlant>(xRun, "CharPosture")); + CPPUNIT_ASSERT(!xProps->getPropertyValue("ListAutoFormat").hasValue()); + } +} + DECLARE_OOXMLEXPORT_TEST(testTdf153909_followTextFlow, "tdf153909_followTextFlow.docx") { // Although MSO's UI reports "layoutInCell" for the rectangle, it isn't specified or honored diff --git a/sw/qa/extras/rtfexport/data/fdo55504-1-min.rtf b/sw/qa/extras/rtfexport/data/fdo55504-1-min.rtf new file mode 100644 index 0000000000..6e76676299 --- /dev/null +++ b/sw/qa/extras/rtfexport/data/fdo55504-1-min.rtf @@ -0,0 +1,49 @@ +{\rtf1\adeflang1025\ansi\ansicpg1251\uc1\adeff0\deff0\stshfdbch0\stshfloch0\stshfhich0\stshfbi0\deflang1049\deflangfe1049{\fonttbl{\f0\froman\fcharset204\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset204\fprq2{\*\panose 020b0604020202020204}Arial;}{\f39\froman\fcharset0\fprq2 Times New Roman;}
+{\f37\froman\fcharset238\fprq2 Times New Roman CE;}{\f40\froman\fcharset161\fprq2 Times New Roman Greek;}{\f41\froman\fcharset162\fprq2 Times New Roman Tur;}{\f42\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\f43\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f44\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f45\froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f49\fswiss\fcharset0\fprq2 Arial;}
+{\f47\fswiss\fcharset238\fprq2 Arial CE;}{\f50\fswiss\fcharset161\fprq2 Arial Greek;}{\f51\fswiss\fcharset162\fprq2 Arial Tur;}{\f52\fbidi \fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f53\fbidi \fswiss\fcharset178\fprq2 Arial (Arabic);}
+{\f54\fswiss\fcharset186\fprq2 Arial Baltic;}{\f55\fswiss\fcharset163\fprq2 Arial (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;
+\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{
+\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1049\langfe1049\cgrid\langnp1049\langfenp1049 \snext0 Normal;}{\*\cs10 \additive \ssemihidden
+Default Paragraph Font;}{\*\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv
+\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \fs20\lang1024\langfe1024\cgrid\langnp1024\langfenp1024 \snext11 \ssemihidden Normal Table;}}
+{\*\latentstyles\lsdstimax156\lsdlockeddef0}{\*\revtbl {Unknown;}}{\*\rsidtbl \rsid3757467}{\*\generator Microsoft Word 11.0.0000;}{\info{\title \'d1\'cf\'d0\'c0\'c2\'ca\'c0 \'b9 6785}{\author Crystal Reports}{\doccomm Powered By Crystal}
+{\operator \'cf\'f0\'ee\'e3\'f0\'e0\'ec\'ec\'e8\'f1\'f2}{\creatim\yr2012\mo9\dy26\hr11\min39}{\revtim\yr2012\mo9\dy26\hr11\min39}{\version2}{\edmins0}{\nofpages2}{\nofwords529}{\nofchars3021}{\*\company Crystal Decisions}{\nofcharsws3543}
+{\vern24611}{\*\password 00000000}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw16836\paperh11904\margl567\margr397\margt567\margb284\gutter0\ltrsect
+\widowctrl\ftnbj\aenddoc\donotembedsysfont0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\horzdoc\dghspace120\dgvspace120\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3
+\jcompress\viewkind1\viewscale100\rsidroot3757467 \fet0{\*\wgrffmtfilter 013f}\ilfomacatclnup0\ltrpar \sectd \ltrsect\lndscpsxn\sbknone\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2
+\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6
+\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang
+{\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\qc \li0\ri0\nowidctlpar
+\tx360\tx720\tx1080\tx1440\tx1800\tx2160\tx2520\tx2880\tx3240\tx3600\tx3960\tx4320\tx4680\tx5040\tx5400\tx5760\tx6120\tx6480\tx6840\tx7200\tx7560\tx7920\tx8280\tx8640\tx9000\tx9360\tx9720\tx10080\tx10440\tx10800\tx11160\tx11520\tx11880
+\tx12240\tx12600\pvpg\phpg\posx2007\posy597\absh-900\absw12870\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1049\langfe1049\cgrid\langnp1049\langfenp1049 {\rtlch\fcs1 \af0 \ltrch\fcs0
+\lang1024\langfe1024\noproof\insrsid3757467 {\shp{\*\shpinst\shpleft6567\shptop3832\shpright8713\shpbottom3832\shpfhdr0\shpbxpage\shpbxignore\shpbypage\shpbyignore\shpwr3\shpwrk0\shpfblwtxt1\shpz0\shplid1026
+{\sp{\sn shapeType}{\sv 20}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}{\sp{\sn lineWidth}{\sv 12700}}{\sp{\sn fLine}{\sv 1}}{\sp{\sn posrelh}{\sv 1}}{\sp{\sn posrelv}{\sv 1}}{\sp{\sn fLayoutInCell}{\sv 0}}{\sp{\sn fBehindDocument}{\sv 1}}
+{\sp{\sn fLayoutInCell}{\sv 0}}}{\shprslt{\*\do\dobxpage\dobypage\dodhgt0\dpline\dpptx0\dppty0\dpptx2146\dppty0\dpx6567\dpy3832\dpxsize2146\dpysize0\dplinew20\dplinecor0\dplinecog0\dplinecob0}}}
+{\shp{\*\shpinst\shpleft9912\shptop3862\shpright12073\shpbottom3862\shpfhdr0\shpbxpage\shpbxignore\shpbypage\shpbyignore\shpwr3\shpwrk0\shpfblwtxt1\shpz1\shplid1027{\sp{\sn shapeType}{\sv 20}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}
+{\sp{\sn lineWidth}{\sv 12700}}{\sp{\sn fLine}{\sv 1}}{\sp{\sn posrelh}{\sv 1}}{\sp{\sn posrelv}{\sv 1}}{\sp{\sn fLayoutInCell}{\sv 0}}{\sp{\sn fBehindDocument}{\sv 1}}{\sp{\sn fLayoutInCell}{\sv 0}}}{\shprslt{\*\do\dobxpage\dobypage\dodhgt1
+\dpline\dpptx0\dppty0\dpptx2161\dppty0\dpx9912\dpy3862\dpxsize2161\dpysize0\dplinew20\dplinecor0\dplinecog0\dplinecob0}}}
+}
+{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\f1\fs17\cf1\insrsid3757467 \'d1\'cf\'d0\'c0\'c2\'ca\'c0 \'b9 6785}{\rtlch\fcs1 \af1 \ltrch\fcs0
+\f1\insrsid3757467
+\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\f1\fs17\cf1\insrsid3757467 \'ce \'d1\'ce\'d1\'d2\'ce\'df\'cd\'c8\'c8 \'d0\'c0\'d1\'d7\'c5\'d2\'ce\'c2 \'cf\'ce \'cd\'c0\'cb\'ce\'c3\'c0\'cc, \'d1\'c1\'ce\'d0\'c0\'cc, \'cf\'c5\'cd\'df\'cc \'c8 \'d8\'d2\'d0\'c0\'d4\'c0\'cc
+}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3757467
+\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\f1\fs17\cf1\insrsid3757467 \'ee\'f0\'e3\'e0\'ed\'e8\'e7\'e0\'f6\'e8\'e9 \'e8 \'e8\'ed\'e4\'e8\'e2\'e8\'e4\'f3\'e0\'eb\'fc\'ed\'fb\'f5 \'ef\'f0\'e5\'e4\'ef\'f0\'e8\'ed\'e8\'ec\'e0\'f2\'e5\'eb\'e5\'e9}{\rtlch\fcs1 \af1
+\ltrch\fcs0 \f1\insrsid3757467
+\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\f1\fs17\cf1\insrsid3757467 \'ef\'ee \'f1\'ee\'f1\'f2\'ee\'ff\'ed\'e8\'fe \'ed\'e0 << 26 >> \'d1\'e5\'ed\'f2\'ff\'e1\'f0\'fc 2012\'e3.}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3757467
+\par }
+\pard \ltrpar\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3757467 \page \sect }\sectd \ltrsect\lndscpsxn\sbknone\linex0\sectdefaultcl\sftnbj \pard\plain \ltrpar\ql \li0\ri0\nowidctlpar
+\tx360\tx720\tx1080\tx1440\tx1800\tx2160\tx2520\tx2880\tx3240\tx3600\tx3960\tx4320\tx4680\tx5040\tx5400\tx5760\tx6120\tx6480\tx6840\tx7200\tx7560\tx7920\tx8280\tx8640\tx9000\tx9360\tx9720\tx10080\tx10440\tx10800\tx11160\tx11520\tx11880
+\tx12240\pvpg\phpg\posx612\posy627\absh-225\absw12480\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1049\langfe1049\cgrid\langnp1049\langfenp1049 {\rtlch\fcs1 \af0 \ltrch\fcs0
+\lang1024\langfe1024\noproof\insrsid3757467 {\shp{\*\shpinst\shpleft567\shptop867\shpright16423\shpbottom867\shpfhdr0\shpbxpage\shpbxignore\shpbypage\shpbyignore\shpwr3\shpwrk0\shpfblwtxt1\shpz29\shplid1055
+{\sp{\sn shapeType}{\sv 20}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}{\sp{\sn lineWidth}{\sv 12700}}{\sp{\sn fLine}{\sv 1}}{\sp{\sn posrelh}{\sv 1}}{\sp{\sn posrelv}{\sv 1}}{\sp{\sn fLayoutInCell}{\sv 0}}{\sp{\sn fBehindDocument}{\sv 1}}
+{\sp{\sn fLayoutInCell}{\sv 0}}}{\shprslt{\*\do\dobxpage\dobypage\dodhgt29\dpline\dpptx0\dppty0\dpptx15856\dppty0\dpx567\dpy867\dpxsize15856\dpysize0\dplinew20\dplinecor0\dplinecog0\dplinecob0}}}
+{\shp{\*\shpinst\shpleft567\shptop1167\shpright16439\shpbottom1167\shpfhdr0\shpbxpage\shpbxignore\shpbypage\shpbyignore\shpwr3\shpwrk0\shpfblwtxt1\shpz30\shplid1056{\sp{\sn shapeType}{\sv 20}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}
+{\sp{\sn lineWidth}{\sv 12700}}{\sp{\sn fLine}{\sv 1}}{\sp{\sn posrelh}{\sv 1}}{\sp{\sn posrelv}{\sv 1}}{\sp{\sn fLayoutInCell}{\sv 0}}{\sp{\sn fBehindDocument}{\sv 1}}{\sp{\sn fLayoutInCell}{\sv 0}}}{\shprslt{\*\do\dobxpage\dobypage\dodhgt30
+\dpline\dpptx0\dppty0\dpptx15872\dppty0\dpx567\dpy1167\dpxsize15872\dpysize0\dplinew20\dplinecor0\dplinecog0\dplinecob0}}}
+}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\fs17\cf1\insrsid3757467 \'cc\'f3\'ed\'e8\'f6\'e8\'ef\'e0\'eb\'fc\'ed\'ee\'e5 \'e4\'ee\'f8\'ea\'ee
+\'eb\'fc\'ed\'ee\'e5 \'ee\'e1\'f0\'e0\'e7\'ee\'e2\'e0\'f2\'e5\'eb\'fc\'ed\'ee\'e5 \'f3\'f7\'f0\'e5\'e6\'e4\'e5\'ed\'e8\'e5 \'e4\'e5\'f2\'f1\'ea\'e8\'e9 \'f1\'e0\'e4 \'b99 "\'d0\'ee\'ec\'e0\'f8\'ea\'e0" \'ca\'f3\'f0\'f1\'ea\'ee\'e3\'ee \'ec\'f3\'ed\'e8\'f6
+\'e8\'ef\'e0\'eb\'fc\'ed\'ee\'e3\'ee \'f0\'e0\'e9\'ee\'ed\'e0 \'d1\'f2\'e0\'e2\'f0\'ee\'ef\'ee\'eb\'fc\'f1\'ea\'ee\'e3\'ee \'ea\'f0\'e0\'ff}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3757467
+\par }
+\pard \ltrpar\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3757467
+\par }}
diff --git a/sw/qa/extras/rtfexport/data/piccrop.rtf b/sw/qa/extras/rtfexport/data/piccrop.rtf new file mode 100644 index 0000000000..4e8a704205 --- /dev/null +++ b/sw/qa/extras/rtfexport/data/piccrop.rtf @@ -0,0 +1,74 @@ +{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi31507\deflang1033\deflangfe1028\themelang1033\themelangfe1028\themelangcs1025{\fonttbl{\f1\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial{\*\falt Arial};}
+{\f14\fbidi \fnil\fcharset136\fprq2{\*\panose 02010601000101010101}PMingLiU{\*\falt Arial Unicode MS};}{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;}
+{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\f291\fbidi \fnil\fcharset136\fprq2{\*\panose 00000000000000000000}@PMingLiU;}
+{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Arial};}{\fdbmajor\f31501\fbidi \fnil\fcharset136\fprq2{\*\panose 02010601000101010101}PMingLiU{\*\falt Arial Unicode MS};}
+{\fhimajor\f31502\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0302020204030204}Calibri Light;}{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Arial};}
+{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Arial};}{\fdbminor\f31505\fbidi \fnil\fcharset136\fprq2{\*\panose 02010601000101010101}PMingLiU{\*\falt Arial Unicode MS};}
+{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\fbiminor\f31507\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial{\*\falt Arial};}{\f302\fbidi \fswiss\fcharset238\fprq2 Arial CE{\*\falt Arial};}
+{\f303\fbidi \fswiss\fcharset204\fprq2 Arial Cyr{\*\falt Arial};}{\f305\fbidi \fswiss\fcharset161\fprq2 Arial Greek{\*\falt Arial};}{\f306\fbidi \fswiss\fcharset162\fprq2 Arial Tur{\*\falt Arial};}
+{\f307\fbidi \fswiss\fcharset177\fprq2 Arial (Hebrew){\*\falt Arial};}{\f308\fbidi \fswiss\fcharset178\fprq2 Arial (Arabic){\*\falt Arial};}{\f309\fbidi \fswiss\fcharset186\fprq2 Arial Baltic{\*\falt Arial};}
+{\f310\fbidi \fswiss\fcharset163\fprq2 Arial (Vietnamese){\*\falt Arial};}{\f632\fbidi \froman\fcharset238\fprq2 Cambria Math CE;}{\f633\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr;}{\f635\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;}
+{\f636\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;}{\f639\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;}{\f640\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese);}{\f662\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}
+{\f663\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\f665\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f666\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f667\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}
+{\f668\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\f669\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\f670\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}
+{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Arial};}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Arial};}
+{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Arial};}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Arial};}
+{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Arial};}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Arial};}
+{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Arial};}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Arial};}{\fhimajor\f31528\fbidi \fswiss\fcharset238\fprq2 Calibri Light CE;}
+{\fhimajor\f31529\fbidi \fswiss\fcharset204\fprq2 Calibri Light Cyr;}{\fhimajor\f31531\fbidi \fswiss\fcharset161\fprq2 Calibri Light Greek;}{\fhimajor\f31532\fbidi \fswiss\fcharset162\fprq2 Calibri Light Tur;}
+{\fhimajor\f31533\fbidi \fswiss\fcharset177\fprq2 Calibri Light (Hebrew);}{\fhimajor\f31534\fbidi \fswiss\fcharset178\fprq2 Calibri Light (Arabic);}{\fhimajor\f31535\fbidi \fswiss\fcharset186\fprq2 Calibri Light Baltic;}
+{\fhimajor\f31536\fbidi \fswiss\fcharset163\fprq2 Calibri Light (Vietnamese);}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Arial};}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Arial};}
+{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Arial};}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Arial};}
+{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Arial};}{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Arial};}
+{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Arial};}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Arial};}
+{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Arial};}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Arial};}
+{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Arial};}{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Arial};}
+{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Arial};}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Arial};}
+{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Arial};}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Arial};}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}
+{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}
+{\fhiminor\f31573\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\fhiminor\f31574\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}
+{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\fbiminor\f31578\fbidi \fswiss\fcharset238\fprq2 Arial CE{\*\falt Arial};}{\fbiminor\f31579\fbidi \fswiss\fcharset204\fprq2 Arial Cyr{\*\falt Arial};}
+{\fbiminor\f31581\fbidi \fswiss\fcharset161\fprq2 Arial Greek{\*\falt Arial};}{\fbiminor\f31582\fbidi \fswiss\fcharset162\fprq2 Arial Tur{\*\falt Arial};}{\fbiminor\f31583\fbidi \fswiss\fcharset177\fprq2 Arial (Hebrew){\*\falt Arial};}
+{\fbiminor\f31584\fbidi \fswiss\fcharset178\fprq2 Arial (Arabic){\*\falt Arial};}{\fbiminor\f31585\fbidi \fswiss\fcharset186\fprq2 Arial Baltic{\*\falt Arial};}{\fbiminor\f31586\fbidi \fswiss\fcharset163\fprq2 Arial (Vietnamese){\*\falt Arial};}
+{\f292\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Arial};}{\f293\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Arial};}{\f295\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Arial};}
+{\f296\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Arial};}{\f297\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Arial};}{\f298\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Arial};}
+{\f299\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Arial};}{\f300\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Arial};}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;
+\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;
+\red128\green128\blue128;\red192\green192\blue192;}{\*\defchp \fs22\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{
+\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1028\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1028
+\snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
+\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa160\sl259\slmult1
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1028\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1028 \snext11 \ssemihidden \sunhideused
+Normal Table;}}{\*\rsidtbl \rsid1539605\rsid6818220\rsid9513591}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\author ms}{\operator ms}
+{\creatim\yr2024\mo2\dy13\hr14\min53}{\revtim\yr2024\mo2\dy13\hr14\min57}{\version1}{\edmins4}{\nofpages1}{\nofwords0}{\nofchars1}{\nofcharsws1}{\vern57435}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}
+\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect
+\widowctrl\ftnbj\aenddoc\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors1\noxlattoyen
+\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1440\dgvorigin1440\dghshow1\dgvshow1
+\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct
+\asianbrkrule\rsidroot1539605\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0
+{\*\wgrffmtfilter 2450}\nofeaturethrottle1\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\headery708\footery708\colsx708\endnhere\sectlinegrid360\sectdefaultcl\sftnbj
+\pard\plain \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0
+\fs22\lang1033\langfe1028\loch\af31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1028 {\rtlch\fcs1 \af31507 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid9513591\charrsid4597901 {\*\shppict
+{\pict{\*\picprop\shplid1025{\sp{\sn shapeType}{\sv 75}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}{\sp{\sn fLockAspectRatio}{\sv 1}}{\sp{\sn fLockPosition}{\sv 0}}{\sp{\sn fLockAgainstSelect}{\sv 0}}{\sp{\sn fLockAgainstGrouping}{\sv 0}}
+{\sp{\sn pictureGray}{\sv 0}}{\sp{\sn pictureBiLevel}{\sv 0}}{\sp{\sn fFilled}{\sv 0}}{\sp{\sn fLine}{\sv 0}}{\sp{\sn wzName}{\sv Picture 1}}{\sp{\sn dhgt}{\sv 251658240}}{\sp{\sn fHidden}{\sv 0}}{\sp{\sn fLayoutInCell}{\sv 1}}}
+\picscalex780\picscaley780\piccropl70\piccropr70\piccropt70\piccropb70\picw503\pich503\picwgoal285\pichgoal285\pngblip\bliptag-2138324634{\*\blipuid 808bc16643ef1085bdc9d6183a9f49dc}
+89504e470d0a1a0a0000000d4948445200000013000000130806000000725036cc0000000467414d410000d6d8d44f58320000001974455874536f6674776172
+650041646f626520496d616765526561647971c9653c000001694944415478da62fcffff3f03b50040003111a3e8e3646ba26c04082026620ce2bf720cc5c049
+eb57fe076174b50001c4448c41479f3232201bd83b733356f50001c4448c4120806e20360010404cc418c4d1b81dc5c04bdef7192e5d7a8da10f208098883148
+53d312c3c05ea1e518860104101331067171f1613510ddcb0001c4448c4120408c810001c4084ab4f80cfaf6ed13dc6618fffaf5e30c3fea3dc162d6d240fd3a
+560cfcb9471901028809dda0a83f5128068134e6752f02d3203ecc852075e82e040820963b56750c0c5640d700258c8ddd195d1ba7fc87790d64c0f42db71926
+95c6810dcc84a8011be86a69c1605dbf84f1ecd99dffcf425d0e10400c206f22e3e486c9ff41e0ebd78fff416c108d8d0f5587a2172080f0e680ddc74fa04400
+888f0f000410130315014000b160130405f48f1f5fb16ac0250e02000184d53050c0e302f7ef5fc229071040580d03c5200cc87bc4e09443070001c448cd921620c000313009ee012707180000000049454e44ae426082}}{\nonshppict
+{\pict\picscalex781\picscaley790\piccropl70\piccropr70\piccropt70\piccropb70\picw503\pich503\picwgoal285\pichgoal285\wmetafile8\bliptag-2138324634{\*\blipuid 808bc16643ef1085bdc9d6183a9f49dc}
+010009000003370100000000b300000000000400000003010800050000000b0200000000050000000c0214001400030000001e00040000000701040004000000
+070104000800000026060f000600544e505006014b000000410b8600ee0013001300000000001300130000000000280000001300000013000000010001000000
+0000000000000000000000000000000000000000000000000000ffffff000000000c0ffe000c0ffe00000ffe00000ffe00000ffe00000ffe0000effee000ffff
+e0007fffc0003fff80001fff00000ffe000507fe000003fe000c01f6000c00e600000040000000000000b3000000410bc6008800130013000000000013001300
+000000002800000013000000130000000100040000000000000000000000000000000000000000000000000000000000ffffff004ba1f3000078ff00b5baa000
+035dcd006d592c00c3d4d400a2907500f3f7f700eaf0f00000000000000000000000000000000000000000001111111111111111111001011111888666668881
+11100101111187761116778111100801111189a61116a98111100706111181961116918111100100111181961116918111100106111181989198918111100101
+77718117898711817770080123556919787919655320090612355791999197553210010011235579111975532110090811123557919755321110070111112355
+797553211110080111111235575532811110010911111123555326411110024c1111111235321641111009011111111123211441111002031111111112111111111005031111111111111111111005070800000026060f000600544e50500701040000002701ffff030000000000}}}{\rtlch\fcs1 \af31507
+\ltrch\fcs0 \insrsid6818220
+\par }
+}
diff --git a/sw/qa/extras/rtfexport/data/tdf159824_axialGradient.odt b/sw/qa/extras/rtfexport/data/tdf159824_axialGradient.odt Binary files differnew file mode 100644 index 0000000000..c1ce5cd31d --- /dev/null +++ b/sw/qa/extras/rtfexport/data/tdf159824_axialGradient.odt diff --git a/sw/qa/extras/rtfexport/rtfexport2.cxx b/sw/qa/extras/rtfexport/rtfexport2.cxx index c718dfffd7..e194db83e4 100644 --- a/sw/qa/extras/rtfexport/rtfexport2.cxx +++ b/sw/qa/extras/rtfexport/rtfexport2.cxx @@ -523,7 +523,8 @@ DECLARE_RTFEXPORT_TEST(testFdo48446, "fdo48446.rtf") DECLARE_RTFEXPORT_TEST(testFdo47495, "fdo47495.rtf") { // Used to have 4 paragraphs, as a result the original bugdoc had 2 pages instead of 1. - CPPUNIT_ASSERT_EQUAL(2, getParagraphs()); + // Word 2013 shows 1 paragraph + CPPUNIT_ASSERT_EQUAL(1, getParagraphs()); } DECLARE_RTFEXPORT_TEST(testAllGapsWord, "all_gaps_word.rtf") diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx b/sw/qa/extras/rtfexport/rtfexport8.cxx index 08ca8452f9..ab787919df 100644 --- a/sw/qa/extras/rtfexport/rtfexport8.cxx +++ b/sw/qa/extras/rtfexport/rtfexport8.cxx @@ -9,9 +9,12 @@ #include <swmodeltestbase.hxx> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/awt/Gradient2.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/text/GraphicCrop.hpp> #include <com/sun/star/text/XFootnote.hpp> #include <com/sun/star/text/XFootnotesSupplier.hpp> -#include <com/sun/star/awt/FontWeight.hpp> #include <com/sun/star/text/XEndnotesSupplier.hpp> #include <com/sun/star/text/XTextFieldsSupplier.hpp> #include <com/sun/star/text/XTextTablesSupplier.hpp> @@ -20,7 +23,9 @@ #include <com/sun/star/style/ParagraphAdjust.hpp> #include <com/sun/star/style/TabStop.hpp> +#include <basegfx/utils/gradienttools.hxx> #include <comphelper/sequenceashashmap.hxx> +#include <docmodel/uno/UnoGradientTools.hxx> #include <tools/UnitConversion.hxx> #include <comphelper/propertyvalue.hxx> @@ -48,6 +53,28 @@ public: } }; +DECLARE_RTFEXPORT_TEST(testTdf155663, "piccrop.rtf") +{ + auto const xShape(getShape(1)); + if (!isExported()) + { + CPPUNIT_ASSERT_EQUAL(sal_Int32(2004), xShape->getSize().Height); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2004), xShape->getSize().Width); + } + else // bit of rounding loss? + { + CPPUNIT_ASSERT_EQUAL(sal_Int32(2013), xShape->getSize().Height); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2013), xShape->getSize().Width); + } + CPPUNIT_ASSERT_EQUAL(sal_Int32(123), getProperty<text::GraphicCrop>(xShape, "GraphicCrop").Top); + CPPUNIT_ASSERT_EQUAL(sal_Int32(123), + getProperty<text::GraphicCrop>(xShape, "GraphicCrop").Bottom); + CPPUNIT_ASSERT_EQUAL(sal_Int32(123), + getProperty<text::GraphicCrop>(xShape, "GraphicCrop").Left); + CPPUNIT_ASSERT_EQUAL(sal_Int32(123), + getProperty<text::GraphicCrop>(xShape, "GraphicCrop").Right); +} + DECLARE_RTFEXPORT_TEST(testTdf158586_0, "tdf158586_pageBreak0.rtf") { // The specified page break must be lost because it is in a text frame @@ -109,6 +136,27 @@ DECLARE_RTFEXPORT_TEST(testTdf158586_lostFrame, "tdf158586_lostFrame.rtf") CPPUNIT_ASSERT_EQUAL(2, getPages()); } +DECLARE_RTFEXPORT_TEST(testTdf158983, "fdo55504-1-min.rtf") +{ + // the problem was that the page break was missing and the shapes were + // all anchored to the same node + + const auto& pLayout = parseLayoutDump(); + assertXPath(pLayout, "/root/page[1]/body/section/txt"_ostr, 1); + assertXPath(pLayout, "/root/page[1]/body/section/txt/anchored/fly"_ostr, 1); + // Word shows these shapes anchored in the fly, not body, but at least they are not lost + assertXPath(pLayout, "/root/page[1]/body/section/txt/anchored/SwAnchoredDrawObject"_ostr, 2); + // page break, paragraph break, section break. + assertXPath(pLayout, "/root/page[2]/body/section[1]/txt"_ostr, 1); + assertXPath(pLayout, "/root/page[2]/body/section[1]/txt/anchored"_ostr, 0); + assertXPath(pLayout, "/root/page[2]/body/section[2]/txt"_ostr, 1); + assertXPath(pLayout, "/root/page[2]/body/section[2]/txt/anchored/fly"_ostr, 1); + // Word shows these shapes anchored in the fly, not body, but at least they are not lost + assertXPath(pLayout, "/root/page[2]/body/section[2]/txt/anchored/SwAnchoredDrawObject"_ostr, 2); + + CPPUNIT_ASSERT_EQUAL(2, getPages()); +} + DECLARE_RTFEXPORT_TEST(testAnnotationPar, "tdf136445-1-min.rtf") { // the problem was that the paragraph break following annotation was missing @@ -130,8 +178,38 @@ DECLARE_RTFEXPORT_TEST(testTdf158826_extraCR, "tdf158826_extraCR.rtf") // The page break defined before the document content should not cause a page break CPPUNIT_ASSERT_EQUAL(1, getPages()); - // There is a two-column floating table [that SHOULD be getParagraphOrTable(1)] - uno::Reference<text::XTextTable> xTable(getParagraphOrTable(2), uno::UNO_QUERY_THROW); + // There is a two-column floating table + uno::Reference<text::XTextTable> xTable(getParagraphOrTable(1), uno::UNO_QUERY_THROW); +} + +CPPUNIT_TEST_FIXTURE(Test, testTdf159824_axialGradient) +{ + // given a frame with an axial gradient (white - green - white) + loadAndReload("tdf159824_axialGradient.odt"); + + uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xIndexAccess(xTextFramesSupplier->getTextFrames(), + uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xFrame(xIndexAccess->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_GRADIENT, + getProperty<drawing::FillStyle>(xFrame, "FillStyle")); + awt::Gradient2 aGradient = getProperty<awt::Gradient2>(xFrame, "FillGradient"); + + //const Color aColA(0x127622); // green + //const Color aColB(0xffffff); // white + + // MCGR: Use the completely imported transparency gradient to check for correctness + basegfx::BColorStops aColorStops = model::gradient::getColorStopsFromUno(aGradient.ColorStops); + + // expected: a 3-color linear gradient (or better yet a 2-color AXIAL gradient) + CPPUNIT_ASSERT_EQUAL(size_t(3), aColorStops.size()); + CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_LINEAR, aGradient.Style); + CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[0].getStopOffset(), 0.0)); + //CPPUNIT_ASSERT_EQUAL(aColB, Color(aColorStops[0].getStopColor())); + // CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[1].getStopOffset(), 0.5)); + // CPPUNIT_ASSERT_EQUAL(aColA, Color(aColorStops[1].getStopColor())); + // CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[2].getStopOffset(), 1.0)); + // CPPUNIT_ASSERT_EQUAL(aColB, Color(aColorStops[2].getStopColor())); } DECLARE_RTFEXPORT_TEST(testTdf158830, "tdf158830.rtf") diff --git a/sw/qa/extras/rtfimport/data/tdf153196.rtf b/sw/qa/extras/rtfimport/data/tdf153196.rtf new file mode 100644 index 0000000000..835cdeeb41 --- /dev/null +++ b/sw/qa/extras/rtfimport/data/tdf153196.rtf @@ -0,0 +1,114 @@ +{\rtf1\adeflang1025\ansi\ansicpg1250\uc1\adeff31507\deff0\stshfdbch31506\stshfloch31506\stshfhich31506\stshfbi31507\deflang1038\deflangfe1038\themelang1038\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}
+{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}{\f39\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}
+{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}
+{\fhimajor\f31502\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0302020204030204}Calibri Light;}{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}
+{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}
+{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman{\*\falt Times New Roman};}
+{\f364\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\f365\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}
+{\f367\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\f368\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}
+{\f369\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\f370\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}
+{\f371\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\f372\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}
+{\f364\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\f365\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}
+{\f367\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\f368\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}
+{\f369\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\f370\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}
+{\f371\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\f372\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}{\f754\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}
+{\f755\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\f757\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f758\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f759\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}
+{\f760\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\f761\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\f762\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}
+{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}
+{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}
+{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}
+{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}
+{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}
+{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}
+{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}
+{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}
+{\fhimajor\f31528\fbidi \fswiss\fcharset238\fprq2 Calibri Light CE;}{\fhimajor\f31529\fbidi \fswiss\fcharset204\fprq2 Calibri Light Cyr;}{\fhimajor\f31531\fbidi \fswiss\fcharset161\fprq2 Calibri Light Greek;}
+{\fhimajor\f31532\fbidi \fswiss\fcharset162\fprq2 Calibri Light Tur;}{\fhimajor\f31533\fbidi \fswiss\fcharset177\fprq2 Calibri Light (Hebrew);}{\fhimajor\f31534\fbidi \fswiss\fcharset178\fprq2 Calibri Light (Arabic);}
+{\fhimajor\f31535\fbidi \fswiss\fcharset186\fprq2 Calibri Light Baltic;}{\fhimajor\f31536\fbidi \fswiss\fcharset163\fprq2 Calibri Light (Vietnamese);}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}
+{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}
+{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}
+{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}
+{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}
+{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}
+{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}
+{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}
+{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}
+{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}
+{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}
+{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}
+{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}
+{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\fhiminor\f31573\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}
+{\fhiminor\f31574\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}
+{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE{\*\falt Times New Roman};}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr{\*\falt Times New Roman};}
+{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek{\*\falt Times New Roman};}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur{\*\falt Times New Roman};}
+{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew){\*\falt Times New Roman};}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic){\*\falt Times New Roman};}
+{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic{\*\falt Times New Roman};}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese){\*\falt Times New Roman};}}{\colortbl;\red0\green0\blue0;
+\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;
+\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\*\defchp \f31506\fs22\lang1038\langfe1033\langfenp1033 }{\*\defpap \ql \li0\ri0\sa160\sl259\slmult1
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025
+\ltrch\fcs0 \f31506\fs22\lang1038\langfe1033\cgrid\langnp1038\langfenp1033 \snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
+\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa160\sl259\slmult1
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1038\langfe1033\cgrid\langnp1038\langfenp1033 \snext11 \ssemihidden \sunhideused Normal Table;}{
+\s15\ql \li0\ri0\widctlpar\tqc\tx4513\tqr\tx9026\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1038\langfe1033\cgrid\langnp1038\langfenp1033
+\sbasedon0 \snext15 \slink16 \sunhideused \styrsid13502046 header;}{\*\cs16 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \sbasedon10 \slink15 \slocked \styrsid13502046 Header Char;}{\s17\ql \li0\ri0\widctlpar
+\tqc\tx4513\tqr\tx9026\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1038\langfe1033\cgrid\langnp1038\langfenp1033
+\sbasedon0 \snext17 \slink18 \sunhideused \styrsid13502046 footer;}{\*\cs18 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \sbasedon10 \slink17 \slocked \styrsid13502046 Footer Char;}}{\*\rsidtbl \rsid4006494\rsid12983264\rsid13502046\rsid16343444}
+\paperw11906\paperh16838\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect
+\deftab708\widowctrl\ftnbj\aenddoc\hyphhotz425\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml1\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0
+\showxmlerrors1\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1440\dgvorigin1440\dghshow1\dgvshow1
+\jexpand\viewkind1\viewscale70\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct
+\asianbrkrule\rsidroot13502046\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0
+\nofeaturethrottle1\ilfomacatclnup0
+\ltrpar \sectd \ltrsect\psz9\sbkeven\linex0\headery0\footery397\colsx708\endnhere\titlepg\sectlinegrid360\sectdefaultcl\sectrsid13502046\sftnbj {\footerf \ltrpar \pard\plain \ltrpar\s17\ql \li0\ri0\widctlpar
+\tqc\tx4513\tqr\tx9026\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1038\langfe1033\cgrid\langnp1038\langfenp1033 {\rtlch\fcs1 \af31507 \ltrch\fcs0 \insrsid13502046
+Hello world!
+\par }}{\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}
+{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8
+\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\sa160\sl259\slmult1
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1038\langfe1033\cgrid\langnp1038\langfenp1033 {\rtlch\fcs1 \af31507 \ltrch\fcs0
+\lang1024\langfe1024\noproof\insrsid13502046 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.
+
+\par Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.
+\par Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin pharetra nonummy pede. Mauris et orci.
+\par Aenean nec lorem. In porttitor. Donec laoreet nonummy augue.
+\par Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc. Mauris eget neque at sem venenatis eleifend. Ut nonummy.
+\par Fusce aliquet pede non pede. Suspendisse dapibus lorem pellentesque magna. Integer nulla.
+\par Donec blandit feugiat ligula. Donec hendrerit, felis et imperdiet euismod, purus ipsum pretium metus, in lacinia nulla nisl eget sapien. Donec ut est in lectus consequat consequat.
+\par Etiam eget dui. Aliquam erat volutpat. Sed at lorem in nunc porta tristique.
+\par Proin nec augue. Quisque aliquam tempor magna. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
+\par Nunc ac magna. Maecenas odio dolor, vulputate vel, auctor ac, accumsan id, felis. Pellentesque cursus sagittis felis.
+\par Pellentesque porttitor, velit lacinia egestas auctor, diam eros tempus arcu, nec vulputate augue magna vel risus. Cras non magna vel ante adipiscing rhoncus. Vivamus a mi.
+\par Morbi neque. Aliquam erat volutpat. Integer ultrices lobortis eros.
+\par Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egest
+as. Proin semper, ante vitae sollicitudin posuere, metus quam iaculis nibh, vitae scelerisque nunc massa eget pede. Sed velit urna, interdum vel, ultricies vel, faucibus at, quam.
+\par Donec elit est, consectetuer eget, consequat quis, tempus quis, wisi. In in nunc. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos.
+\par Donec ullamcorper fringilla eros. Fusce in sapien eu purus dapibus commodo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
+\par Cras faucibus condimentum odio. Sed ac ligula. Aliquam at eros.
+\par Etiam at ligula et tellus ullamcorper ultrices. In fermentum, lorem non cursus porttitor, diam urna accumsan lacus, sed interdum wisi nibh nec nisl. Ut tincidunt volutpat urna.
+\par Mauris eleifend nulla eget mauris. Sed cursus quam id felis. Curabitur posuere quam vel nibh.
+\par Cras dapibus dapibus nisl. Vestibulum quis dolor a felis congue vehicula. Maecenas pede purus, tristique ac, tempus eget, egestas quis, mauris.
+\par Curabitur non eros. Nullam hendrerit bibendum justo. Fusce iaculis, est quis lacinia pretium, pede metus molestie lacus, at gravida wisi ante at libero.
+\par Quisque ornare placerat risus. Ut molestie magna at mi. Integer aliquet mauris et nibh.
+\par Ut mattis ligula posuere velit. Nunc sagittis. Curabitur varius fringilla nisl.
+\par Duis pretium mi euismod erat. Maecenas id augue. Nam vulputate.
+\par Duis a quam non neque lobortis malesuada. Praesent euismod. Donec nulla augue, venenatis scelerisque, dapibus a, consequat at, leo.
+\par Pellentesque libero lectus, tristique ac, consectetuer sit amet, imperdiet ut, justo. Sed aliquam odio vitae tortor. Proin hendrerit tempus arcu.
+\par In hac habitasse platea dictumst. Suspendisse potenti. Vivamus vitae massa adipiscing est lacinia sodales.
+\par Donec metus massa, mollis vel, tempus placerat, vestibulum condimentum, ligula. Nunc lacus metus, posuere eget, lacinia eu, varius quis, libero. Aliquam nonummy adipiscing augue.
+\par Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.
+\par Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.
+\par }\pard \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid13502046 {\rtlch\fcs1 \af31507 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid13502046
+Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin pharetra nonummy pede. Mauris et orci.
+\par }{\rtlch\fcs1 \af31507 \ltrch\fcs0 \insrsid13502046
+\par }{\rtlch\fcs1 \af31507 \ltrch\fcs0 \insrsid13502046\charrsid13502046 \sect }\sectd \ltrsect\linex0\headery708\footery708\colsx708\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\footerr \ltrpar \pard\plain \ltrpar\s17\ql \li0\ri0\widctlpar
+\tqc\tx4513\tqr\tx9026\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid13502046 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1038\langfe1033\cgrid\langnp1038\langfenp1033 {\rtlch\fcs1 \af31507 \ltrch\fcs0
+\insrsid13502046 Other footer}{\rtlch\fcs1 \af31507 \ltrch\fcs0 \insrsid13502046\charrsid13502046
+\par }}\pard\plain \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1038\langfe1033\cgrid\langnp1038\langfenp1033 {\rtlch\fcs1
+\af31507 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid13502046
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.
+\par Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.
+\par Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin pharetra nonummy pede. Mauris et orci.
+\par Aenean nec lorem. In porttitor. Donec laoreet nonummy augue.
+\par Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc. Mauris eget neque at sem venenatis eleifend. Ut nonummy.}{\rtlch\fcs1 \af31507 \ltrch\fcs0 \insrsid12983264
+\par }
+}
diff --git a/sw/qa/extras/rtfimport/rtfimport.cxx b/sw/qa/extras/rtfimport/rtfimport.cxx index 1a6d1c9772..58a6857cff 100644 --- a/sw/qa/extras/rtfimport/rtfimport.cxx +++ b/sw/qa/extras/rtfimport/rtfimport.cxx @@ -1602,6 +1602,26 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf115242) getProperty<sal_Int32>(getParagraph(1), "ParaLeftMargin")); } +CPPUNIT_TEST_FIXTURE(Test, testTdf153196) +{ + createSwDoc("tdf153196.rtf"); + + const auto& pLayout = parseLayoutDump(); + + CPPUNIT_ASSERT_EQUAL(4, getPages()); + + // TODO: Writer creates an empty page 1 here, which Word does not + assertXPath(pLayout, "/root/page[1]/footer"_ostr, 0); + assertXPath(pLayout, "/root/page[2]/footer"_ostr, 1); + // the first page (2) has a page style applied, which has a follow page + // style; the problem was that the follow page style had a footer. + assertXPath(pLayout, "/root/page[3]/footer"_ostr, 0); + assertXPath(pLayout, "/root/page[4]/footer"_ostr, 1); + + // TODO exporting this, wrongly produces "even" footer from stashed one + // TODO importing that, wrongly creates a footer even without evenAndOddHeaders +} + CPPUNIT_TEST_FIXTURE(Test, testDefaultValues) { createSwDoc("default-values.rtf"); diff --git a/sw/qa/extras/uiwriter/data/FrameInHiddenSection.fodt b/sw/qa/extras/uiwriter/data/FrameInHiddenSection.fodt new file mode 100644 index 0000000000..2095c71730 --- /dev/null +++ b/sw/qa/extras/uiwriter/data/FrameInHiddenSection.fodt @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:body> + <office:text> + <text:section text:name="Section1"> + <text:section text:name="Section2Hidden" text:display="none"> + <text:p><draw:frame text:anchor-type="paragraph" svg:x="1cm" svg:y="1cm" svg:width="1cm"> + <draw:text-box/> + </draw:frame>lorem</text:p> + </text:section> + <text:section text:name="Section3"/> + <text:section text:name="Section4"/> + <text:section text:name="Section5"> + <text:p>ipsum</text:p> + </text:section> + </text:section> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/qa/extras/uiwriter/data/hiddenSectionsAroundPageBreak.fodt b/sw/qa/extras/uiwriter/data/hiddenSectionsAroundPageBreak.fodt new file mode 100644 index 0000000000..12761847ed --- /dev/null +++ b/sw/qa/extras/uiwriter/data/hiddenSectionsAroundPageBreak.fodt @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph" style:master-page-name="Landscape"> + <style:paragraph-properties style:page-number="auto" fo:break-before="page"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <text:section text:name="Section 1" text:display="none"/> + <text:section text:name="Section 2"> + <text:p text:style-name="P1">A paragraph with a page-break-before</text:p> + </text:section> + <text:section text:name="Section 3" text:display="none"/> + <text:section text:name="Section 4"> + <text:p>Lorem</text:p> + </text:section> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/qa/extras/uiwriter/uiwriter4.cxx b/sw/qa/extras/uiwriter/uiwriter4.cxx index c1f0be1757..98fcbcae22 100644 --- a/sw/qa/extras/uiwriter/uiwriter4.cxx +++ b/sw/qa/extras/uiwriter/uiwriter4.cxx @@ -682,8 +682,7 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testBookmarkCollapsed) // 6. Hit Del, thus deleting "abc" (The bookmark "test" is still there). // 7. Save the document: // <text:p text:style-name="Standard"> -// <text:bookmark-start text:name="test"/> -// <text:bookmark-end text:name="test"/> +// <text:bookmark text:name="test"/> // def // </text:p> // @@ -737,14 +736,10 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testRemoveBookmarkText) // load only content.xml from the resaved document xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); - constexpr OString aPath("/office:document-content/office:body/office:text/text:p"_ostr); - - CPPUNIT_ASSERT_ASSERTION_FAIL(getXPathPosition(pXmlDoc, aPath, "bookmark")); // not found - const int pos2 = getXPathPosition(pXmlDoc, aPath, "bookmark-start"); - const int pos3 = getXPathPosition(pXmlDoc, aPath, "bookmark-end"); - - CPPUNIT_ASSERT_EQUAL(0, pos2); // found, and it is first - CPPUNIT_ASSERT_EQUAL(1, pos3); // found, and it is second + // Bookmark without text becomes collapsed + assertXPath(pXmlDoc, "//office:body/office:text/text:p/text:bookmark"_ostr, 1); + assertXPath(pXmlDoc, "//office:body/office:text/text:p/text:bookmark-start"_ostr, 0); + assertXPath(pXmlDoc, "//office:body/office:text/text:p/text:bookmark-end"_ostr, 0); } // 1. Open a new writer document diff --git a/sw/qa/extras/uiwriter/uiwriter9.cxx b/sw/qa/extras/uiwriter/uiwriter9.cxx index 1a3e49c257..3772955dd9 100644 --- a/sw/qa/extras/uiwriter/uiwriter9.cxx +++ b/sw/qa/extras/uiwriter/uiwriter9.cxx @@ -16,6 +16,8 @@ #include <com/sun/star/text/XTextTable.hpp> #include <com/sun/star/text/XTextViewCursorSupplier.hpp> #include <com/sun/star/text/XPageCursor.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> + #include <comphelper/propertysequence.hxx> #include <swdtflvr.hxx> #include <o3tl/string_view.hxx> @@ -26,8 +28,10 @@ #include <ndtxt.hxx> #include <toxmgr.hxx> #include <IDocumentFieldsAccess.hxx> +#include <IDocumentLayoutAccess.hxx> #include <IDocumentRedlineAccess.hxx> #include <fmtinfmt.hxx> +#include <rootfrm.hxx> namespace { @@ -122,6 +126,80 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf135083) CPPUNIT_ASSERT(!getProperty<OUString>(xLastPara, u"ListId"_ustr).isEmpty()); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testHiddenSectionsAroundPageBreak) +{ + createSwDoc("hiddenSectionsAroundPageBreak.fodt"); + + CPPUNIT_ASSERT_EQUAL(1, getPages()); + + auto xModel(mxComponent.queryThrow<frame::XModel>()); + auto xTextViewCursorSupplier( + xModel->getCurrentController().queryThrow<text::XTextViewCursorSupplier>()); + auto xCursor(xTextViewCursorSupplier->getViewCursor().queryThrow<text::XPageCursor>()); + + // Make sure that the page style is set correctly + xCursor->jumpToFirstPage(); + CPPUNIT_ASSERT_EQUAL(u"Landscape"_ustr, getProperty<OUString>(xCursor, "PageStyleName")); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159565) +{ + // Given a document with a hidden section in the beginning, additionally containing a frame + createSwDoc("FrameInHiddenSection.fodt"); + + dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {}); + + // Check that the selection covers the whole visible text + auto xModel(mxComponent.queryThrow<css::frame::XModel>()); + auto xSelSupplier(xModel->getCurrentController().queryThrow<css::view::XSelectionSupplier>()); + auto xSelections(xSelSupplier->getSelection().queryThrow<css::container::XIndexAccess>()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSelections->getCount()); + auto xSelection(xSelections->getByIndex(0).queryThrow<css::text::XTextRange>()); + + // Without the fix, this would fail - there was no selection + CPPUNIT_ASSERT_EQUAL(u"" SAL_NEWLINE_STRING SAL_NEWLINE_STRING "ipsum"_ustr, + xSelection->getString()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159816) +{ + createSwDoc(); + + SwDoc* pDoc = getSwDoc(); + CPPUNIT_ASSERT(pDoc); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + CPPUNIT_ASSERT(pWrtShell); + + // Add 5 empty paragraphs + pWrtShell->SplitNode(); + pWrtShell->SplitNode(); + pWrtShell->SplitNode(); + pWrtShell->SplitNode(); + pWrtShell->SplitNode(); + + // Add a bookmark at the very end + IDocumentMarkAccess& rIDMA(*pDoc->getIDocumentMarkAccess()); + rIDMA.makeMark(*pWrtShell->GetCursor(), "Mark", IDocumentMarkAccess::MarkType::BOOKMARK, + sw::mark::InsertMode::New); + + // Get coordinates of the end point in the document + SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + SwFrame* pPage = pLayout->Lower(); + SwFrame* pBody = pPage->GetLower(); + SwFrame* pLastPara = pBody->GetLower()->GetNext()->GetNext()->GetNext()->GetNext()->GetNext(); + Point ptTo = pLastPara->getFrameArea().BottomRight(); + + pWrtShell->SelAll(); + + // Drag-n-drop to its own end + rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell); + // Without the fix, this would crash: either in CopyFlyInFlyImpl (tdf#159813): + // Assertion failed: !pCopiedPaM || pCopiedPaM->End()->GetNode() == rRg.aEnd.GetNode() + // or in BigPtrArray::operator[] (tdf#159816): + // Assertion failed: idx < m_nSize + xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/qa/extras/ww8export/data/listWithLgl.doc b/sw/qa/extras/ww8export/data/listWithLgl.doc Binary files differnew file mode 100644 index 0000000000..94de2967fe --- /dev/null +++ b/sw/qa/extras/ww8export/data/listWithLgl.doc diff --git a/sw/qa/extras/ww8export/ww8export4.cxx b/sw/qa/extras/ww8export/ww8export4.cxx index d47c934d9d..d31bf17a31 100644 --- a/sw/qa/extras/ww8export/ww8export4.cxx +++ b/sw/qa/extras/ww8export/ww8export4.cxx @@ -228,6 +228,30 @@ DECLARE_WW8EXPORT_TEST(testInlinePageBreakFirstLine, "inlinePageBreakFirstLine.d CPPUNIT_ASSERT(IsFirstLine(aTextNodes[2])); } +CPPUNIT_TEST_FIXTURE(Test, testLegalNumbering) +{ + auto verify = [this]() { + // Second level's numbering should use Arabic numbers for first level reference + auto xPara = getParagraph(1); + CPPUNIT_ASSERT_EQUAL(OUString("CH I"), getProperty<OUString>(xPara, "ListLabelString")); + xPara = getParagraph(2); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: Sect 1.01 + // - Actual : Sect I.01 + // i.e. fLegal was ignored on import/export. + CPPUNIT_ASSERT_EQUAL(OUString("Sect 1.01"), getProperty<OUString>(xPara, "ListLabelString")); + xPara = getParagraph(3); + CPPUNIT_ASSERT_EQUAL(OUString("CH II"), getProperty<OUString>(xPara, "ListLabelString")); + xPara = getParagraph(4); + CPPUNIT_ASSERT_EQUAL(OUString("Sect 2.01"), getProperty<OUString>(xPara, "ListLabelString")); + }; + + createSwDoc("listWithLgl.doc"); + verify(); + saveAndReload(mpFilter); + verify(); +} + DECLARE_WW8EXPORT_TEST(testNonInlinePageBreakFirstLine, "nonInlinePageBreakFirstLine.doc") { SwDoc* pDoc = getSwDoc(); diff --git a/sw/qa/inc/swmodeltestbase.hxx b/sw/qa/inc/swmodeltestbase.hxx index 950136e66e..669fd6dea4 100644 --- a/sw/qa/inc/swmodeltestbase.hxx +++ b/sw/qa/inc/swmodeltestbase.hxx @@ -273,13 +273,6 @@ protected: int getShapes() const; /** - * Returns an xml stream of an exported file. - * To be used when the exporter doesn't create zip archives, but single files - * (like Flat ODF Export) - */ - xmlDocUniquePtr parseExportedFile(); - - /** * Creates a new document to be used with the internal sw/ API. * * Examples: diff --git a/sw/qa/uitest/data/tdf150443.docx b/sw/qa/uitest/data/tdf150443.docx Binary files differindex 162aec01f9..f1897c4712 100644 --- a/sw/qa/uitest/data/tdf150443.docx +++ b/sw/qa/uitest/data/tdf150443.docx diff --git a/sw/qa/uitest/writer_tests7/tdf150443.py b/sw/qa/uitest/writer_tests7/tdf150443.py index fb39bd8a03..91937551a4 100644 --- a/sw/qa/uitest/writer_tests7/tdf150443.py +++ b/sw/qa/uitest/writer_tests7/tdf150443.py @@ -26,7 +26,9 @@ class tdf150443(UITestCase): xsearch = xDialog.getChild("search") xsearch.executeAction("CLICK", tuple()) #first search xToolkit.processEventsToIdle() - self.assertEqual(get_state_as_dict(xWriterEdit)["CurrentPage"], "4") + page = get_state_as_dict(xWriterEdit)["CurrentPage"] + # page may depend on font subsitution, just check it moved + self.assertTrue(page == "4" or page == "5") # reject the tracked table row in Manage Changes dialog window with self.ui_test.execute_modeless_dialog_through_command(".uno:AcceptTrackedChanges", close_button="close") as xTrackDlg: diff --git a/sw/qa/unit/swmodeltestbase.cxx b/sw/qa/unit/swmodeltestbase.cxx index d5248bd414..730ece0596 100644 --- a/sw/qa/unit/swmodeltestbase.cxx +++ b/sw/qa/unit/swmodeltestbase.cxx @@ -517,12 +517,6 @@ int SwModelTestBase::getShapes() const return xDraws->getCount(); } -xmlDocUniquePtr SwModelTestBase::parseExportedFile() -{ - auto stream(SvFileStream(maTempFile.GetURL(), StreamMode::READ | StreamMode::TEMPORARY)); - return parseXmlStream(&stream); -} - void SwModelTestBase::createSwDoc(const char* pName, const char* pPassword) { if (!pName) diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx index 173414ed4d..b7f6962982 100644 --- a/sw/source/core/crsr/crsrsh.cxx +++ b/sw/source/core/crsr/crsrsh.cxx @@ -775,6 +775,8 @@ static typename SwCursorShell::StartsWith StartsWith(SwStartNode const& rStart) switch (rNode.GetNodeType()) { case SwNodeType::Section: + if (rNode.GetSectionNode()->GetSection().IsHidden()) + return SwCursorShell::StartsWith::HiddenSection; continue; case SwNodeType::Table: return SwCursorShell::StartsWith::Table; @@ -799,11 +801,16 @@ static typename SwCursorShell::StartsWith EndsWith(SwStartNode const& rStart) switch (rNode.GetNodeType()) { case SwNodeType::End: - if (rNode.StartOfSectionNode()->IsTableNode()) + if (auto pStartNode = rNode.StartOfSectionNode(); pStartNode->IsTableNode()) { return SwCursorShell::StartsWith::Table; } -//TODO buggy SwUndoRedline in testTdf137503? assert(rNode.StartOfSectionNode()->IsSectionNode()); + else if (pStartNode->IsSectionNode()) + { + if (pStartNode->GetSectionNode()->GetSection().IsHidden()) + return SwCursorShell::StartsWith::HiddenSection; + } + //TODO buggy SwUndoRedline in testTdf137503? assert(rNode.StartOfSectionNode()->IsSectionNode()); break; case SwNodeType::Text: if (rNode.GetTextNode()->IsHidden()) @@ -944,14 +951,14 @@ bool SwCursorShell::MovePage( SwWhichPage fnWhichPage, SwPosPage fnPosPage ) return bRet; } -bool SwCursorShell::isInHiddenTextFrame(SwShellCursor* pShellCursor) +bool SwCursorShell::isInHiddenFrame(SwShellCursor* pShellCursor) { SwContentNode *pCNode = pShellCursor->GetPointContentNode(); std::pair<Point, bool> tmp(pShellCursor->GetPtPos(), false); SwContentFrame *const pFrame = pCNode ? pCNode->getLayoutFrame(GetLayout(), pShellCursor->GetPoint(), &tmp) : nullptr; - return !pFrame || (pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsHiddenNow()); + return !pFrame || pFrame->IsHiddenNow(); } // sw_redlinehide: this should work for all cases: GoCurrPara, GoNextPara, GoPrevPara @@ -992,7 +999,7 @@ bool SwCursorShell::MovePara(SwWhichPara fnWhichPara, SwMoveFnCollection const & //which is what SwCursorShell::UpdateCursorPos will reset //the position to if we pass it a position in an //invisible hidden paragraph field - while (isInHiddenTextFrame(pTmpCursor) + while (isInHiddenFrame(pTmpCursor) || !IsAtStartOrEndOfFrame(this, pTmpCursor, fnPosPara)) { if (!pTmpCursor->MovePara(fnWhichPara, fnPosPara)) @@ -1796,7 +1803,7 @@ void SwCursorShell::UpdateCursorPos() SwShellCursor* pShellCursor = getShellCursor( true ); Size aOldSz( GetDocSize() ); - if (isInHiddenTextFrame(pShellCursor) && !ExtendedSelectedAll()) + if (isInHiddenFrame(pShellCursor) && !ExtendedSelectedAll()) { SwCursorMoveState aTmpState(CursorMoveState::SetOnlyText); aTmpState.m_bSetInReadOnly = IsReadOnlyAvailable(); @@ -1805,14 +1812,14 @@ void SwCursorShell::UpdateCursorPos() pShellCursor->DeleteMark(); // kde45196-1.html: try to get to a non-hidden paragraph, there must // be one in the document body - while (isInHiddenTextFrame(pShellCursor)) + while (isInHiddenFrame(pShellCursor)) { if (!pShellCursor->MovePara(GoNextPara, fnParaStart)) { break; } } - while (isInHiddenTextFrame(pShellCursor)) + while (isInHiddenFrame(pShellCursor)) { if (!pShellCursor->MovePara(GoPrevPara, fnParaStart)) { @@ -3470,7 +3477,7 @@ bool SwCursorShell::FindValidContentNode( bool bOnlyText ) GetDoc()->GetDocShell()->IsReadOnlyUI() ) return true; - if( m_pCurrentCursor->HasMark() ) + if( m_pCurrentCursor->HasMark() && !mbSelectAll ) ClearMark(); // first check for frames diff --git a/sw/source/core/crsr/pam.cxx b/sw/source/core/crsr/pam.cxx index 25bf8d0ef6..4f2ceb0a84 100644 --- a/sw/source/core/crsr/pam.cxx +++ b/sw/source/core/crsr/pam.cxx @@ -1060,7 +1060,7 @@ SwContentNode* GetNode( SwPaM & rPam, bool& rbFirst, SwMoveFnCollection const & ( nullptr == pFrame || ( !bInReadOnly && pFrame->IsProtected() ) || - (pFrame->IsTextFrame() && static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow()) + pFrame->IsHiddenNow() ) || ( !bInReadOnly && pNd->FindSectionNode() && pNd->FindSectionNode()->GetSection().IsProtect() @@ -1101,8 +1101,7 @@ SwContentNode* GetNode( SwPaM & rPam, bool& rbFirst, SwMoveFnCollection const & SwContentFrame const*const pFrame(pNd->getLayoutFrame(pLayout)); if (nullptr == pFrame || ( !bInReadOnly && pFrame->IsProtected() ) || - ( pFrame->IsTextFrame() && - static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow())) + pFrame->IsHiddenNow()) { pNd = nullptr; continue; diff --git a/sw/source/core/crsr/swcrsr.cxx b/sw/source/core/crsr/swcrsr.cxx index 8d0246bed1..5a2f9afead 100644 --- a/sw/source/core/crsr/swcrsr.cxx +++ b/sw/source/core/crsr/swcrsr.cxx @@ -913,7 +913,7 @@ static bool lcl_MakeSelFwrd( const SwNode& rSttNd, const SwNode& rEndNd, rPam.SetMark(); rPam.GetPoint()->Assign(rEndNd); - pCNd = SwNodes::GoPrevious( rPam.GetPoint() ); + pCNd = SwNodes::GoPrevious(rPam.GetPoint(), true); if( !pCNd ) return false; rPam.GetPoint()->AssignEndIndex(*pCNd); @@ -933,7 +933,7 @@ static bool lcl_MakeSelBkwrd( const SwNode& rSttNd, const SwNode& rEndNd, if( !bFirst ) { rPam.GetPoint()->Assign(rSttNd); - pCNd = SwNodes::GoPrevious( rPam.GetPoint() ); + pCNd = SwNodes::GoPrevious(rPam.GetPoint(), true); if( !pCNd ) return false; rPam.GetPoint()->AssignEndIndex(*pCNd); diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx index 09e0a1233e..57b8e58310 100644 --- a/sw/source/core/doc/DocumentContentOperationsManager.cxx +++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx @@ -3788,11 +3788,16 @@ void DocumentContentOperationsManager::CopyWithFlyInFly( SwDoc& rDest = rInsPos.GetDoc(); SwNodeIndex aSavePos( rInsPos ); + SwPaM aCopiedPaM(rRg.aStart, rRg.aEnd); + if (pCopiedPaM) + aCopiedPaM = pCopiedPaM->first; + if (rRg.aStart != rRg.aEnd) { bool bEndIsEqualEndPos = rInsPos == rRg.aEnd.GetNode(); --aSavePos; SaveRedlEndPosForRestore aRedlRest( rInsPos, 0 ); + auto savedEndContentIndex = aCopiedPaM.End()->GetContentIndex(); // insert behind the already copied start node m_rDoc.GetNodes().CopyNodes( rRg, rInsPos, false, true ); @@ -3801,6 +3806,10 @@ void DocumentContentOperationsManager::CopyWithFlyInFly( if (bEndIsEqualEndPos) { const_cast<SwNodeIndex&>(rRg.aEnd).Assign(aSavePos.GetNode(), +1); + // pCopiedPaM->first now spans a range from the start of the original selection + // to the end of newly added text, and the insertion point is in the middle of + // that range. Adjust the local copy to cover the original copied PaM. + aCopiedPaM.End()->Assign(rRg.aEnd, savedEndContentIndex); } } @@ -3810,7 +3819,6 @@ void DocumentContentOperationsManager::CopyWithFlyInFly( // sw_fieldmarkhide: also needs to be done before making frames if (m_rDoc.getIDocumentMarkAccess()->getAllMarksCount()) { - SwPaM aRgTmp( rRg.aStart, rRg.aEnd ); SwPosition targetPos(aSavePos, SwNodeOffset(rRg.aStart != rRg.aEnd ? +1 : 0)); if (pCopiedPaM && rRg.aStart != pCopiedPaM->first.Start()->GetNode()) { @@ -3823,7 +3831,7 @@ void DocumentContentOperationsManager::CopyWithFlyInFly( targetPos = pCopiedPaM->second; } - sw::CopyBookmarks(pCopiedPaM ? pCopiedPaM->first : aRgTmp, targetPos, flags); + sw::CopyBookmarks(aCopiedPaM, targetPos, flags); } if (rRg.aStart != rRg.aEnd) @@ -3914,7 +3922,7 @@ void DocumentContentOperationsManager::CopyWithFlyInFly( { ::sw::UndoGuard const undoGuard(rDest.GetIDocumentUndoRedo()); - CopyFlyInFlyImpl(rRg, pCopiedPaM ? &pCopiedPaM->first : nullptr, + CopyFlyInFlyImpl(rRg, pCopiedPaM ? &aCopiedPaM : nullptr, // see comment below regarding use of pCopiedPaM->second (pCopiedPaM && rRg.aStart != pCopiedPaM->first.Start()->GetNode()) ? pCopiedPaM->second.GetNode() diff --git a/sw/source/core/doc/docedt.cxx b/sw/source/core/doc/docedt.cxx index c78d8e18b6..2a5aad64de 100644 --- a/sw/source/core/doc/docedt.cxx +++ b/sw/source/core/doc/docedt.cxx @@ -553,7 +553,7 @@ uno::Any SwDoc::Spell( SwPaM& rPaM, { nCurrNd = pNd->EndOfSectionIndex(); } - else if( !static_cast<SwTextFrame*>(pContentFrame)->IsHiddenNow() ) + else if( !pContentFrame->IsHiddenNow() ) { if( pPageCnt && *pPageCnt && pPageSt ) { @@ -766,7 +766,7 @@ static bool lcl_HyphenateNode( SwNode* pNd, void* pArgs ) // sw_redlinehide: this will be called once per node for merged nodes; // the fully deleted ones won't have frames so are skipped. SwContentFrame* pContentFrame = pNode->getLayoutFrame( pNode->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() ); - if( pContentFrame && !static_cast<SwTextFrame*>(pContentFrame)->IsHiddenNow() ) + if( pContentFrame && !pContentFrame->IsHiddenNow() ) { sal_uInt16 *pPageSt = pHyphArgs->GetPageSt(); sal_uInt16 *pPageCnt = pHyphArgs->GetPageCnt(); diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx index d6c943dbcd..1c696bebb6 100644 --- a/sw/source/core/doc/docfmt.cxx +++ b/sw/source/core/doc/docfmt.cxx @@ -1553,21 +1553,21 @@ void SwDoc::CopyPageDesc( const SwPageDesc& rSrcDesc, SwPageDesc& rDstDesc, { if (pStashedFormatSrc->GetDoc() != this) { - SwFrameFormat* pNewFormat = new SwFrameFormat(GetAttrPool(), "CopyDesc", GetDfltFrameFormat()); + SwFrameFormat newFormat(GetAttrPool(), "CopyDesc", GetDfltFrameFormat()); SfxItemSet aAttrSet(pStashedFormatSrc->GetAttrSet()); aAttrSet.ClearItem(RES_HEADER); aAttrSet.ClearItem(RES_FOOTER); - pNewFormat->DelDiffs( aAttrSet ); - pNewFormat->SetFormatAttr( aAttrSet ); + newFormat.DelDiffs(aAttrSet); + newFormat.SetFormatAttr(aAttrSet); if (bHeader) - CopyHeader(*pStashedFormatSrc, *pNewFormat); + CopyHeader(*pStashedFormatSrc, newFormat); else - CopyFooter(*pStashedFormatSrc, *pNewFormat); + CopyFooter(*pStashedFormatSrc, newFormat); - rDstDesc.StashFrameFormat(*pNewFormat, bHeader, bLeft, bFirst); + rDstDesc.StashFrameFormat(newFormat, bHeader, bLeft, bFirst); } else { diff --git a/sw/source/core/doc/doctxm.cxx b/sw/source/core/doc/doctxm.cxx index f03687d810..d29223050b 100644 --- a/sw/source/core/doc/doctxm.cxx +++ b/sw/source/core/doc/doctxm.cxx @@ -1057,7 +1057,7 @@ void SwTOXBaseSection::Update(const SfxItemSet* pAttr, SwSectionFormat* pSectFormat = rDoc.MakeSectionFormat(); rDoc.GetNodes().InsertTextSection( *pHeadNd, *pSectFormat, headerData, nullptr, &aIdx.GetNode(), true, false); - + pSectFormat->GetSection()->SetProtect(SwTOXBase::IsProtected()); if (pUndo) { pUndo->TitleSectionInserted(*pSectFormat); diff --git a/sw/source/core/docnode/ndsect.cxx b/sw/source/core/docnode/ndsect.cxx index cf96e1d509..1da9ecb43e 100644 --- a/sw/source/core/docnode/ndsect.cxx +++ b/sw/source/core/docnode/ndsect.cxx @@ -1022,9 +1022,9 @@ SwSectionNode::~SwSectionNode() } } -SwFrame *SwSectionNode::MakeFrame( SwFrame *pSib ) +SwFrame* SwSectionNode::MakeFrame(SwFrame* pSib, bool bHidden) { - m_pSection->m_Data.SetHiddenFlag(false); + m_pSection->m_Data.SetHiddenFlag(bHidden); return new SwSectionFrame( *m_pSection, pSib ); } diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx index a7a2bee478..f3b3a07d63 100644 --- a/sw/source/core/docnode/ndtbl.cxx +++ b/sw/source/core/docnode/ndtbl.cxx @@ -888,6 +888,34 @@ const SwTable* SwDoc::TextToTable( const SwInsertTableOptions& rInsTableOpts, return &rNdTable; } +static void lcl_RemoveBreaksTable(SwTableNode & rNode, SwTableFormat *const pTableFormat) +{ + // delete old layout frames, new ones need to be created... + rNode.DelFrames(nullptr); + + // remove PageBreaks/PageDesc/ColBreak + SwFrameFormat & rFormat(*rNode.GetTable().GetFrameFormat()); + + if (const SvxFormatBreakItem* pItem = rFormat.GetItemIfSet(RES_BREAK, false)) + { + if (pTableFormat) + { + pTableFormat->SetFormatAttr(*pItem); + } + rFormat.ResetFormatAttr(RES_BREAK); + } + + SwFormatPageDesc const*const pPageDescItem(rFormat.GetItemIfSet(RES_PAGEDESC, false)); + if (pPageDescItem && pPageDescItem->GetPageDesc()) + { + if (pTableFormat) + { + pTableFormat->SetFormatAttr(*pPageDescItem); + } + rFormat.ResetFormatAttr(RES_PAGEDESC); + } +} + static void lcl_RemoveBreaks(SwContentNode & rNode, SwTableFormat *const pTableFormat) { // delete old layout frames, new ones need to be created... @@ -1385,10 +1413,19 @@ SwTableNode* SwNodes::TextToTable( const SwNodes::TableRanges_t & rTableNodes, // delete frames of all contained content nodes for( nLines = 0; aNodeIndex <= rTableNodes.rbegin()->rbegin()->aEnd; ++aNodeIndex,++nLines ) { - SwNode& rNode = aNodeIndex.GetNode(); - if( rNode.IsContentNode() ) + SwNode* pNode(&aNodeIndex.GetNode()); + while (pNode->IsSectionNode()) // could be ToX field in table + { + pNode = pNode->GetNodes()[pNode->GetIndex()+1]; + } + if (pNode->IsTableNode()) + { + lcl_RemoveBreaksTable(static_cast<SwTableNode&>(*pNode), + (0 == nLines) ? pTableFormat : nullptr); + } + else if (pNode->IsContentNode()) { - lcl_RemoveBreaks(static_cast<SwContentNode&>(rNode), + lcl_RemoveBreaks(static_cast<SwContentNode&>(*pNode), (0 == nLines) ? pTableFormat : nullptr); } } diff --git a/sw/source/core/docnode/nodes.cxx b/sw/source/core/docnode/nodes.cxx index c6ecb9ccf9..3506dff230 100644 --- a/sw/source/core/docnode/nodes.cxx +++ b/sw/source/core/docnode/nodes.cxx @@ -1336,34 +1336,68 @@ SwContentNode* SwNodes::GoNext(SwPosition *pIdx) const return static_cast<SwContentNode*>(pNd); } -SwContentNode* SwNodes::GoPrevious(SwNodeIndex *pIdx) +SwNodeOffset SwNodes::StartOfGlobalSection(const SwNode& node) const +{ + const SwNodeOffset pos = node.GetIndex(); + if (GetEndOfExtras().GetIndex() < pos) + // Regular ContentSection + return GetEndOfExtras().GetIndex() + SwNodeOffset(1); + if (GetEndOfAutotext().GetIndex() < pos) + // Redlines + return GetEndOfAutotext().GetIndex() + SwNodeOffset(1); + if (GetEndOfInserts().GetIndex() < pos) + { + // Flys/Headers/Footers + if (auto* p = node.FindFlyStartNode()) + return p->GetIndex(); + if (auto* p = node.FindHeaderStartNode()) + return p->GetIndex(); + if (auto* p = node.FindFooterStartNode()) + return p->GetIndex(); + return GetEndOfInserts().GetIndex() + SwNodeOffset(1); + } + if (GetEndOfPostIts().GetIndex() < pos) + { + // Footnotes + if (auto* p = node.FindFootnoteStartNode()) + return p->GetIndex(); + return GetEndOfPostIts().GetIndex() + SwNodeOffset(1); + } + return SwNodeOffset(0); +} + +SwContentNode* SwNodes::GoPrevious(SwNodeIndex* pIdx, bool canCrossBoundary) { if( !pIdx->GetIndex() ) return nullptr; SwNodeIndex aTmp( *pIdx, -1 ); + SwNodeOffset aGlobalStart( + canCrossBoundary ? SwNodeOffset(0) : aTmp.GetNodes().StartOfGlobalSection(pIdx->GetNode())); SwNode* pNd = nullptr; - while( aTmp.GetIndex() && !( pNd = &aTmp.GetNode())->IsContentNode() ) + while (aTmp > aGlobalStart && !(pNd = &aTmp.GetNode())->IsContentNode()) --aTmp; - if( !aTmp.GetIndex() ) + if (aTmp <= aGlobalStart) pNd = nullptr; else (*pIdx) = aTmp; return static_cast<SwContentNode*>(pNd); } -SwContentNode* SwNodes::GoPrevious(SwPosition *pIdx) +SwContentNode* SwNodes::GoPrevious(SwPosition* pIdx, bool canCrossBoundary) { if( !pIdx->GetNodeIndex() ) return nullptr; SwNodeIndex aTmp( pIdx->GetNode(), -1 ); + SwNodeOffset aGlobalStart( + canCrossBoundary ? SwNodeOffset(0) : aTmp.GetNodes().StartOfGlobalSection(pIdx->GetNode())); SwNode* pNd = nullptr; - while( aTmp.GetIndex() && !( pNd = &aTmp.GetNode())->IsContentNode() ) + while( aTmp > aGlobalStart && !( pNd = &aTmp.GetNode())->IsContentNode() ) --aTmp; - if( !aTmp.GetIndex() ) + if (aTmp <= aGlobalStart) pNd = nullptr; else pIdx->Assign(aTmp); @@ -1963,7 +1997,7 @@ SwContentNode* SwNodes::GoNextSection( SwNodeIndex * pIdx, if (SwNodeType::Section == pNd->GetNodeType()) { const SwSection& rSect = static_cast<const SwSectionNode*>(pNd)->GetSection(); - if( (bSkipHidden && rSect.IsHiddenFlag()) || + if( (bSkipHidden && rSect.CalcHiddenFlag()) || (bSkipProtect && rSect.IsProtectFlag()) ) // than skip the section aTmp = *pNd->EndOfSectionNode(); @@ -1974,7 +2008,7 @@ SwContentNode* SwNodes::GoNextSection( SwNodeIndex * pIdx, { const SwSection& rSect = static_cast<SwSectionNode*>(pNd-> m_pStartOfSection)->GetSection(); - if( (bSkipHidden && rSect.IsHiddenFlag()) || + if( (bSkipHidden && rSect.CalcHiddenFlag()) || (bSkipProtect && rSect.IsProtectFlag()) ) // than skip the section aTmp = *pNd->EndOfSectionNode(); @@ -1985,7 +2019,7 @@ SwContentNode* SwNodes::GoNextSection( SwNodeIndex * pIdx, const SwSectionNode* pSectNd; if( ( bSkipHidden || bSkipProtect ) && nullptr != (pSectNd = pNd->FindSectionNode() ) && - ( ( bSkipHidden && pSectNd->GetSection().IsHiddenFlag() ) || + ( ( bSkipHidden && pSectNd->GetSection().CalcHiddenFlag() ) || ( bSkipProtect && pSectNd->GetSection().IsProtectFlag() )) ) { aTmp = *pSectNd->EndOfSectionNode(); @@ -2072,8 +2106,9 @@ SwContentNode* SwNodes::GoPrevSection( SwNodeIndex * pIdx, { bool bFirst = true; SwNodeIndex aTmp( *pIdx ); + SwNodeOffset aGlobalStart(aTmp.GetNodes().StartOfGlobalSection(pIdx->GetNode())); const SwNode* pNd; - while( aTmp > SwNodeOffset(0) ) + while (aTmp > aGlobalStart) { pNd = & aTmp.GetNode(); if (SwNodeType::End == pNd->GetNodeType()) @@ -2129,8 +2164,9 @@ SwContentNode* SwNodes::GoPrevSection( SwPosition * pIdx, { bool bFirst = true; SwNodeIndex aTmp( pIdx->GetNode() ); + SwNodeOffset aGlobalStart(aTmp.GetNodes().StartOfGlobalSection(pIdx->GetNode())); const SwNode* pNd; - while( aTmp > SwNodeOffset(0) ) + while (aTmp > aGlobalStart) { pNd = & aTmp.GetNode(); if (SwNodeType::End == pNd->GetNodeType()) diff --git a/sw/source/core/docnode/section.cxx b/sw/source/core/docnode/section.cxx index 12d9e281c2..53418541eb 100644 --- a/sw/source/core/docnode/section.cxx +++ b/sw/source/core/docnode/section.cxx @@ -299,14 +299,11 @@ void SwSection::ImplSetHiddenFlag(bool const bTmpHidden, bool const bCondition) // Tell all Children that they are hidden const sw::SectionHidden aHint; pFormat->CallSwClientNotify(aHint); - - // Delete all Frames - pFormat->DelFrames(); } } else if (m_Data.IsHiddenFlag()) // show Nodes again { - // Show all Frames (Child Sections are accounted for by MakeFrames) + // Show all Frames // Only if the Parent Section is not restricting us! SwSection* pParentSect = pFormat->GetParentSection(); if( !pParentSect || !pParentSect->IsHiddenFlag() ) @@ -314,8 +311,6 @@ void SwSection::ImplSetHiddenFlag(bool const bTmpHidden, bool const bCondition) // Tell all Children that the Parent is not hidden anymore const sw::SectionHidden aHint(false); pFormat->CallSwClientNotify(aHint); - - pFormat->MakeFrames(); } } } diff --git a/sw/source/core/edit/editsh.cxx b/sw/source/core/edit/editsh.cxx index 333eecd352..0400dc8871 100644 --- a/sw/source/core/edit/editsh.cxx +++ b/sw/source/core/edit/editsh.cxx @@ -796,7 +796,7 @@ void SwEditShell::SetNumberingRestart() if( nullptr != pContentFrame ) { // skip hidden frames - ignore protection! - if( !static_cast<SwTextFrame*>(pContentFrame)->IsHiddenNow() ) + if( !pContentFrame->IsHiddenNow() ) { // if the node is numbered and the starting value of the numbering equals the // start value of the numbering rule then set this value as hard starting value diff --git a/sw/source/core/edit/edsect.cxx b/sw/source/core/edit/edsect.cxx index a7e652aea9..070a37a90d 100644 --- a/sw/source/core/edit/edsect.cxx +++ b/sw/source/core/edit/edsect.cxx @@ -308,89 +308,121 @@ static const SwNode* lcl_SpecialInsertNode(const SwPosition* pCurrentPos) // pInnermostNode contains the section/table before/after which we should // insert our empty paragraph, or it will be NULL if none is found. const SwNode* pInnermostNode = nullptr; + const SwSection* pSection = nullptr; { const SwNode* pTableNode = rCurrentNode.FindTableNode(); const SwNode* pSectionNode = rCurrentNode.FindSectionNode(); // find the table/section which is close if( pTableNode == nullptr ) + { + if( pSectionNode == nullptr ) + return nullptr; + pInnermostNode = pSectionNode; + pSection = &static_cast<const SwSectionNode*>(pSectionNode)->GetSection(); + } else if ( pSectionNode == nullptr ) pInnermostNode = pTableNode; else { // compare and choose the larger one - pInnermostNode = - ( pSectionNode->GetIndex() > pTableNode->GetIndex() ) - ? pSectionNode : pTableNode; + if (pSectionNode->GetIndex() > pTableNode->GetIndex()) + { + pInnermostNode = pSectionNode; + pSection = &static_cast<const SwSectionNode*>(pSectionNode)->GetSection(); + } + else + pInnermostNode = pTableNode; } } - - // The previous version had a check to skip empty read-only sections. Those - // shouldn't occur, so we only need to check whether our pInnermostNode is - // inside a protected area. - - // Now, pInnermostNode is NULL or the innermost section or table node. - if( (pInnermostNode != nullptr) && !pInnermostNode->IsProtect() ) + if(pInnermostNode != nullptr) { - OSL_ENSURE( pInnermostNode->IsTableNode() || - pInnermostNode->IsSectionNode(), "wrong node found" ); - OSL_ENSURE( ( pInnermostNode->GetIndex() <= rCurrentNode.GetIndex() )&& - ( pInnermostNode->EndOfSectionNode()->GetIndex() >= - rCurrentNode.GetIndex() ), "wrong node found" ); - - // we now need to find the possible start/end positions - - // we found a start if - // - we're at or just before a start node - // - there are only start nodes between the current and pInnermostNode - SwNodeIndex aBegin( pCurrentPos->GetNode() ); - if( rCurrentNode.IsContentNode() && - (pCurrentPos->GetContentIndex() == 0)) - --aBegin; - while( (aBegin != pInnermostNode->GetIndex()) && - aBegin.GetNode().IsStartNode() ) - --aBegin; - bool bStart = ( aBegin == pInnermostNode->GetIndex() ); - - // we found an end if - // - we're at or just before an end node - // - there are only end nodes between the current node and - // pInnermostNode's end node or - // - there are only end nodes between the last table cell merged with - // the current cell and pInnermostNode's end node - SwNodeIndex aEnd( pCurrentPos->GetNode() ); - if( rCurrentNode.IsContentNode() && - ( pCurrentPos->GetContentIndex() == - rCurrentNode.GetContentNode()->Len() ) ) + bool bIsProtected = pInnermostNode->IsProtect(); + + //special case - ToxSection + // - in this case the inner section could be tox header + // section but the new node should be before the content section + // protection of the tox should not prevent the insertion + // only protection outside needs to be checked + if( pSection && + (SectionType::ToxHeader == pSection->GetType() || + SectionType::ToxContent == pSection->GetType())) { - ++aEnd; + if (SectionType::ToxHeader == pSection->GetType()) + { + if (const SwSection* pSectionParent = pSection->GetParent()) + pInnermostNode = pSectionParent->GetFormat()->GetSectionNode(); + } + bIsProtected = static_cast<const SwSectionNode*>(pInnermostNode)->IsInProtectSect(); + } - // tdf#156492 handle cells merged vertically in the bottom right corner - if ( pInnermostNode->IsTableNode() ) + // The previous version had a check to skip empty read-only sections. Those + // shouldn't occur, so we only need to check whether our pInnermostNode is + // inside a protected area. + + // Now, pInnermostNode is NULL or the innermost section or table node. + if(!bIsProtected) + { + OSL_ENSURE( pInnermostNode->IsTableNode() || + pInnermostNode->IsSectionNode(), "wrong node found" ); + OSL_ENSURE( ( pInnermostNode->GetIndex() <= rCurrentNode.GetIndex() )&& + ( pInnermostNode->EndOfSectionNode()->GetIndex() >= + rCurrentNode.GetIndex() ), "wrong node found" ); + + // we now need to find the possible start/end positions + + // we found a start if + // - we're at or just before a start node + // - there are only start nodes between the current and pInnermostNode + SwNodeIndex aBegin( pCurrentPos->GetNode() ); + if( rCurrentNode.IsContentNode() && + (pCurrentPos->GetContentIndex() == 0)) + --aBegin; + while( (aBegin != pInnermostNode->GetIndex()) && + aBegin.GetNode().IsStartNode() ) + --aBegin; + bool bStart = ( aBegin == pInnermostNode->GetIndex() ); + + // we found an end if + // - we're at or just before an end node + // - there are only end nodes between the current node and + // pInnermostNode's end node or + // - there are only end nodes between the last table cell merged with + // the current cell and pInnermostNode's end node + SwNodeIndex aEnd( pCurrentPos->GetNode() ); + if( rCurrentNode.IsContentNode() && + ( pCurrentPos->GetContentIndex() == + rCurrentNode.GetContentNode()->Len() ) ) { - const SwNode* pTableBoxStartNode = pCurrentPos->GetNode().FindTableBoxStartNode(); - const SwTableBox* pTableBox = pTableBoxStartNode->GetTableBox(); - if ( pTableBox && pTableBox->getRowSpan() > 1 ) + ++aEnd; + + // tdf#156492 handle cells merged vertically in the bottom right corner + if ( pInnermostNode->IsTableNode() ) { - const SwTableNode* pTableNd = pInnermostNode->FindTableNode(); - pTableBox = & pTableBox->FindEndOfRowSpan( pTableNd->GetTable(), - pTableBox->getRowSpan() ); - pTableBoxStartNode = pTableBox->GetSttNd(); - aEnd = pTableBoxStartNode->GetIndex() + 2; + const SwNode* pTableBoxStartNode = pCurrentPos->GetNode().FindTableBoxStartNode(); + const SwTableBox* pTableBox = pTableBoxStartNode->GetTableBox(); + if ( pTableBox && pTableBox->getRowSpan() > 1 ) + { + const SwTableNode* pTableNd = pInnermostNode->FindTableNode(); + pTableBox = & pTableBox->FindEndOfRowSpan( pTableNd->GetTable(), + pTableBox->getRowSpan() ); + pTableBoxStartNode = pTableBox->GetSttNd(); + aEnd = pTableBoxStartNode->GetIndex() + 2; + } } } + while( (aEnd != pInnermostNode->EndOfSectionNode()->GetIndex()) && + aEnd.GetNode().IsEndNode() ) + ++aEnd; + bool bEnd = ( aEnd == pInnermostNode->EndOfSectionNode()->GetIndex() ); + + // evaluate result: if both start + end, end is preferred + if( bEnd ) + pReturn = pInnermostNode->EndOfSectionNode(); + else if ( bStart ) + pReturn = pInnermostNode; } - while( (aEnd != pInnermostNode->EndOfSectionNode()->GetIndex()) && - aEnd.GetNode().IsEndNode() ) - ++aEnd; - bool bEnd = ( aEnd == pInnermostNode->EndOfSectionNode()->GetIndex() ); - - // evaluate result: if both start + end, end is preferred - if( bEnd ) - pReturn = pInnermostNode->EndOfSectionNode(); - else if ( bStart ) - pReturn = pInnermostNode; } OSL_ENSURE( ( pReturn == nullptr ) || pReturn->IsStartNode() || diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx index d57654f6a9..604488a18c 100644 --- a/sw/source/core/inc/frame.hxx +++ b/sw/source/core/inc/frame.hxx @@ -891,6 +891,8 @@ public: // Fly in ... and footnotes bool IsProtected() const; + virtual bool IsHiddenNow() const; + bool IsColLocked() const { return mbColLocked; } virtual bool IsDeleteForbidden() const { return mnForbidDelete > 0; } diff --git a/sw/source/core/inc/sectfrm.hxx b/sw/source/core/inc/sectfrm.hxx index c07d78b12b..69158b3358 100644 --- a/sw/source/core/inc/sectfrm.hxx +++ b/sw/source/core/inc/sectfrm.hxx @@ -88,6 +88,8 @@ public: virtual void Cut() override; virtual void Paste( SwFrame* pParent, SwFrame* pSibling = nullptr ) override; + virtual bool IsHiddenNow() const override; + inline const SwSectionFrame *GetFollow() const; inline SwSectionFrame *GetFollow(); SwSectionFrame* FindMaster() const; diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx index e60dbd20fb..df11ca589b 100644 --- a/sw/source/core/inc/txtfrm.hxx +++ b/sw/source/core/inc/txtfrm.hxx @@ -559,7 +559,7 @@ public: #endif /// Hidden - bool IsHiddenNow() const; // bHidden && pOut == pPrt + virtual bool IsHiddenNow() const override; // bHidden && pOut == pPrt void HideHidden(); // Remove appendage if Hidden void HideFootnotes(TextFrameIndex nStart, TextFrameIndex nEnd); diff --git a/sw/source/core/layout/calcmove.cxx b/sw/source/core/layout/calcmove.cxx index c2bbdd8904..e13fdf0121 100644 --- a/sw/source/core/layout/calcmove.cxx +++ b/sw/source/core/layout/calcmove.cxx @@ -177,7 +177,7 @@ bool SwContentFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool & ) if ( nMoveAnyway < 3 ) { - if ( nSpace ) + if (nSpace || IsHiddenNow()) { // Do not notify footnotes which are stuck to the paragraph: // This would require extremely confusing code, taking into @@ -209,7 +209,7 @@ bool SwContentFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool & ) } // Check for space left in new upper - return nSpace != 0; + return nSpace != 0 || IsHiddenNow(); } } return false; @@ -532,7 +532,7 @@ static SwFrame* lcl_NotHiddenPrev( SwFrame* pFrame ) do { pRet = lcl_Prev( pRet ); - } while ( pRet && pRet->IsTextFrame() && static_cast<SwTextFrame*>(pRet)->IsHiddenNow() ); + } while ( pRet && pRet->IsHiddenNow() ); return pRet; } @@ -1083,9 +1083,8 @@ void SwContentFrame::MakePrtArea( const SwBorderAttrs &rAttrs ) setFramePrintAreaValid(true); SwRectFnSet aRectFnSet(this); - const bool bTextFrame = IsTextFrame(); SwTwips nUpper = 0; - if ( bTextFrame && static_cast<SwTextFrame*>(this)->IsHiddenNow() ) + if (IsTextFrame() && IsHiddenNow()) { if ( static_cast<SwTextFrame*>(this)->HasFollow() ) static_cast<SwTextFrame*>(this)->JoinFrame(); @@ -1715,7 +1714,7 @@ void SwContentFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/) const bool bMoveFwdInvalid = nullptr != GetIndNext(); const bool bNxtNew = ( 0 == aRectFnSet.GetHeight(pNxt->getFramePrintArea()) ) && - (!pNxt->IsTextFrame() ||!static_cast<SwTextFrame*>(pNxt)->IsHiddenNow()); + !pNxt->IsHiddenNow(); pNxt->Calc(getRootFrame()->GetCurrShell()->GetOut()); @@ -2217,7 +2216,7 @@ bool SwContentFrame::WouldFit_( SwTwips nSpace, pTmpPrev = nullptr; else { - if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsHiddenNow() ) + if (pFrame->IsHiddenNow()) pTmpPrev = lcl_NotHiddenPrev( pFrame ); else pTmpPrev = pFrame; diff --git a/sw/source/core/layout/findfrm.cxx b/sw/source/core/layout/findfrm.cxx index 5331baacd9..0dd64c6aec 100644 --- a/sw/source/core/layout/findfrm.cxx +++ b/sw/source/core/layout/findfrm.cxx @@ -994,7 +994,7 @@ SwFrame *SwFrame::FindNext_() (!bFootnote || pSct->IsInFootnote() ) ) return pSct; } - return pRet; + return pRet == this ? nullptr : pRet; } // #i27138# - add parameter <_bInSameFootnote> @@ -1380,11 +1380,7 @@ void SwFrame::InvalidateNextPrtArea() SwFrame* pNextFrame = FindNext(); // skip empty section frames and hidden text frames { - while ( pNextFrame && - ( ( pNextFrame->IsSctFrame() && - !static_cast<SwSectionFrame*>(pNextFrame)->GetSection() ) || - ( pNextFrame->IsTextFrame() && - static_cast<SwTextFrame*>(pNextFrame)->IsHiddenNow() ) ) ) + while (pNextFrame && pNextFrame->IsHiddenNow()) { pNextFrame = pNextFrame->FindNext(); } diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx index da509e2a6b..88158161c5 100644 --- a/sw/source/core/layout/flowfrm.cxx +++ b/sw/source/core/layout/flowfrm.cxx @@ -1271,8 +1271,7 @@ bool SwFlowFrame::IsPageBreak( bool bAct ) const // Determine predecessor const SwFrame *pPrev = m_rThis.FindPrev(); - while ( pPrev && ( !pPrev->IsInDocBody() || - ( pPrev->IsTextFrame() && static_cast<const SwTextFrame*>(pPrev)->IsHiddenNow() ) ) ) + while (pPrev && (!pPrev->IsInDocBody() || pPrev->IsHiddenNow())) pPrev = pPrev->FindPrev(); if ( pPrev ) @@ -1333,7 +1332,7 @@ bool SwFlowFrame::IsColBreak( bool bAct ) const // Determine predecessor const SwFrame *pPrev = m_rThis.FindPrev(); while( pPrev && ( ( !pPrev->IsInDocBody() && !m_rThis.IsInFly() && !m_rThis.FindFooterOrHeader() ) || - ( pPrev->IsTextFrame() && static_cast<const SwTextFrame*>(pPrev)->IsHiddenNow() ) ) ) + pPrev->IsHiddenNow() ) ) pPrev = pPrev->FindPrev(); if ( pPrev ) @@ -1364,6 +1363,14 @@ bool SwFlowFrame::IsColBreak( bool bAct ) const return false; } +// Skip hidden paragraphs and empty sections on the same level +static const SwFrame* skipHiddenSiblingFrames_(const SwFrame* pFrame) +{ + while (pFrame && pFrame->IsHiddenNow()) + pFrame = pFrame->GetPrev(); + return pFrame; +} + bool SwFlowFrame::HasParaSpaceAtPages( bool bSct ) const { if( m_rThis.IsInSct() ) @@ -1379,7 +1386,7 @@ bool SwFlowFrame::HasParaSpaceAtPages( bool bSct ) const return !pTmp->GetPrev() || IsPageBreak(true); if( pTmp->IsColumnFrame() && pTmp->GetPrev() ) return IsColBreak( true ); - if( pTmp->IsSctFrame() && ( !bSct || pTmp->GetPrev() ) ) + if (pTmp->IsSctFrame() && (!bSct || skipHiddenSiblingFrames_(pTmp->GetPrev()))) return false; pTmp = pTmp->GetUpper(); } @@ -1401,6 +1408,31 @@ bool SwFlowFrame::HasParaSpaceAtPages( bool bSct ) const return pTmp && !pTmp->GetPrev(); } +// Skip hidden paragraphs and empty sections +static const SwFrame* skipHiddenFrames_(const SwFrame* pFrame) +{ + do + { + pFrame = skipHiddenSiblingFrames_(pFrame); + if (!pFrame || !pFrame->IsSctFrame()) + return pFrame; + // Special case: found previous frame is a section + // Search for the last content in the section + auto pSectFrame = static_cast<const SwSectionFrame*>(pFrame); + pFrame = pSectFrame->FindLastContent(); + // If the last content is in a table _inside_ the section, + // take the table herself. + // Correction: Check directly, if table is inside table, instead of indirectly + // by checking, if section isn't inside a table + if (pFrame && pFrame->IsInTab()) + { + const SwTabFrame* pTableFrame = pFrame->FindTabFrame(); + if (pSectFrame->IsAnLower(pTableFrame)) + return pTableFrame; + } + } while (true); +} + /** helper method to determine previous frame for calculation of the upper space @@ -1408,73 +1440,21 @@ bool SwFlowFrame::HasParaSpaceAtPages( bool bSct ) const */ const SwFrame* SwFlowFrame::GetPrevFrameForUpperSpaceCalc_( const SwFrame* _pProposedPrevFrame ) const { - const SwFrame* pPrevFrame = _pProposedPrevFrame - ? _pProposedPrevFrame - : m_rThis.GetPrev(); - - // Skip hidden paragraphs and empty sections - while ( pPrevFrame && - ( ( pPrevFrame->IsTextFrame() && - static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) || - ( pPrevFrame->IsSctFrame() && - !static_cast<const SwSectionFrame*>(pPrevFrame)->GetSection() ) ) ) - { - pPrevFrame = pPrevFrame->GetPrev(); - } + const SwFrame* pPrevFrame + = skipHiddenFrames_(_pProposedPrevFrame ? _pProposedPrevFrame : m_rThis.GetPrev()); + if (pPrevFrame || !m_rThis.IsInFootnote() + || !(m_rThis.IsSctFrame() || !m_rThis.IsInSct() || !m_rThis.FindSctFrame()->IsInFootnote())) + return pPrevFrame; // Special case: no direct previous frame is found but frame is in footnote // Search for a previous frame in previous footnote, // if frame isn't in a section, which is also in the footnote - if ( !pPrevFrame && m_rThis.IsInFootnote() && - ( m_rThis.IsSctFrame() || - !m_rThis.IsInSct() || !m_rThis.FindSctFrame()->IsInFootnote() ) ) - { - const SwFootnoteFrame* pPrevFootnoteFrame = - static_cast<const SwFootnoteFrame*>(m_rThis.FindFootnoteFrame()->GetPrev()); - if ( pPrevFootnoteFrame ) - { - pPrevFrame = pPrevFootnoteFrame->GetLastLower(); - - // Skip hidden paragraphs and empty sections - while ( pPrevFrame && - ( ( pPrevFrame->IsTextFrame() && - static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) || - ( pPrevFrame->IsSctFrame() && - !static_cast<const SwSectionFrame*>(pPrevFrame)->GetSection() ) ) ) - { - pPrevFrame = pPrevFrame->GetPrev(); - } - } - } - // Special case: found previous frame is a section - // Search for the last content in the section - if( pPrevFrame && pPrevFrame->IsSctFrame() ) - { - const SwSectionFrame* pPrevSectFrame = - static_cast<const SwSectionFrame*>(pPrevFrame); - pPrevFrame = pPrevSectFrame->FindLastContent(); - // If the last content is in a table _inside_ the section, - // take the table herself. - // Correction: Check directly, if table is inside table, instead of indirectly - // by checking, if section isn't inside a table - if ( pPrevFrame && pPrevFrame->IsInTab() ) - { - const SwTabFrame* pTableFrame = pPrevFrame->FindTabFrame(); - if ( pPrevSectFrame->IsAnLower( pTableFrame ) ) - { - pPrevFrame = pTableFrame; - } - } - // Correction: skip hidden text frames - while ( pPrevFrame && - pPrevFrame->IsTextFrame() && - static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) - { - pPrevFrame = pPrevFrame->GetPrev(); - } - } + const SwFootnoteFrame* pPrevFootnoteFrame = + static_cast<const SwFootnoteFrame*>(m_rThis.FindFootnoteFrame()->GetPrev()); + if ( pPrevFootnoteFrame ) + return skipHiddenFrames_(pPrevFootnoteFrame->GetLastLower()); - return pPrevFrame; + return nullptr; } // This should be renamed to something like lcl_UseULSpacing @@ -1912,6 +1892,8 @@ SwTwips SwFlowFrame::CalcAddLowerSpaceAsLastInTableCell( /// Moves the Frame forward if it seems necessary regarding the current conditions and attributes. bool SwFlowFrame::CheckMoveFwd( bool& rbMakePage, bool bKeep, bool bIgnoreMyOwnKeepValue ) { + if (m_rThis.IsHiddenNow()) + return false; const SwFrame* pNxt = m_rThis.GetIndNext(); if ( bKeep && //!bMovedBwd && @@ -2299,7 +2281,8 @@ bool SwFlowFrame::MoveBwd( bool &rbReformat ) ) pNewUpper = m_rThis.GetLeaf( MAKEPAGE_FTN, false ); } - else if ( IsPageBreak( true ) ) // Do we have to respect a PageBreak? + // Do we have to respect a PageBreak? + else if (IsPageBreak(true) && (!m_rThis.IsInSct() || !m_rThis.FindSctFrame()->IsHiddenNow())) { // If the previous page doesn't have a Frame in the body, // flowing back makes sense despite the PageBreak (otherwise, @@ -2366,7 +2349,7 @@ bool SwFlowFrame::MoveBwd( bool &rbReformat ) } } } - else if ( IsColBreak( true ) ) + else if (IsColBreak(true)) { // If the previous column doesn't contain a ContentFrame, flowing back // makes sense despite the ColumnBreak, as otherwise we'd get diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx index eeab5c60c1..baf632d6eb 100644 --- a/sw/source/core/layout/frmtool.cxx +++ b/sw/source/core/layout/frmtool.cxx @@ -844,11 +844,7 @@ void SwContentNotify::ImplDestroy() SwFrame* pPrevFrame = pCnt->FindPrev(); // skip empty section frames and hidden text frames { - while ( pPrevFrame && - ( ( pPrevFrame->IsSctFrame() && - !static_cast<SwSectionFrame*>(pPrevFrame)->GetSection() ) || - ( pPrevFrame->IsTextFrame() && - static_cast<SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) ) ) + while (pPrevFrame && pPrevFrame->IsHiddenNow()) { pPrevFrame = pPrevFrame->FindPrev(); } @@ -1608,7 +1604,7 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc, pFrame = pNode->IsTextNode() ? sw::MakeTextFrame(*pNode->GetTextNode(), pLay, eMode) : pNode->MakeFrame(pLay); - if( pPageMaker ) + if (pPageMaker && !pLay->IsHiddenNow()) pPageMaker->CheckInsert( nIndex ); pFrame->InsertBehind( pLay, pPrv ); @@ -1766,15 +1762,11 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc, continue; // skip it } SwSectionNode *pNode = static_cast<SwSectionNode*>(pNd); - if( pNode->GetSection().CalcHiddenFlag() ) - // is hidden, skip the area - nIndex = pNode->EndOfSectionIndex(); - else { if (pActualSection) pActualSection->SetLastPos(pPrv); - pFrame = pNode->MakeFrame( pLay ); + pFrame = pNode->MakeFrame(pLay, pNode->GetSection().CalcHiddenFlag()); pActualSection.reset( new SwActualSection( pActualSection.release(), static_cast<SwSectionFrame*>(pFrame), pNode ) ); if ( pActualSection->GetUpper() ) @@ -1945,7 +1937,8 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc, } else { - pFrame = pActualSection->GetSectionNode()->MakeFrame( pLay ); + pFrame = pActualSection->GetSectionNode()->MakeFrame( + pLay, pActualSection->GetSectionNode()->GetSection().IsHiddenFlag()); pFrame->InsertBehind( pLay, pPrv ); static_cast<SwSectionFrame*>(pFrame)->Init(); @@ -2523,8 +2516,7 @@ void SwBorderAttrs::CalcJoinedWithPrev( const SwFrame& _rFrame, // one as previous frame. const SwFrame* pPrevFrame = _pPrevFrame ? _pPrevFrame : _rFrame.GetPrev(); // OD 2004-02-13 #i25029# - skip hidden text frames. - while ( pPrevFrame && pPrevFrame->IsTextFrame() && - static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) + while (pPrevFrame && pPrevFrame->IsHiddenNow()) { pPrevFrame = pPrevFrame->GetPrev(); } @@ -2555,8 +2547,7 @@ void SwBorderAttrs::CalcJoinedWithNext( const SwFrame& _rFrame ) // corresponding attribute set is set at current text frame. // OD 2004-02-13 #i25029# - get next frame, but skip hidden text frames. const SwFrame* pNextFrame = _rFrame.GetNext(); - while ( pNextFrame && pNextFrame->IsTextFrame() && - static_cast<const SwTextFrame*>(pNextFrame)->IsHiddenNow() ) + while (pNextFrame && pNextFrame->IsHiddenNow()) { pNextFrame = pNextFrame->GetNext(); } diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx index 70453c5727..f4e6072498 100644 --- a/sw/source/core/layout/ftnfrm.cxx +++ b/sw/source/core/layout/ftnfrm.cxx @@ -2965,13 +2965,9 @@ SwContentFrame* SwFootnoteFrame::FindLastContent() while ( pTmpLastLower && pTmpLastLower->GetNext() ) { pTmpLastLower = pTmpLastLower->GetNext(); - if ( ( pTmpLastLower->IsTextFrame() && - !static_cast<SwTextFrame*>(pTmpLastLower)->IsHiddenNow() ) || - ( pTmpLastLower->IsSctFrame() && - static_cast<SwSectionFrame*>(pTmpLastLower)->GetSection() && - static_cast<SwSectionFrame*>(pTmpLastLower)->ContainsContent() ) || - ( pTmpLastLower->IsTabFrame() && - static_cast<SwTabFrame*>(pTmpLastLower)->ContainsContent() ) ) + if (!pTmpLastLower->IsHiddenNow() + && (!pTmpLastLower->IsLayoutFrame() + || static_cast<SwLayoutFrame*>(pTmpLastLower)->ContainsContent())) { pLastLowerOfFootnote = pTmpLastLower; } diff --git a/sw/source/core/layout/pagechg.cxx b/sw/source/core/layout/pagechg.cxx index bf4bcc45ea..f8c029ea12 100644 --- a/sw/source/core/layout/pagechg.cxx +++ b/sw/source/core/layout/pagechg.cxx @@ -789,7 +789,10 @@ SwPageDesc *SwPageFrame::FindPageDesc() return pRet; } - SwFrame *pFlow = FindFirstBodyContent(); + SwContentFrame* pFirstContent = FindFirstBodyContent(); + while (pFirstContent && pFirstContent->IsHiddenNow()) + pFirstContent = pFirstContent->GetNextContentFrame(); + SwFrame* pFlow = pFirstContent; if ( pFlow && pFlow->IsInTab() ) pFlow = pFlow->FindTabFrame(); diff --git a/sw/source/core/layout/pagedesc.cxx b/sw/source/core/layout/pagedesc.cxx index 2b78823327..f9679bb2a8 100644 --- a/sw/source/core/layout/pagedesc.cxx +++ b/sw/source/core/layout/pagedesc.cxx @@ -83,13 +83,13 @@ SwPageDesc::SwPageDesc( const SwPageDesc &rCpy ) , m_FootnoteInfo( rCpy.GetFootnoteInfo() ) , m_pdList( nullptr ) { - m_aStashedHeader.m_pStashedFirst = rCpy.m_aStashedHeader.m_pStashedFirst; - m_aStashedHeader.m_pStashedLeft = rCpy.m_aStashedHeader.m_pStashedLeft; - m_aStashedHeader.m_pStashedFirstLeft = rCpy.m_aStashedHeader.m_pStashedFirstLeft; + m_aStashedHeader.m_oStashedFirst = rCpy.m_aStashedHeader.m_oStashedFirst; + m_aStashedHeader.m_oStashedLeft = rCpy.m_aStashedHeader.m_oStashedLeft; + m_aStashedHeader.m_oStashedFirstLeft = rCpy.m_aStashedHeader.m_oStashedFirstLeft; - m_aStashedFooter.m_pStashedFirst = rCpy.m_aStashedFooter.m_pStashedFirst; - m_aStashedFooter.m_pStashedLeft = rCpy.m_aStashedFooter.m_pStashedLeft; - m_aStashedFooter.m_pStashedFirstLeft = rCpy.m_aStashedFooter.m_pStashedFirstLeft; + m_aStashedFooter.m_oStashedFirst = rCpy.m_aStashedFooter.m_oStashedFirst; + m_aStashedFooter.m_oStashedLeft = rCpy.m_aStashedFooter.m_oStashedLeft; + m_aStashedFooter.m_oStashedFirstLeft = rCpy.m_aStashedFooter.m_oStashedFirstLeft; if (rCpy.m_pTextFormatColl && rCpy.m_aDepends.IsListeningTo(rCpy.m_pTextFormatColl)) { @@ -110,13 +110,13 @@ SwPageDesc & SwPageDesc::operator = (const SwPageDesc & rSrc) m_FirstMaster = rSrc.m_FirstMaster; m_FirstLeft = rSrc.m_FirstLeft; - m_aStashedHeader.m_pStashedFirst = rSrc.m_aStashedHeader.m_pStashedFirst; - m_aStashedHeader.m_pStashedLeft = rSrc.m_aStashedHeader.m_pStashedLeft; - m_aStashedHeader.m_pStashedFirstLeft = rSrc.m_aStashedHeader.m_pStashedFirstLeft; + m_aStashedHeader.m_oStashedFirst = rSrc.m_aStashedHeader.m_oStashedFirst; + m_aStashedHeader.m_oStashedLeft = rSrc.m_aStashedHeader.m_oStashedLeft; + m_aStashedHeader.m_oStashedFirstLeft = rSrc.m_aStashedHeader.m_oStashedFirstLeft; - m_aStashedFooter.m_pStashedFirst = rSrc.m_aStashedFooter.m_pStashedFirst; - m_aStashedFooter.m_pStashedLeft = rSrc.m_aStashedFooter.m_pStashedLeft; - m_aStashedFooter.m_pStashedFirstLeft = rSrc.m_aStashedFooter.m_pStashedFirstLeft; + m_aStashedFooter.m_oStashedFirst = rSrc.m_aStashedFooter.m_oStashedFirst; + m_aStashedFooter.m_oStashedLeft = rSrc.m_aStashedFooter.m_oStashedLeft; + m_aStashedFooter.m_oStashedFirstLeft = rSrc.m_aStashedFooter.m_oStashedFirstLeft; m_aDepends.EndListeningAll(); if (rSrc.m_pTextFormatColl && rSrc.m_aDepends.IsListeningTo(rSrc.m_pTextFormatColl)) @@ -416,30 +416,30 @@ void SwPageDesc::ChgFirstShare( bool bNew ) void SwPageDesc::StashFrameFormat(const SwFrameFormat& rFormat, bool bHeader, bool bLeft, bool bFirst) { assert(rFormat.GetRegisteredIn()); - std::shared_ptr<SwFrameFormat>* pFormat = nullptr; + std::optional<SwFrameFormat>* pFormat = nullptr; if (bHeader) { if (bLeft && !bFirst) - pFormat = &m_aStashedHeader.m_pStashedLeft; + pFormat = &m_aStashedHeader.m_oStashedLeft; else if (!bLeft && bFirst) - pFormat = &m_aStashedHeader.m_pStashedFirst; + pFormat = &m_aStashedHeader.m_oStashedFirst; else if (bLeft && bFirst) - pFormat = &m_aStashedHeader.m_pStashedFirstLeft; + pFormat = &m_aStashedHeader.m_oStashedFirstLeft; } else { if (bLeft && !bFirst) - pFormat = &m_aStashedFooter.m_pStashedLeft; + pFormat = &m_aStashedFooter.m_oStashedLeft; else if (!bLeft && bFirst) - pFormat = &m_aStashedFooter.m_pStashedFirst; + pFormat = &m_aStashedFooter.m_oStashedFirst; else if (bLeft && bFirst) - pFormat = &m_aStashedFooter.m_pStashedFirstLeft; + pFormat = &m_aStashedFooter.m_oStashedFirstLeft; } if (pFormat) { - *pFormat = std::make_shared<SwFrameFormat>(rFormat); + pFormat->emplace(rFormat); } else { @@ -451,24 +451,24 @@ void SwPageDesc::StashFrameFormat(const SwFrameFormat& rFormat, bool bHeader, bo const SwFrameFormat* SwPageDesc::GetStashedFrameFormat(bool bHeader, bool bLeft, bool bFirst) const { - std::shared_ptr<SwFrameFormat>* pFormat = nullptr; + std::optional<SwFrameFormat>* pFormat = nullptr; if (bLeft && !bFirst) { - pFormat = bHeader ? &m_aStashedHeader.m_pStashedLeft : &m_aStashedFooter.m_pStashedLeft; + pFormat = bHeader ? &m_aStashedHeader.m_oStashedLeft : &m_aStashedFooter.m_oStashedLeft; } else if (!bLeft && bFirst) { - pFormat = bHeader ? &m_aStashedHeader.m_pStashedFirst : &m_aStashedFooter.m_pStashedFirst; + pFormat = bHeader ? &m_aStashedHeader.m_oStashedFirst : &m_aStashedFooter.m_oStashedFirst; } else if (bLeft && bFirst) { - pFormat = bHeader ? &m_aStashedHeader.m_pStashedFirstLeft : &m_aStashedFooter.m_pStashedFirstLeft; + pFormat = bHeader ? &m_aStashedHeader.m_oStashedFirstLeft : &m_aStashedFooter.m_oStashedFirstLeft; } if (pFormat) { - return pFormat->get(); + return pFormat->has_value() ? &**pFormat : nullptr; } else { @@ -483,15 +483,15 @@ bool SwPageDesc::HasStashedFormat(bool bHeader, bool bLeft, bool bFirst) const { if (bLeft && !bFirst) { - return m_aStashedHeader.m_pStashedLeft != nullptr; + return m_aStashedHeader.m_oStashedLeft.has_value(); } else if (!bLeft && bFirst) { - return m_aStashedHeader.m_pStashedFirst != nullptr; + return m_aStashedHeader.m_oStashedFirst.has_value(); } else if (bLeft && bFirst) { - return m_aStashedHeader.m_pStashedFirstLeft != nullptr; + return m_aStashedHeader.m_oStashedFirstLeft.has_value(); } else { @@ -503,15 +503,15 @@ bool SwPageDesc::HasStashedFormat(bool bHeader, bool bLeft, bool bFirst) const { if (bLeft && !bFirst) { - return m_aStashedFooter.m_pStashedLeft != nullptr; + return m_aStashedFooter.m_oStashedLeft.has_value(); } else if (!bLeft && bFirst) { - return m_aStashedFooter.m_pStashedFirst != nullptr; + return m_aStashedFooter.m_oStashedFirst.has_value(); } else if (bLeft && bFirst) { - return m_aStashedFooter.m_pStashedFirstLeft != nullptr; + return m_aStashedFooter.m_oStashedFirstLeft.has_value(); } else { @@ -527,15 +527,15 @@ void SwPageDesc::RemoveStashedFormat(bool bHeader, bool bLeft, bool bFirst) { if (bLeft && !bFirst) { - m_aStashedHeader.m_pStashedLeft.reset(); + m_aStashedHeader.m_oStashedLeft.reset(); } else if (!bLeft && bFirst) { - m_aStashedHeader.m_pStashedFirst.reset(); + m_aStashedHeader.m_oStashedFirst.reset(); } else if (bLeft && bFirst) { - m_aStashedHeader.m_pStashedFirstLeft.reset(); + m_aStashedHeader.m_oStashedFirstLeft.reset(); } else { @@ -546,15 +546,15 @@ void SwPageDesc::RemoveStashedFormat(bool bHeader, bool bLeft, bool bFirst) { if (bLeft && !bFirst) { - m_aStashedFooter.m_pStashedLeft.reset(); + m_aStashedFooter.m_oStashedLeft.reset(); } else if (!bLeft && bFirst) { - m_aStashedFooter.m_pStashedFirst.reset(); + m_aStashedFooter.m_oStashedFirst.reset(); } else if (bLeft && bFirst) { - m_aStashedFooter.m_pStashedFirstLeft.reset(); + m_aStashedFooter.m_oStashedFirstLeft.reset(); } else { diff --git a/sw/source/core/layout/sectfrm.cxx b/sw/source/core/layout/sectfrm.cxx index a1fd849ec4..3967a1f564 100644 --- a/sw/source/core/layout/sectfrm.cxx +++ b/sw/source/core/layout/sectfrm.cxx @@ -189,6 +189,13 @@ SwSectionFrame::~SwSectionFrame() { } +//virtual +bool SwSectionFrame::IsHiddenNow() const +{ + const auto* pSection = GetSection(); + return !pSection || pSection->CalcHiddenFlag(); +} + void SwSectionFrame::DelEmpty( bool bRemove ) { if( IsColLocked() ) @@ -1371,6 +1378,20 @@ void SwSectionFrame::Format( vcl::RenderContext* pRenderContext, const SwBorderA SwRectFnSet aRectFnSet(this); + if (GetSection()->CalcHiddenFlag()) + { + { + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aRectFnSet.SetHeight(aFrm, 0); + } + { + SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); + aRectFnSet.SetHeight(aPrt, 0); + } + setFrameAreaSizeValid(true); + setFramePrintAreaValid(true); + } + if ( !isFramePrintAreaValid() ) { PROTOCOL( this, PROT::PrintArea, DbgAction::NONE, nullptr ) @@ -2182,6 +2203,11 @@ bool SwSectionFrame::Growable() const SwTwips SwSectionFrame::Grow_( SwTwips nDist, bool bTst ) { + if (GetSection()->CalcHiddenFlag()) + { + return 0; + } + if ( !IsColLocked() && !HasFixSize() ) { SwRectFnSet aRectFnSet(this); @@ -2646,6 +2672,17 @@ void SwSectionFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint) return; SwSectionFrame::MoveContentAndDelete(this, pHint->IsSaveContent()); } + else if (rHint.GetId() == SfxHintId::SwSectionHidden) + { + InvalidateAll(); + InvalidateObjs(false); + + for (SwFrame* pLowerFrame = Lower(); pLowerFrame; pLowerFrame = pLowerFrame->GetNext()) + { + pLowerFrame->InvalidateAll(); + pLowerFrame->InvalidateObjs(false); + } + } else SwFrame::SwClientNotify(rMod, rHint); } diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index f757824561..c4a742c037 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -667,7 +667,7 @@ static bool lcl_RecalcSplitLine( SwRowFrame& rLastLine, SwRowFrame& rFollowLine, { SwContentFrame const*const pAnchor = pFootnote->GetRef(); SwTabFrame const* pTab = pAnchor->FindTabFrame(); - if (pTab == &rTab) + if (pTab) { while (pTab->GetUpper()->IsInTab()) { @@ -1454,6 +1454,8 @@ namespace auto IsAllHiddenSection(SwSectionFrame const& rSection) -> bool { + if (rSection.IsHiddenNow()) + return true; for (SwFrame const* pFrame = rSection.Lower(); pFrame; pFrame = pFrame->GetNext()) { if (pFrame->IsColumnFrame()) @@ -1474,7 +1476,7 @@ namespace } else if (pFrame->IsTextFrame()) { - if (!static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow()) + if (!pFrame->IsHiddenNow()) { return false; } @@ -1509,7 +1511,7 @@ namespace } else if (pFrame->IsTextFrame()) { - if (!static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow()) + if (!pFrame->IsHiddenNow()) { return false; } @@ -3371,7 +3373,15 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper, } bool bFlyHoriOrientLeft = text::HoriOrientation::LEFT == rHori.GetHoriOrient(); - if (bSplitFly && !bFlyHoriOrientLeft) + + bool bToplevelSplitFly = false; + if (bSplitFly) + { + // Floating table wrapped by table: avoid this in the nested case. + bToplevelSplitFly = !pFly->GetAnchorFrame()->IsInTab(); + } + + if (bToplevelSplitFly && !bFlyHoriOrientLeft) { // Only shift to the right if we don't have enough space on the left. SwTwips nTabWidth = getFramePrintArea().Width(); diff --git a/sw/source/core/layout/trvlfrm.cxx b/sw/source/core/layout/trvlfrm.cxx index a8445e90dd..89a5f03302 100644 --- a/sw/source/core/layout/trvlfrm.cxx +++ b/sw/source/core/layout/trvlfrm.cxx @@ -52,6 +52,7 @@ #include <ndtxt.hxx> #include <undobj.hxx> #include <flyfrms.hxx> +#include <sectfrm.hxx> #include <swselectionlist.hxx> #include <comphelper/lok.hxx> @@ -828,8 +829,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart, //If I'm in the DocumentBody, I want to stay there. if ( pStart->IsInDocBody() ) { - while ( pCnt && (!pCnt->IsInDocBody() || - (pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow()))) + while (pCnt && (!pCnt->IsInDocBody() || pCnt->IsHiddenNow())) { pCnt = (*fnNxtPrv)( pCnt ); pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel ); @@ -840,8 +840,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart, //case of necessity. else if ( pStart->IsInFootnote() ) { - while ( pCnt && (!pCnt->IsInFootnote() || - (pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow()))) + while (pCnt && (!pCnt->IsInFootnote() || pCnt->IsHiddenNow())) { pCnt = (*fnNxtPrv)( pCnt ); pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel ); @@ -851,7 +850,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart, //In Flys we can go ahead blindly as long as we find a Content. else if ( pStart->IsInFly() ) { - if ( pCnt && pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow() ) + if (pCnt && pCnt->IsHiddenNow()) { pCnt = (*fnNxtPrv)( pCnt ); pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel ); @@ -875,7 +874,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart, } if ( !bSame ) pCnt = nullptr; - else if (pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow()) // i73332 + else if (pCnt->IsHiddenNow()) // i73332 { pCnt = (*fnNxtPrv)( pCnt ); pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel ); @@ -958,8 +957,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart, } } - } while ( !bEnd || - (pCnt && pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow())); + } while (!bEnd || (pCnt && pCnt->IsHiddenNow())); if (pCnt == nullptr) { @@ -1246,7 +1244,7 @@ const SwContentFrame *SwLayoutFrame::GetContentPos( Point& rPoint, if ( pComp != pContent ) continue; - if ( !pContent->IsTextFrame() || !static_cast<const SwTextFrame*>(pContent)->IsHiddenNow() ) + if (!pContent->IsHiddenNow()) { SwRect aContentFrame( pContent->UnionFrame() ); if ( aContentFrame.Contains( rPoint ) ) @@ -1727,6 +1725,15 @@ bool SwFrame::IsProtected() const return false; } +// virtual +bool SwFrame::IsHiddenNow() const +{ + if (const auto* pSectFrame = FindSctFrame()) + return pSectFrame->IsHiddenNow(); + + return false; +} + /** @return the physical page number */ sal_uInt16 SwFrame::GetPhyPageNum() const { diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx index 302302a9a2..52a51ff1a5 100644 --- a/sw/source/core/text/txtfrm.cxx +++ b/sw/source/core/text/txtfrm.cxx @@ -1485,6 +1485,9 @@ bool SwTextFrame::IsHiddenNow() const return true; } + if (SwContentFrame::IsHiddenNow()) + return true; + bool bHiddenCharsHidePara(false); bool bHiddenParaField(false); if (m_pMergedPara) @@ -1554,22 +1557,14 @@ bool SwTextFrame::IsHiddenNow() const // be visible - check this for the 1st body paragraph if (IsInDocBody() && FindPrevCnt() == nullptr) { - bool isAllHidden(true); for (SwContentFrame const* pNext = FindNextCnt(true); pNext != nullptr; pNext = pNext->FindNextCnt(true)) { - if (!pNext->IsTextFrame() - || !static_cast<SwTextFrame const*>(pNext)->IsHiddenNow()) - { - isAllHidden = false; - break; - } - } - if (isAllHidden) - { - SAL_INFO("sw.core", "unhiding one body paragraph"); - return false; + if (!pNext->IsHiddenNow()) + return true; } + SAL_INFO("sw.core", "unhiding one body paragraph"); + return false; } return true; } diff --git a/sw/source/core/tox/tox.cxx b/sw/source/core/tox/tox.cxx index 04f43e5d41..b29bafde11 100644 --- a/sw/source/core/tox/tox.cxx +++ b/sw/source/core/tox/tox.cxx @@ -148,7 +148,13 @@ void SwTOXMark::RegisterToTOXType(SwTOXType& rType) bool SwTOXMark::operator==( const SfxPoolItem& rAttr ) const { assert(SfxPoolItem::operator==(rAttr)); - return m_pType == static_cast<const SwTOXMark&>(rAttr).m_pType; + // tdf#158783 this item was never 'pooled', so operator== was not really + // ever used. We discussed to implement it (there is quite some + // content), but we came to the point that it's only safe to say + // instances are equal when same instance -> fallback to ptr compare. + // NOTE: Do *not* use areSfxPoolItemPtrsEqual here, with DBG_UTIL + // active the contol/test code there would again call operator== + return this == &rAttr; } SwTOXMark* SwTOXMark::Clone( SfxItemPool* ) const diff --git a/sw/source/core/unocore/unocrsrhelper.cxx b/sw/source/core/unocore/unocrsrhelper.cxx index 70a724814c..30f6d6e619 100644 --- a/sw/source/core/unocore/unocrsrhelper.cxx +++ b/sw/source/core/unocore/unocrsrhelper.cxx @@ -225,7 +225,7 @@ void GetSelectableFromAny(uno::Reference<uno::XInterface> const& xIfc, return; } - uno::Reference<text::XTextRange> const xTextRange(xTunnel, UNO_QUERY); + uno::Reference<text::XTextRange> const xTextRange(xIfc, UNO_QUERY); if (xTextRange.is()) { SwUnoInternalPaM aPam(rTargetDoc); diff --git a/sw/source/core/unocore/unomap1.cxx b/sw/source/core/unocore/unomap1.cxx index 12db464a87..f9e16b1f42 100644 --- a/sw/source/core/unocore/unomap1.cxx +++ b/sw/source/core/unocore/unomap1.cxx @@ -307,6 +307,7 @@ std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetAutoCharS { UNO_NAME_CHAR_BORDER_TOP_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_TOP_COLOR }, { UNO_NAME_CHAR_BORDER_BOTTOM_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_BOTTOM_COLOR }, { UNO_NAME_CHAR_SHADOW_FORMAT, RES_CHRATR_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PROPERTY_NONE, CONVERT_TWIPS}, + { UNO_NAME_CHAR_STYLE_NAME, RES_TXTATR_CHARFMT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0 }, }; return aAutoCharStyleMap; diff --git a/sw/source/core/unocore/unoobj.cxx b/sw/source/core/unocore/unoobj.cxx index b2f83fee30..49562c1d02 100644 --- a/sw/source/core/unocore/unoobj.cxx +++ b/sw/source/core/unocore/unoobj.cxx @@ -539,11 +539,6 @@ SwUnoCursorHelper::SetCursorPropertyValue( rMap.getByName(prop.Name); if (!pEntry) { - if (prop.Name == "CharStyleName") - { - lcl_setCharStyle(rPam.GetDoc(), prop.Value, items); - continue; - } throw beans::UnknownPropertyException( "Unknown property: " + prop.Name); } @@ -552,7 +547,14 @@ SwUnoCursorHelper::SetCursorPropertyValue( throw beans::PropertyVetoException( "Property is read-only: " + prop.Name); } - rPropSet.setPropertyValue(*pEntry, prop.Value, items); + if (prop.Name == "CharStyleName") + { + lcl_setCharStyle(rPam.GetDoc(), prop.Value, items); + } + else + { + rPropSet.setPropertyValue(*pEntry, prop.Value, items); + } } IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess(); diff --git a/sw/source/core/unocore/unoportenum.cxx b/sw/source/core/unocore/unoportenum.cxx index 186b5c5b23..494cec7468 100644 --- a/sw/source/core/unocore/unoportenum.cxx +++ b/sw/source/core/unocore/unoportenum.cxx @@ -84,7 +84,17 @@ static void lcl_CreatePortions( namespace { enum class BkmType { - Start, End, StartEnd + // The order is important: BookmarkCompareStruct::operator () depends on it. + // When different bookmarks' starts/ends appear at one position, by default (when there's no + // frames at the position - see lcl_ExportBookmark), first previous bookmarks close, then + // collapsed ones appear, then new bookmarks open. + End, StartEnd, Start + }; + + enum class ExportBookmarkPass + { + before_frames, + after_frames, }; struct SwXBookmarkPortion_Impl @@ -124,7 +134,8 @@ namespace // start of the 2nd bookmark BEFORE the end of the first bookmark // See bug #i58438# for more details. The below code is correct and // fixes both #i58438 and #i16896# - return r1->aPosition < r2->aPosition; + return std::make_pair(r1->aPosition, r1->nBkmType) + < std::make_pair(r2->aPosition, r2->nBkmType); } }; typedef std::multiset < SwXBookmarkPortion_ImplSharedPtr, BookmarkCompareStruct > SwXBookmarkPortion_ImplList; @@ -132,13 +143,15 @@ namespace /// Inserts pBkmk to rBkmArr in case it starts or ends at rOwnNode void lcl_FillBookmark(sw::mark::IMark* const pBkmk, const SwNode& rOwnNode, SwDoc& rDoc, SwXBookmarkPortion_ImplList& rBkmArr) { - bool const hasOther = pBkmk->IsExpanded(); + bool const isExpanded = pBkmk->IsExpanded(); const SwPosition& rStartPos = pBkmk->GetMarkStart(); const SwPosition& rEndPos = pBkmk->GetMarkEnd(); + // A bookmark where the text was deleted becomes collapsed + bool const hasOther = isExpanded && rStartPos != rEndPos; bool const bStartPosInNode = rStartPos.GetNode() == rOwnNode; bool const bEndPosInNode = rEndPos.GetNode() == rOwnNode; sw::mark::CrossRefBookmark* const pCrossRefMark - = !hasOther && (bStartPosInNode || bEndPosInNode) + = !isExpanded && bStartPosInNode ? dynamic_cast<sw::mark::CrossRefBookmark*>(pBkmk) : nullptr; @@ -560,15 +573,23 @@ lcl_CreateContentControlPortion(const css::uno::Reference<SwXText>& xParent, * Exports all bookmarks from rBkmArr into rPortions that have the same start * or end position as nIndex. * - * @param rBkmArr the array of bookmarks. If bOnlyFrameStarts is true, then - * this is only read, otherwise consumed entries are removed. + * @param rBkmArr the array of bookmarks. * * @param rFramePositions the list of positions where there is an at-char / * anchored frame. + * Collapsed (BkmType::StartEnd) bookmarks, as well as bookmarks that start/end + * at the frame anchor position, are considered as wrapping the frames, if any + * (i.e., starts are output before the frames; ends are output after frames). + * When there's no frame here, bookmarks are expected to not overlap (#i58438): + * first, non-collapsed bookmarks' ends are output; then collapsed bookmarks; + * then non-collapsed bookmarks' starts. * - * @param bOnlyFrameStarts If true: export only the start of the bookmarks - * which cover an at-char anchored frame. If false: export the end of the same - * bookmarks and everything else. + * @param stage Case before_frames: if there is a frame at this index, output + * starts of both collapsed and non-collapsed bookmarks (remove non-collapsed + * starts from rBkmArr, convert collapsed ones to ends); if there's no frame, + * doesn't output anything. + * Case after_frames: outputs (and removes from rBkmArr) everything (left) at + * this index, in the order of occurrence in rBkmArr (see #i58438). */ static void lcl_ExportBookmark( TextRangeList_t & rPortions, @@ -577,54 +598,56 @@ static void lcl_ExportBookmark( SwXBookmarkPortion_ImplList& rBkmArr, const sal_Int32 nIndex, const o3tl::sorted_vector<sal_Int32>& rFramePositions, - bool bOnlyFrameStarts) + ExportBookmarkPass stage) { for ( SwXBookmarkPortion_ImplList::iterator aIter = rBkmArr.begin(), aEnd = rBkmArr.end(); aIter != aEnd; ) { const SwXBookmarkPortion_ImplSharedPtr& pPtr = *aIter; if ( nIndex > pPtr->getIndex() ) { - if (bOnlyFrameStarts) - ++aIter; - else - aIter = rBkmArr.erase(aIter); + assert(!"Some bookmarks were not consumed earlier"); continue; } if ( nIndex < pPtr->getIndex() ) break; - if ((BkmType::Start == pPtr->nBkmType && bOnlyFrameStarts) || - (BkmType::StartEnd == pPtr->nBkmType)) + if (stage == ExportBookmarkPass::before_frames) { - bool bFrameStart = rFramePositions.find(nIndex) != rFramePositions.end(); - bool bEnd = pPtr->nBkmType == BkmType::StartEnd && bFrameStart && !bOnlyFrameStarts; - if (pPtr->nBkmType == BkmType::Start || bFrameStart || !bOnlyFrameStarts) + if (rFramePositions.find(nIndex) == rFramePositions.end()) // No frames at this index + break; // Do nothing; everything will be output at after_frames pass + + if (pPtr->nBkmType == BkmType::End) { - // At this we create a text portion, due to one of these - // reasons: - // - this is the real start of a non-collapsed bookmark - // - this is the real position of a collapsed bookmark - // - this is the start or end (depending on bOnlyFrameStarts) - // of a collapsed bookmark at the same position as an at-char - // anchored frame - rtl::Reference<SwXTextPortion> pPortion = - new SwXTextPortion(pUnoCursor, xParent, bEnd ? PORTION_BOOKMARK_END : PORTION_BOOKMARK_START); - rPortions.emplace_back(pPortion); - pPortion->SetBookmark(pPtr->xBookmark); - pPortion->SetCollapsed( BkmType::StartEnd == pPtr->nBkmType && !bFrameStart ); + ++aIter; + continue; // Only consider BkmType::Start and BkmType::StartEnd in this pass } } - else if (BkmType::End == pPtr->nBkmType && !bOnlyFrameStarts) - { - rtl::Reference<SwXTextPortion> pPortion = - new SwXTextPortion(pUnoCursor, xParent, PORTION_BOOKMARK_END); - rPortions.emplace_back(pPortion); - pPortion->SetBookmark(pPtr->xBookmark); - } + + // At this we create a text portion, due to one of these + // reasons: + // - this is the real start of a non-collapsed bookmark + // - this is the real end of a non-collapsed bookmark + // - this is the real position of a collapsed bookmark + // - this is the start or end of a collapsed bookmark at the same position as an at-char + // anchored frame + const SwTextPortionType portionType + = pPtr->nBkmType == BkmType::End ? PORTION_BOOKMARK_END : PORTION_BOOKMARK_START; + const bool collapsed + = pPtr->nBkmType == BkmType::StartEnd && stage == ExportBookmarkPass::after_frames; + + rtl::Reference<SwXTextPortion> pPortion = new SwXTextPortion(pUnoCursor, xParent, portionType); + rPortions.emplace_back(pPortion); + pPortion->SetBookmark(pPtr->xBookmark); + pPortion->SetCollapsed(collapsed); // next bookmark - if (bOnlyFrameStarts) + if (pPtr->nBkmType == BkmType::StartEnd && stage == ExportBookmarkPass::before_frames) + { + // This is a collapsed bookmark around a frame, and its start portion was just emitted; + // turn it into an end bookmark to process after_frames + pPtr->nBkmType = BkmType::End; ++aIter; + } else aIter = rBkmArr.erase(aIter); } @@ -1168,13 +1191,12 @@ static void lcl_ExportBkmAndRedline( SwSoftPageBreakList& rBreakArr, const sal_Int32 nIndex, const o3tl::sorted_vector<sal_Int32>& rFramePositions, - bool bOnlyFrameBookmarkStarts) + ExportBookmarkPass stage) { if (!rBkmArr.empty()) - lcl_ExportBookmark(rPortions, xParent, pUnoCursor, rBkmArr, nIndex, rFramePositions, - bOnlyFrameBookmarkStarts); + lcl_ExportBookmark(rPortions, xParent, pUnoCursor, rBkmArr, nIndex, rFramePositions, stage); - if (bOnlyFrameBookmarkStarts) + if (stage == ExportBookmarkPass::before_frames) // Only exporting the start of some collapsed bookmarks: no export of // other arrays. return; @@ -1401,7 +1423,7 @@ static void lcl_CreatePortions( // Then export start of collapsed bookmarks which "cover" at-char // anchored frames. lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText, - pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/true ); + pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, ExportBookmarkPass::before_frames ); lcl_ExportAnnotationStarts( *PortionStack.top().first, @@ -1419,7 +1441,7 @@ static void lcl_CreatePortions( // Export ends of the previously started collapsed bookmarks + all // other bookmarks, redlines, etc. lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText, - pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/false ); + pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, ExportBookmarkPass::after_frames ); lcl_ExportAnnotationStarts( *PortionStack.top().first, diff --git a/sw/source/core/unocore/unotext.cxx b/sw/source/core/unocore/unotext.cxx index f959d6a610..93603d6d40 100644 --- a/sw/source/core/unocore/unotext.cxx +++ b/sw/source/core/unocore/unotext.cxx @@ -1634,6 +1634,9 @@ SwXText::convertToTextFrame( // see testFlyInFly for why this checks only the edges of the selection, // and testFloatingTablesAnchor for why it excludes pre/post table // added nodes + // TODO: isGraphicNode here looks dubious; see also tdf#47036 fix; + // this needs more investigation when exactly Word considers something + // anchored in text frame vs. anchored in body. if (!isGraphicNode(pFrameFormat) && (IsAtParaMatch(*oAnchorCheckPam, rAnchor) || (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId() diff --git a/sw/source/filter/html/css1atr.cxx b/sw/source/filter/html/css1atr.cxx index 30ba8d3c0a..2587edfaf2 100644 --- a/sw/source/filter/html/css1atr.cxx +++ b/sw/source/filter/html/css1atr.cxx @@ -3301,14 +3301,16 @@ SwHTMLWriter& OutCSS1_SvxBox( SwHTMLWriter& rWrt, const SfxPoolItem& rHt ) if( rHt.Which() == RES_CHRATR_BOX ) { + constexpr std::string_view inline_block("inline-block"); if( rWrt.m_bTagOn ) { // Inline-block to make the line height changing correspond to the character border - rWrt.OutCSS1_PropertyAscii(sCSS1_P_display, "inline-block"); + rWrt.OutCSS1_PropertyAscii(sCSS1_P_display, inline_block); } else { - HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span), false ); + if (!IgnorePropertyForReqIF(rWrt.mbReqIF, sCSS1_P_display, inline_block)) + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span), false ); return rWrt; } } diff --git a/sw/source/filter/html/htmlatr.cxx b/sw/source/filter/html/htmlatr.cxx index 9f67d1ee03..c880082018 100644 --- a/sw/source/filter/html/htmlatr.cxx +++ b/sw/source/filter/html/htmlatr.cxx @@ -1058,7 +1058,7 @@ public: HTMLStartEndPos( const SfxPoolItem& rItem, sal_Int32 nStt, sal_Int32 nE ); - const SfxPoolItem* GetItem() const { return m_pItem.get(); } + const SfxPoolItem& GetItem() const { return *m_pItem; } void SetStart(sal_Int32 nStt) { m_nStart = nStt; } sal_Int32 GetStart() const { return m_nStart; } @@ -1075,7 +1075,7 @@ HTMLStartEndPos::HTMLStartEndPos(const SfxPoolItem& rItem, sal_Int32 nStt, sal_I , m_pItem(rItem.Clone()) {} -typedef std::vector<HTMLStartEndPos *> HTMLStartEndPositions; +typedef std::map<sal_Int32, std::vector<HTMLStartEndPos*>> HTMLStartEndPositions; namespace { @@ -1091,8 +1091,8 @@ enum HTMLOnOffState { HTML_NOT_SUPPORTED, // unsupported Attribute class HTMLEndPosLst { - HTMLStartEndPositions m_aStartLst; // list, sorted for start positions - HTMLStartEndPositions m_aEndLst; // list, sorted for end positions + HTMLStartEndPositions m_aStartLst; // list, each position's elements sorted by appearance order + HTMLStartEndPositions m_aEndLst; // list, no sort of elements in position std::deque<sal_Int32> m_aScriptChgLst; // positions where script changes // 0 is not contained in this list, // but the text length @@ -1110,8 +1110,7 @@ class HTMLEndPosLst // Insert/remove a SttEndPos in/from the Start and End lists. // The end position is known. - void InsertItem_( HTMLStartEndPos *pPos, HTMLStartEndPositions::size_type nEndPos ); - void RemoveItem_( HTMLStartEndPositions::size_type nEndPos ); + void InsertItem_(HTMLStartEndPos* pPos); // determine the 'type' of the attribute HTMLOnOffState GetHTMLItemState( const SfxPoolItem& rItem ); @@ -1125,8 +1124,7 @@ class HTMLEndPosLst sal_Int32 nEndPos ); // adapt the end of a split item - void FixSplittedItem( HTMLStartEndPos *pPos, sal_Int32 nNewEnd, - HTMLStartEndPositions::size_type nStartPos ); + void FixSplittedItem(HTMLStartEndPos* pPos, sal_Int32 nNewEnd); // insert an attribute in the lists and, if necessary, split it void InsertItem( const SfxPoolItem& rItem, sal_Int32 nStart, @@ -1144,6 +1142,8 @@ class HTMLEndPosLst const SwHTMLFormatInfo *GetFormatInfo( const SwFormat& rFormat, SwHTMLFormatInfos& rFormatInfos ); + void OutEndAttrs(SwHTMLWriter& rWrt, std::vector<HTMLStartEndPos*>& posItems); + public: HTMLEndPosLst( SwDoc *pDoc, SwDoc* pTemplate, std::optional<Color> xDfltColor, @@ -1169,36 +1169,46 @@ public: bool IsHTMLMode(sal_uLong nMode) const { return (m_nHTMLMode & nMode) != 0; } }; -} - -void HTMLEndPosLst::InsertItem_( HTMLStartEndPos *pPos, HTMLStartEndPositions::size_type nEndPos ) +struct SortEnds { - // Insert the attribute in the Start list behind all attributes that - // were started before, or at the same position. - sal_Int32 nStart = pPos->GetStart(); - HTMLStartEndPositions::size_type i {0}; + HTMLStartEndPositions& m_startList; + SortEnds(HTMLStartEndPositions& startList) : m_startList(startList) {} + bool operator()(const HTMLStartEndPos* p1, const HTMLStartEndPos* p2) + { + // if p1 start after p2, then it ends before + if (p1->GetStart() > p2->GetStart()) + return true; + if (p1->GetStart() < p2->GetStart()) + return false; + for (const auto p : m_startList[p1->GetStart()]) + { + if (p == p1) + return false; + if (p == p2) + return true; + } + assert(!"Neither p1 nor p2 found in their start list"); + return false; + } +}; - while (i < m_aStartLst.size() && m_aStartLst[i]->GetStart() <= nStart) - ++i; - m_aStartLst.insert(m_aStartLst.begin() + i, pPos); +#ifndef NDEBUG +bool IsEmpty(const HTMLStartEndPositions& l) +{ + return std::find_if(l.begin(), l.end(), [](auto& i) { return !i.second.empty(); }) == l.end(); +} +#endif - // the position in the End list was supplied - m_aEndLst.insert(m_aEndLst.begin() + nEndPos, pPos); } -void HTMLEndPosLst::RemoveItem_( HTMLStartEndPositions::size_type nEndPos ) +void HTMLEndPosLst::InsertItem_(HTMLStartEndPos* pPos) { - HTMLStartEndPos* pPos = m_aEndLst[nEndPos]; + // Character border attribute must be the first which is written out because of border merge. + auto& posItems1 = m_aStartLst[pPos->GetStart()]; + auto it = pPos->GetItem().Which() == RES_CHRATR_BOX ? posItems1.begin() : posItems1.end(); + posItems1.insert(it, pPos); - // now, we are looking for it in the Start list - HTMLStartEndPositions::iterator it = std::find(m_aStartLst.begin(), m_aStartLst.end(), pPos); - OSL_ENSURE(it != m_aStartLst.end(), "Item not found in Start List!"); - if (it != m_aStartLst.end()) - m_aStartLst.erase(it); - - m_aEndLst.erase(m_aEndLst.begin() + nEndPos); - - delete pPos; + m_aEndLst[pPos->GetEnd()].push_back(pPos); } HTMLOnOffState HTMLEndPosLst::GetHTMLItemState( const SfxPoolItem& rItem ) @@ -1352,23 +1362,25 @@ HTMLOnOffState HTMLEndPosLst::GetHTMLItemState( const SfxPoolItem& rItem ) bool HTMLEndPosLst::ExistsOnTagItem( sal_uInt16 nWhich, sal_Int32 nPos ) { - for (auto pTest : m_aStartLst) + for (const auto& [startPos, items] : m_aStartLst) { - if( pTest->GetStart() > nPos ) + if (startPos > nPos) { // this attribute, and all attributes that follow, start later break; } - else if( pTest->GetEnd() > nPos ) + + for (const auto* pTest : items) { - // the attribute starts before, or at, the current position and - // ends after it - const SfxPoolItem *pItem = pTest->GetItem(); - if( pItem->Which() == nWhich && - HTML_ON_VALUE == GetHTMLItemState(*pItem) ) + if (pTest->GetEnd() > nPos) { - // an OnTag attribute was found - return true; + // the attribute starts before, or at, the current position and ends after it + const SfxPoolItem& rItem = pTest->GetItem(); + if (rItem.Which() == nWhich && HTML_ON_VALUE == GetHTMLItemState(rItem)) + { + // an OnTag attribute was found + return true; + } } } } @@ -1386,24 +1398,17 @@ bool HTMLEndPosLst::ExistsOffTagItem( sal_uInt16 nWhich, sal_Int32 nStartPos, return false; } - for (auto pTest : m_aStartLst) + for (const auto* pTest : m_aStartLst[nStartPos]) { - if( pTest->GetStart() > nStartPos ) - { - // this attribute, and all attributes that follow, start later - break; - } - else if( pTest->GetStart()==nStartPos && - pTest->GetEnd()==nEndPos ) + if (pTest->GetEnd() == nEndPos) { - // the attribute starts before or at the current position and - // ends after it - const SfxPoolItem *pItem = pTest->GetItem(); - sal_uInt16 nTstWhich = pItem->Which(); + // the attribute starts before or at the current position and ends after it + const SfxPoolItem& rItem = pTest->GetItem(); + sal_uInt16 nTstWhich = rItem.Which(); if( (nTstWhich == RES_CHRATR_CROSSEDOUT || nTstWhich == RES_CHRATR_UNDERLINE || nTstWhich == RES_CHRATR_BLINK) && - HTML_OFF_VALUE == GetHTMLItemState(*pItem) ) + HTML_OFF_VALUE == GetHTMLItemState(rItem) ) { // an OffTag attribute was found that is exported the same // way as the current item @@ -1415,55 +1420,51 @@ bool HTMLEndPosLst::ExistsOffTagItem( sal_uInt16 nWhich, sal_Int32 nStartPos, return false; } -void HTMLEndPosLst::FixSplittedItem( HTMLStartEndPos *pPos, sal_Int32 nNewEnd, - HTMLStartEndPositions::size_type nStartPos ) +void HTMLEndPosLst::FixSplittedItem(HTMLStartEndPos* pPos, sal_Int32 nNewEnd) { + // remove the item from the End list + std::erase(m_aEndLst[pPos->GetEnd()], pPos); // fix the end position accordingly pPos->SetEnd( nNewEnd ); - - // remove the item from the End list - HTMLStartEndPositions::iterator it = std::find(m_aEndLst.begin(), m_aEndLst.end(), pPos); - OSL_ENSURE(it != m_aEndLst.end(), "Item not found in End List!"); - if (it != m_aEndLst.end()) - m_aEndLst.erase(it); - - // from now on, it is closed as the last one at the corresponding position - HTMLStartEndPositions::size_type nEndPos {0}; - while (nEndPos < m_aEndLst.size() && m_aEndLst[nEndPos]->GetEnd() <= nNewEnd) - ++nEndPos; - m_aEndLst.insert(m_aEndLst.begin() + nEndPos, pPos); + // from now on, it is closed at the corresponding position + m_aEndLst[nNewEnd].push_back(pPos); // now, adjust the attributes that got started afterwards - for (HTMLStartEndPositions::size_type i = nStartPos + 1; i < m_aStartLst.size(); ++i) + const sal_Int32 nPos = pPos->GetStart(); + for (const auto& [startPos, items] : m_aStartLst) { - HTMLStartEndPos* pTest = m_aStartLst[i]; - sal_Int32 nTestEnd = pTest->GetEnd(); - if( pTest->GetStart() >= nNewEnd ) - { - // the Test attribute and all the following ones start, after the - // split attribute ends + if (startPos < nPos) + continue; + + if (startPos >= nNewEnd) break; + + auto it = items.begin(); + if (startPos == nPos) + { + it = std::find(items.begin(), items.end(), pPos); + if (it != items.end()) + ++it; } - else if( nTestEnd > nNewEnd ) + for (; it != items.end(); ++it) { + HTMLStartEndPos* pTest = *it; + const sal_Int32 nTestEnd = pTest->GetEnd(); + if (nTestEnd <= nNewEnd) + continue; + // the Test attribute starts before the split attribute // ends, and ends afterwards, i.e., it must be split, as well + // remove the attribute from the End list + std::erase(m_aEndLst[pTest->GetEnd()], pTest); // set the new end pTest->SetEnd( nNewEnd ); - - // remove the attribute from the End list - it = std::find(m_aEndLst.begin(), m_aEndLst.end(), pTest); - OSL_ENSURE(it != m_aEndLst.end(), "Item not found in End List!"); - if (it != m_aEndLst.end()) - m_aEndLst.erase(it); - - // it now ends as the first attribute in the respective position. - // We already know this position in the End list. - m_aEndLst.insert(m_aEndLst.begin() + nEndPos, pTest); + // it now ends in the respective position. + m_aEndLst[nNewEnd].push_back(pTest); // insert the 'rest' of the attribute - InsertItem( *pTest->GetItem(), nNewEnd, nTestEnd ); + InsertItem( pTest->GetItem(), nNewEnd, nTestEnd ); } } } @@ -1471,36 +1472,38 @@ void HTMLEndPosLst::FixSplittedItem( HTMLStartEndPos *pPos, sal_Int32 nNewEnd, void HTMLEndPosLst::InsertItem( const SfxPoolItem& rItem, sal_Int32 nStart, sal_Int32 nEnd ) { - HTMLStartEndPositions::size_type i; - for (i = 0; i < m_aEndLst.size(); i++) + assert(nStart < nEnd); + + for (auto& [endPos, items] : m_aEndLst) { - HTMLStartEndPos* pTest = m_aEndLst[i]; - sal_Int32 nTestEnd = pTest->GetEnd(); - if( nTestEnd <= nStart ) + if (endPos <= nStart) { // the Test attribute ends, before the new one starts continue; } - else if( nTestEnd < nEnd ) + if (endPos >= nEnd) + { + // the Test attribute (and all that follow) ends, before the new + // one ends + break; + } + + std::sort(items.begin(), items.end(), SortEnds(m_aStartLst)); + + for (HTMLStartEndPos* pTest : items) { if( pTest->GetStart() < nStart ) { // the Test attribute ends, before the new one ends. Thus, the // new attribute must be split. - InsertItem_( new HTMLStartEndPos( rItem, nStart, nTestEnd ), i ); - nStart = nTestEnd; + InsertItem_(new HTMLStartEndPos(rItem, nStart, endPos)); + nStart = endPos; } } - else - { - // the Test attribute (and all that follow) ends, before the new - // one ends - break; - } } // one attribute must still be inserted - InsertItem_( new HTMLStartEndPos( rItem, nStart, nEnd ), i ); + InsertItem_(new HTMLStartEndPos(rItem, nStart, nEnd)); } void HTMLEndPosLst::SplitItem( const SfxPoolItem& rItem, sal_Int32 nStart, @@ -1511,59 +1514,47 @@ void HTMLEndPosLst::SplitItem( const SfxPoolItem& rItem, sal_Int32 nStart, // first, we must search for the old items by using the start list and // determine the new item range - for (HTMLStartEndPositions::size_type i = 0; i < m_aStartLst.size(); ++i) + for (auto& [nTestStart, items] : m_aStartLst) { - HTMLStartEndPos* pTest = m_aStartLst[i]; - sal_Int32 nTestStart = pTest->GetStart(); - sal_Int32 nTestEnd = pTest->GetEnd(); - if( nTestStart >= nEnd ) { // this attribute, and all that follow, start later break; } - else if( nTestEnd > nStart ) + + for (auto it = items.begin(); it != items.end();) { + HTMLStartEndPos* pTest = *it; + sal_Int32 nTestEnd = pTest->GetEnd(); + if (nTestEnd <= nStart) + continue; + // the Test attribute ends in the range that must be deleted - const SfxPoolItem *pItem = pTest->GetItem(); + const SfxPoolItem& rTestItem = pTest->GetItem(); // only the corresponding OnTag attributes have to be considered - if( pItem->Which() == nWhich && - HTML_ON_VALUE == GetHTMLItemState( *pItem ) ) + if (rTestItem.Which() == nWhich && HTML_ON_VALUE == GetHTMLItemState(rTestItem)) { - bool bDelete = true; + // if necessary, insert the second part of the split + // attribute + if (nTestEnd > nEnd) + InsertItem(pTest->GetItem(), nEnd, nTestEnd); - if( nTestStart < nStart ) - { - // the start of the new attribute corresponds to the new - // end of the attribute - FixSplittedItem( pTest, nStart, i ); - bDelete = false; - } - else + if (nTestStart >= nStart) { // the Test item only starts after the new end of the // attribute. Therefore, it can be completely erased. - m_aStartLst.erase(m_aStartLst.begin() + i); - i--; - - HTMLStartEndPositions::iterator it - = std::find(m_aEndLst.begin(), m_aEndLst.end(), pTest); - OSL_ENSURE(it != m_aEndLst.end(), "Item not found in End List!"); - if (it != m_aEndLst.end()) - m_aEndLst.erase(it); - } - - // if necessary, insert the second part of the split - // attribute - if( nTestEnd > nEnd ) - { - InsertItem( *pTest->GetItem(), nEnd, nTestEnd ); + it = items.erase(it); + std::erase(m_aEndLst[pTest->GetEnd()], pTest); + delete pTest; + continue; } - if( bDelete ) - delete pTest; + // the start of the new attribute corresponds to the new + // end of the attribute + FixSplittedItem(pTest, nStart); } + ++it; } } } @@ -1611,8 +1602,8 @@ HTMLEndPosLst::HTMLEndPosLst(SwDoc* pD, SwDoc* pTempl, std::optional<Color> xDfl HTMLEndPosLst::~HTMLEndPosLst() { - OSL_ENSURE(m_aStartLst.empty(), "Start List not empty in destructor"); - OSL_ENSURE(m_aEndLst.empty(), "End List not empty in destructor"); + assert(IsEmpty(m_aStartLst) && "Start List not empty in destructor"); + assert(IsEmpty(m_aEndLst) && "End List not empty in destructor"); } void HTMLEndPosLst::InsertNoScript( const SfxPoolItem& rItem, @@ -1900,53 +1891,25 @@ void HTMLEndPosLst::OutStartAttrs( SwHTMLWriter& rWrt, sal_Int32 nPos ) { rWrt.m_bTagOn = true; - // Character border attribute must be the first which is written out - // because of border merge. - HTMLStartEndPositions::size_type nCharBoxIndex = 0; - while (nCharBoxIndex < m_aStartLst.size() - && m_aStartLst[nCharBoxIndex]->GetItem()->Which() != RES_CHRATR_BOX) - { - ++nCharBoxIndex; - } - + auto it = m_aStartLst.find(nPos); + if (it == m_aStartLst.end()) + return; // the attributes of the start list are sorted in ascending order - for (HTMLStartEndPositions::size_type i = 0; i < m_aStartLst.size(); ++i) + for (HTMLStartEndPos* pPos : it->second) { - HTMLStartEndPos *pPos = nullptr; - if (nCharBoxIndex < m_aStartLst.size()) - { - if( i == 0 ) - pPos = m_aStartLst[nCharBoxIndex]; - else if( i == nCharBoxIndex ) - pPos = m_aStartLst[0]; - else - pPos = m_aStartLst[i]; - } - else - pPos = m_aStartLst[i]; - - sal_Int32 nStart = pPos->GetStart(); - if( nStart > nPos ) - { - // this attribute, and all that follow, will be opened later on - break; - } - else if( nStart == nPos ) + // output the attribute + sal_uInt16 nCSS1Script = rWrt.m_nCSS1Script; + sal_uInt16 nWhich = pPos->GetItem().Which(); + if( RES_TXTATR_CHARFMT == nWhich || + RES_TXTATR_INETFMT == nWhich || + RES_PARATR_DROP == nWhich ) { - // output the attribute - sal_uInt16 nCSS1Script = rWrt.m_nCSS1Script; - sal_uInt16 nWhich = pPos->GetItem()->Which(); - if( RES_TXTATR_CHARFMT == nWhich || - RES_TXTATR_INETFMT == nWhich || - RES_PARATR_DROP == nWhich ) - { - rWrt.m_nCSS1Script = GetScriptAtPos( nPos, nCSS1Script ); - } - HTMLOutFuncs::FlushToAscii( rWrt.Strm() ); // was one time only - do we still need it? - Out( aHTMLAttrFnTab, *pPos->GetItem(), rWrt ); - rWrt.maStartedAttributes[pPos->GetItem()->Which()]++; - rWrt.m_nCSS1Script = nCSS1Script; + rWrt.m_nCSS1Script = GetScriptAtPos( nPos, nCSS1Script ); } + HTMLOutFuncs::FlushToAscii( rWrt.Strm() ); // was one time only - do we still need it? + Out( aHTMLAttrFnTab, pPos->GetItem(), rWrt ); + rWrt.maStartedAttributes[pPos->GetItem().Which()]++; + rWrt.m_nCSS1Script = nCSS1Script; } } @@ -1954,59 +1917,55 @@ void HTMLEndPosLst::OutEndAttrs( SwHTMLWriter& rWrt, sal_Int32 nPos ) { rWrt.m_bTagOn = false; - // the attributes in the End list are sorted in ascending order - HTMLStartEndPositions::size_type i {0}; - while (i < m_aEndLst.size()) + if (nPos == SAL_MAX_INT32) + { + for (auto& element : m_aEndLst) + OutEndAttrs(rWrt, element.second); + } + else { - HTMLStartEndPos* pPos = m_aEndLst[i]; - sal_Int32 nEnd = pPos->GetEnd(); + auto it = m_aEndLst.find(nPos); + if (it != m_aEndLst.end()) + OutEndAttrs(rWrt, it->second); + } +} - if( SAL_MAX_INT32 == nPos || nEnd == nPos ) +void HTMLEndPosLst::OutEndAttrs(SwHTMLWriter& rWrt, std::vector<HTMLStartEndPos*>& posItems) +{ + std::sort(posItems.begin(), posItems.end(), SortEnds(m_aStartLst)); + for (auto it = posItems.begin(); it != posItems.end(); it = posItems.erase(it)) + { + HTMLStartEndPos* pPos = *it; + HTMLOutFuncs::FlushToAscii( rWrt.Strm() ); // was one time only - do we still need it? + // Skip closing span if next character span has the same border (border merge) + bool bSkipOut = false; + if( pPos->GetItem().Which() == RES_CHRATR_BOX ) { - HTMLOutFuncs::FlushToAscii( rWrt.Strm() ); // was one time only - do we still need it? - // Skip closing span if next character span has the same border (border merge) - bool bSkipOut = false; - if( pPos->GetItem()->Which() == RES_CHRATR_BOX ) + auto& startPosItems = m_aStartLst[pPos->GetEnd()]; + for (auto it2 = startPosItems.begin(); it2 != startPosItems.end(); ++it2) { - HTMLStartEndPositions::iterator it - = std::find(m_aStartLst.begin(), m_aStartLst.end(), pPos); - OSL_ENSURE(it != m_aStartLst.end(), "Item not found in Start List!"); - if (it != m_aStartLst.end()) - ++it; - while (it != m_aStartLst.end()) + HTMLStartEndPos* pEndPos = *it2; + if( pEndPos->GetItem().Which() == RES_CHRATR_BOX && + static_cast<const SvxBoxItem&>(pEndPos->GetItem()) == + static_cast<const SvxBoxItem&>(pPos->GetItem()) ) { - HTMLStartEndPos *pEndPos = *it; - if( pEndPos->GetItem()->Which() == RES_CHRATR_BOX && - *static_cast<const SvxBoxItem*>(pEndPos->GetItem()) == - *static_cast<const SvxBoxItem*>(pPos->GetItem()) ) - { - pEndPos->SetStart(pPos->GetStart()); - bSkipOut = true; - break; - } - ++it; + startPosItems.erase(it2); + pEndPos->SetStart(pPos->GetStart()); + auto& oldStartPosItems = m_aStartLst[pEndPos->GetStart()]; + oldStartPosItems.insert(oldStartPosItems.begin(), pEndPos); + bSkipOut = true; + break; } } - if( !bSkipOut ) - { - Out( aHTMLAttrFnTab, *pPos->GetItem(), rWrt ); - rWrt.maStartedAttributes[pPos->GetItem()->Which()]--; - } - RemoveItem_( i ); - } - else if( nEnd > nPos ) - { - // this attribute, and all that follow, are closed later on - break; } - else + if( !bSkipOut ) { - // The attribute is closed before the current position. This - // is not allowed, but we can handle it anyway. - OSL_ENSURE( nEnd >= nPos, - "The attribute should've been closed a long time ago" ); - i++; + Out( aHTMLAttrFnTab, pPos->GetItem(), rWrt ); + rWrt.maStartedAttributes[pPos->GetItem().Which()]--; } + + std::erase(m_aStartLst[pPos->GetStart()], pPos); + delete pPos; } } diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index d84549d430..28da6d2883 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -161,6 +161,8 @@ #include <frozen/bits/defines.h> #include <frozen/bits/elsa_std.h> #include <frozen/unordered_map.h> +#include <IDocumentDeviceAccess.hxx> +#include <sfx2/printer.hxx> using ::editeng::SvxBorderLine; @@ -1965,7 +1967,22 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In } // if there is some redlining in the document, output it - StartRedline( m_pRedlineData, bLastRun ); + bool bSkipRedline = false; + if (nLen == 1) + { + // Don't redline content-controls--Word doesn't do them. + SwTextAttr* pAttr + = pNode->GetTextAttrAt(nPos, RES_TXTATR_CONTENTCONTROL, sw::GetTextAttrMode::Default); + if (pAttr && pAttr->GetStart() == nPos) + { + bSkipRedline = true; + } + } + + if (!bSkipRedline) + { + StartRedline(m_pRedlineData, bLastRun); + } // XML_r node should be surrounded with bookmark-begin and bookmark-end nodes if it has bookmarks. // The same is applied for permission ranges. @@ -2042,6 +2059,13 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In // append the actual run end m_pSerializer->endElementNS( XML_w, XML_r ); + // if there is some redlining in the document, output it + // (except in the case of fields with multiple runs) + if (!bSkipRedline) + { + EndRedline(m_pRedlineData, bLastRun); + } + if (nLen != -1) { sal_Int32 nEnd = nPos + nLen; @@ -2052,10 +2076,6 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In } } - // if there is some redlining in the document, output it - // (except in the case of fields with multiple runs) - EndRedline( m_pRedlineData, bLastRun ); - // enclose in a sdt block, if necessary: if one is already started, then don't do it for now // (so on export sdt blocks are never nested ATM) if ( !m_bAnchorLinkedToNode && !m_aRunSdt.m_bStartedSdt) @@ -9118,9 +9138,15 @@ void DocxAttributeOutput::FormatFrameSize( const SwFormatFrameSize& rSize ) } } -void DocxAttributeOutput::FormatPaperBin( const SvxPaperBinItem& ) +void DocxAttributeOutput::FormatPaperBin(const SvxPaperBinItem& rPaperBin) { - SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::FormatPaperBin()" ); + sal_Int8 nPaperBin = rPaperBin.GetValue(); + rtl::Reference<FastAttributeList> attrList = FastSerializerHelper::createAttrList( ); + SfxPrinter* pPrinter = m_rExport.m_rDoc.getIDocumentDeviceAccess().getPrinter(true); + sal_Int16 nPaperSource = pPrinter->GetSourceIndexByPaperBin(nPaperBin); + attrList->add( FSNS( XML_w, XML_first ), OString::number(nPaperSource) ); + attrList->add( FSNS( XML_w, XML_other ), OString::number(nPaperSource) ); + m_pSerializer->singleElementNS( XML_w, XML_paperSrc, attrList ); } void DocxAttributeOutput::FormatFirstLineIndent(SvxFirstLineIndentItem const& rFirstLine) diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx index 2d68556e8a..7dcda8f73f 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.cxx +++ b/sw/source/filter/ww8/rtfattributeoutput.cxx @@ -94,6 +94,8 @@ #include <formatflysplit.hxx> #include <fmtwrapinfluenceonobjpos.hxx> #include "rtfexport.hxx" +#include <IDocumentDeviceAccess.hxx> +#include <sfx2/printer.hxx> using namespace ::com::sun::star; using namespace sw::util; @@ -3324,9 +3326,14 @@ void RtfAttributeOutput::FormatFrameSize(const SwFormatFrameSize& rSize) } } -void RtfAttributeOutput::FormatPaperBin(const SvxPaperBinItem& /*rItem*/) +void RtfAttributeOutput::FormatPaperBin(const SvxPaperBinItem& rItem) { - SAL_INFO("sw.rtf", "TODO: " << __func__); + SfxPrinter* pPrinter = m_rExport.m_rDoc.getIDocumentDeviceAccess().getPrinter(true); + sal_Int16 nPaperSource = pPrinter->GetSourceIndexByPaperBin(rItem.GetValue()); + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_BINFSXN); + m_aSectionBreaks.append(static_cast<sal_Int32>(nPaperSource)); + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_BINSXN); + m_aSectionBreaks.append(static_cast<sal_Int32>(nPaperSource)); } void RtfAttributeOutput::FormatFirstLineIndent(SvxFirstLineIndentItem const& rFirstLine) @@ -3747,6 +3754,12 @@ void RtfAttributeOutput::FormatFillGradient(const XFillGradientItem& rFillGradie const Color aEndColor(rColorStops.back().getStopColor()); m_aFlyProperties.push_back(std::make_pair<OString, OString>( "fillBackColor"_ostr, OString::number(wwUtility::RGBToBGR(aEndColor)))); + + if (rGradient.GetGradientStyle() == awt::GradientStyle_AXIAL) + { + m_aFlyProperties.push_back( + std::make_pair<OString, OString>("fillFocus"_ostr, OString::number(50))); + } } else { diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index 39e2f88523..68437c9529 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -2478,6 +2478,14 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) bool bStartedPostponedRunProperties = false; OUString aSavedSnippet ; + // Don't redline content-controls--Word doesn't do them. + SwTextAttr* pAttr = rNode.GetTextAttrAt(nCurrentPos, RES_TXTATR_CONTENTCONTROL, + sw::GetTextAttrMode::Default); + if (pAttr && pAttr->GetStart() == nCurrentPos) + { + pRedlineData = nullptr; + } + sal_Int32 nNextAttr = GetNextPos( &aAttrIter, rNode, nCurrentPos ); // Skip un-exportable attributes. diff --git a/sw/source/filter/ww8/wrtw8num.cxx b/sw/source/filter/ww8/wrtw8num.cxx index 8d59434db6..681961a377 100644 --- a/sw/source/filter/ww8/wrtw8num.cxx +++ b/sw/source/filter/ww8/wrtw8num.cxx @@ -279,7 +279,7 @@ void WW8AttributeOutput::NumberingLevel( sal_uInt8 /*nLevel*/, sal_Int16 nListTabPos, const OUString &rNumberingString, const SvxBrushItem* pBrush, //For i120928,to transfer graphic of bullet - bool /*isLegal*/ + bool isLegal ) { // Start value @@ -303,6 +303,13 @@ void WW8AttributeOutput::NumberingLevel( sal_uInt8 /*nLevel*/, nAlign = 0; break; } + + if (isLegal) + { + // 3rd bit. + nAlign |= 0x04; + } + m_rWW8Export.m_pTableStrm->WriteUChar( nAlign ); // Write the rgbxchNums[9], positions of placeholders for paragraph diff --git a/sw/source/filter/ww8/ww8par3.cxx b/sw/source/filter/ww8/ww8par3.cxx index d0a294b144..41b203f924 100644 --- a/sw/source/filter/ww8/ww8par3.cxx +++ b/sw/source/filter/ww8/ww8par3.cxx @@ -368,6 +368,8 @@ struct WW8LVL // only THE entries, WE need! short nDxaLeft1; // first line indent sal_uInt8 nNFC; // number format code + /// Legal numbering: whether this level overrides the nfc of all inherited level numbers. + bool fLegal; // Offset of fieldcodes in Num-X-String sal_uInt8 aOfsNumsXCH[WW8ListManager::nMaxLevel]; sal_uInt8 nLenGrpprlChpx; // length, in bytes, of the LVL's grpprlChpx @@ -662,7 +664,15 @@ bool WW8ListManager::ReadLVL(SwNumFormat& rNumFormat, std::unique_ptr<SfxItemSet m_rSt.ReadUChar( aLVL.nNFC ); m_rSt.ReadUChar( aBits1 ); if( ERRCODE_NONE != m_rSt.GetError() ) return false; + // 1st..2nd bits. aLVL.nAlign = (aBits1 & 0x03); + + if (aBits1 & 0x04) + { + // 3rd bit. + aLVL.fLegal = true; + } + if( aBits1 & 0x10 ) aLVL.bV6Prev = true; if( aBits1 & 0x20 ) aLVL.bV6PrSp = true; if( aBits1 & 0x40 ) aLVL.bV6 = true; @@ -898,6 +908,7 @@ bool WW8ListManager::ReadLVL(SwNumFormat& rNumFormat, std::unique_ptr<SfxItemSet if( bSetStartNo && 0 <= aLVL.nStartAt) rNumFormat.SetStart(o3tl::narrowing<sal_uInt16>(aLVL.nStartAt)); rNumFormat.SetNumberingType( nType ); + rNumFormat.SetIsLegal(aLVL.fLegal); rNumFormat.SetNumAdjust( eAdj ); if( style::NumberingType::CHAR_SPECIAL == nType ) diff --git a/sw/source/ui/index/swuiidxmrk.cxx b/sw/source/ui/index/swuiidxmrk.cxx index 39443f7e7b..8a6f74b86e 100644 --- a/sw/source/ui/index/swuiidxmrk.cxx +++ b/sw/source/ui/index/swuiidxmrk.cxx @@ -287,19 +287,20 @@ void SwIndexMarkPane::InitControls() bool bShow = false; pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_PRV ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + // tdf#158783 ptr compare OK for SwTOXMark (more below) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) { m_pSh->GotoTOXMark( *pMoveMark, TOX_NXT ); bShow = true; } - m_xPrevBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark)); + m_xPrevBT->set_sensitive(!areSfxPoolItemPtrsEqual(pMoveMark, pMark)); pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_NXT ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) { m_pSh->GotoTOXMark( *pMoveMark, TOX_PRV ); bShow = true; } - m_xNextBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark)); + m_xNextBT->set_sensitive(!areSfxPoolItemPtrsEqual(pMoveMark, pMark)); if( bShow ) { m_xPrevBT->show(); @@ -308,19 +309,19 @@ void SwIndexMarkPane::InitControls() } pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_PRV ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) { m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_NXT ); bShow = true; } - m_xPrevSameBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark)); + m_xPrevSameBT->set_sensitive(!areSfxPoolItemPtrsEqual(pMoveMark, pMark)); pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_NXT ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) { m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_PRV ); bShow = true; } - m_xNextSameBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark)); + m_xNextSameBT->set_sensitive(!areSfxPoolItemPtrsEqual(pMoveMark, pMark)); if( bShow ) { m_xNextSameBT->show(); @@ -894,25 +895,26 @@ void SwIndexMarkPane::UpdateDialog() if( m_xPrevBT->get_visible() ) { const SwTOXMark* pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_PRV ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + // tdf#158783 ptr compare OK for SwTOXMark (more below) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) m_pSh->GotoTOXMark( *pMoveMark, TOX_NXT ); - m_xPrevBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) ); + m_xPrevBT->set_sensitive( !areSfxPoolItemPtrsEqual(pMoveMark, pMark) ); pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_NXT ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) m_pSh->GotoTOXMark( *pMoveMark, TOX_PRV ); - m_xNextBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) ); + m_xNextBT->set_sensitive( !areSfxPoolItemPtrsEqual(pMoveMark, pMark) ); } if (m_xPrevSameBT->get_visible()) { const SwTOXMark* pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_PRV ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_NXT ); - m_xPrevSameBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) ); + m_xPrevSameBT->set_sensitive( !areSfxPoolItemPtrsEqual(pMoveMark, pMark) ); pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_NXT ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_PRV ); - m_xNextSameBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) ); + m_xNextSameBT->set_sensitive( !areSfxPoolItemPtrsEqual(pMoveMark, pMark) ); } const bool bEnable = !m_pSh->HasReadonlySel(); @@ -1013,7 +1015,8 @@ void SwIndexMarkPane::ReInitDlg(SwWrtShell& rWrtShell, SwTOXMark const * pCurTOX if(pCurTOXMark) { for(sal_uInt16 i = 0; i < m_pTOXMgr->GetTOXMarkCount(); i++) - if (SfxPoolItem::areSame(m_pTOXMgr->GetTOXMark(i), pCurTOXMark)) + // tdf#158783 ptr compare OK for SwTOXMark (more below) + if (areSfxPoolItemPtrsEqual(m_pTOXMgr->GetTOXMark(i), pCurTOXMark)) { m_pTOXMgr->SetCurTOXMark(i); break; diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx index cb96c08527..ea419d2326 100644 --- a/sw/source/uibase/dochdl/swdtflvr.cxx +++ b/sw/source/uibase/dochdl/swdtflvr.cxx @@ -382,7 +382,8 @@ const Graphic* SwTransferable::FindOLEReplacementGraphic() const void SwTransferable::RemoveDDELinkFormat(vcl::Window& rWin) { RemoveFormat( SotClipboardFormatId::LINK ); - CopyToClipboard(&rWin); + if (rWin.GetClipboard()->getContents().get() == this) + CopyToClipboard(&rWin); } void SwTransferable::DisconnectDDE() diff --git a/sw/source/uibase/docvw/AnnotationWin2.cxx b/sw/source/uibase/docvw/AnnotationWin2.cxx index a1780f9132..6b8895f1d9 100644 --- a/sw/source/uibase/docvw/AnnotationWin2.cxx +++ b/sw/source/uibase/docvw/AnnotationWin2.cxx @@ -504,7 +504,7 @@ void SwAnnotationWin::SetMenuButtonColors() const tools::Long nBorderDistanceBottom = ((aSymbolRect.GetHeight() * 150) + 500) / 1000; aSymbolRect.AdjustBottom( -nBorderDistanceBottom ); DecorationView aDecoView(xVirDev.get()); - aDecoView.DrawSymbol(aSymbolRect, SymbolType::SPIN_DOWN, GetTextColor(), + aDecoView.DrawSymbol(aSymbolRect, SymbolType::SPIN_DOWN, COL_BLACK, DrawSymbolFlags::NONE); mxMenuButton->set_image(xVirDev); mxMenuButton->set_size_request(aSize.Width() + 4, aSize.Height() + 4); diff --git a/sw/source/uibase/docvw/SidebarWinAcc.cxx b/sw/source/uibase/docvw/SidebarWinAcc.cxx index f489bc140b..3b2b4c758e 100644 --- a/sw/source/uibase/docvw/SidebarWinAcc.cxx +++ b/sw/source/uibase/docvw/SidebarWinAcc.cxx @@ -23,9 +23,9 @@ #include <viewsh.hxx> #include <accmap.hxx> #include <toolkit/awt/vclxaccessiblecomponent.hxx> +#include <vcl/svapp.hxx> #include <com/sun/star/accessibility/AccessibleRole.hpp> -#include <mutex> namespace sw::sidebarwindows { @@ -47,7 +47,7 @@ class SidebarWinAccessibleContext : public VCLXAccessibleComponent void ChangeAnchor( const SwFrame* pAnchorFrame ) { - std::scoped_lock aGuard(maMutex); + SolarMutexGuard aGuard; mpAnchorFrame = pAnchorFrame; } @@ -55,7 +55,7 @@ class SidebarWinAccessibleContext : public VCLXAccessibleComponent virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent() override { - std::scoped_lock aGuard(maMutex); + SolarMutexGuard aGuard; css::uno::Reference< css::accessibility::XAccessible > xAccParent; @@ -70,7 +70,7 @@ class SidebarWinAccessibleContext : public VCLXAccessibleComponent virtual sal_Int64 SAL_CALL getAccessibleIndexInParent() override { - std::scoped_lock aGuard(maMutex); + SolarMutexGuard aGuard; sal_Int64 nIndex( -1 ); @@ -87,8 +87,6 @@ class SidebarWinAccessibleContext : public VCLXAccessibleComponent private: SwViewShell& mrViewShell; const SwFrame* mpAnchorFrame; - - std::mutex maMutex; }; } diff --git a/sw/source/uibase/index/toxmgr.cxx b/sw/source/uibase/index/toxmgr.cxx index 8b8ff6dbd8..c7cd813eb4 100644 --- a/sw/source/uibase/index/toxmgr.cxx +++ b/sw/source/uibase/index/toxmgr.cxx @@ -47,7 +47,8 @@ void SwTOXMgr::DeleteTOXMark() if( m_pCurTOXMark ) { pNext = const_cast<SwTOXMark*>(&m_pSh->GotoTOXMark( *m_pCurTOXMark, TOX_NXT )); - if (SfxPoolItem::areSame( pNext, m_pCurTOXMark )) + // tdf#158783 ptr compare OK for SwTOXMark (more below) + if (areSfxPoolItemPtrsEqual( pNext, m_pCurTOXMark )) pNext = nullptr; m_pSh->DeleteTOXMark( m_pCurTOXMark ); diff --git a/sw/source/uibase/shells/textsh.cxx b/sw/source/uibase/shells/textsh.cxx index 0924935b3d..97de985401 100644 --- a/sw/source/uibase/shells/textsh.cxx +++ b/sw/source/uibase/shells/textsh.cxx @@ -877,7 +877,20 @@ void SwTextShell::ExecTransliteration( SfxRequest const & rReq ) void SwTextShell::ExecRotateTransliteration( SfxRequest const & rReq ) { if( rReq.GetSlot() == SID_TRANSLITERATE_ROTATE_CASE ) - GetShell().TransliterateText( m_aRotateCase.getNextMode() ); + { + SwWrtShell& rSh = GetShell(); + if (rSh.HasSelection()) + { + rSh.TransliterateText(m_aRotateCase.getNextMode()); + } + else + { + rSh.Push(); // save cur cursor + if ((rSh.IsEndWrd() || rSh.IsStartWord() || rSh.IsInWord()) && rSh.SelWrd()) + rSh.TransliterateText(m_aRotateCase.getNextMode()); + rSh.Pop(SwCursorShell::PopMode::DeleteCurrent); + } + } } SwTextShell::SwTextShell(SwView &_rView) : diff --git a/sw/source/uibase/sidebar/PageSizeControl.cxx b/sw/source/uibase/sidebar/PageSizeControl.cxx index 4ea5995c09..a2dbe406f3 100644 --- a/sw/source/uibase/sidebar/PageSizeControl.cxx +++ b/sw/source/uibase/sidebar/PageSizeControl.cxx @@ -168,7 +168,6 @@ PageSizeControl::PageSizeControl(PageSizePopup* pControl, weld::Widget* pParent) } mxSizeValueSet->SetNoSelection(); mxSizeValueSet->SetSelectHdl( LINK(this, PageSizeControl, ImplSizeHdl ) ); - mxSizeValueSet->SetOptimalDrawingAreaHeight(); mxSizeValueSet->Show(); mxSizeValueSet->Resize(); diff --git a/sw/source/uibase/uiview/view2.cxx b/sw/source/uibase/uiview/view2.cxx index cc6faf78a3..f7a10a49f7 100644 --- a/sw/source/uibase/uiview/view2.cxx +++ b/sw/source/uibase/uiview/view2.cxx @@ -286,14 +286,21 @@ OUString SwView::GetPageStr(sal_uInt16 nPhyNum, sal_uInt16 nVirtNum, const OUStr ? SwResId(STR_PAGE_COUNT_PRINTED) : (extra.isEmpty() ? SwResId(STR_PAGE_COUNT) : SwResId(STR_PAGE_COUNT_CUSTOM))); aStr = aStr.replaceFirst("%1", OUString::number(nPhyNum)); - aStr = aStr.replaceFirst("%2", OUString::number(nPageCount)); if (nPageCount != nPrintedPageCount) { + aStr = aStr.replaceFirst("%2", OUString::number(nPageCount)); aStr = aStr.replaceFirst("%3", OUString::number(nPrintedPhyNum)); aStr = aStr.replaceFirst("%4", OUString::number(nPrintedPageCount)); } - else - aStr = aStr.replaceFirst("%3", extra); + else { + if (extra.isEmpty()) + aStr = aStr.replaceFirst("%2", OUString::number(nPageCount)); + else + { + aStr = aStr.replaceFirst("%2", extra); + aStr = aStr.replaceFirst("%3", OUString::number(nPageCount)); + } + } return aStr; } diff --git a/sw/source/uibase/utlui/uitool.cxx b/sw/source/uibase/utlui/uitool.cxx index fd50bf6678..dfaffe3480 100644 --- a/sw/source/uibase/utlui/uitool.cxx +++ b/sw/source/uibase/utlui/uitool.cxx @@ -392,6 +392,7 @@ void ItemSetToPageDesc( const SfxItemSet& rSet, SwPageDesc& rPageDesc ) if(rMaster.GetFooter().IsActive()) { rMaster.SetFormatAttr(SwFormatFooter(false)); + // why reset this? but not doing it causes testTdf112694 to fail rPageDesc.ChgFooterShare(false); } } diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx b/sw/source/uibase/wrtsh/wrtsh1.cxx index 4b2402fc93..0054eca4cb 100644 --- a/sw/source/uibase/wrtsh/wrtsh1.cxx +++ b/sw/source/uibase/wrtsh/wrtsh1.cxx @@ -115,6 +115,7 @@ #include <frmtool.hxx> #include <viewopt.hxx> +#include <IDocumentRedlineAccess.hxx> #include <IDocumentUndoRedo.hxx> #include <UndoInsert.hxx> #include <UndoCore.hxx> @@ -1177,8 +1178,12 @@ void SwWrtShell::InsertContentControl(SwContentControlType eType) Left(SwCursorSkipMode::Chars, /*bSelect=*/true, aPlaceholder.getLength(), /*bBasicCall=*/false); } + + const RedlineFlags oldRedlineFlags = getIDocumentRedlineAccess().GetRedlineFlags(); + getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::Ignore); SwFormatContentControl aContentControl(pContentControl, RES_TXTATR_CONTENTCONTROL); SetAttrItem(aContentControl); + getIDocumentRedlineAccess().SetRedlineFlags(oldRedlineFlags); } // Insert footnote |