diff options
Diffstat (limited to '')
-rw-r--r-- | sw/qa/core/text/text.cxx | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/sw/qa/core/text/text.cxx b/sw/qa/core/text/text.cxx new file mode 100644 index 000000000..eaf5cce31 --- /dev/null +++ b/sw/qa/core/text/text.cxx @@ -0,0 +1,596 @@ +/* -*- 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 <swmodeltestbase.hxx> + +#include <memory> + +#include <com/sun/star/text/BibliographyDataType.hpp> +#include <com/sun/star/text/WritingMode2.hpp> + +#include <vcl/gdimtf.hxx> +#include <vcl/filter/PDFiumLibrary.hxx> +#include <comphelper/propertyvalue.hxx> +#include <unotools/mediadescriptor.hxx> + +#include <docsh.hxx> +#include <unotxdoc.hxx> +#include <wrtsh.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <rootfrm.hxx> +#include <txtfrm.hxx> +#include <porlay.hxx> +#include <pormulti.hxx> +#include <formatlinebreak.hxx> +#include <sortedobjs.hxx> +#include <anchoredobject.hxx> +#include <fmtcntnt.hxx> +#include <fmtfsize.hxx> +#include <IDocumentRedlineAccess.hxx> + +constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/core/text/data/"; + +/// Covers sw/source/core/text/ fixes. +class SwCoreTextTest : public SwModelTestBase +{ +}; + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testFootnoteConnect) +{ + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "footnote-connect.fodt"); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + // Jump to the start of the next page. + pWrtShell->SttNxtPg(); + // Remove the page break. + pWrtShell->DelLeft(); + // Split the multi-line text frame, containing an endnote. + pWrtShell->DelLeft(); + // Join the split text frame. + pWrtShell->DelLeft(); + // Turn the 3 page document into a 2 page one, so the endnote frame is moved. + // Without the accompanying fix in place, this test would have crashed due to a use-after-free + // in SwFootnoteFrame::GetRef(). + pWrtShell->DelLeft(); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testSemiTransparentText) +{ + // Create an in-memory empty document. + loadURL("private:factory/swriter", nullptr); + + // Set text to half-transparent and type a character. + uno::Reference<beans::XPropertySet> xParagraph(getParagraph(1), uno::UNO_QUERY); + CPPUNIT_ASSERT(xParagraph.is()); + sal_Int16 nTransparence = 50; + xParagraph->setPropertyValue("CharTransparence", uno::Any(nTransparence)); + uno::Reference<text::XTextRange> xTextRange(xParagraph, uno::UNO_QUERY); + CPPUNIT_ASSERT(xTextRange.is()); + xTextRange->setString("x"); + + // Render the document to a metafile. + SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get()); + CPPUNIT_ASSERT(pTextDoc); + SwDocShell* pDocShell = pTextDoc->GetDocShell(); + CPPUNIT_ASSERT(pDocShell); + std::shared_ptr<GDIMetaFile> xMetaFile = pDocShell->GetPreviewMetaFile(); + CPPUNIT_ASSERT(xMetaFile); + + // Make sure that DrawTransparent() was used during rendering. + MetafileXmlDump dumper; + xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile); + CPPUNIT_ASSERT(pXmlDoc); + assertXPath(pXmlDoc, "//floattransparent"); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testBibliographyUrlPdfExport) +{ + // Given a document with a bibliography entry field: + std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + { + return; + } + createSwDoc(); + uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xField( + xFactory->createInstance("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY); + uno::Sequence<beans::PropertyValue> aFields = { + comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW), + comphelper::makePropertyValue("Identifier", OUString("AT")), + comphelper::makePropertyValue("Author", OUString("Author")), + comphelper::makePropertyValue("Title", OUString("Title")), + comphelper::makePropertyValue("URL", OUString("http://www.example.com/test.pdf#page=1")), + }; + xField->setPropertyValue("Fields", uno::Any(aFields)); + uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xTextDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + uno::Reference<text::XTextContent> xContent(xField, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xContent, /*bAbsorb=*/false); + + // When exporting to PDF: + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Then make sure the field links the source. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument + = pPDFium->openDocument(aMemory.GetData(), aMemory.GetSize(), OString()); + CPPUNIT_ASSERT(pPdfDocument); + std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); + // Without the accompanying fix in place, this test would have failed, the field was not + // clickable (while it was clickable on the UI). + CPPUNIT_ASSERT(pPdfPage->hasLinks()); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testTabOverMarginSection) +{ + createSwDoc(DATA_DIRECTORY, "tabovermargin-section.fodt"); + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + sal_Int32 nWidth + = getXPath(pXmlDoc, "//Text[@nType='PortionType::TabRight']", "nWidth").toInt32(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected less than: 5000 + // - Actual : 9372 + // i.e. the tab portion width was not the expected 4386, but much larger, so the number after + // the tab portion was not visible. + CPPUNIT_ASSERT_LESS(static_cast<sal_Int32>(5000), nWidth); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testLineHeight) +{ + // Given a document with an as-char image, height in twips not fitting into sal_uInt16: + createSwDoc(DATA_DIRECTORY, "line-height.fodt"); + + // When laying out that document: + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + + // Then make sure its top is the top of the page: + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 284 + // - Actual : -65252 + // due to various unsigned integer truncations. + assertXPath(pXmlDoc, "//fly/infos/bounds", "top", OUString::number(DOCUMENTBORDER)); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testLineWidth) +{ + // Given a document with an as-char image, width in twips not fitting into sal_uInt16: + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "line-width.fodt"); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + sal_Int32 nOldLeft = pWrtShell->GetCharRect().Left(); + + // When moving the cursor to the right: + pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false); + + // Then make sure we move to the right by the image width: + sal_Int32 nNewLeft = pWrtShell->GetCharRect().Left(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected greater than: 65536 + // - Actual : 1872 + // i.e. the width (around 67408 twips) was truncated. + CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32>(65536), nNewLeft - nOldLeft); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testChineseAutoFirstLineIndent) +{ + // The test document contains two simple multi-line paragraph. For both paragraphs, the first line indent + // is set to 'auto'. Line spacing is 100% for the 1st paragraph and 200% for the 2nd paragraph. + // Also, there is a "AutoFirstLineIndentDisregardLineSpace" capability flag set in the document. + createSwDoc(DATA_DIRECTORY, "firstLineIndent-withFlag.fodt"); + + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + + // Get the line width of the first line for the 1st paragraph. + sal_Int32 nFirstLineWidth + = getXPath(pXmlDoc, "//body/txt[1]/SwParaPortion/SwLineLayout[1]", "width").toInt32(); + // Get the line width of the first line for the 2nd paragraph. + sal_Int32 nSecondLineWidth + = getXPath(pXmlDoc, "//body/txt[2]/SwParaPortion/SwLineLayout[1]", "width").toInt32(); + + // Tdf#129448: the changing of line-height should not affect the auto first line indent. + // As a result, the first line width of the two paragraphs should be the same. + CPPUNIT_ASSERT_EQUAL(nSecondLineWidth, nFirstLineWidth); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testRuby) +{ + // Given a document with multiple ruby portions: + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "ruby.fodt"); + + // When laying out that document: + SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + + // Then make sure that no unwanted margin portions are created, making the actual text + // invisible: + SwFrame* pPageFrame = pLayout->GetLower(); + SwFrame* pBodyFrame = pPageFrame->GetLower(); + SwFrame* pFrame = pBodyFrame->GetLower(); + CPPUNIT_ASSERT(pFrame->IsTextFrame()); + auto pTextFrame = static_cast<SwTextFrame*>(pFrame); + SwParaPortion* pPara = pTextFrame->GetPara(); + bool bFirst = true; + for (SwLinePortion* pPor = pPara->GetFirstPortion(); pPor; pPor = pPor->GetNextPortion()) + { + // Look for multi-portions in the only paragraph of the document. + if (pPor->GetWhichPor() != PortionType::Multi) + { + continue; + } + + if (bFirst) + { + bFirst = false; + continue; + } + + // The second multi-portion has two lines, check the start of the second line. + auto pMulti = static_cast<SwMultiPortion*>(pPor); + // Without the accompanying fix in place, this test would have failed, as the portion was a + // margin portion, not a text portion. The margin was so large that the actual text portion was + // hidden. No margin is needed here at all. + CPPUNIT_ASSERT(pMulti->GetRoot().GetNext()->GetFirstPortion()->IsTextPortion()); + } +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testEmptyNumberingPageSplit) +{ + // Given a document with 2 pages: the only para on page 1 is a numbering without a number + // portion: + createSwDoc(DATA_DIRECTORY, "empty-numbering-page-split.fodt"); + + // When inserting an image that doesn't fit the body frame: + // Then make sure that the layout update after insertion finishes: + uno::Sequence<beans::PropertyValue> aArgs = { + comphelper::makePropertyValue("FileName", + m_directories.getURLFromSrc(DATA_DIRECTORY) + "image.png"), + }; + // Without the accompanying fix in place, this never finished. + dispatchCommand(mxComponent, ".uno:InsertGraphic", aArgs); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreak) +{ + // Given a document with a fly frame and two characters wrapped around it: + createSwDoc(DATA_DIRECTORY, "clearing-break.fodt"); + // Insert a clearing break between "A" and "B": + uno::Reference<text::XTextDocument> xDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + xCursor->gotoEnd(/*bSelect=*/false); + xCursor->goLeft(/*nCount=*/1, /*bSelect=*/false); + uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XTextContent> xLineBreak( + xFactory->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY); + auto eClear = static_cast<sal_Int16>(SwLineBreakClear::ALL); + xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear)); + xText->insertTextContent(xCursor, xLineBreak, /*bAbsorb=*/false); + + // When laying out that document: + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + + // Then make sure that the second line "jumps down", below the fly frame: + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1024 + // - Actual : 276 + // i.e. the line height wasn't the twips value of the 1.806 cm from the file, but was based on + // the font size of the text, which is only correct for non-clearing breaks. + assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout[1]", "height", "1024"); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreakAtStart) +{ + // Given a document with a fly frame and a character wrapped around it: + createSwDoc(DATA_DIRECTORY, "clearing-break-start.fodt"); + // Insert a clearing break before "X": + uno::Reference<text::XTextDocument> xDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + xCursor->gotoEnd(/*bSelect=*/false); + xCursor->goLeft(/*nCount=*/1, /*bSelect=*/false); + uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XTextContent> xLineBreak( + xFactory->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY); + auto eClear = static_cast<sal_Int16>(SwLineBreakClear::ALL); + xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear)); + xText->insertTextContent(xCursor, xLineBreak, /*bAbsorb=*/false); + + // When laying out that document: + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + + // Then make sure that the second line "jumps down", below the fly frame: + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1024 + // - Actual : 276 + // i.e. the line height was too small, but only in case the full line was a fly and a break + // portion, without any real content. + assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout[1]", "height", "1024"); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreakLeft) +{ + // Given a document with two anchored objects (left height is 5cm, right height is 7.5cm) and a + // clearing break (type=left): + loadURL("private:factory/swriter", nullptr); + uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XTextDocument> xDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + { + uno::Reference<drawing::XShape> xShape( + xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); + xShape->setSize(awt::Size(5000, 5000)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + xShapeProps->setPropertyValue("AnchorType", + uno::Any(text::TextContentAnchorType_AT_CHARACTER)); + uno::Reference<text::XTextContent> xShapeContent(xShape, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xShapeContent, /*bAbsorb=*/false); + } + { + uno::Reference<drawing::XShape> xShape( + xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); + xShape->setSize(awt::Size(5000, 7500)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + xShapeProps->setPropertyValue("AnchorType", + uno::Any(text::TextContentAnchorType_AT_CHARACTER)); + xShapeProps->setPropertyValue("HoriOrientPosition", uno::Any(sal_Int32(10000))); + uno::Reference<text::XTextContent> xShapeContent2(xShape, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xShapeContent2, /*bAbsorb=*/false); + } + uno::Reference<text::XTextContent> xLineBreak( + xFactory->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY); + auto eClear = static_cast<sal_Int16>(SwLineBreakClear::LEFT); + xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear)); + xText->insertString(xCursor, "foo", /*bAbsorb=*/false); + xText->insertTextContent(xCursor, xLineBreak, /*bAbsorb=*/false); + xText->insertString(xCursor, "bar", /*bAbsorb=*/false); + + // When laying out that document: + calcLayout(); + + // Then make sure the "bar" jumps down below the left shape, but not below the right shape (due + // to type=left): + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 2837 + // - Actual : 4254 + // i.e. any non-none type was handled as type=all, and this was jumping below both shapes. + assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout[1]", "height", "2837"); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreakLeftRTL) +{ + // Given a document with an anchored object in an RTL para and a clearing break (type=left): + loadURL("private:factory/swriter", nullptr); + uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XTextDocument> xDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + uno::Reference<beans::XPropertySet> xCursorProps(xCursor, uno::UNO_QUERY); + xCursorProps->setPropertyValue("WritingMode", uno::Any(text::WritingMode2::RL_TB)); + { + uno::Reference<drawing::XShape> xShape( + xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); + xShape->setSize(awt::Size(5000, 5000)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + xShapeProps->setPropertyValue("AnchorType", + uno::Any(text::TextContentAnchorType_AT_CHARACTER)); + uno::Reference<text::XTextContent> xShapeContent(xShape, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xShapeContent, /*bAbsorb=*/false); + } + uno::Reference<text::XTextContent> xLineBreak( + xFactory->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY); + auto eClear = static_cast<sal_Int16>(SwLineBreakClear::RIGHT); + xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear)); + xText->insertString(xCursor, "foo", /*bAbsorb=*/false); + xText->insertTextContent(xCursor, xLineBreak, /*bAbsorb=*/false); + xText->insertString(xCursor, "bar", /*bAbsorb=*/false); + + // When laying out that document: + calcLayout(); + + // Then make sure the "bar" does not jump down (due to type=left && RTL): + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 276 + // - Actual : 2837 + // i.e. left/right was not ignored in the RTL case. + assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout[1]", "height", "276"); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreakVertical) +{ + // Given a document with an anchored object in a vertical page and a clearing break (type=all): + loadURL("private:factory/swriter", nullptr); + uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XTextDocument> xDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + uno::Reference<beans::XPropertySet> xStandard(getStyles("PageStyles")->getByName("Standard"), + uno::UNO_QUERY); + xStandard->setPropertyValue("WritingMode", uno::Any(text::WritingMode2::TB_RL)); + { + uno::Reference<drawing::XShape> xShape( + xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); + xShape->setSize(awt::Size(5000, 5000)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + xShapeProps->setPropertyValue("AnchorType", + uno::Any(text::TextContentAnchorType_AT_CHARACTER)); + uno::Reference<text::XTextContent> xShapeContent(xShape, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xShapeContent, /*bAbsorb=*/false); + } + uno::Reference<text::XTextContent> xLineBreak( + xFactory->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY); + auto eClear = static_cast<sal_Int16>(SwLineBreakClear::ALL); + xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear)); + xText->insertString(xCursor, "foo", /*bAbsorb=*/false); + xText->insertTextContent(xCursor, xLineBreak, /*bAbsorb=*/false); + xText->insertString(xCursor, "bar", /*bAbsorb=*/false); + + // When laying out that document: + calcLayout(); + + // Then make sure the "bar" does jump (logic) down the correct amount: + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 2837 + // - Actual : 7135 + // i.e. the expected break height is the twips value of the 5cm rectangle size, it was much + // more. + assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout[1]/SwBreakPortion", "height", "2837"); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreakHeader) +{ + // Given a document with a shape in the header and a clearing break in the body text: + createSwDoc(DATA_DIRECTORY, "clearing-break-header.fodt"); + + // When laying out that document: + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + + // Then make sure that the shape from the header is ignored while calculating the line height: + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 276 + // - Actual : 15398 + // i.e. the shape was in the background, but we failed to ignore it for the break portion. + assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout[1]", "height", "276"); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testAsCharImageDocModelFromViewPoint) +{ + // Given a document with an as-char image: + SwDoc* pDoc = createSwDoc(); + uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xTextGraphic( + xFactory->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY); + // Only set the anchor type, the actual bitmap content is not interesting. + xTextGraphic->setPropertyValue("AnchorType", + uno::Any(text::TextContentAnchorType_AS_CHARACTER)); + uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xBodyText = xTextDocument->getText(); + uno::Reference<text::XTextCursor> xCursor(xBodyText->createTextCursor()); + uno::Reference<text::XTextContent> xTextContent(xTextGraphic, uno::UNO_QUERY); + xBodyText->insertTextContent(xCursor, xTextContent, false); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + SwRootFrame* pRootFrame = pWrtShell->GetLayout(); + SwFrame* pPageFrame = pRootFrame->GetLower(); + SwFrame* pBodyFrame = pPageFrame->GetLower(); + SwFrame* pTextFrame = pBodyFrame->GetLower(); + const SwSortedObjs& rSortedObjs = *pTextFrame->GetDrawObjs(); + const SwAnchoredObject* pAnchoredObject = rSortedObjs[0]; + // The content points to the start node, the next node is the graphic node. + SwNodeIndex aGraphicNode = *pAnchoredObject->GetFrameFormat().GetContent().GetContentIdx(); + ++aGraphicNode; + tools::Rectangle aFlyFrame = pAnchoredObject->GetDrawObj()->GetLastBoundRect(); + Point aDocPos = aFlyFrame.Center(); + + // When translating the view point to the model position: + pWrtShell->SttCursorMove(); + pWrtShell->CallSetCursor(&aDocPos, /*bOnlyText=*/false); + pWrtShell->EndCursorMove(); + + // Then make sure that we find the graphic node, and not its anchor: + SwShellCursor* pShellCursor = pWrtShell->getShellCursor(/*bBlock=*/false); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: SwNodeIndex (node 6) + // - Actual : SwNodeIndex (node 12) + // i.e. the cursor position was the text node hosting the as-char image, not the graphic node of + // the image. + CPPUNIT_ASSERT_EQUAL(aGraphicNode, pShellCursor->GetMark()->nNode); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testRedlineDelete) +{ + // Given a document with A4 paper size, some text, redlining on, but hidden: + SwDoc* pDoc = createSwDoc(); + SwDocShell* pDocShell = pDoc->GetDocShell(); + SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); + { + // Set page size to A4. + size_t nCurIdx = pWrtShell->GetCurPageDesc(); + SwPageDesc aPageDesc(pWrtShell->GetPageDesc(nCurIdx)); + SwFrameFormat& rMaster = aPageDesc.GetMaster(); + SwFormatFrameSize aSize(SwFrameSize::Fixed); + aSize.SetSize(Size(11906, 16838)); + rMaster.SetFormatAttr(aSize); + pWrtShell->ChgPageDesc(nCurIdx, aPageDesc); + } + OUString aBefore("aaaaaaaaa aaaaaaaaaa aa aa aa "); + OUString aDelete("delete eeeeeeeeeee ee eeeeeeeeeee ee eeeeee"); + pWrtShell->Insert(aBefore + " " + aDelete + + " zz zzz zzzzzzzzz zzz zzzz zzzz zzzzzzzzz zzzzzz zzz zzzzzzzzzzz zzz"); + // Enable redlining. + pDocShell->SetChangeRecording(/*bActivate=*/true); + // Hide redlining. + pWrtShell->StartAllAction(); + pWrtShell->GetLayout()->SetHideRedlines(true); + pWrtShell->EndAllAction(); + + // When deleting content in the middle of the paragraph: + pWrtShell->SttEndDoc(/*bStt=*/true); + pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, /*nCount=*/aBefore.getLength(), + /*bBasicCall=*/false); + pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, /*nCount=*/aDelete.getLength(), + /*bBasicCall=*/false); + // Without the accompanying fix in place, this test would have crashed: + pWrtShell->Delete(); + + // Then make sure that the redline is created: + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), + pDoc->getIDocumentRedlineAccess().GetRedlineTable().size()); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testNumberPortionFormat) +{ + // Given a document with a single paragraph, direct formatting asks 24pt font size for the + // numbering and the text portion: + createSwDoc(DATA_DIRECTORY, "number-portion-format.odt"); + + // When laying out that document: + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + + // Then make sure that the numbering portion has the correct font size: + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 480 + // - Actual : 240 + // i.e. the numbering portion font size was 12pt, not 24pt (but only when the doc had a + // bookmark). + assertXPath(pXmlDoc, "//Special[@nType='PortionType::Number']", "nHeight", "480"); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testNumberPortionNoformat) +{ + // Given a document with a numbering and a single paragraph, the entire run is red: + createSwDoc(DATA_DIRECTORY, "number-portion-noformat.docx"); + + // When laying out that document: + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + + // Then make sure that just because the entire run is red, the numbering portion is not red: + // Without the accompanying fix in place, this test would have failed with: + // - Expected: ffffffff (COL_AUTO) + // - Actual : 00ff0000 (COL_LIGHTRED) + // i.e. the run color affected the color of the number portion in Writer, but not in Word. + CPPUNIT_ASSERT_EQUAL( + OUString("ffffffff"), + getXPath(pXmlDoc, "//Special[@nType='PortionType::Number']/SwFont", "color")); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |