/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { /** * Covers sw/source/filter/ww8/ fixes. * * Note that these tests are meant to be simple: either load a file and assert some result or build * a document model with code, export and assert that result. * * Keep using the various sw_import/export suites for multiple filter calls inside a single * test. */ class Test : public SwModelTestBase { public: Test() : SwModelTestBase("/sw/qa/filter/ww8/data/") { } }; CPPUNIT_TEST_FIXTURE(Test, testNegativePageBorderDocImport) { // Given a document with a border distance that is larger than the margin, when loading that // document: createSwDoc("negative-page-border.doc"); // Then make sure we map that to a negative border distance (move border from the edge of body // frame towards the center of the page, not towards the edge of the page): uno::Reference xStyleFamily = getStyles("PageStyles"); uno::Reference xStyle(xStyleFamily->getByName("Standard"), uno::UNO_QUERY); auto nTopMargin = xStyle->getPropertyValue("TopMargin").get(); // Without the accompanying fix in place, this test would have failed with: // - Expected: 501 // - Actual : 342 // i.e. the border properties influenced the margin, which was 284 twips in the sprmSDyaTop // SPRM. CPPUNIT_ASSERT_EQUAL(static_cast(501), nTopMargin); auto aTopBorder = xStyle->getPropertyValue("TopBorder").get(); CPPUNIT_ASSERT_EQUAL(static_cast(159), aTopBorder.LineWidth); auto nTopBorderDistance = xStyle->getPropertyValue("TopBorderDistance").get(); CPPUNIT_ASSERT_EQUAL(static_cast(-646), nTopBorderDistance); } CPPUNIT_TEST_FIXTURE(Test, testPlainTextContentControlExport) { // Given a document with a plain text content control around a text portion: createSwDoc(); uno::Reference xMSF(mxComponent, uno::UNO_QUERY); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xTextDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); xText->insertString(xCursor, "test", /*bAbsorb=*/false); xCursor->gotoStart(/*bExpand=*/false); xCursor->gotoEnd(/*bExpand=*/true); uno::Reference xContentControl( xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); xContentControlProps->setPropertyValue("PlainText", uno::Any(true)); xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); // When exporting to DOCX: save("Office Open XML Text"); // Then make sure the expected markup is used: xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); // Without the accompanying fix in place, this test would have failed with: // - Expected: 1 // - Actual : 0 // - XPath '//w:sdt/w:sdtPr/w:text' number of nodes is incorrect // i.e. the plain text content control was turned into a rich text one on export. assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:text", 1); } CPPUNIT_TEST_FIXTURE(Test, testDocxComboBoxContentControlExport) { // Given a document with a combo box content control around a text portion: createSwDoc(); SwDoc* pDoc = getSwDoc(); SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); pWrtShell->InsertContentControl(SwContentControlType::COMBO_BOX); // When exporting to DOCX: save("Office Open XML Text"); // Then make sure the expected markup is used: xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); // Without the accompanying fix in place, this test would have failed with: // - Expected: 1 // - Actual : 0 // - XPath '//w:sdt/w:sdtPr/w:comboBox' number of nodes is incorrect // i.e. the combo box content control was turned into a drop-down one on export. assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:comboBox", 1); } CPPUNIT_TEST_FIXTURE(Test, testDocxHyperlinkShape) { // Given a document with a hyperlink at char positions 0 -> 6 and a shape with text anchored at // char position 6: createSwDoc(); uno::Reference xMSF(mxComponent, uno::UNO_QUERY); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xTextDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); xText->insertString(xCursor, "beforeafter", /*bAbsorb=*/false); xCursor->gotoStart(/*bExpand=*/false); xCursor->goRight(/*nCount=*/6, /*bExpand=*/true); uno::Reference xCursorProps(xCursor, uno::UNO_QUERY); xCursorProps->setPropertyValue("HyperLinkURL", uno::Any(OUString("http://www.example.com/"))); xCursor->gotoStart(/*bExpand=*/false); xCursor->goRight(/*nCount=*/6, /*bExpand=*/false); uno::Reference xFactory(mxComponent, uno::UNO_QUERY); uno::Reference xShape( xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); xShape->setSize(awt::Size(5000, 5000)); uno::Reference xShapeProps(xShape, uno::UNO_QUERY); xShapeProps->setPropertyValue("AnchorType", uno::Any(text::TextContentAnchorType_AT_CHARACTER)); uno::Reference xShapeContent(xShape, uno::UNO_QUERY); xText->insertTextContent(xCursor, xShapeContent, /*bAbsorb=*/false); xShapeProps->setPropertyValue("TextBox", uno::Any(true)); // When saving this document to DOCX, then make sure we don't crash on export (due to an // assertion failure for not-well-formed XML output): save("Office Open XML Text"); } CPPUNIT_TEST_FIXTURE(Test, testDocxContentControlDropdownEmptyDisplayText) { // Given a document with a dropdown content control, the only list item has no display text // (only a value): createSwDoc(); SwDoc* pDoc = getSwDoc(); SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); pWrtShell->InsertContentControl(SwContentControlType::DROP_DOWN_LIST); // When saving to DOCX: save("Office Open XML Text"); // Then make sure that no display text attribute is written: xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); // Without the accompanying fix in place, this test would have failed with: // - XPath '//w:sdt/w:sdtPr/w:dropDownList/w:listItem' unexpected 'displayText' attribute // i.e. we wrote an empty attribute instead of omitting it. assertXPathNoAttribute(pXmlDoc, "//w:sdt/w:sdtPr/w:dropDownList/w:listItem", "displayText"); } CPPUNIT_TEST_FIXTURE(Test, testDocxSymbolFontExport) { // Create document with symbol character and font Wingdings mxComponent = loadFromDesktop("private:factory/swriter"); uno::Reference xMSF(mxComponent, uno::UNO_QUERY); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xTextDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); xText->insertString(xCursor, u"", true); uno::Reference xRange = xCursor; uno::Reference xTextProps(xRange, uno::UNO_QUERY); xTextProps->setPropertyValue("CharFontName", uno::Any(OUString("Wingdings"))); xTextProps->setPropertyValue("CharFontNameAsian", uno::Any(OUString("Wingdings"))); xTextProps->setPropertyValue("CharFontNameComplex", uno::Any(OUString("Wingdings"))); xTextProps->setPropertyValue("CharFontCharSet", uno::Any(awt::CharSet::SYMBOL)); // When exporting to DOCX: save("Office Open XML Text"); // Then make sure the expected markup is used: xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); assertXPath(pXmlDoc, "//w:p/w:r/w:sym", 1); assertXPath(pXmlDoc, "//w:p/w:r/w:sym[1]", "font", "Wingdings"); assertXPath(pXmlDoc, "//w:p/w:r/w:sym[1]", "char", "f0e0"); } CPPUNIT_TEST_FIXTURE(Test, testDocxFloatingTableExport) { // Given a document with a floating table: createSwDoc(); SwDoc* pDoc = getSwDoc(); SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); // Insert a table: SwInsertTableOptions aTableOptions(SwInsertTableFlags::DefaultBorder, 0); pWrtShell->InsertTable(aTableOptions, 1, 1); pWrtShell->MoveTable(GotoPrevTable, fnTableStart); // Select it: pWrtShell->SelAll(); // Wrap in a fly: SwFlyFrameAttrMgr aMgr(true, pWrtShell, Frmmgr_Type::TEXT, nullptr); pWrtShell->StartAllAction(); aMgr.InsertFlyFrame(RndStdIds::FLY_AT_PARA, aMgr.GetPos(), aMgr.GetSize()); // Mark it as a floating table: SwFrameFormats& rFlys = *pDoc->GetSpzFrameFormats(); SwFrameFormat* pFly = rFlys[0]; SwAttrSet aSet(pFly->GetAttrSet()); aSet.Put(SwFormatFlySplit(true)); pDoc->SetAttr(aSet, *pFly); pWrtShell->EndAllAction(); // When saving to docx: save("Office Open XML Text"); // Then make sure we write a floating table, not a textframe containing a table: xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); // Without the accompanying fix in place, this test would have failed with: // - XPath '//w:tbl/w:tblPr/w:tblpPr' number of nodes is incorrect // i.e. no floating table was exported. assertXPath(pXmlDoc, "//w:tbl/w:tblPr/w:tblpPr", 1); } CPPUNIT_TEST_FIXTURE(Test, testDocFloatingTableImport) { // Given a document with 2 pages: createSwDoc("floattable-compat14.doc"); // When laying out that document: calcLayout(); // Make sure that the table is split between page 1 and page 2: SwDoc* pDoc = getSwDoc(); SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); auto pPage1 = dynamic_cast(pLayout->Lower()); CPPUNIT_ASSERT(pPage1); // Without the accompanying fix in place, this test would have failed, the fly frame was not // split between page 1 and page 2. CPPUNIT_ASSERT(pPage1->GetNext()); } CPPUNIT_TEST_FIXTURE(Test, testWrapThroughLayoutInCell) { // Given a document with a shape, "keep inside text boundaries" is off, wrap type is set to // "through": createSwDoc(); uno::Reference xFactory(mxComponent, uno::UNO_QUERY); uno::Reference xShape( xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); xShape->setSize(awt::Size(10000, 10000)); uno::Reference xShapeProps(xShape, uno::UNO_QUERY); xShapeProps->setPropertyValue("AnchorType", uno::Any(text::TextContentAnchorType_AT_CHARACTER)); xShapeProps->setPropertyValue("Surround", uno::Any(text::WrapTextMode_THROUGH)); xShapeProps->setPropertyValue("HoriOrientRelation", uno::Any(text::RelOrientation::FRAME)); uno::Reference xDrawPageSupplier(mxComponent, uno::UNO_QUERY); xDrawPageSupplier->getDrawPage()->add(xShape); // When saving to docx: save("Office Open XML Text"); // Then make sure that layoutInCell is undoing the effect of the import-time tweak: xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); // Without the accompanying fix in place, this test would have failed with: // - Expected: 1 // - Actual : 0 // - attribute 'layoutInCell' of '//wp:anchor' incorrect value. // i.e. layoutInCell was disabled, leading to bad layout in Word. assertXPath(pXmlDoc, "//wp:anchor", "layoutInCell", "1"); } CPPUNIT_TEST_FIXTURE(Test, testDoNotBreakWrappedTables) { // Given a document with the DO_NOT_BREAK_WRAPPED_TABLES compat mode enabled: createSwDoc(); SwDoc* pDoc = getSwDoc(); IDocumentSettingAccess& rIDSA = pDoc->getIDocumentSettingAccess(); rIDSA.set(DocumentSettingId::DO_NOT_BREAK_WRAPPED_TABLES, true); // When saving to docx: save("Office Open XML Text"); // Then make sure the compat flag is serialized: xmlDocUniquePtr pXmlDoc = parseExport("word/settings.xml"); // Without the accompanying fix in place, this test would have failed with: // - Expected: 1 // - Actual : 0 // - XPath '/w:settings/w:compat/w:doNotBreakWrappedTables' number of nodes is incorrect // i.e. was not written. assertXPath(pXmlDoc, "/w:settings/w:compat/w:doNotBreakWrappedTables", 1); } } CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */