include/vcl/filter/PDFiumLibrary.hxx        |    1 
 sw/qa/core/text/text.cxx                    |   24 +++++++++++++++++++++
 sw/qa/filter/html/data/centered-table.xhtml |    9 ++++++++
 sw/qa/filter/html/html.cxx                  |   19 +++++++++++++++++
 sw/source/core/text/itrform2.cxx            |   22 +++++++++----------
 sw/source/filter/html/htmltab.cxx           |   29 ++++++++++++++++++++++++++
 sw/source/filter/html/svxcss1.cxx           |   16 ++++++++++++++
 sw/source/filter/html/svxcss1.hxx           |    2 +
 vcl/source/pdf/PDFiumLibrary.cxx            |   31 ++++++++++++++++++++++++++++
 9 files changed, 141 insertions(+), 12 deletions(-)

New commits:
commit e80593e219dffd85ab16ebd2954cba8fa8c84637
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Jan 19 19:53:12 2023 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Tue Jan 24 11:47:23 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>
    (cherry picked from commit 14da39fcfffe8006a79971ac0b670e12d0d7a0ea)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146017
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

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 c4821f5d6eae..9ffae51f175f 100644
--- a/sw/qa/core/text/text.cxx
+++ b/sw/qa/core/text/text.cxx
@@ -679,6 +679,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)
 {
     std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
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)
 {
commit 68c003154e7eb0dcf0473b41ce112283659a1cac
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri Jan 20 12:15:48 2023 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Tue Jan 24 11:47:15 2023 +0000

    sw HTML import: initial CSS support on tables
    
    This is the import side of commit
    6ce374140f3bd1cede959ccc8da69fdacecff191 (sw XHTML export: use CSS
    instead of <center> for tables, 2023-01-19), otherwise the import would
    not handle the new markup of the export.
    
    Change-Id: I7d18b06e10adff877dbbf1745861c65a07f807cb
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145863
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit 44c75d56cd441ad3d174db75a6e5ae672b7d2a08)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145946
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sw/qa/filter/html/data/centered-table.xhtml 
b/sw/qa/filter/html/data/centered-table.xhtml
new file mode 100644
index 000000000000..4ec88792f119
--- /dev/null
+++ b/sw/qa/filter/html/data/centered-table.xhtml
@@ -0,0 +1,9 @@
+<reqif-xhtml:div>
+       <reqif-xhtml:table width="400" cellpadding="0" cellspacing="0" 
style="margin-left: auto; margin-right: auto">
+               <reqif-xhtml:tr>
+                       <reqif-xhtml:td><reqif-xhtml:p>A1</reqif-xhtml:p>
+                       </reqif-xhtml:td>
+               </reqif-xhtml:tr>
+       </reqif-xhtml:table>
+<reqif-xhtml:p></reqif-xhtml:p>
+</reqif-xhtml:div>
diff --git a/sw/qa/filter/html/html.cxx b/sw/qa/filter/html/html.cxx
index 65f67b7378d1..2b0c36508378 100644
--- a/sw/qa/filter/html/html.cxx
+++ b/sw/qa/filter/html/html.cxx
@@ -226,6 +226,25 @@ CPPUNIT_TEST_FIXTURE(Test, testCenteredTableCSSExport)
     assertXPath(pXmlDoc, "//reqif-xhtml:center", 0);
     assertXPath(pXmlDoc, "//reqif-xhtml:table", "style", "margin-left: auto; 
margin-right: auto");
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testCenteredTableCSSImport)
+{
+    // Given an XHTML file with a centered (with inline CSS) table, when 
importing that document:
+    setImportFilterOptions("xhtmlns=reqif-xhtml");
+    setImportFilterName("HTML (StarWriter)");
+    createSwDoc("centered-table.xhtml");
+
+    // Then make sure that the table is centered:
+    SwDoc* pDoc = getSwDoc();
+    const SwFrameFormats& rTableFormats = *pDoc->GetTableFrameFormats();
+    const SwFrameFormat* pTableFormat = rTableFormats[0];
+    sal_Int16 eHoriOrient = pTableFormat->GetHoriOrient().GetHoriOrient();
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 2 (CENTER)
+    // - Actual  : 3 (LEFT)
+    // i.e. the table alignment was lost on import.
+    CPPUNIT_ASSERT_EQUAL(text::HoriOrientation::CENTER, eHoriOrient);
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/filter/html/htmltab.cxx 
b/sw/source/filter/html/htmltab.cxx
index fe55cec381ac..7913cd9e85fa 100644
--- a/sw/source/filter/html/htmltab.cxx
+++ b/sw/source/filter/html/htmltab.cxx
@@ -4917,6 +4917,35 @@ std::shared_ptr<HTMLTable> 
SwHTMLParser::BuildTable(SvxAdjust eParentAdjust,
     else
     {
         m_xTable.reset();
+
+        // Parse CSS on the table.
+        OUString aStyle;
+        const HTMLOptions& rHTMLOptions = GetOptions();
+        for (size_t i = rHTMLOptions.size(); i;)
+        {
+            const HTMLOption& rOption = rHTMLOptions[--i];
+            if (rOption.GetToken() == HtmlOptionId::STYLE)
+            {
+                aStyle = rOption.GetString();
+            }
+        }
+        if (!aStyle.isEmpty())
+        {
+            // Have inline CSS.
+            SfxItemSet aItemSet(m_xDoc->GetAttrPool(), 
m_pCSS1Parser->GetWhichMap());
+            SvxCSS1PropertyInfo aPropInfo;
+            if (ParseStyleOptions(aStyle, /*aId=*/OUString(), 
/*aClass=*/OUString(), aItemSet,
+                                  aPropInfo))
+            {
+                if (aPropInfo.m_eLeftMarginType == SVX_CSS1_LTYPE_AUTO
+                    && aPropInfo.m_eRightMarginType == SVX_CSS1_LTYPE_AUTO)
+                {
+                    // Both left & right is set to auto: that's our center.
+                    eParentAdjust = SvxAdjust::Center;
+                }
+            }
+        }
+
         HTMLTableOptions aTableOptions(GetOptions(), eParentAdjust);
 
         if (!aTableOptions.aId.isEmpty())
diff --git a/sw/source/filter/html/svxcss1.cxx 
b/sw/source/filter/html/svxcss1.cxx
index 256656a6df1e..9b312e0b3239 100644
--- a/sw/source/filter/html/svxcss1.cxx
+++ b/sw/source/filter/html/svxcss1.cxx
@@ -399,6 +399,8 @@ SvxCSS1PropertyInfo::SvxCSS1PropertyInfo( const 
SvxCSS1PropertyInfo& rProp ) :
     m_eTopType( rProp.m_eTopType ),
     m_eWidthType( rProp.m_eWidthType ),
     m_eHeightType( rProp.m_eHeightType ),
+    m_eLeftMarginType( rProp.m_eLeftMarginType ),
+    m_eRightMarginType( rProp.m_eRightMarginType ),
     m_eSizeType( rProp.m_eSizeType ),
     m_ePageBreakBefore( rProp.m_ePageBreakBefore ),
     m_ePageBreakAfter( rProp.m_ePageBreakAfter )
@@ -438,6 +440,8 @@ void SvxCSS1PropertyInfo::Clear()
 
     m_nLeft = m_nTop = m_nWidth = m_nHeight = 0;
     m_eLeftType = m_eTopType = m_eWidthType = m_eHeightType = 
SVX_CSS1_LTYPE_NONE;
+    m_eLeftMarginType = SVX_CSS1_LTYPE_NONE;
+    m_eRightMarginType = SVX_CSS1_LTYPE_NONE;
 
 // Feature: PrintExt
     m_eSizeType = SVX_CSS1_STYPE_NONE;
@@ -2042,6 +2046,12 @@ static void ParseCSS1_margin_left( const CSS1Expression 
*pExpr,
         ;
     }
 
+    if (pExpr->GetString() == "auto")
+    {
+        rPropInfo.m_bLeftMargin = true;
+        rPropInfo.m_eLeftMarginType = SVX_CSS1_LTYPE_AUTO;
+    }
+
     if( !bSet )
         return;
 
@@ -2099,6 +2109,12 @@ static void ParseCSS1_margin_right( const CSS1Expression 
*pExpr,
         ;
     }
 
+    if (pExpr->GetString() == "auto")
+    {
+        rPropInfo.m_bRightMargin = true;
+        rPropInfo.m_eRightMarginType = SVX_CSS1_LTYPE_AUTO;
+    }
+
     if( !bSet )
         return;
 
diff --git a/sw/source/filter/html/svxcss1.hxx 
b/sw/source/filter/html/svxcss1.hxx
index 0ca92f314ea9..30c5a7b4accb 100644
--- a/sw/source/filter/html/svxcss1.hxx
+++ b/sw/source/filter/html/svxcss1.hxx
@@ -136,6 +136,8 @@ public:
 
     SvxCSS1LengthType m_eLeftType, m_eTopType;
     SvxCSS1LengthType m_eWidthType, m_eHeightType;
+    SvxCSS1LengthType m_eLeftMarginType;
+    SvxCSS1LengthType m_eRightMarginType;
 
     SvxCSS1SizeType m_eSizeType;
 

Reply via email to