summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorMichael Stahl <michael.stahl@allotropia.de>2022-10-25 13:41:05 +0200
committerMichael Stahl <michael.stahl@allotropia.de>2022-10-25 20:50:04 +0200
commitfa3f04bdd4f73a1b3be70dfb709c44638ef7e3d9 (patch)
treef6b64a6f11acabe4b524bfed275a3ef30f96c21b /vcl
parentee912e56d85345489234196266216e660a5dee46 (diff)
tdf#148934 PDF/UA export: add Contents entry to Link annotations
* Specification: ISO 14289-1:2014, Clause: 7.18.5, Test number: 2 Links shall contain an alternate description via their Contents key as described in ISO 32000-1:2008, 14.9.3. These links are created all over the code, in some cases it's a bit dubious what the content/alt-text should be, but let's try to use the most suitable looking bit of text in whatever the context is. * Specification: ISO 14289-1:2014, Clause: 7.18.3, Test number: 1 Every page on which there is an annotation shall contain in its page dictionary the key Tabs, and its value shall be S. Change-Id: I7b63feb759f0c75047f854ed9997918f829a537e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141826 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/pdf/pdfwriter_impl.hxx6
-rw-r--r--vcl/qa/cppunit/pdfexport/pdfexport.cxx8
-rw-r--r--vcl/source/gdi/pdfextoutdevdata.cxx6
-rw-r--r--vcl/source/gdi/pdfwriter.cxx4
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx13
5 files changed, 29 insertions, 8 deletions
diff --git a/vcl/inc/pdf/pdfwriter_impl.hxx b/vcl/inc/pdf/pdfwriter_impl.hxx
index f415475e5441..6102b64a8956 100644
--- a/vcl/inc/pdf/pdfwriter_impl.hxx
+++ b/vcl/inc/pdf/pdfwriter_impl.hxx
@@ -422,10 +422,12 @@ struct PDFLink : public PDFAnnotation
sal_Int32 m_nDest; // set to -1 for URL, to a dest else
OUString m_aURL;
sal_Int32 m_nStructParent; // struct parent entry
+ OUString m_AltText;
- PDFLink()
+ PDFLink(OUString const& rAltText)
: m_nDest( -1 ),
m_nStructParent( -1 )
+ , m_AltText(rAltText)
{}
};
@@ -1273,7 +1275,7 @@ public:
sal_Int32 emitDocumentMetadata();
// links
- sal_Int32 createLink( const tools::Rectangle& rRect, sal_Int32 nPageNr );
+ sal_Int32 createLink(const tools::Rectangle& rRect, sal_Int32 nPageNr, OUString const& rAltText);
sal_Int32 createDest( const tools::Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType );
sal_Int32 registerDestReference( sal_Int32 nDestId, const tools::Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType );
void setLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId );
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index 7c5ee9f67952..0e8c4fb05407 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -3596,6 +3596,9 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testURIs)
CPPUNIT_ASSERT_EQUAL(
OString("Annot"),
static_cast<vcl::filter::PDFNameElement*>(pAnnot->Lookup("Type"))->GetValue());
+ CPPUNIT_ASSERT_EQUAL(
+ OString("Link"),
+ static_cast<vcl::filter::PDFNameElement*>(pAnnot->Lookup("Subtype"))->GetValue());
auto pAction = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pAnnot->Lookup("A"));
CPPUNIT_ASSERT(pAction);
auto pURIElem
@@ -3603,6 +3606,11 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testURIs)
CPPUNIT_ASSERT(pURIElem);
// Check it matches
CPPUNIT_ASSERT_EQUAL(URIs[i].out, pURIElem->GetValue());
+ // tdf#148934 check a11y
+ CPPUNIT_ASSERT_EQUAL(
+ OUString("Test pdf"),
+ ::vcl::filter::PDFDocument::DecodeHexStringUTF16BE(
+ *dynamic_cast<vcl::filter::PDFHexStringElement*>(pAnnot->Lookup("Contents"))));
}
}
diff --git a/vcl/source/gdi/pdfextoutdevdata.cxx b/vcl/source/gdi/pdfextoutdevdata.cxx
index 96a77a15d94d..00e4f4a9c1bd 100644
--- a/vcl/source/gdi/pdfextoutdevdata.cxx
+++ b/vcl/source/gdi/pdfextoutdevdata.cxx
@@ -181,11 +181,12 @@ void GlobalSyncData::PlayGlobalActions( PDFWriter& rWriter )
rWriter.Push( PushFlags::MAPMODE );
rWriter.SetMapMode( mParaMapModes.front() );
mParaMapModes.pop_front();
- mParaIds.push_back( rWriter.CreateLink( mParaRects.front(), mParaInts.front() ) );
+ mParaIds.push_back( rWriter.CreateLink(mParaRects.front(), mParaInts.front(), mParaOUStrings.front()) );
// resolve LinkAnnotation structural attribute
rWriter.SetLinkPropertyID( mParaIds.back(), sal_Int32(mParaIds.size()-1) );
mParaRects.pop_front();
mParaInts.pop_front();
+ mParaOUStrings.pop_front();
rWriter.Pop();
}
break;
@@ -659,12 +660,13 @@ sal_Int32 PDFExtOutDevData::CreateDest( const tools::Rectangle& rRect, sal_Int32
mpGlobalSyncData->mParaDestAreaTypes.push_back( eType );
return mpGlobalSyncData->mCurId++;
}
-sal_Int32 PDFExtOutDevData::CreateLink( const tools::Rectangle& rRect, sal_Int32 nPageNr )
+sal_Int32 PDFExtOutDevData::CreateLink(const tools::Rectangle& rRect, OUString const& rAltText, sal_Int32 nPageNr)
{
mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::CreateLink );
mpGlobalSyncData->mParaRects.push_back( rRect );
mpGlobalSyncData->mParaMapModes.push_back( mrOutDev.GetMapMode() );
mpGlobalSyncData->mParaInts.push_back( nPageNr == -1 ? mnPage : nPageNr );
+ mpGlobalSyncData->mParaOUStrings.push_back(rAltText);
return mpGlobalSyncData->mCurId++;
}
diff --git a/vcl/source/gdi/pdfwriter.cxx b/vcl/source/gdi/pdfwriter.cxx
index ca9fb352eb74..efea6a987f5b 100644
--- a/vcl/source/gdi/pdfwriter.cxx
+++ b/vcl/source/gdi/pdfwriter.cxx
@@ -330,9 +330,9 @@ void PDFWriter::DrawJPGBitmap( SvStream& rStreamData, bool bIsTrueColor, const S
xImplementation->drawJPGBitmap( rStreamData, bIsTrueColor, rSrcSizePixel, rTargetArea, rAlphaMask, rGraphic );
}
-sal_Int32 PDFWriter::CreateLink( const tools::Rectangle& rRect, sal_Int32 nPageNr )
+sal_Int32 PDFWriter::CreateLink(const tools::Rectangle& rRect, sal_Int32 nPageNr, OUString const& rAltText)
{
- return xImplementation->createLink( rRect, nPageNr );
+ return xImplementation->createLink(rRect, nPageNr, rAltText);
}
sal_Int32 PDFWriter::CreateScreen(const tools::Rectangle& rRect, sal_Int32 nPageNr)
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 8fbbea859f2b..6214489203b3 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -737,6 +737,12 @@ bool PDFPage::emit(sal_Int32 nParentObject )
aLine.append( ((i+1)%15) ? " " : "\n" );
}
aLine.append( "]\n" );
+ if (m_pWriter->m_aContext.Version != PDFWriter::PDFVersion::PDF_A_1
+ && PDFWriter::PDFVersion::PDF_1_5 <= m_pWriter->m_aContext.Version)
+ {
+ // ISO 14289-1:2014, Clause: 7.18.3
+ aLine.append( "/Tabs(S)\n" );
+ }
}
if( !m_aMCIDParents.empty() )
{
@@ -3520,6 +3526,9 @@ bool PDFWriterImpl::emitLinkAnnotations()
aLine.append( ' ' );
appendFixedInt( rLink.m_aRect.Bottom(), aLine );
aLine.append( "]" );
+ // ISO 14289-1:2014, Clause: 7.18.5
+ aLine.append("/Contents");
+ appendUnicodeTextStringEncrypt(rLink.m_AltText, rLink.m_nObject, aLine);
if( rLink.m_nDest >= 0 )
{
aLine.append( "/Dest" );
@@ -10158,7 +10167,7 @@ void PDFWriterImpl::createNote( const tools::Rectangle& rRect, const PDFNote& rN
m_aPages[nPageNr].m_aAnnotations.push_back(rNoteEntry.m_aPopUpAnnotation.m_nObject);
}
-sal_Int32 PDFWriterImpl::createLink( const tools::Rectangle& rRect, sal_Int32 nPageNr )
+sal_Int32 PDFWriterImpl::createLink(const tools::Rectangle& rRect, sal_Int32 nPageNr, OUString const& rAltText)
{
if( nPageNr < 0 )
nPageNr = m_nCurrentPage;
@@ -10168,7 +10177,7 @@ sal_Int32 PDFWriterImpl::createLink( const tools::Rectangle& rRect, sal_Int32 nP
sal_Int32 nRet = m_aLinks.size();
- m_aLinks.emplace_back( );
+ m_aLinks.emplace_back(rAltText);
m_aLinks.back().m_nObject = createObject();
m_aLinks.back().m_nPage = nPageNr;
m_aLinks.back().m_aRect = rRect;