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)
 {

Reply via email to