include/vcl/filter/PDFiumLibrary.hxx | 1 + sw/qa/core/text/text.cxx | 24 ++++++++++++++++++++++++ sw/source/core/text/itrform2.cxx | 22 ++++++++++------------ vcl/source/pdf/PDFiumLibrary.cxx | 31 +++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 12 deletions(-)
New commits: commit 14da39fcfffe8006a79971ac0b670e12d0d7a0ea Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Thu Jan 19 19:53:12 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Fri Jan 20 07:50:29 2023 +0000 tdf#153047 sw: fix PDF export of content controls in placeholder mode Importing an inline content control from DOCX used to be just plain text in Writer, so the PDF export of that was also just plain text. Now that content controls are actually supported, we used to not emit them as plain text in the PDF export, since 82d90529dc2b3cb8359dec78852cbd910a66d275 (sw content controls, rich text: add initial PDF export, 2022-09-12). Part of this was to write the string value of the content control as the /V (value) key of the form, when it's not in placeholder mode. This made sure that once the form is filled in, no overlap between the plain text and the filled in text happens. Try to support both use-cases at the same time by also mapping the value of the content control to /V, even if it's in placeholder mode. This keeps avoiding the unwanted overlap, but this way the placeholder text is no longer lost on PDF export. An alternative would have been to map the placeholder text to description when the alias/title is empty, but that would show up only as a mouse tooltip, so won't change the behavior when the PDF is printed. Change-Id: I9408b5abe36af28cd00845a74a3dfff13973b83a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145828 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/include/vcl/filter/PDFiumLibrary.hxx b/include/vcl/filter/PDFiumLibrary.hxx index 347b64619045..9c278d281a1c 100644 --- a/include/vcl/filter/PDFiumLibrary.hxx +++ b/include/vcl/filter/PDFiumLibrary.hxx @@ -110,6 +110,7 @@ public: virtual OUString getFormAdditionalActionJavaScript(PDFiumDocument* pDoc, PDFAnnotAActionType eEvent) = 0; + virtual OUString getFormFieldValue(PDFiumDocument* pDoc) = 0; }; class PDFiumTextPage; diff --git a/sw/qa/core/text/text.cxx b/sw/qa/core/text/text.cxx index db1895b795c0..9391630acd51 100644 --- a/sw/qa/core/text/text.cxx +++ b/sw/qa/core/text/text.cxx @@ -675,6 +675,30 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testContentControlPDF) pAnnotation->getFormFieldAlternateName(pPdfDocument.get())); } +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testContentControlPlaceholderPDF) +{ + // Given a file with a content control, in placeholder mode: + createSwDoc(); + SwDoc* pDoc = getSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->InsertContentControl(SwContentControlType::RICH_TEXT); + + // When exporting to PDF: + save("writer_pdf_Export"); + + // Then make sure that a fillable form widget is emitted with the expected value: + std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); + 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); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: Click here to enter text + // - Actual : + // i.e. the value of the content control was empty, the placeholder value was lost. + CPPUNIT_ASSERT_EQUAL(SwResId(STR_CONTENT_CONTROL_PLACEHOLDER), + pAnnotation->getFormFieldValue(pPdfDocument.get())); +} + CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testCheckboxContentControlPDF) { // Given a file with a checkbox content control: diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx index 9f075014fd9a..91f73ed87825 100644 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -1047,18 +1047,16 @@ bool SwContentControlPortion::DescribePDFControl(const SwTextPaintInfo& rInf) co pDescriptor->Description = pContentControl->GetAlias(); } - if (!pContentControl->GetShowingPlaceHolder()) - { - SwPosition aPoint(*pTextNode, nStart); - SwPosition aMark(*pTextNode, nEnd); - SwPaM aPam(aMark, aPoint); - OUString aText = aPam.GetText(); - static sal_Unicode const aForbidden[] = { - CH_TXTATR_BREAKWORD, - 0 - }; - pDescriptor->Text = comphelper::string::removeAny(aText, aForbidden); - } + // Map the text of the content control to the descriptor's text. + SwPosition aPoint(*pTextNode, nStart); + SwPosition aMark(*pTextNode, nEnd); + SwPaM aPam(aMark, aPoint); + OUString aText = aPam.GetText(); + static sal_Unicode const aForbidden[] = { + CH_TXTATR_BREAKWORD, + 0 + }; + pDescriptor->Text = comphelper::string::removeAny(aText, aForbidden); // Calculate the bounding rectangle of this content control, which can be one or more layout // portions in one or more lines. diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx index 9fa291898f8c..e0562c4dbf9b 100644 --- a/vcl/source/pdf/PDFiumLibrary.cxx +++ b/vcl/source/pdf/PDFiumLibrary.cxx @@ -268,6 +268,7 @@ public: int getFormFieldFlags(PDFiumDocument* pDoc) override; OUString getFormAdditionalActionJavaScript(PDFiumDocument* pDoc, PDFAnnotAActionType eEvent) override; + OUString getFormFieldValue(PDFiumDocument* pDoc) override; }; class PDFiumPageObjectImpl final : public PDFiumPageObject @@ -1233,6 +1234,36 @@ OUString PDFiumAnnotationImpl::getFormFieldAlternateName(PDFiumDocument* pDoc) return aString; } +OUString PDFiumAnnotationImpl::getFormFieldValue(PDFiumDocument* pDoc) +{ + auto pDocImpl = static_cast<PDFiumDocumentImpl*>(pDoc); + OUString aString; + unsigned long nSize + = FPDFAnnot_GetFormFieldValue(pDocImpl->getFormHandlePointer(), mpAnnotation, nullptr, 0); + assert(nSize % 2 == 0); + nSize /= 2; + if (nSize > 1) + { + std::unique_ptr<sal_Unicode[]> pText(new sal_Unicode[nSize]); + unsigned long nStringSize + = FPDFAnnot_GetFormFieldValue(pDocImpl->getFormHandlePointer(), mpAnnotation, + reinterpret_cast<FPDF_WCHAR*>(pText.get()), nSize * 2); + assert(nStringSize % 2 == 0); + nStringSize /= 2; + if (nStringSize > 0) + { +#if defined OSL_BIGENDIAN + for (unsigned long i = 0; i != nStringSize; ++i) + { + pText[i] = OSL_SWAPWORD(pText[i]); + } +#endif + aString = OUString(pText.get()); + } + } + return aString; +} + OUString PDFiumAnnotationImpl::getFormAdditionalActionJavaScript(PDFiumDocument* pDoc, PDFAnnotAActionType eEvent) {