diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2022-09-20 08:30:53 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2022-09-20 09:22:28 +0200 |
commit | addfb3cce0f7ce8fbd0b169d467b6956ed95dbb5 (patch) | |
tree | 44ad218bf4ee32be4b77003c0deea853ad60e41e | |
parent | 6754b647c145cded1f54b49d53d37ad35ace211c (diff) |
sw content controls: add a11y description for PDF export
Acrobat Reader shows these descriptions on mouse hovering on a form
widget.
Change-Id: I8614222e46c992baca8a57b13a948f88973e8911
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140215
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
-rw-r--r-- | external/pdfium/UnpackedTarball_pdfium.mk | 1 | ||||
-rw-r--r-- | external/pdfium/annot-alternate-name.patch.1 | 40 | ||||
-rw-r--r-- | include/vcl/filter/PDFiumLibrary.hxx | 1 | ||||
-rw-r--r-- | sw/qa/core/text/text.cxx | 13 | ||||
-rw-r--r-- | sw/source/core/text/itrform2.cxx | 14 | ||||
-rw-r--r-- | vcl/source/pdf/PDFiumLibrary.cxx | 31 |
6 files changed, 100 insertions, 0 deletions
diff --git a/external/pdfium/UnpackedTarball_pdfium.mk b/external/pdfium/UnpackedTarball_pdfium.mk index 272fa5cb606f..4c9f483f8ed7 100644 --- a/external/pdfium/UnpackedTarball_pdfium.mk +++ b/external/pdfium/UnpackedTarball_pdfium.mk @@ -29,6 +29,7 @@ pdfium_patches += include.patch pdfium_patches += abseil-trivial.patch pdfium_patches += annot.patch.1 +pdfium_patches += annot-alternate-name.patch.1 $(eval $(call gb_UnpackedTarball_UnpackedTarball,pdfium)) diff --git a/external/pdfium/annot-alternate-name.patch.1 b/external/pdfium/annot-alternate-name.patch.1 new file mode 100644 index 000000000000..6ed619c8ec45 --- /dev/null +++ b/external/pdfium/annot-alternate-name.patch.1 @@ -0,0 +1,40 @@ +diff --git a/fpdfsdk/fpdf_annot.cpp b/fpdfsdk/fpdf_annot.cpp +index 05ec46f01..2aa1ce912 100644 +--- a/fpdfsdk/fpdf_annot.cpp ++++ b/fpdfsdk/fpdf_annot.cpp +@@ -1289,6 +1289,18 @@ FPDFAnnot_GetFormFieldName(FPDF_FORMHANDLE hHandle, + buflen); + } + ++FPDF_EXPORT unsigned long FPDF_CALLCONV ++FPDFAnnot_GetFormFieldAlternateName(FPDF_FORMHANDLE hHandle, ++ FPDF_ANNOTATION annot, ++ FPDF_WCHAR* buffer, ++ unsigned long buflen) { ++ const CPDF_FormField* pFormField = GetFormField(hHandle, annot); ++ if (!pFormField) ++ return 0; ++ return Utf16EncodeMaybeCopyAndReturnLength(pFormField->GetAlternateName(), buffer, ++ buflen); ++} ++ + FPDF_EXPORT int FPDF_CALLCONV + FPDFAnnot_GetFormFieldType(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot) { + const CPDF_FormField* pFormField = GetFormField(hHandle, annot); +diff --git a/public/fpdf_annot.h b/public/fpdf_annot.h +index e4217056b..7ce6f3caf 100644 +--- a/public/fpdf_annot.h ++++ b/public/fpdf_annot.h +@@ -735,6 +735,12 @@ FPDFAnnot_GetFormFieldName(FPDF_FORMHANDLE hHandle, + FPDF_WCHAR* buffer, + unsigned long buflen); + ++FPDF_EXPORT unsigned long FPDF_CALLCONV ++FPDFAnnot_GetFormFieldAlternateName(FPDF_FORMHANDLE hHandle, ++ FPDF_ANNOTATION annot, ++ FPDF_WCHAR* buffer, ++ unsigned long buflen); ++ + // Experimental API. + // Gets the form field type of |annot|, which is an interactive form annotation. + // diff --git a/include/vcl/filter/PDFiumLibrary.hxx b/include/vcl/filter/PDFiumLibrary.hxx index 390c826cd57b..1dc1382643d0 100644 --- a/include/vcl/filter/PDFiumLibrary.hxx +++ b/include/vcl/filter/PDFiumLibrary.hxx @@ -103,6 +103,7 @@ public: virtual std::vector<basegfx::B2DPoint> getLineGeometry() = 0; virtual PDFFormFieldType getFormFieldType(PDFiumDocument* pDoc) = 0; virtual float getFormFontSize(PDFiumDocument* pDoc) = 0; + virtual OUString getFormFieldAlternateName(PDFiumDocument* pDoc) = 0; }; class PDFiumTextPage; diff --git a/sw/qa/core/text/text.cxx b/sw/qa/core/text/text.cxx index 12dc50884f23..245f8c230ca6 100644 --- a/sw/qa/core/text/text.cxx +++ b/sw/qa/core/text/text.cxx @@ -35,6 +35,7 @@ #include <fmtfsize.hxx> #include <IDocumentRedlineAccess.hxx> #include <formatcontentcontrol.hxx> +#include <strings.hrc> constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/core/text/data/"; @@ -623,6 +624,12 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testContentControlPDF) SwDoc* pDoc = createSwDoc(); SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); pWrtShell->InsertContentControl(SwContentControlType::RICH_TEXT); + pWrtShell->SttEndDoc(/*bStt=*/true); + pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false); + sal_Int32 nPlaceHolderLen = SwResId(STR_CONTENT_CONTROL_PLACEHOLDER).getLength(); + pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, nPlaceHolderLen, + /*bBasicCall=*/false); + pWrtShell->Insert("mydesc"); // When exporting to PDF: StoreToTempFile("writer_pdf_Export"); @@ -635,6 +642,12 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testContentControlPDF) // - Actual : 0 // i.e. the content control was just exported as normal text. CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount()); + std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0); + CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType()); + + // Also verify that the widget description is correct, it was empty: + CPPUNIT_ASSERT_EQUAL(OUString("mydesc"), + pAnnotation->getFormFieldAlternateName(pPdfDocument.get())); } CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testCheckboxContentControlPDF) diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx index 320133b0ffce..f07ea0bc1de7 100644 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -56,6 +56,7 @@ #include <IDocumentMarkAccess.hxx> #include <comphelper/processfactory.hxx> #include <vcl/pdfextoutdevdata.hxx> +#include <comphelper/string.hxx> #include <docsh.hxx> #include <unocrsrhelper.hxx> #include <textcontentcontrol.hxx> @@ -984,6 +985,19 @@ bool SwContentControlPortion::DescribePDFControl(const SwTextPaintInfo& rInf) co pDescriptor->TextFont = pFont->GetActualFont(); } + // Description for accessibility purposes. + SwTextContentControl* pTextAttr = pContentControl->GetTextAttr(); + SwTextNode* pTextNode = pContentControl->GetTextNode(); + SwPosition aPoint(*pTextNode, pTextAttr->GetStart()); + SwPosition aMark(*pTextNode, *pTextAttr->GetEnd()); + SwPaM aPam(aMark, aPoint); + OUString aDescription = aPam.GetText(); + static sal_Unicode const aForbidden[] = { + CH_TXTATR_BREAKWORD, + 0 + }; + pDescriptor->Description = comphelper::string::removeAny(aDescription, aForbidden); + SwRect aLocation; rInf.CalcRect(*this, &aLocation); pDescriptor->Location = aLocation.SVRect(); diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx index bb371ca930dc..e64aa2f5e3e5 100644 --- a/vcl/source/pdf/PDFiumLibrary.cxx +++ b/vcl/source/pdf/PDFiumLibrary.cxx @@ -251,6 +251,7 @@ public: std::vector<basegfx::B2DPoint> getLineGeometry() override; PDFFormFieldType getFormFieldType(PDFiumDocument* pDoc) override; float getFormFontSize(PDFiumDocument* pDoc) override; + OUString getFormFieldAlternateName(PDFiumDocument* pDoc) override; }; class PDFiumPageObjectImpl final : public PDFiumPageObject @@ -1148,6 +1149,36 @@ float PDFiumAnnotationImpl::getFormFontSize(PDFiumDocument* pDoc) return fRet; } +OUString PDFiumAnnotationImpl::getFormFieldAlternateName(PDFiumDocument* pDoc) +{ + auto pDocImpl = static_cast<PDFiumDocumentImpl*>(pDoc); + OUString aString; + unsigned long nSize = FPDFAnnot_GetFormFieldAlternateName(pDocImpl->getFormHandlePointer(), + mpAnnotation, nullptr, 0); + assert(nSize % 2 == 0); + nSize /= 2; + if (nSize > 1) + { + std::unique_ptr<sal_Unicode[]> pText(new sal_Unicode[nSize]); + unsigned long nStringSize = FPDFAnnot_GetFormFieldAlternateName( + pDocImpl->getFormHandlePointer(), mpAnnotation, + reinterpret_cast<FPDF_WCHAR*>(pText.get()), nSize * 2); + assert(nStringSize % 2 == 0); + nStringSize /= 2; + if (nStringSize > 0) + { +#if defined OSL_BIGENDIAN + for (unsigned long i = 0; i != nStringSize; ++i) + { + pText[i] = OSL_SWAPWORD(pText[i]); + } +#endif + aString = OUString(pText.get()); + } + } + return aString; +} + namespace { bool getBorderProperties(FPDF_ANNOTATION mpAnnotation, float& rHorizontalCornerRadius, |