diff options
Diffstat (limited to 'sw/qa/core/text/text.cxx')
-rw-r--r-- | sw/qa/core/text/text.cxx | 376 |
1 files changed, 366 insertions, 10 deletions
diff --git a/sw/qa/core/text/text.cxx b/sw/qa/core/text/text.cxx index f43727ed5f3f..8cc59e8e3a2a 100644 --- a/sw/qa/core/text/text.cxx +++ b/sw/qa/core/text/text.cxx @@ -12,11 +12,14 @@ #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 <editeng/fhgtitem.hxx> +#include <editeng/wghtitem.hxx> #include <docsh.hxx> #include <unotxdoc.hxx> @@ -32,6 +35,11 @@ #include <fmtcntnt.hxx> #include <fmtfsize.hxx> #include <IDocumentRedlineAccess.hxx> +#include <formatcontentcontrol.hxx> +#include <strings.hrc> +#include <ndtxt.hxx> +#include <txatbase.hxx> +#include <textcontentcontrol.hxx> constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/core/text/data/"; @@ -114,18 +122,10 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testBibliographyUrlPdfExport) 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()); + StoreToTempFile("writer_pdf_Export"); // 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()); - CPPUNIT_ASSERT(pPdfDocument); + std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile(); 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). @@ -349,6 +349,90 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreakLeft) 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]", "height", "2837"); +} + CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreakHeader) { // Given a document with a shape in the header and a clearing break in the body text: @@ -449,6 +533,278 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testRedlineDelete) pDoc->getIDocumentRedlineAccess().GetRedlineTable().size()); } +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testContentControlPDF) +{ + // Given a file with a content control: + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->InsertContentControl(SwContentControlType::RICH_TEXT); + pWrtShell->SttEndDoc(/*bStt=*/true); + pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false); + sal_Int32 nPlaceHolderLen = SwResId(STR_CONTENT_CONTROL_PLACEHOLDER).getLength(); + pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, nPlaceHolderLen, + /*bBasicCall=*/false); + pWrtShell->Insert("mycontent"); + const SwPosition* pStart = pWrtShell->GetCursor()->Start(); + SwTextNode* pTextNode = pStart->nNode.GetNode().GetTextNode(); + sal_Int32 nIndex = pStart->nContent.GetIndex(); + SwTextAttr* pAttr + = pTextNode->GetTextAttrAt(nIndex, RES_TXTATR_CONTENTCONTROL, SwTextNode::PARENT); + auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr); + const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl(); + std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl(); + // Alias/title, to be mapped to PDF's description. + pContentControl->SetAlias("mydesc"); + + // When exporting to PDF: + StoreToTempFile("writer_pdf_Export"); + + // Then make sure that a fillable form widget is emitted: + std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile(); + std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // i.e. the content control was just exported as normal text. + CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount()); + std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0); + CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType()); + + // Also verify that the widget description is correct, it was empty: + CPPUNIT_ASSERT_EQUAL(OUString("mydesc"), + pAnnotation->getFormFieldAlternateName(pPdfDocument.get())); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testCheckboxContentControlPDF) +{ + // Given a file with a checkbox content control: + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->InsertContentControl(SwContentControlType::CHECKBOX); + + // When exporting to PDF: + StoreToTempFile("writer_pdf_Export"); + + // Then make sure that a checkbox form widget is emitted: + std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile(); + std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // i.e. the checkbox content control was just exported as normal text. + CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount()); + std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0); + CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType()); + // Also check the form widget type: + CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFFormFieldType::CheckBox, + pAnnotation->getFormFieldType(pPdfDocument.get())); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testDropdownContentControlPDF) +{ + // Given a file with a dropdown content control: + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->InsertContentControl(SwContentControlType::DROP_DOWN_LIST); + + // When exporting to PDF: + StoreToTempFile("writer_pdf_Export"); + + // Then make sure that a dropdown form widget is emitted: + std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile(); + std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // i.e. the dropdown content control was just exported as normal text. + CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount()); + std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0); + CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType()); + // Also check the form widget type (our dropdown is called combo in PDF terms): + CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFFormFieldType::ComboBox, + pAnnotation->getFormFieldType(pPdfDocument.get())); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testDateContentControlPDF) +{ + // Given a file with a date content control: + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->InsertContentControl(SwContentControlType::DATE); + + // When exporting to PDF: + StoreToTempFile("writer_pdf_Export"); + + // Then make sure that a date form widget is emitted: + std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile(); + std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // i.e. the date content control was just exported as normal text. + CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount()); + std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0); + CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType()); + // Also check the form widget type (our date is a mode of text in PDF terms): + CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFFormFieldType::TextField, + pAnnotation->getFormFieldType(pPdfDocument.get())); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testContentControlPDFFont) +{ + // Given a document with a custom 24pt font size and a content control: + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + SfxItemSetFixed<RES_CHRATR_FONTSIZE, RES_CHRATR_FONTSIZE> aSet(pWrtShell->GetAttrPool()); + SvxFontHeightItem aItem(480, 100, RES_CHRATR_FONTSIZE); + aSet.Put(aItem); + pWrtShell->SetAttrSet(aSet); + pWrtShell->InsertContentControl(SwContentControlType::RICH_TEXT); + + // When exporting that document to PDF: + StoreToTempFile("writer_pdf_Export"); + + // Then make sure that the widget in the PDF result has that custom font size: + std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile(); + std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0); + pPage->onAfterLoadPage(pPdfDocument.get()); + CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount()); + std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 24 + // - Actual : 8 + // i.e. i.e. the font size was some default, not the 24pt specified in the model. + CPPUNIT_ASSERT_EQUAL(24.0f, pAnnotation->getFontSize(pPdfDocument.get())); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testComboContentControlPDF) +{ + // Given a file with a combo box content control: + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->InsertContentControl(SwContentControlType::COMBO_BOX); + + // When exporting to PDF: + StoreToTempFile("writer_pdf_Export"); + + // Then make sure that a combo box form widget is emitted: + std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile(); + std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // i.e. the combo box content control was exported as plain text. + CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount()); + std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0); + CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType()); + CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFFormFieldType::ComboBox, + pAnnotation->getFormFieldType(pPdfDocument.get())); + // 19th bit: combo box, not dropdown. + CPPUNIT_ASSERT(pAnnotation->getFormFieldFlags(pPdfDocument.get()) & 0x00040000); +} + +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testRichContentControlPDF) +{ + // Given a file with a rich content control, its value set to "xxx<b>yyy</b>": + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->InsertContentControl(SwContentControlType::RICH_TEXT); + pWrtShell->SttEndDoc(/*bStt=*/true); + pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false); + sal_Int32 nPlaceHolderLen = SwResId(STR_CONTENT_CONTROL_PLACEHOLDER).getLength(); + pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, nPlaceHolderLen, + /*bBasicCall=*/false); + pWrtShell->Insert("xxxyyy"); + pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 3, /*bBasicCall=*/false); + SfxItemSetFixed<RES_CHRATR_WEIGHT, RES_CHRATR_WEIGHT> aSet(pWrtShell->GetAttrPool()); + SvxWeightItem aItem(WEIGHT_BOLD, RES_CHRATR_WEIGHT); + aSet.Put(aItem); + pWrtShell->SetAttrSet(aSet); + + // When exporting to PDF: + StoreToTempFile("writer_pdf_Export"); + + // Then make sure that a single fillable form widget is emitted: + std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile(); + std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 2 + // i.e. "xxx<b>yyy</b>" was exported as 2 widgets, not 1. + CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount()); +} + +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_TEST_FIXTURE(SwCoreTextTest, testCheckedCheckboxContentControlPDF) +{ + std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + return; + + // Given a file with a checked checkbox content control: + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->InsertContentControl(SwContentControlType::CHECKBOX); + // Toggle it, so we get a checked one: + SwTextContentControl* pTextContentControl = pWrtShell->CursorInsideContentControl(); + const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl(); + pWrtShell->GotoContentControl(rFormatContentControl); + + // When exporting to PDF: + StoreToTempFile("writer_pdf_Export"); + + // Then make sure that a checked checkbox form widget is emitted: + std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile(); + std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0); + CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount()); + std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0); + CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType()); + CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFFormFieldType::CheckBox, + pAnnotation->getFormFieldType(pPdfDocument.get())); + OUString aActual = pAnnotation->getFormFieldValue(pPdfDocument.get()); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: Yes + // - Actual : Off + // i.e. the /AP -> /N key of the checkbox widget annotation object didn't have a sub-key that + // would match /V, leading to not showing the checked state. + CPPUNIT_ASSERT_EQUAL(OUString("Yes"), aActual); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |