diff options
-rw-r--r-- | filter/source/pdf/pdfexport.cxx | 16 | ||||
-rw-r--r-- | vcl/qa/cppunit/pdfexport/pdfexport.cxx | 90 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 4 |
3 files changed, 108 insertions, 2 deletions
diff --git a/filter/source/pdf/pdfexport.cxx b/filter/source/pdf/pdfexport.cxx index eb43260d8a83..f9c5fb44af6b 100644 --- a/filter/source/pdf/pdfexport.cxx +++ b/filter/source/pdf/pdfexport.cxx @@ -1262,6 +1262,13 @@ void PDFExport::ImplWriteWatermark( vcl::PDFWriter& rWriter, const Size& rPageSi pDev->Pop(); rWriter.Push(); + // tdf#152235 tag around the reference to the XObject on the page + rWriter.BeginStructureElement(vcl::PDFWriter::NonStructElement, ::std::u16string_view()); + rWriter.SetStructureAttribute(vcl::PDFWriter::Type, vcl::PDFWriter::Pagination); + rWriter.SetStructureAttribute(vcl::PDFWriter::Subtype, vcl::PDFWriter::Watermark); + // HACK: this should produce *nothing* itself but is necessary to output + // the Artifact tag here, not inside the XObject + rWriter.DrawPolyLine({}); rWriter.SetMapMode( MapMode( MapUnit::MapPoint ) ); rWriter.SetFont( aFont ); rWriter.SetTextColor(maWatermarkColor); @@ -1304,6 +1311,7 @@ void PDFExport::ImplWriteWatermark( vcl::PDFWriter& rWriter, const Size& rPageSi rWriter.BeginTransparencyGroup(); rWriter.DrawText( aTextPoint, msWatermark ); rWriter.EndTransparencyGroup( aTextRect, 50 ); + rWriter.EndStructureElement(); rWriter.Pop(); } @@ -1350,6 +1358,13 @@ void PDFExport::ImplWriteTiledWatermark( vcl::PDFWriter& rWriter, const Size& rP pDev->Pop(); rWriter.Push(); + // tdf#152235 tag around the reference to the XObject on the page + rWriter.BeginStructureElement(vcl::PDFWriter::NonStructElement, ::std::u16string_view()); + rWriter.SetStructureAttribute(vcl::PDFWriter::Type, vcl::PDFWriter::Pagination); + rWriter.SetStructureAttribute(vcl::PDFWriter::Subtype, vcl::PDFWriter::Watermark); + // HACK: this should produce *nothing* itself but is necessary to output + // the Artifact tag here, not inside the XObject + rWriter.DrawPolyLine({}); rWriter.SetMapMode( MapMode( MapUnit::MapPoint ) ); rWriter.SetFont(aFont); rWriter.SetTextColor( Color(19,20,22) ); @@ -1385,6 +1400,7 @@ void PDFExport::ImplWriteTiledWatermark( vcl::PDFWriter& rWriter, const Size& rP aTextPoint.Move( nTextWidth*1.5, 0 ); } + rWriter.EndStructureElement(); rWriter.Pop(); } diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx index 5698288b4c22..34e733c115c3 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx @@ -3314,6 +3314,96 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf152231) CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nPara)>(12), nPara); } +CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf152235) +{ + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + // Enable PDF/UA + uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence( + { { "PDFUACompliance", uno::Any(true) }, + { "Watermark", uno::Any(OUString("kendy")) }, + // need to set a font to avoid assertions about missing "Helvetica" + { "WatermarkFontName", uno::Any(OUString("Liberation Sans")) }, + { "SelectPdfVersion", uno::Any(sal_Int32(17)) } })); + aMediaDescriptor["FilterData"] <<= aFilterData; + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + + vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + vcl::filter::PDFStreamElement* pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + // Uncompress it. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + auto pStart = static_cast<const char*>(aUncompressed.GetData()); + const char* const pEnd = pStart + aUncompressed.GetSize(); + + enum + { + Default, + Artifact, + Tagged + } state + = Default; + + auto nLine(0); + auto nTagged(0); + auto nArtifacts(0); + while (true) + { + ++nLine; + auto const pLine = ::std::find(pStart, pEnd, '\n'); + if (pLine == pEnd) + { + break; + } + std::string_view const line(pStart, pLine - pStart); + pStart = pLine + 1; + if (!line.empty() && line[0] != '%') + { + ::std::cerr << nLine << ": " << line << "\n"; + if (o3tl::starts_with(line, "/Artifact ")) + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default, state); + state = Artifact; + ++nArtifacts; + } + else if (o3tl::starts_with(line, "/Standard<</MCID ")) + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default, state); + state = Tagged; + ++nTagged; + } + else if (line == "EMC") + { + CPPUNIT_ASSERT_MESSAGE("unexpected end", state != Default); + state = Default; + } + else if (nLine > 1) // first line is expected "0.1 w" + { + CPPUNIT_ASSERT_MESSAGE("unexpected content outside MCS", state != Default); + } + } + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("unclosed MCS", Default, state); + CPPUNIT_ASSERT(nTagged >= 0); // text in body + CPPUNIT_ASSERT(nArtifacts >= 2); // 1 watermark + 1 other thing +} + CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf149140) { aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 80abe227788a..432f25b04ba1 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -11045,8 +11045,8 @@ bool PDFWriterImpl::setStructureAttribute( enum PDFWriter::StructAttribute eAttr && (m_bEmitStructure // allow it for topmost non-structured element || (m_aContext.Tagged - && 0 < m_aStructure[m_nCurrentStructElement].m_nParentElement - && m_aStructure[m_aStructure[m_nCurrentStructElement].m_nParentElement].m_eType != PDFWriter::NonStructElement))) + && (0 == m_aStructure[m_nCurrentStructElement].m_nParentElement + || m_aStructure[m_aStructure[m_nCurrentStructElement].m_nParentElement].m_eType != PDFWriter::NonStructElement)))) { PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType; switch( eAttr ) |