[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.4' - sd/qa vcl/source

Tomaž Vajngerl (via logerrit) logerrit at kemper.freedesktop.org
Mon Jun 29 19:53:50 UTC 2020


 sd/qa/unit/SdrPdfImportTest.cxx   |    9 +-
 vcl/source/gdi/pdfwriter_impl.cxx |  129 ++++++++++++++++++++++++++++----------
 vcl/source/gdi/pdfwriter_impl.hxx |   16 ++++
 3 files changed, 115 insertions(+), 39 deletions(-)

New commits:
commit 601eeb015243937727926096f69fd53e3b410160
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sat Jun 20 08:43:58 2020 +0200
Commit:     Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Mon Jun 29 21:53:18 2020 +0200

    pdf export: support pop-up annotation for notes / comments
    
    This changes pdf export for annotation, so the comments are
    exported as "text" annotation with an child "pop-up" annotations.
    This seems to be more common what PDF readers do (even when text
    annotation only should be enough).
    
    Also changes the test, so that it now works as expected.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96765
    Tested-by: Tomaž Vajngerl <quikee at gmail.com>
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>
    (cherry picked from commit 51d529c18dadb05754590a01ce4c1f06f41cf412)
    
    Change-Id: I95bc12939f490effe7759dad54e136c44e44a2f8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97443
    Tested-by: Tomaž Vajngerl <quikee at gmail.com>
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/sd/qa/unit/SdrPdfImportTest.cxx b/sd/qa/unit/SdrPdfImportTest.cxx
index 16b31774a784..ca022d585c48 100644
--- a/sd/qa/unit/SdrPdfImportTest.cxx
+++ b/sd/qa/unit/SdrPdfImportTest.cxx
@@ -232,14 +232,13 @@ CPPUNIT_TEST_FIXTURE(SdrPdfImportTest, testAnnotationsImportExport)
         auto pPDFPage = pPDFDocument->openPage(0);
         CPPUNIT_ASSERT(pPDFPage);
 
-        // TODO: Should be 2 really
-        CPPUNIT_ASSERT_EQUAL(1, pPDFPage->getAnnotationCount());
+        CPPUNIT_ASSERT_EQUAL(2, pPDFPage->getAnnotationCount());
 
         auto pPDFAnnotation1 = pPDFPage->getAnnotation(0);
         CPPUNIT_ASSERT_EQUAL(1, pPDFAnnotation1->getSubType()); // Text annotation
 
-        //auto pPDFAnnotation2 = pPDFPage->getAnnotation(1);
-        //CPPUNIT_ASSERT_EQUAL(16, pPDFAnnotation2->getSubType()); // Pop-up annotation
+        auto pPDFAnnotation2 = pPDFPage->getAnnotation(1);
+        CPPUNIT_ASSERT_EQUAL(16, pPDFAnnotation2->getSubType()); // Pop-up annotation
 
         // Load document again
         mxComponent = loadFromDesktop(aTempFile.GetURL());
@@ -250,7 +249,7 @@ CPPUNIT_TEST_FIXTURE(SdrPdfImportTest, testAnnotationsImportExport)
         SdPage* pPage = pNewViewShell->GetActualPage();
         CPPUNIT_ASSERT(pPage);
 
-        //CPPUNIT_ASSERT_EQUAL(false, pPage->getAnnotations().empty());
+        CPPUNIT_ASSERT(!pPage->getAnnotations().empty());
     }
 
 #endif // HAVE_FEATURE_PDFIUM
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 8e38a85dfa71..2ef065f61afd 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -3567,50 +3567,112 @@ we check in the following sequence:
     return true;
 }
 
+namespace
+{
+
+void appendAnnotationRect(tools::Rectangle const & rRectangle, OStringBuffer & aLine)
+{
+    aLine.append("/Rect[");
+    appendFixedInt(rRectangle.Left(), aLine);
+    aLine.append(' ');
+    appendFixedInt(rRectangle.Top(), aLine);
+    aLine.append(' ');
+    appendFixedInt(rRectangle.Right(), aLine);
+    aLine.append(' ');
+    appendFixedInt(rRectangle.Bottom(), aLine);
+    aLine.append("] ");
+}
+
+void appendObjectID(sal_Int32 nObjectID, OStringBuffer & aLine)
+{
+    aLine.append(nObjectID);
+    aLine.append(" 0 obj\n");
+}
+
+void appendObjectReference(sal_Int32 nObjectID, OStringBuffer & aLine)
+{
+    aLine.append(nObjectID);
+    aLine.append(" 0 R ");
+}
+
+} // end anonymous namespace
+
+void PDFWriterImpl::emitTextAnnotationLine(OStringBuffer & aLine, PDFNoteEntry const & rNote)
+{
+    appendObjectID(rNote.m_nObject, aLine);
+
+    aLine.append("<</Type /Annot /Subtype /Text ");
+
+// i59651: key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should'
+// see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
+    if (m_bIsPDF_A1 || m_bIsPDF_A2)
+        aLine.append("/F 4 ");
+
+    appendAnnotationRect(rNote.m_aRect, aLine);
+
+    aLine.append("/Popup ");
+    appendObjectReference(rNote.m_aPopUpAnnotation.m_nObject, aLine);
+
+    // contents of the note (type text string)
+    aLine.append("/Contents ");
+    appendUnicodeTextStringEncrypt(rNote.m_aContents.Contents, rNote.m_nObject, aLine);
+    aLine.append("\n");
+
+    // optional title
+    if (!rNote.m_aContents.Title.isEmpty())
+    {
+        aLine.append("/T ");
+        appendUnicodeTextStringEncrypt(rNote.m_aContents.Title, rNote.m_nObject, aLine);
+        aLine.append("\n");
+    }
+    aLine.append(">>\n");
+    aLine.append("endobj\n\n");
+}
+
+void PDFWriterImpl::emitPopupAnnotationLine(OStringBuffer & aLine, PDFPopupAnnotation const & rPopUp)
+{
+    appendObjectID(rPopUp.m_nObject, aLine);
+    aLine.append("<</Type /Annot /Subtype /Popup ");
+    aLine.append("/Parent ");
+    appendObjectReference(rPopUp.m_nParentObject, aLine);
+    aLine.append(">>\n");
+    aLine.append("endobj\n\n");
+}
+
 bool PDFWriterImpl::emitNoteAnnotations()
 {
     // emit note annotations
     int nAnnots = m_aNotes.size();
     for( int i = 0; i < nAnnots; i++ )
     {
-        const PDFNoteEntry& rNote       = m_aNotes[i];
-        if( ! updateObject( rNote.m_nObject ) )
-            return false;
+        const PDFNoteEntry& rNote = m_aNotes[i];
+        const PDFPopupAnnotation& rPopUp = rNote.m_aPopUpAnnotation;
 
-        OStringBuffer aLine( 1024 );
-        aLine.append( rNote.m_nObject );
-        aLine.append( " 0 obj\n" );
-// i59651: key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should'
-// see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
-        aLine.append( "<</Type/Annot" );
-        if( m_bIsPDF_A1 || m_bIsPDF_A2 )
-            aLine.append( "/F 4" );
-        aLine.append( "/Subtype/Text/Rect[" );
 
-        appendFixedInt( rNote.m_aRect.Left(), aLine );
-        aLine.append( ' ' );
-        appendFixedInt( rNote.m_aRect.Top(), aLine );
-        aLine.append( ' ' );
-        appendFixedInt( rNote.m_aRect.Right(), aLine );
-        aLine.append( ' ' );
-        appendFixedInt( rNote.m_aRect.Bottom(), aLine );
-        aLine.append( "]" );
+        {
+            if (!updateObject(rNote.m_nObject))
+                return false;
 
-        // contents of the note (type text string)
-        aLine.append( "/Contents\n" );
-        appendUnicodeTextStringEncrypt( rNote.m_aContents.Contents, rNote.m_nObject, aLine );
-        aLine.append( "\n" );
+            OStringBuffer aLine(1024);
 
-        // optional title
-        if( !rNote.m_aContents.Title.isEmpty() )
-        {
-            aLine.append( "/T" );
-            appendUnicodeTextStringEncrypt( rNote.m_aContents.Title, rNote.m_nObject, aLine );
-            aLine.append( "\n" );
+            emitTextAnnotationLine(aLine, rNote);
+
+            if (!writeBuffer(aLine.getStr(), aLine.getLength()))
+                return false;
         }
 
-        aLine.append( ">>\nendobj\n\n" );
-        CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+        {
+
+            if (!updateObject(rPopUp.m_nObject))
+                return false;
+
+            OStringBuffer aLine(1024);
+
+            emitPopupAnnotationLine(aLine, rPopUp);
+
+            if (!writeBuffer(aLine.getStr(), aLine.getLength()))
+                return false;
+        }
     }
     return true;
 }
@@ -9888,6 +9950,8 @@ void PDFWriterImpl::createNote( const tools::Rectangle& rRect, const PDFNote& rN
     m_aNotes.emplace_back();
     auto & rNoteEntry = m_aNotes.back();
     rNoteEntry.m_nObject = createObject();
+    rNoteEntry.m_aPopUpAnnotation.m_nObject = createObject();
+    rNoteEntry.m_aPopUpAnnotation.m_nParentObject = rNoteEntry.m_nObject;
     rNoteEntry.m_aContents = rNote;
     rNoteEntry.m_aRect = rRect;
     // convert to default user space now, since the mapmode may change
@@ -9895,6 +9959,7 @@ void PDFWriterImpl::createNote( const tools::Rectangle& rRect, const PDFNote& rN
 
     // insert note to page's annotation list
     m_aPages[nPageNr].m_aAnnotations.push_back(rNoteEntry.m_nObject);
+    m_aPages[nPageNr].m_aAnnotations.push_back(rNoteEntry.m_aPopUpAnnotation.m_nObject);
 }
 
 sal_Int32 PDFWriterImpl::createLink( const tools::Rectangle& rRect, sal_Int32 nPageNr )
diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx
index 43774333a182..79df86f9b679 100644
--- a/vcl/source/gdi/pdfwriter_impl.hxx
+++ b/vcl/source/gdi/pdfwriter_impl.hxx
@@ -438,9 +438,17 @@ public:
         }
     };
 
+    struct PDFPopupAnnotation : public PDFAnnotation
+    {
+        /// ID of the parent object.
+        sal_Int32 m_nParentObject;
+    };
+
     struct PDFNoteEntry : public PDFAnnotation
     {
-        PDFNote                     m_aContents;
+        PDFNote m_aContents;
+
+        PDFPopupAnnotation m_aPopUpAnnotation;
 
         PDFNoteEntry()
         {}
@@ -878,10 +886,14 @@ i12626
     bool appendDest( sal_Int32 nDestID, OStringBuffer& rBuffer );
     // write all links
     bool emitLinkAnnotations();
-    /// Write all screen annotations.
+    // Write all screen annotations.
     bool emitScreenAnnotations();
+
+    void emitTextAnnotationLine(OStringBuffer & aLine, PDFNoteEntry const & rNote);
+    static void emitPopupAnnotationLine(OStringBuffer & aLine, PDFPopupAnnotation const & rPopUp);
     // write all notes
     bool emitNoteAnnotations();
+
     // write the appearance streams of a widget
     bool emitAppearances( PDFWidget& rWidget, OStringBuffer& rAnnotDict );
     // clean up radio button "On" values


More information about the Libreoffice-commits mailing list