editeng/source/editeng/impedit3.cxx | 52 +++++++++++++++++--------- sc/qa/extras/scpdfexport.cxx | 60 +++++++++++++++++++++++++++++++ sc/qa/extras/testdocuments/tdf159065.ods |binary 3 files changed, 94 insertions(+), 18 deletions(-)
New commits: commit 4202218af61573825edfe5ec5a1bba710d7df1f7 Author: Tibor Nagy <tibor.nagy.ext...@allotropia.de> AuthorDate: Tue Jan 9 23:54:43 2024 +0100 Commit: Nagy Tibor <tibor.nagy.ext...@allotropia.de> CommitDate: Wed Jan 10 08:49:29 2024 +0100 tdf#159065 sc: fix PDF/UA link annotation Change-Id: I1586608780cc82908eaef62158887afee69c148f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161843 Tested-by: Jenkins Reviewed-by: Nagy Tibor <tibor.nagy.ext...@allotropia.de> diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx index d50c2eb1338e..bc93802694fd 100644 --- a/editeng/source/editeng/impedit3.cxx +++ b/editeng/source/editeng/impedit3.cxx @@ -3855,6 +3855,25 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po ' ' == aText[nTextStart + nTextLen - 1] ) --nTextLen; + // PDF export: + const SvxFieldData* pFieldData = nullptr; + if (pPDFExtOutDevData) + { + if (rTextPortion.GetKind() == PortionKind::FIELD) + { + const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex); + const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem()); + if (pFieldItem) + { + pFieldData = pFieldItem->GetField(); + auto pUrlField = dynamic_cast<const SvxURLField*>(pFieldData); + if (pUrlField) + if (pPDFExtOutDevData->GetIsExportTaggedPDF()) + pPDFExtOutDevData->WrapBeginStructureElement(vcl::PDFWriter::Link, "Link"); + } + } + } + // output directly aTmpFont.QuickDrawText( &rOutDev, aRealOutPos, aText, nTextStart, nTextLen, pDXArray, pKashidaArray ); @@ -3869,27 +3888,24 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po } // PDF export: - if ( pPDFExtOutDevData ) + if (pPDFExtOutDevData) { - if ( rTextPortion.GetKind() == PortionKind::FIELD ) + if (auto pUrlField = dynamic_cast<const SvxURLField*>(pFieldData)) { - const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex); - const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem()); - if( pFieldItem ) + Point aTopLeft(aTmpPos); + aTopLeft.AdjustY(-(pLine->GetMaxAscent())); + + tools::Rectangle aRect(aTopLeft, rTextPortion.GetSize()); + vcl::PDFExtOutDevBookmarkEntry aBookmark; + aBookmark.nLinkId = pPDFExtOutDevData->CreateLink(aRect, pUrlField->GetRepresentation()); + aBookmark.aBookmark = pUrlField->GetURL(); + std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFExtOutDevData->GetBookmarks(); + rBookmarks.push_back(aBookmark); + + if (pPDFExtOutDevData->GetIsExportTaggedPDF()) { - const SvxFieldData* pFieldData = pFieldItem->GetField(); - if ( auto pUrlField = dynamic_cast< const SvxURLField* >( pFieldData ) ) - { - Point aTopLeft( aTmpPos ); - aTopLeft.AdjustY( -(pLine->GetMaxAscent()) ); - - tools::Rectangle aRect( aTopLeft, rTextPortion.GetSize() ); - vcl::PDFExtOutDevBookmarkEntry aBookmark; - aBookmark.nLinkId = pPDFExtOutDevData->CreateLink(aRect, pUrlField->GetRepresentation()); - aBookmark.aBookmark = pUrlField->GetURL(); - std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFExtOutDevData->GetBookmarks(); - rBookmarks.push_back( aBookmark ); - } + pPDFExtOutDevData->SetStructureAttributeNumerical(vcl::PDFWriter::LinkAnnotation, aBookmark.nLinkId); + pPDFExtOutDevData->EndStructureElement(); } } } diff --git a/sc/qa/extras/scpdfexport.cxx b/sc/qa/extras/scpdfexport.cxx index 3bfa55eb3dcf..ae85dbb9b442 100644 --- a/sc/qa/extras/scpdfexport.cxx +++ b/sc/qa/extras/scpdfexport.cxx @@ -65,6 +65,7 @@ public: void testExportFitToPage_Tdf103516(); void testUnoCommands_Tdf120161(); void testTdf64703_hiddenPageBreak(); + void testTdf159065(); void testTdf123870(); void testTdf143978(); void testTdf120190(); @@ -77,6 +78,7 @@ public: CPPUNIT_TEST(testExportFitToPage_Tdf103516); CPPUNIT_TEST(testUnoCommands_Tdf120161); CPPUNIT_TEST(testTdf64703_hiddenPageBreak); + CPPUNIT_TEST(testTdf159065); CPPUNIT_TEST(testTdf123870); CPPUNIT_TEST(testTdf143978); CPPUNIT_TEST(testTdf120190); @@ -394,6 +396,64 @@ void ScPDFExportTest::testTdf64703_hiddenPageBreak() } } +void ScPDFExportTest::testTdf159065() +{ + loadFromFile(u"tdf159065.ods"); + uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY); + + // A1:A3 + ScRange range1(0, 0, 0, 0, 2, 0); + exportToPDF(xModel, range1); + + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + // The document has one page. + 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"_ostr); + 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(); + + auto nLink(0); + auto nLine(0); + while (true) + { + ++nLine; + auto const pLine = ::std::find(pStart, pEnd, ' '); + if (pLine == pEnd) + { + break; + } + std::string_view const line(pStart, pLine - pStart); + pStart = pLine + 1; + if (!line.empty() && line[0] != '%') + { + ::std::cerr << nLine << ": " << line << " "; + if (o3tl::starts_with(line, "/Link<</MCID") && o3tl::ends_with(line, ">>BDC")) + nLink++; + } + } + + // The tagged PDF file have to contains two link annotation + CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nLink)>(2), nLink); +} + void ScPDFExportTest::testTdf123870() { loadFromFile(u"tdf123870.ods"); diff --git a/sc/qa/extras/testdocuments/tdf159065.ods b/sc/qa/extras/testdocuments/tdf159065.ods new file mode 100644 index 000000000000..c75d782f9914 Binary files /dev/null and b/sc/qa/extras/testdocuments/tdf159065.ods differ