include/vcl/filter/pdfdocument.hxx     |    4 ++-
 vcl/source/filter/ipdf/pdfdocument.cxx |   29 ++++++++++++++++++++++----
 vcl/source/gdi/pdfwriter_impl.cxx      |   36 ++++++++++++++++++++++-----------
 3 files changed, 52 insertions(+), 17 deletions(-)

New commits:
commit 2ba9d58d5978c94352c4c6cf9c47aa3de79d05fe
Author: Miklos Vajna <vmik...@collabora.co.uk>
Date:   Mon Mar 27 15:39:04 2017 +0200

    tdf#106693 vcl PDF export, norefxobj: handle multiple refs in copied dicts
    
    When copying font definitions the dictionary has multiple values where
    the type is a reference. Improve PDFWriterImpl::copyExternalResource(),
    so that multiple references are copied correctly as well.
    
    With this the bugdoc (from comment 5) text appears in the output.
    
    Change-Id: I2343e616d8b36e3cdcbd4e713bd3f7fa7bce6d3b
    Reviewed-on: https://gerrit.libreoffice.org/35760
    Reviewed-by: Miklos Vajna <vmik...@collabora.co.uk>
    Tested-by: Jenkins <c...@libreoffice.org>

diff --git a/include/vcl/filter/pdfdocument.hxx 
b/include/vcl/filter/pdfdocument.hxx
index 9ccbb43d0225..d6b44e88d027 100644
--- a/include/vcl/filter/pdfdocument.hxx
+++ b/include/vcl/filter/pdfdocument.hxx
@@ -80,10 +80,12 @@ public:
     sal_uInt64 GetDictionaryOffset();
     void SetDictionaryLength(sal_uInt64 nDictionaryLength);
     sal_uInt64 GetDictionaryLength();
-    PDFDictionaryElement* GetDictionary() const;
+    PDFDictionaryElement* GetDictionary();
     void SetDictionary(PDFDictionaryElement* pDictionaryElement);
     /// Get access to the parsed key-value items from the object dictionary.
     const std::map<OString, PDFElement*>& GetDictionaryItems() const;
+    /// Same as GetDictionaryItems(), but entries are sorted by file offset.
+    std::vector< std::pair<OString, PDFElement*> > 
GetDictionaryItemsByOffset();
     void SetArray(PDFArrayElement* pArrayElement);
     void SetStream(PDFStreamElement* pStreamElement);
     /// Access to the stream of the object, if it has any.
diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx 
b/vcl/source/filter/ipdf/pdfdocument.cxx
index 926ebb0500fd..1a85c4f3fd5e 100644
--- a/vcl/source/filter/ipdf/pdfdocument.cxx
+++ b/vcl/source/filter/ipdf/pdfdocument.cxx
@@ -1933,7 +1933,7 @@ bool PDFNumberElement::Read(SvStream& rStream)
         return false;
     }
     if (!rtl::isAsciiDigit(static_cast<unsigned char>(ch)) && ch != '-'
-        && ch != '.')
+            && ch != '.')
     {
         rStream.SeekRel(-1);
         return false;
@@ -1941,7 +1941,7 @@ bool PDFNumberElement::Read(SvStream& rStream)
     while (!rStream.IsEof())
     {
         if (!rtl::isAsciiDigit(static_cast<unsigned char>(ch)) && ch != '-'
-            && ch != '.')
+                && ch != '.')
         {
             rStream.SeekRel(-1);
             m_nLength = rStream.Tell() - m_nOffset;
@@ -2446,8 +2446,10 @@ sal_uInt64 PDFObjectElement::GetArrayLength()
     return m_nArrayLength;
 }
 
-PDFDictionaryElement* PDFObjectElement::GetDictionary() const
+PDFDictionaryElement* PDFObjectElement::GetDictionary()
 {
+    if (m_aDictionary.empty())
+        PDFDictionaryElement::Parse(m_rDoc.GetElements(), this, m_aDictionary);
     return m_pDictionaryElement;
 }
 
@@ -2456,6 +2458,25 @@ void 
PDFObjectElement::SetDictionary(PDFDictionaryElement* pDictionaryElement)
     m_pDictionaryElement = pDictionaryElement;
 }
 
+std::vector< std::pair<OString, PDFElement*> > 
PDFObjectElement::GetDictionaryItemsByOffset()
+{
+    std::vector< std::pair<OString, PDFElement*> > aRet;
+
+    for (const auto& rItem : m_aDictionary)
+        aRet.push_back(rItem);
+
+    PDFDictionaryElement* pDictionary = GetDictionary();
+    if (!pDictionary)
+        return aRet;
+
+    std::sort(aRet.begin(), aRet.end(), [pDictionary](const std::pair<OString, 
PDFElement*>& a, const std::pair<OString, PDFElement*>& b) -> bool
+    {
+        return pDictionary->GetKeyOffset(a.first) < 
pDictionary->GetKeyOffset(b.first);
+    });
+
+    return aRet;
+}
+
 const std::map<OString, PDFElement*>& PDFObjectElement::GetDictionaryItems() 
const
 {
     return m_aDictionary;
@@ -2841,7 +2862,7 @@ bool PDFNameElement::Read(SvStream& rStream)
     while (!rStream.IsEof())
     {
         if (rtl::isAsciiWhiteSpace(static_cast<unsigned char>(ch)) || ch == '/'
-            || ch == '[' || ch == ']' || ch == '<' || ch == '>' || ch == '(')
+                || ch == '[' || ch == ']' || ch == '<' || ch == '>' || ch == 
'(')
         {
             rStream.SeekRel(-1);
             m_aValue = aBuf.makeStringAndClear();
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx 
b/vcl/source/gdi/pdfwriter_impl.cxx
index eb9d00cac010..7d435e404837 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -10863,10 +10863,11 @@ sal_Int32 
PDFWriterImpl::copyExternalResource(SvMemoryStream& rDocBuffer, filter
     {
         aLine.append("<<");
 
-        // Complex case: can't copy the dictionary byte array as is, as it 
contains a reference.
+        // Complex case: can't copy the dictionary byte array as is, as it may 
contain references.
         bool bDone = false;
-        const std::map<OString, filter::PDFElement*>& rItems = 
rObject.GetDictionaryItems();
-        for (const auto& rItem : rItems)
+        std::vector< std::pair<OString, filter::PDFElement*> > aItems = 
rObject.GetDictionaryItemsByOffset();
+        sal_uInt64 nCopyStart = 0;
+        for (const auto& rItem : aItems)
         {
             auto pReference = 
dynamic_cast<filter::PDFReferenceElement*>(rItem.second);
             if (pReference)
@@ -10877,27 +10878,36 @@ sal_Int32 
PDFWriterImpl::copyExternalResource(SvMemoryStream& rDocBuffer, filter
                     // Copy the referenced object.
                     sal_Int32 nRef = copyExternalResource(rDocBuffer, 
*pReferenced);
 
-                    sal_uInt64 nDictStart = rObject.GetDictionaryOffset();
                     sal_uInt64 nReferenceStart = 
pDictionary->GetKeyOffset(rItem.first) + rItem.first.getLength();
                     sal_uInt64 nReferenceEnd = 
pDictionary->GetKeyOffset(rItem.first) + 
pDictionary->GetKeyValueLength(rItem.first);
-                    sal_uInt64 nDictEnd = nDictStart + 
rObject.GetDictionaryLength();
-                    // Dict start -> reference start.
-                    aLine.append(static_cast<const 
sal_Char*>(rDocBuffer.GetData()) + nDictStart, nReferenceStart - nDictStart);
+                    sal_uInt64 nOffset = 0;
+                    if (nCopyStart == 0)
+                        // Dict start -> reference start.
+                        nOffset = rObject.GetDictionaryOffset();
+                    else
+                        // Previous reference end -> reference start.
+                        nOffset = nCopyStart;
+                    aLine.append(static_cast<const 
sal_Char*>(rDocBuffer.GetData()) + nOffset, nReferenceStart - nOffset);
                     // Write the updated reference.
                     aLine.append(" ");
                     aLine.append(nRef);
                     aLine.append(" 0 R");
-                    // Reference end -> dict end.
-                    aLine.append(static_cast<const 
sal_Char*>(rDocBuffer.GetData()) + nReferenceEnd, nDictEnd - nReferenceEnd);
+                    // Start copying here next time.
+                    nCopyStart = nReferenceEnd;
 
                     bDone = true;
-                    break;
                 }
             }
         }
 
-        // Can copy it as-is.
-        if (!bDone)
+        if (bDone)
+        {
+            // Copy the last part here, in the complex case.
+            sal_uInt64 nDictEnd = rObject.GetDictionaryOffset() + 
rObject.GetDictionaryLength();
+            aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + 
nCopyStart, nDictEnd - nCopyStart);
+        }
+        else
+            // Can copy it as-is.
             aLine.append(static_cast<const sal_Char*>(rDocBuffer.GetData()) + 
rObject.GetDictionaryOffset(), rObject.GetDictionaryLength());
 
         aLine.append(">>\n");
@@ -11057,6 +11067,7 @@ void 
PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
             return;
         }
 
+        OString sFonts = copyExternalResources(*pPage, "Font");
         OString sXObjects = copyExternalResources(*pPage, "XObject");
 
         filter::PDFObjectElement* pPageContents = 
pPage->LookupObject("Contents");
@@ -11078,6 +11089,7 @@ void 
PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit)
         aLine.append("<< /Type /XObject");
         aLine.append(" /Subtype /Form");
         aLine.append(" /Resources <<");
+        aLine.append(sFonts);
         aLine.append(sXObjects);
         aLine.append(">>");
         aLine.append(" /BBox [ 0 0 ");
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to