[Libreoffice-commits] core.git: Branch 'feature/accessibilitycheck' - 1333 commits - accessibility/inc accessibility/Library_acc.mk accessibility/source android/Bootstrap android/source autogen.sh avmedia/Library_avmedia.mk avmedia/source basctl/inc basctl/source basegfx/source basic/CppunitTest_basic_macros.mk basic/inc basic/qa basic/source bin/check-elf-dynamic-objects bin/find-can-be-private-symbols.classes.results bin/find-can-be-private-symbols.functions.results bin/find-can-be-private-symbols.py bin/gen-boost-headers bin/symstore.sh bin/update_pch bridges/inc bridges/Library_cpp_uno.mk bridges/source canvas/source canvas/workben chart2/inc chart2/qa chart2/source chart2/uiconfig chart2/workbench codemaker/source comphelper/inc comphelper/qa comphelper/source compilerplugins/clang compilerplugins/Makefile-clang.mk config_host/config_features.h.in config_host/config_global.h.in config_host/config_poppler.h.in config_host/config_skia.h.in config_host/config_vclplug.h.in config_host.mk.in conf igmgr/source configure.ac connectivity/CppunitTest_connectivity_commontools.mk connectivity/CppunitTest_connectivity_sharedresources.mk connectivity/inc connectivity/IwyuFilter_connectivity.yaml connectivity/qa connectivity/source connectivity/workben cppcanvas/inc cppcanvas/source cppuhelper/Library_cppuhelper.mk cppuhelper/source cppu/qa cppu/source cpputools/source cui/inc cui/source cui/uiconfig dbaccess/CppunitTest_dbaccess_hsqlbinary_import.mk dbaccess/CppunitTest_dbaccess_tdf119625.mk dbaccess/CppunitTest_dbaccess_tdf126268.mk dbaccess/inc dbaccess/source dbaccess/uiconfig desktop/inc desktop/Library_sofficeapp.mk desktop/qa desktop/source desktop/uiconfig desktop/win32 distro-configs/LibreOfficeCoverity.conf distro-configs/LibreOfficeOnline.conf distro-configs/LibreOfficeOssFuzz.conf download.lst drawinglayer/Library_drawinglayer.mk drawinglayer/source dtrans/source editeng/inc editeng/IwyuFilter_editeng.yaml editeng/qa editeng/source embeddedobj/source embeddedobj/test embe dserv/source emfio/CppunitTest_emfio_emf_test.mk emfio/inc emfio/IwyuFilter_emfio.yaml emfio/qa emfio/source eventattacher/source extensions/inc extensions/source extensions/test extensions/uiconfig extensions/UIConfig_spropctrlr.mk external/boost external/cairo external/clucene external/cppunit external/icu external/liblangtag external/libpng external/mdds external/Module_external.mk external/neon external/nss external/skia extras/CustomTarget_fontconfig.mk extras/Module_extras.mk extras/Package_fontconfig.mk extras/source filter/CppunitTest_filter_textfilterdetect.mk filter/inc filter/IwyuFilter_filter.yaml filter/qa filter/source filter/uiconfig forms/inc forms/source formula/source fpicker/source framework/inc framework/Library_fwm.mk framework/source .git-blame-ignore-revs .git-hooks/commit-msg helpcompiler/inc helpcompiler/source helpcontent2 hwpfilter/source i18nlangtag/source i18npool/inc i18npool/qa i18npool/source i18nutil/source icon-themes/colibre icon-themes/colibre_svg idlc/inc idlc/source include/avmedia include/basegfx include/basic include/canvas include/codemaker include/com include/comphelper include/connectivity include/cppcanvas include/dbaccess include/drawinglayer include/editeng include/filter include/i18nlangtag include/ios include/jvmfwk include/LibreOfficeKit include/linguistic include/o3tl include/oox include/rtl include/sal include/sax include/sfx2 include/svl include/svtools include/svx include/test include/toolkit include/tools include/ucbhelper include/unotools include/vbahelper include/vcl include/xmloff instsetoo_native/inc_ooohelppack instsetoo_native/inc_openoffice instsetoo_native/inc_sdkoo ios/Module_ios.mk io/source ios/source ios/StaticLibrary_ios.mk io/test javaunohelper/source jvmfwk/inc jvmfwk/plugins jvmfwk/source l10ntools/inc l10ntools/source libreofficekit/qa libreofficekit/source lingucomponent/source linguistic/source linguistic/workben lotuswordpro/inc lotuswordpro/source Makefile.fetch o3tl/qa odk/docs odk/exa mples offapi/com offapi/UnoApi_offapi.mk officecfg/registry oovbaapi/ooo oox/CppunitTest_oox_vml.mk oox/inc oox/Library_oox.mk oox/Module_oox.mk oox/qa oox/source opencl/source package/source pch/inc postprocess/CustomTarget_fontconfig.mk postprocess/CustomTarget_registry.mk postprocess/Module_postprocess.mk postprocess/Package_fontconfig.mk pyuno/demo pyuno/qa pyuno/source qadevOOo/tests readlicense_oo/docs readlicense_oo/license registry/source registry/test remotebridges/source reportdesign/inc reportdesign/source reportdesign/uiconfig RepositoryExternal.mk Repository.mk RepositoryModule_host.mk sal/android sal/CppunitTest_sal_osl.mk sal/osl sal/qa sal/rtl sal/textenc sax/source sax/test scaddins/inc scaddins/source sc/CppunitTest_sc_check_data_pilot_field.mk sc/CppunitTest_sc_check_data_pilot_table.mk sc/CppunitTest_sc_check_xcell_ranges_query.mk sc/CppunitTest_sc_shapetest.mk sc/CppunitTest_sc_subsequent_export_test.mk sc/CppunitTest_sc_subsequent_filters_test.mk schema/libreof fice sc/inc sc/Library_sc.mk sc/Module_sc.mk scp2/source sc/qa scripting/source sc/source sc/uiconfig sdext/source sd/inc sd/Library_sd.mk sd/qa sd/sdi sd/source sd/uiconfig sd/UIConfig_sdraw.mk sd/UIConfig_simpress.mk sd/workben setup_native/source sfx2/inc sfx2/IwyuFilter_sfx2.yaml sfx2/Library_sfx.mk sfx2/sdi sfx2/source shell/source slideshow/inc slideshow/Library_slideshow.mk slideshow/source solenv/bin solenv/clang-format solenv/CompilerTest_compilerplugins_clang.mk solenv/flatpak-manifest.in solenv/gbuild solenv/PythonTest_solenv_python.mk solenv/qa solenv/sanitizers sot/source starmath/inc starmath/qa starmath/source starmath/visual-editor-todo stoc/source stoc/test store/source svgio/inc svgio/IwyuFilter_svgio.yaml svgio/qa svgio/source svl/CppunitTest_svl_lockfiles.mk svl/inc svl/qa svl/source svtools/inc svtools/Library_svt.mk svtools/qa svtools/source svtools/uiconfig svx/inc svx/Library_svxcore.mk svx/Library_svx.mk svx/qa svx/sdi svx/source svx/uiconfig svx/UIConfig_sv x.mk sw/CppunitTest_sw_core_accessibilitycheck.mk sw/inc sw/IwyuFilter_sw.yaml sw/Library_sw.mk sw/Module_sw.mk sw/PythonTest_sw_python.mk sw/qa sw/sdi sw/source sw/uiconfig sw/UIConfig_swriter.mk sw/UITest_writer_tests7.mk test/IwyuFilter_test.yaml test/source testtools/source toolkit/inc toolkit/source tools/qa tools/source ucbhelper/source ucb/qa ucb/source uitest/packaging uitest/ui_logger_dsl UnoControls/inc unodevtools/inc unodevtools/source unotools/inc unotools/source unoxml/inc unoxml/source uui/source vbahelper/inc vbahelper/source vcl/android vcl/backendtest vcl/CppunitTest_vcl_outdev.mk vcl/CppunitTest_vcl_png_test.mk vcl/headless vcl/inc vcl/ios vcl/Library_vcl.mk vcl/Library_vclplug_gen.mk vcl/Library_vclplug_win.mk vcl/opengl vcl/osx vcl/qa vcl/qt5 vcl/quartz vcl/README.vars vcl/skia vcl/source vcl/uiconfig vcl/unx vcl/win vcl/workben winaccessibility/inc winaccessibility/source wizards/source writerfilter/CppunitTest_writerfilter_dmapper.mk writerfilter/CppunitTest_w riterfilter_filters_test.mk writerfilter/CppunitTest_writerfilter_rtftok.mk writerfilter/inc writerfilter/Module_writerfilter.mk writerfilter/qa writerfilter/source writerperfect/CppunitTest_writerperfect_calc.mk writerperfect/CppunitTest_writerperfect_draw.mk writerperfect/CppunitTest_writerperfect_import.mk writerperfect/CppunitTest_writerperfect_impress.mk writerperfect/CppunitTest_writerperfect_writer.mk writerperfect/inc writerperfect/Library_wpftqahelper.mk writerperfect/source xmerge/source xmlhelp/Library_ucpchelp1.mk xmlhelp/source xmloff/inc xmloff/source xmloff/util xmlscript/inc xmlscript/source xmlsecurity/inc xmlsecurity/source xmlsecurity/uiconfig

Tomaž Vajngerl (via logerrit) logerrit at kemper.freedesktop.org
Wed Dec 25 21:05:48 UTC 2019


Rebased ref, commits from common ancestor:
commit f3465f3f024ddd3d8406c0cf6a74fda8266ab339
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Wed Dec 25 13:27:32 2019 +0100
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Wed Dec 25 13:39:19 2019 +0100

    acc. check: implement goto for OLE/Graphic objects
    
    This implements goto function for Graphic/OLE objects that are
    reported in a AccessibilityCheckResult. So this enables to go
    to the object inside a document for which we have reported an
    accessibility issue.
    
    Change-Id: I699966b116a76ea032cb1acc9a431687fa204e07

diff --git a/include/svx/AccessibilityCheck.hxx b/include/svx/AccessibilityCheck.hxx
index ba4b01d9d6a5..23fdd31c6e8a 100644
--- a/include/svx/AccessibilityCheck.hxx
+++ b/include/svx/AccessibilityCheck.hxx
@@ -37,6 +37,7 @@ public:
     {
     }
     virtual ~AccessibilityCheckResult() {}
+    virtual bool canGotoIssue() const = 0;
     virtual void gotoIssue() const = 0;
 };
 
diff --git a/svx/source/dialog/AccessibilityCheckDialog.cxx b/svx/source/dialog/AccessibilityCheckDialog.cxx
index e88ca36ebb89..8189f5e9ba65 100644
--- a/svx/source/dialog/AccessibilityCheckDialog.cxx
+++ b/svx/source/dialog/AccessibilityCheckDialog.cxx
@@ -24,6 +24,7 @@ AccessibilityCheckEntry::AccessibilityCheckEntry(
     , m_rAccessibilityCheckResult(rAccessibilityCheckResult)
 {
     m_xLabel->set_label(m_rAccessibilityCheckResult->m_aIssueText);
+    m_xGotoButton->set_visible(rAccessibilityCheckResult->canGotoIssue());
     m_xGotoButton->connect_clicked(LINK(this, AccessibilityCheckEntry, GotoButtonClicked));
     m_xContainer->show();
 }
diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk
index acab4210994b..8fa7132da457 100644
--- a/sw/Library_sw.mk
+++ b/sw/Library_sw.mk
@@ -96,6 +96,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
     sw/source/core/SwNumberTree/SwNodeNum \
     sw/source/core/SwNumberTree/SwNumberTree \
     sw/source/core/access/AccessibilityCheck \
+    sw/source/core/access/AccessibilityCheckResult \
     sw/source/core/access/acccell \
     sw/source/core/access/acccontext \
     sw/source/core/access/accdoc \
diff --git a/sw/source/core/access/AccessibilityCheck.cxx b/sw/source/core/access/AccessibilityCheck.cxx
index b06f9012f738..78571c50f786 100644
--- a/sw/source/core/access/AccessibilityCheck.cxx
+++ b/sw/source/core/access/AccessibilityCheck.cxx
@@ -45,12 +45,14 @@ OUString sTextBlinking("Blinking text.");
 OUString sAvoidFootnotes("Avoid footnotes.");
 OUString sAvoidEndnotes("Avoid endnotes.");
 
-void lclAddIssue(svx::AccessibilityCheckResultCollection& rResultCollection, OUString const& rText,
-                 svx::AccessibilityIssueID eIssue = svx::AccessibilityIssueID::UNSPECIFIED)
+std::shared_ptr<sw::AccessibilityCheckResult>
+lclAddIssue(svx::AccessibilityCheckResultCollection& rResultCollection, OUString const& rText,
+            svx::AccessibilityIssueID eIssue = svx::AccessibilityIssueID::UNSPECIFIED)
 {
     auto pResult = std::make_shared<sw::AccessibilityCheckResult>(eIssue);
     pResult->m_aIssueText = rText;
     rResultCollection.getResults().push_back(pResult);
+    return pResult;
 }
 }
 
@@ -91,7 +93,20 @@ class NoTextNodeAltTextCheck : public NodeCheck
         {
             OUString sName = pNoTextNode->GetFlyFormat()->GetName();
             OUString sIssueText = sNoAlt.replaceAll("%OBJECT_NAME%", sName);
-            lclAddIssue(m_rResultCollection, sIssueText);
+            auto pResult = lclAddIssue(m_rResultCollection, sIssueText);
+
+            if (pNoTextNode->IsOLENode())
+            {
+                pResult->setDoc(pNoTextNode->GetDoc());
+                pResult->setIssueObject(IssueObject::OLE);
+                pResult->setObjectID(pNoTextNode->GetFlyFormat()->GetName());
+            }
+            else if (pNoTextNode->IsGrfNode())
+            {
+                pResult->setDoc(pNoTextNode->GetDoc());
+                pResult->setIssueObject(IssueObject::GRAPHIC);
+                pResult->setObjectID(pNoTextNode->GetFlyFormat()->GetName());
+            }
         }
     }
 
diff --git a/sw/source/core/access/AccessibilityCheckResult.cxx b/sw/source/core/access/AccessibilityCheckResult.cxx
new file mode 100644
index 000000000000..6d85cb040f0c
--- /dev/null
+++ b/sw/source/core/access/AccessibilityCheckResult.cxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <AccessibilityCheckResult.hxx>
+#include <wrtsh.hxx>
+#include <docsh.hxx>
+
+namespace sw
+{
+AccessibilityCheckResult::AccessibilityCheckResult(svx::AccessibilityIssueID eIssueID)
+    : svx::AccessibilityCheckResult(eIssueID)
+    , m_eIssueObject(IssueObject::UNKNOWN)
+    , m_pDoc(nullptr)
+{
+}
+
+void AccessibilityCheckResult::setIssueObject(IssueObject eIssueObject)
+{
+    m_eIssueObject = eIssueObject;
+}
+
+void AccessibilityCheckResult::setDoc(SwDoc* pDoc) { m_pDoc = pDoc; }
+
+void AccessibilityCheckResult::setObjectID(OUString const& rID) { m_sObjectID = rID; }
+
+bool AccessibilityCheckResult::canGotoIssue() const
+{
+    if (m_eIssueObject != IssueObject::UNKNOWN)
+        return true;
+    return false;
+}
+
+void AccessibilityCheckResult::gotoIssue() const
+{
+    switch (m_eIssueObject)
+    {
+        case IssueObject::GRAPHIC:
+        case IssueObject::OLE:
+        {
+            SwWrtShell* pWrtShell = m_pDoc->GetDocShell()->GetWrtShell();
+            pWrtShell->GotoFly(m_sObjectID, FLYCNTTYPE_ALL, true);
+        }
+        break;
+        default:
+            break;
+    }
+}
+
+} // end sw namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/AccessibilityCheck.hxx b/sw/source/core/inc/AccessibilityCheck.hxx
index 05a88a3a4975..741d3159d484 100644
--- a/sw/source/core/inc/AccessibilityCheck.hxx
+++ b/sw/source/core/inc/AccessibilityCheck.hxx
@@ -12,22 +12,11 @@
 #define INCLUDED_SW_SOURCE_CORE_ACCESSIBILITYCHECK_HXX
 
 #include <svx/AccessibilityCheck.hxx>
+#include <AccessibilityCheckResult.hxx>
 #include <doc.hxx>
 
 namespace sw
 {
-class SW_DLLPUBLIC AccessibilityCheckResult final : public svx::AccessibilityCheckResult
-{
-public:
-    AccessibilityCheckResult(svx::AccessibilityIssueID eIssueID
-                             = svx::AccessibilityIssueID::UNSPECIFIED)
-        : svx::AccessibilityCheckResult(eIssueID)
-    {
-    }
-
-    void gotoIssue() const override {}
-};
-
 class SW_DLLPUBLIC AccessibilityCheck final : public svx::AccessibilityCheck
 {
 private:
diff --git a/sw/source/core/inc/AccessibilityCheckResult.hxx b/sw/source/core/inc/AccessibilityCheckResult.hxx
new file mode 100644
index 000000000000..ffc46a86412f
--- /dev/null
+++ b/sw/source/core/inc/AccessibilityCheckResult.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#ifndef INCLUDED_SW_SOURCE_CORE_ACCESSIBILITYCHECKRESULT_HXX
+#define INCLUDED_SW_SOURCE_CORE_ACCESSIBILITYCHECKRESULT_HXX
+
+#include <svx/AccessibilityCheck.hxx>
+#include <doc.hxx>
+
+namespace sw
+{
+enum class IssueObject
+{
+    UNKNOWN,
+    GRAPHIC,
+    OLE,
+};
+
+class SW_DLLPUBLIC AccessibilityCheckResult final : public svx::AccessibilityCheckResult
+{
+private:
+    IssueObject m_eIssueObject;
+    SwDoc* m_pDoc;
+    OUString m_sObjectID;
+
+public:
+    AccessibilityCheckResult(svx::AccessibilityIssueID eIssueID
+                             = svx::AccessibilityIssueID::UNSPECIFIED);
+
+    void setIssueObject(IssueObject eIssueObject);
+    void setDoc(SwDoc* pDoc);
+    void setObjectID(OUString const& rID);
+
+    bool canGotoIssue() const override;
+    void gotoIssue() const override;
+};
+
+} // end sw namespace
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 9cb3e29f2c683eb0207e6101597f3ca2a81525f8
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Tue Dec 24 16:03:23 2019 +0100
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Wed Dec 25 13:39:19 2019 +0100

    pdf: Add option for PDF/UA to the PDF export dialog
    
    This is adding PDF/UA option to the PDF export dialog. When PDF/UA
    support is enabled, it automatically enables PDFTag support as it
    is required for PDF/UA.
    
    Change-Id: Ib3dece964523d4ed9884c98a6022a91120c6065f

diff --git a/filter/source/pdf/impdialog.cxx b/filter/source/pdf/impdialog.cxx
index 477098a85114..d19458a00e4d 100644
--- a/filter/source/pdf/impdialog.cxx
+++ b/filter/source/pdf/impdialog.cxx
@@ -186,6 +186,8 @@ ImpPDFTabDialog::ImpPDFTabDialog(weld::Window* pParent, Sequence< PropertyValue
     mbUseTaggedPDFUserSelection = mbUseTaggedPDF;
 
     mnPDFTypeSelection =  maConfigItem.ReadInt32( "SelectPdfVersion", 0 );
+    mbPDFUACompliance = maConfigItem.ReadBool("PDFUACompliance", false);
+
     if ( mbIsPresentation )
     {
         mbExportNotesPages = maConfigItem.ReadBool( "ExportNotesPages", false );
@@ -368,10 +370,14 @@ Sequence< PropertyValue > ImpPDFTabDialog::GetFilterData()
     maConfigItem.WriteBool( "ReduceImageResolution", mbReduceImageResolution );
     maConfigItem.WriteInt32("MaxImageResolution", mnMaxImageResolution );
 
-    // always write the user selection, never the overridden PDF/A value
+    // always write the user selection, never the overridden value
+    const bool bIsPDFUA = mbPDFUACompliance;
     const bool bIsPDFA = (1 == mnPDFTypeSelection) || (2 == mnPDFTypeSelection);
-    maConfigItem.WriteBool("UseTaggedPDF", bIsPDFA ? mbUseTaggedPDFUserSelection : mbUseTaggedPDF);
+    const bool bUserSelectionTags = bIsPDFA || bIsPDFUA;
+    maConfigItem.WriteBool("UseTaggedPDF", bUserSelectionTags ? mbUseTaggedPDFUserSelection : mbUseTaggedPDF);
+
     maConfigItem.WriteInt32("SelectPdfVersion", mnPDFTypeSelection );
+    maConfigItem.WriteBool("PDFUACompliance", mbPDFUACompliance);
 
     if ( mbIsPresentation )
     {
@@ -471,6 +477,7 @@ ImpPDFTabGeneralPage::ImpPDFTabGeneralPage(weld::Container* pPage, weld::DialogC
     , mxCbPDFA(m_xBuilder->weld_check_button("pdfa"))
     , mxRbPDFA1b(m_xBuilder->weld_radio_button("pdfa1"))
     , mxRbPDFA2b(m_xBuilder->weld_radio_button("pdfa2"))
+    , mxCbPDFUA(m_xBuilder->weld_check_button("pdfua"))
     , mxCbTaggedPDF(m_xBuilder->weld_check_button("tagged"))
     , mxCbExportFormFields(m_xBuilder->weld_check_button("forms"))
     , mxFormsFrame(m_xBuilder->weld_widget("formsframe"))
@@ -540,7 +547,7 @@ void ImpPDFTabGeneralPage::SetFilterConfigItem(ImpPDFTabDialog* pParent)
     mxCbWatermark->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleWatermarkHdl ) );
     mxFtWatermark->set_sensitive(false );
     mxEdWatermark->set_sensitive( false );
-    mxCbPDFA->connect_toggled(LINK(this, ImpPDFTabGeneralPage, ToggleExportPDFAHdl));
+    mxCbPDFA->connect_toggled(LINK(this, ImpPDFTabGeneralPage, TogglePDFVersionOrUniversalAccessibilityHandle));
 
     const bool bIsPDFA = (1 == pParent->mnPDFTypeSelection) || (2 == pParent->mnPDFTypeSelection);
     mxCbPDFA->set_active(bIsPDFA);
@@ -556,13 +563,18 @@ void ImpPDFTabGeneralPage::SetFilterConfigItem(ImpPDFTabDialog* pParent)
         mxRbPDFA2b->set_active(true);
         break;
     }
-    // the ToggleExportPDFAHdl handler will read or write the *UserSelection based
+
+    const bool bIsPDFUA = pParent->mbPDFUACompliance;
+    mxCbPDFUA->set_active(bIsPDFUA);
+    mxCbPDFUA->connect_toggled(LINK(this, ImpPDFTabGeneralPage, TogglePDFVersionOrUniversalAccessibilityHandle));
+
+    // the TogglePDFVersionOrUniversalAccessibilityHandle handler will read or write the *UserSelection based
     // on the mxCbPDFA (= bIsPDFA) state, so we have to prepare the correct input state.
-    if (bIsPDFA)
+    if (bIsPDFA || bIsPDFUA)
         mxCbTaggedPDF->set_active(pParent->mbUseTaggedPDFUserSelection);
     else
         mbUseTaggedPDFUserSelection = pParent->mbUseTaggedPDFUserSelection;
-    ToggleExportPDFAHdl( *mxCbPDFA );
+    TogglePDFVersionOrUniversalAccessibilityHandle(*mxCbPDFA);
 
     mxCbExportFormFields->set_active(pParent->mbExportFormFields);
     mxCbExportFormFields->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleExportFormFieldsHdl ) );
@@ -675,14 +687,20 @@ void ImpPDFTabGeneralPage::GetFilterConfigItem( ImpPDFTabDialog* pParent )
     pParent->mbUseTaggedPDF = mxCbTaggedPDF->get_active();
 
     const bool bIsPDFA = mxCbPDFA->get_active();
+    const bool bIsPDFUA = mxCbPDFUA->get_active();
+
     if (bIsPDFA)
     {
         pParent->mnPDFTypeSelection = 2;
         if( mxRbPDFA1b->get_active() )
             pParent->mnPDFTypeSelection = 1;
     }
-    else
+
+    pParent->mbPDFUACompliance = bIsPDFUA;
+
+    if (!bIsPDFA && !bIsPDFUA)
         mbUseTaggedPDFUserSelection = pParent->mbUseTaggedPDF;
+
     pParent->mbUseTaggedPDFUserSelection = mbUseTaggedPDFUserSelection;
     pParent->mbExportFormFields = mxCbExportFormFields->get_active();
 
@@ -784,20 +802,21 @@ IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleAddStreamHdl, weld::ToggleButton&, v
     }
 }
 
-IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleExportPDFAHdl, weld::ToggleButton&, void)
+IMPL_LINK_NOARG(ImpPDFTabGeneralPage, TogglePDFVersionOrUniversalAccessibilityHandle, weld::ToggleButton&, void)
 {
     const bool bIsPDFA = mxCbPDFA->get_active();
+    const bool bIsPDFUA = mxCbPDFUA->get_active();
 
     // set the security page status (and its controls as well)
     ImpPDFTabSecurityPage* pSecPage = mpParent ? mpParent->getSecurityPage() : nullptr;
     if (pSecPage)
         pSecPage->ImplPDFASecurityControl(!bIsPDFA);
 
-    mxCbTaggedPDF->set_sensitive(!bIsPDFA);
+    mxCbTaggedPDF->set_sensitive(!bIsPDFA && !bIsPDFUA);
     mxRbPDFA1b->set_sensitive(bIsPDFA);
     mxRbPDFA2b->set_sensitive(bIsPDFA);
 
-    if (bIsPDFA)
+    if (bIsPDFA || bIsPDFUA)
     {
         // store the users selection of subordinate controls and set required PDF/A values
         mbUseTaggedPDFUserSelection = mxCbTaggedPDF->get_active();
diff --git a/filter/source/pdf/impdialog.hxx b/filter/source/pdf/impdialog.hxx
index f3599f6587ec..52a37ad5cf4a 100644
--- a/filter/source/pdf/impdialog.hxx
+++ b/filter/source/pdf/impdialog.hxx
@@ -78,6 +78,7 @@ class ImpPDFTabDialog final : public SfxTabDialogController
     bool                        mbUseTaggedPDF;
     bool                        mbUseTaggedPDFUserSelection;
     sal_Int32                   mnPDFTypeSelection;
+    bool                        mbPDFUACompliance;
     bool                        mbExportNotes;
     bool                        mbViewPDF;
     bool                        mbUseReferenceXObject;
@@ -189,6 +190,7 @@ class ImpPDFTabGeneralPage : public SfxTabPage
     std::unique_ptr<weld::CheckButton> mxCbPDFA;
     std::unique_ptr<weld::RadioButton> mxRbPDFA1b;
     std::unique_ptr<weld::RadioButton> mxRbPDFA2b;
+    std::unique_ptr<weld::CheckButton> mxCbPDFUA;
     std::unique_ptr<weld::CheckButton> mxCbTaggedPDF;
     std::unique_ptr<weld::CheckButton> mxCbExportFormFields;
     std::unique_ptr<weld::Widget> mxFormsFrame;
@@ -224,8 +226,9 @@ class ImpPDFTabGeneralPage : public SfxTabPage
     void                        TogglePagesHdl();
     void                        EnableExportNotesPages();
 
+    DECL_LINK(TogglePDFVersionOrUniversalAccessibilityHandle, weld::ToggleButton&, void);
+
 public:
-    DECL_LINK(ToggleExportPDFAHdl, weld::ToggleButton&, void);
 
     ImpPDFTabGeneralPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet);
     virtual                     ~ImpPDFTabGeneralPage() override;
diff --git a/filter/source/pdf/pdfexport.cxx b/filter/source/pdf/pdfexport.cxx
index d00e371338b4..00e279047f73 100644
--- a/filter/source/pdf/pdfexport.cxx
+++ b/filter/source/pdf/pdfexport.cxx
@@ -80,6 +80,7 @@ PDFExport::PDFExport( const Reference< XComponent >& rxSrcDoc,
     mxIH                        ( rxIH ),
     mbUseTaggedPDF              ( false ),
     mnPDFTypeSelection          ( 0 ),
+    mbPDFUACompliance           ( false),
     mbExportNotes               ( true ),
     mbExportPlaceholders        ( false ),
     mbUseReferenceXObject       ( false ),
@@ -473,6 +474,8 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >&
                     rFilterData[ nData ].Value >>= mbUseTaggedPDF;
                 else if ( rFilterData[ nData ].Name == "SelectPdfVersion" )
                     rFilterData[ nData ].Value >>= mnPDFTypeSelection;
+                else if ( rFilterData[ nData ].Name == "PDFUACompliance" )
+                    rFilterData[ nData ].Value >>= mbPDFUACompliance;
                 else if ( rFilterData[ nData ].Name == "ExportNotes" )
                     rFilterData[ nData ].Value >>= mbExportNotes;
                 else if ( rFilterData[ nData ].Name == "ExportNotesPages" )
diff --git a/filter/source/pdf/pdfexport.hxx b/filter/source/pdf/pdfexport.hxx
index 426416628e24..54784cce1abb 100644
--- a/filter/source/pdf/pdfexport.hxx
+++ b/filter/source/pdf/pdfexport.hxx
@@ -52,6 +52,7 @@ private:
 
     bool                mbUseTaggedPDF;
     sal_Int32           mnPDFTypeSelection;
+    bool                mbPDFUACompliance;
     bool                mbExportNotes;
     bool                mbExportPlaceholders;
     bool                mbUseReferenceXObject;
diff --git a/filter/source/pdf/pdffilter.cxx b/filter/source/pdf/pdffilter.cxx
index 5dfb9396a590..5a7e5fbaedf0 100644
--- a/filter/source/pdf/pdffilter.cxx
+++ b/filter/source/pdf/pdffilter.cxx
@@ -84,6 +84,7 @@ bool PDFFilter::implExport( const Sequence< PropertyValue >& rDescriptor )
         aCfgItem.ReadInt32( "MaxImageResolution", 300 );
         aCfgItem.ReadBool(  "UseTaggedPDF", false );
         aCfgItem.ReadInt32( "SelectPdfVersion", 0 );
+        aCfgItem.ReadBool("PDFUACompliance", false);
         aCfgItem.ReadBool(  "ExportNotes", false );
         aCfgItem.ReadBool( "ExportPlaceholders", false );
         aCfgItem.ReadBool(  "ExportNotesPages", false );
diff --git a/filter/uiconfig/ui/pdfgeneralpage.ui b/filter/uiconfig/ui/pdfgeneralpage.ui
index 3d59a633b027..1fbde5ceb6f4 100644
--- a/filter/uiconfig/ui/pdfgeneralpage.ui
+++ b/filter/uiconfig/ui/pdfgeneralpage.ui
@@ -473,7 +473,7 @@
                       </object>
                       <packing>
                         <property name="left_attach">0</property>
-                        <property name="top_attach">2</property>
+                        <property name="top_attach">3</property>
                       </packing>
                     </child>
                     <child>
@@ -489,7 +489,7 @@
                       </object>
                       <packing>
                         <property name="left_attach">0</property>
-                        <property name="top_attach">3</property>
+                        <property name="top_attach">4</property>
                       </packing>
                     </child>
                     <child>
@@ -554,7 +554,7 @@
                       </object>
                       <packing>
                         <property name="left_attach">0</property>
-                        <property name="top_attach">4</property>
+                        <property name="top_attach">5</property>
                       </packing>
                     </child>
                     <child>
@@ -631,6 +631,22 @@
                         <property name="top_attach">1</property>
                       </packing>
                     </child>
+                    <child>
+                      <object class="GtkCheckButton" id="pdfua">
+                        <property name="label" translatable="yes" context="pdfgeneralpage|pdfua">U_niversal Accessibility (PDF/UA)</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="tooltip_text" translatable="yes" context="pdfgeneralpage|pdfua|tooltip_text">Creates an universal accessibility compliant PDF file that follows the requirements of PDF/UA (ISO 14289) specifications.</property>
+                        <property name="halign">start</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">2</property>
+                      </packing>
+                    </child>
                   </object>
                 </child>
               </object>
diff --git a/include/vcl/pdfwriter.hxx b/include/vcl/pdfwriter.hxx
index 47d2528aa460..c68feba88f93 100644
--- a/include/vcl/pdfwriter.hxx
+++ b/include/vcl/pdfwriter.hxx
@@ -552,6 +552,10 @@ The following structure describes the permissions used in PDF security
 
         /* decides the PDF language level to be produced */
         PDFVersion                      Version;
+
+        /* PDF/UA compliance */
+        bool UniversalAccessibilityCompliance;
+
         /* valid for PDF >= 1.4
            causes the MarkInfo entry in the document catalog to be set
         */
diff --git a/officecfg/registry/schema/org/openoffice/Office/Common.xcs b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
index c8bdec0fd74e..675f173e5b36 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
@@ -5331,6 +5331,14 @@
             <value>0</value>
           </prop>
           <!-- END PDF Version selection -->
+          <!-- PDF/UA Compliance -->
+          <prop oor:name="PDFUACompliance" oor:type="xs:boolean" oor:nillable="false">
+            <info>
+              <desc>Specifies if the document is PDF/UA (Universal Accessibility) compliant</desc>
+            </info>
+            <value>false</value>
+          </prop>
+          <!-- END PDF/UA Compliance -->
           <!-- PDF Relative Link -->
           <prop oor:name="ExportLinksRelativeFsys" oor:type="xs:boolean" oor:nillable="false">
             <info>
@@ -5452,9 +5460,9 @@
       <prop oor:name="UseWebDAVFileLocking" oor:type="xs:boolean" oor:nillable="false">
         <info>
           <desc>Determines if WebDAV-specific file locking is used for documents
-	  on WebDAV shares. It is not recommended to set this option to 'false' in
-	  scenarios where multi-user, concurrent read/write access to WebDAV share
-	  is required</desc>
+          on WebDAV shares. It is not recommended to set this option to 'false' in
+          scenarios where multi-user, concurrent read/write access to WebDAV share
+          is required</desc>
         </info>
         <value>true</value>
       </prop>
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index e55efc180bb3..51a78f8f8efa 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -1398,6 +1398,12 @@ void PDFWriterImpl::PDFPage::appendWaveLine( sal_Int32 nWidth, sal_Int32 nY, sal
     if( m_bIsPDF_A2 )
         m_aContext.Version = PDFWriter::PDFVersion::PDF_1_6; //we could even use 1.7 features
 
+    if (m_aContext.UniversalAccessibilityCompliance)
+    {
+        m_bIsPDF_UA = true;
+        m_aContext.Tagged = true;
+    }
+
     if( m_aContext.DPIx == 0 || m_aContext.DPIy == 0 )
         SetReferenceDevice( VirtualDevice::RefDevMode::PDF1 );
     else
commit 0b19312db98ab58ba652fe26035bbff86c2a40a9
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Fri Dec 20 12:12:35 2019 +0100
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Wed Dec 25 13:39:19 2019 +0100

    acc. check: add "goto" button to see the acc. issue in document
    
    This adds the UI for the goto functionality to the UI, but
    currently no goto implementation to jump to the specific issue
    area in the document is written.
    
    Change-Id: I5b326a000e62231c491c179b1ff8accde15e1e98

diff --git a/include/svx/AccessibilityCheck.hxx b/include/svx/AccessibilityCheck.hxx
index db66ccb24fd4..ba4b01d9d6a5 100644
--- a/include/svx/AccessibilityCheck.hxx
+++ b/include/svx/AccessibilityCheck.hxx
@@ -37,6 +37,7 @@ public:
     {
     }
     virtual ~AccessibilityCheckResult() {}
+    virtual void gotoIssue() const = 0;
 };
 
 class SVX_DLLPUBLIC AccessibilityCheckResultCollection
diff --git a/include/svx/AccessibilityCheckDialog.hxx b/include/svx/AccessibilityCheckDialog.hxx
index 4b602a911a42..10a9a1803ad6 100644
--- a/include/svx/AccessibilityCheckDialog.hxx
+++ b/include/svx/AccessibilityCheckDialog.hxx
@@ -27,6 +27,7 @@ private:
     std::unique_ptr<weld::Builder> m_xBuilder;
     std::unique_ptr<weld::Container> m_xContainer;
     std::unique_ptr<weld::Label> m_xLabel;
+    std::unique_ptr<weld::Button> m_xGotoButton;
 
     std::shared_ptr<AccessibilityCheckResult> const& m_rAccessibilityCheckResult;
 
@@ -35,6 +36,8 @@ public:
         weld::Container* pParent, weld::Window* pDialog,
         std::shared_ptr<AccessibilityCheckResult> const& rAccessibilityCheckResult);
     weld::Widget* get_widget() const { return m_xContainer.get(); }
+
+    DECL_LINK(GotoButtonClicked, weld::Button&, void);
 };
 
 class SVX_DLLPUBLIC AccessibilityCheckDialog final : public weld::GenericDialogController
diff --git a/svx/source/dialog/AccessibilityCheckDialog.cxx b/svx/source/dialog/AccessibilityCheckDialog.cxx
index f6add929e351..e88ca36ebb89 100644
--- a/svx/source/dialog/AccessibilityCheckDialog.cxx
+++ b/svx/source/dialog/AccessibilityCheckDialog.cxx
@@ -20,12 +20,19 @@ AccessibilityCheckEntry::AccessibilityCheckEntry(
     , m_xBuilder(Application::CreateBuilder(pParent, "svx/ui/accessibilitycheckentry.ui"))
     , m_xContainer(m_xBuilder->weld_container("accessibilityCheckEntryBox"))
     , m_xLabel(m_xBuilder->weld_label("accessibilityCheckEntryLabel"))
+    , m_xGotoButton(m_xBuilder->weld_button("accessibilityCheckEntryGotoButton"))
     , m_rAccessibilityCheckResult(rAccessibilityCheckResult)
 {
     m_xLabel->set_label(m_rAccessibilityCheckResult->m_aIssueText);
+    m_xGotoButton->connect_clicked(LINK(this, AccessibilityCheckEntry, GotoButtonClicked));
     m_xContainer->show();
 }
 
+IMPL_LINK_NOARG(AccessibilityCheckEntry, GotoButtonClicked, weld::Button&, void)
+{
+    m_rAccessibilityCheckResult->gotoIssue();
+}
+
 AccessibilityCheckDialog::AccessibilityCheckDialog(
     weld::Window* pParent,
     AccessibilityCheckResultCollection const& rAccessibilityCheckResultCollection)
diff --git a/svx/uiconfig/ui/accessibilitycheckentry.ui b/svx/uiconfig/ui/accessibilitycheckentry.ui
index bfd013491e51..4a4633eb3f14 100644
--- a/svx/uiconfig/ui/accessibilitycheckentry.ui
+++ b/svx/uiconfig/ui/accessibilitycheckentry.ui
@@ -10,7 +10,9 @@
       <object class="GtkLabel" id="accessibilityCheckEntryLabel">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
+        <property name="hexpand">True</property>
         <property name="selectable">True</property>
+        <property name="xalign">0</property>
       </object>
       <packing>
         <property name="expand">False</property>
@@ -19,7 +21,17 @@
       </packing>
     </child>
     <child>
-      <placeholder/>
+      <object class="GtkButton" id="accessibilityCheckEntryGotoButton">
+        <property name="label" translatable="yes" context="accessibilitycheckentry|accessibilityCheckEntryGotoButton">Goto Issue</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="position">1</property>
+      </packing>
     </child>
   </object>
 </interface>
diff --git a/sw/source/core/inc/AccessibilityCheck.hxx b/sw/source/core/inc/AccessibilityCheck.hxx
index 0ce80bf49f45..05a88a3a4975 100644
--- a/sw/source/core/inc/AccessibilityCheck.hxx
+++ b/sw/source/core/inc/AccessibilityCheck.hxx
@@ -24,6 +24,8 @@ public:
         : svx::AccessibilityCheckResult(eIssueID)
     {
     }
+
+    void gotoIssue() const override {}
 };
 
 class SW_DLLPUBLIC AccessibilityCheck final : public svx::AccessibilityCheck
commit 78864ed1cef5884c51fce11eb85023930639df72
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Fri Dec 20 09:57:23 2019 +0100
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Wed Dec 25 13:39:18 2019 +0100

    acc. check: add writer specific accessibility check result
    
    This adds sw::AccessibilityCheckResult and refactors the existing
    code to work with it.
    In addition adds AccessibilityCheckResultCollection which holds
    the vector of results.
    
    Change-Id: Ide0fdbdba337bbf8c2fd18770895fb63a22528b6

diff --git a/include/svx/AccessibilityCheck.hxx b/include/svx/AccessibilityCheck.hxx
index 526082b42a4d..db66ccb24fd4 100644
--- a/include/svx/AccessibilityCheck.hxx
+++ b/include/svx/AccessibilityCheck.hxx
@@ -11,9 +11,10 @@
 #ifndef INCLUDED_SVX_ACCESSIBILITYCHECK_HXX
 #define INCLUDED_SVX_ACCESSIBILITYCHECK_HXX
 
+#include <svx/svxdllapi.h>
 #include <vector>
+#include <memory>
 #include <rtl/ustring.hxx>
-#include <svx/svxdllapi.h>
 
 namespace svx
 {
@@ -25,7 +26,7 @@ enum class AccessibilityIssueID
     STYLE_LANGUAGE
 };
 
-class SVX_DLLPUBLIC AccessibilityCheckResult final
+class SVX_DLLPUBLIC AccessibilityCheckResult
 {
 public:
     AccessibilityIssueID m_eIssueID;
@@ -35,22 +36,29 @@ public:
         : m_eIssueID(eIssueID)
     {
     }
+    virtual ~AccessibilityCheckResult() {}
+};
+
+class SVX_DLLPUBLIC AccessibilityCheckResultCollection
+{
+private:
+    std::vector<std::shared_ptr<AccessibilityCheckResult>> m_aResults;
+
+public:
+    std::vector<std::shared_ptr<AccessibilityCheckResult>>& getResults() { return m_aResults; }
 };
 
 class SVX_DLLPUBLIC AccessibilityCheck
 {
 protected:
-    std::vector<AccessibilityCheckResult> m_aResultCollection;
+    AccessibilityCheckResultCollection m_aResultCollection;
 
 public:
     virtual ~AccessibilityCheck() {}
 
     virtual void check() = 0;
 
-    std::vector<AccessibilityCheckResult> const& getResultCollecton()
-    {
-        return m_aResultCollection;
-    }
+    AccessibilityCheckResultCollection& getResultCollecton() { return m_aResultCollection; }
 };
 
 } // end svx namespace
diff --git a/include/svx/AccessibilityCheckDialog.hxx b/include/svx/AccessibilityCheckDialog.hxx
index d66bf3b887aa..4b602a911a42 100644
--- a/include/svx/AccessibilityCheckDialog.hxx
+++ b/include/svx/AccessibilityCheckDialog.hxx
@@ -28,18 +28,19 @@ private:
     std::unique_ptr<weld::Container> m_xContainer;
     std::unique_ptr<weld::Label> m_xLabel;
 
-    AccessibilityCheckResult const& m_rAccessibilityCheckResult;
+    std::shared_ptr<AccessibilityCheckResult> const& m_rAccessibilityCheckResult;
 
 public:
-    AccessibilityCheckEntry(weld::Container* pParent, weld::Window* pDialog,
-                            AccessibilityCheckResult const& rAccessibilityCheckResult);
+    AccessibilityCheckEntry(
+        weld::Container* pParent, weld::Window* pDialog,
+        std::shared_ptr<AccessibilityCheckResult> const& rAccessibilityCheckResult);
     weld::Widget* get_widget() const { return m_xContainer.get(); }
 };
 
 class SVX_DLLPUBLIC AccessibilityCheckDialog final : public weld::GenericDialogController
 {
 private:
-    std::vector<AccessibilityCheckResult> m_rAccessibilityCheckResultCollection;
+    AccessibilityCheckResultCollection m_aAccessibilityCheckResultCollection;
     std::vector<std::unique_ptr<AccessibilityCheckEntry>> m_aAccessibilityCheckEntries;
 
     // Controls
@@ -48,7 +49,7 @@ private:
 public:
     AccessibilityCheckDialog(
         weld::Window* pParent,
-        std::vector<AccessibilityCheckResult> const& rAccessibilityCheckResultCollection);
+        AccessibilityCheckResultCollection const& rAccessibilityCheckResultCollection);
     virtual ~AccessibilityCheckDialog() override;
     virtual short run() override;
 };
diff --git a/svx/source/dialog/AccessibilityCheckDialog.cxx b/svx/source/dialog/AccessibilityCheckDialog.cxx
index e40f2187f445..f6add929e351 100644
--- a/svx/source/dialog/AccessibilityCheckDialog.cxx
+++ b/svx/source/dialog/AccessibilityCheckDialog.cxx
@@ -15,23 +15,23 @@ namespace svx
 {
 AccessibilityCheckEntry::AccessibilityCheckEntry(
     weld::Container* pParent, weld::Window* pDialog,
-    AccessibilityCheckResult const& rAccessibilityCheckResult)
+    std::shared_ptr<AccessibilityCheckResult> const& rAccessibilityCheckResult)
     : m_pDialog(pDialog)
     , m_xBuilder(Application::CreateBuilder(pParent, "svx/ui/accessibilitycheckentry.ui"))
     , m_xContainer(m_xBuilder->weld_container("accessibilityCheckEntryBox"))
     , m_xLabel(m_xBuilder->weld_label("accessibilityCheckEntryLabel"))
     , m_rAccessibilityCheckResult(rAccessibilityCheckResult)
 {
-    m_xLabel->set_label(m_rAccessibilityCheckResult.m_aIssueText);
+    m_xLabel->set_label(m_rAccessibilityCheckResult->m_aIssueText);
     m_xContainer->show();
 }
 
 AccessibilityCheckDialog::AccessibilityCheckDialog(
     weld::Window* pParent,
-    std::vector<AccessibilityCheckResult> const& rAccessibilityCheckResultCollection)
+    AccessibilityCheckResultCollection const& rAccessibilityCheckResultCollection)
     : GenericDialogController(pParent, "svx/ui/accessibilitycheckdialog.ui",
                               "AccessibilityCheckDialog")
-    , m_rAccessibilityCheckResultCollection(rAccessibilityCheckResultCollection)
+    , m_aAccessibilityCheckResultCollection(rAccessibilityCheckResultCollection)
     , m_xAccessibilityCheckBox(m_xBuilder->weld_box("accessibilityCheckBox"))
 {
 }
@@ -42,7 +42,8 @@ short AccessibilityCheckDialog::run()
 {
     sal_Int32 i = 0;
 
-    for (AccessibilityCheckResult const& rResult : m_rAccessibilityCheckResultCollection)
+    for (std::shared_ptr<AccessibilityCheckResult> const& rResult :
+         m_aAccessibilityCheckResultCollection.getResults())
     {
         auto xEntry = std::make_unique<AccessibilityCheckEntry>(m_xAccessibilityCheckBox.get(),
                                                                 m_xDialog.get(), rResult);
diff --git a/sw/qa/core/accessibilitycheck/AccessibilityCheckTest.cxx b/sw/qa/core/accessibilitycheck/AccessibilityCheckTest.cxx
index eff09430e92d..48f980b505e5 100644
--- a/sw/qa/core/accessibilitycheck/AccessibilityCheckTest.cxx
+++ b/sw/qa/core/accessibilitycheck/AccessibilityCheckTest.cxx
@@ -29,10 +29,10 @@ CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testCheck)
     CPPUNIT_ASSERT(pDoc);
     sw::AccessibilityCheck aCheck(pDoc);
     aCheck.check();
-    auto& aResults = aCheck.getResultCollecton();
+    auto const& aResults = aCheck.getResultCollecton().getResults();
     CPPUNIT_ASSERT_EQUAL(size_t(2), aResults.size());
-    CPPUNIT_ASSERT_EQUAL(svx::AccessibilityIssueID::DOCUMENT_LANGUAGE, aResults[0].m_eIssueID);
-    CPPUNIT_ASSERT_EQUAL(svx::AccessibilityIssueID::DOCUMENT_TITLE, aResults[1].m_eIssueID);
+    CPPUNIT_ASSERT_EQUAL(svx::AccessibilityIssueID::DOCUMENT_LANGUAGE, aResults[0]->m_eIssueID);
+    CPPUNIT_ASSERT_EQUAL(svx::AccessibilityIssueID::DOCUMENT_TITLE, aResults[1]->m_eIssueID);
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/access/AccessibilityCheck.cxx b/sw/source/core/access/AccessibilityCheck.cxx
index c37f5975a04b..b06f9012f738 100644
--- a/sw/source/core/access/AccessibilityCheck.cxx
+++ b/sw/source/core/access/AccessibilityCheck.cxx
@@ -44,15 +44,23 @@ OUString sTextContrast("Text contrast is too low.");
 OUString sTextBlinking("Blinking text.");
 OUString sAvoidFootnotes("Avoid footnotes.");
 OUString sAvoidEndnotes("Avoid endnotes.");
+
+void lclAddIssue(svx::AccessibilityCheckResultCollection& rResultCollection, OUString const& rText,
+                 svx::AccessibilityIssueID eIssue = svx::AccessibilityIssueID::UNSPECIFIED)
+{
+    auto pResult = std::make_shared<sw::AccessibilityCheckResult>(eIssue);
+    pResult->m_aIssueText = rText;
+    rResultCollection.getResults().push_back(pResult);
+}
 }
 
 class BaseCheck
 {
 protected:
-    std::vector<svx::AccessibilityCheckResult>& m_rResultCollection;
+    svx::AccessibilityCheckResultCollection& m_rResultCollection;
 
 public:
-    BaseCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
+    BaseCheck(svx::AccessibilityCheckResultCollection& rResultCollection)
         : m_rResultCollection(rResultCollection)
     {
     }
@@ -62,7 +70,7 @@ public:
 class NodeCheck : public BaseCheck
 {
 public:
-    NodeCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
+    NodeCheck(svx::AccessibilityCheckResultCollection& rResultCollection)
         : BaseCheck(rResultCollection)
     {
     }
@@ -82,14 +90,13 @@ class NoTextNodeAltTextCheck : public NodeCheck
         if (sAlternative.isEmpty())
         {
             OUString sName = pNoTextNode->GetFlyFormat()->GetName();
-            svx::AccessibilityCheckResult aResult;
-            aResult.m_aIssueText = sNoAlt.replaceAll("%OBJECT_NAME%", sName);
-            m_rResultCollection.push_back(aResult);
+            OUString sIssueText = sNoAlt.replaceAll("%OBJECT_NAME%", sName);
+            lclAddIssue(m_rResultCollection, sIssueText);
         }
     }
 
 public:
-    NoTextNodeAltTextCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
+    NoTextNodeAltTextCheck(svx::AccessibilityCheckResultCollection& rResultCollection)
         : NodeCheck(rResultCollection)
     {
     }
@@ -118,9 +125,8 @@ private:
         if (rTable.IsTableComplex())
         {
             OUString sName = rTable.GetTableStyleName();
-            svx::AccessibilityCheckResult aResult;
-            aResult.m_aIssueText = sTableMergeSplit.replaceAll("%OBJECT_NAME%", sName);
-            m_rResultCollection.push_back(aResult);
+            OUString sIssueText = sTableMergeSplit.replaceAll("%OBJECT_NAME%", sName);
+            lclAddIssue(m_rResultCollection, sIssueText);
         }
         else
         {
@@ -149,9 +155,8 @@ private:
                 if (!bAllColumnsSameSize)
                 {
                     OUString sName = rTable.GetTableStyleName();
-                    svx::AccessibilityCheckResult aResult;
-                    aResult.m_aIssueText = sTableMergeSplit.replaceAll("%OBJECT_NAME%", sName);
-                    m_rResultCollection.push_back(aResult);
+                    OUString sIssueText = sTableMergeSplit.replaceAll("%OBJECT_NAME%", sName);
+                    lclAddIssue(m_rResultCollection, sIssueText);
                 }
             }
         }
@@ -159,7 +164,7 @@ private:
 
 public:
     TableNodeMergeSplitCheck(
-        std::vector<svx::AccessibilityCheckResult>& rAccessibilityCheckResultCollection)
+        svx::AccessibilityCheckResultCollection& rAccessibilityCheckResultCollection)
         : NodeCheck(rAccessibilityCheckResultCollection)
     {
     }
@@ -186,7 +191,7 @@ private:
     };
 
 public:
-    NumberingCheck(std::vector<svx::AccessibilityCheckResult>& rAccessibilityCheckResultCollection)
+    NumberingCheck(svx::AccessibilityCheckResultCollection& rAccessibilityCheckResultCollection)
         : NodeCheck(rAccessibilityCheckResultCollection)
         , pPreviousTextNode(nullptr)
     {
@@ -203,10 +208,9 @@ public:
                     if (pCurrent->GetTextNode()->GetText().startsWith(rPair.second)
                         && pPreviousTextNode->GetText().startsWith(rPair.first))
                     {
-                        svx::AccessibilityCheckResult aResult;
                         OUString sNumbering = rPair.first + " " + rPair.second + "...";
-                        aResult.m_aIssueText = sFakeNumbering.replaceAll("%NUMBERING%", sNumbering);
-                        m_rResultCollection.push_back(aResult);
+                        OUString sIssueText = sFakeNumbering.replaceAll("%NUMBERING%", sNumbering);
+                        lclAddIssue(m_rResultCollection, sIssueText);
                     }
                 }
             }
@@ -230,16 +234,15 @@ private:
                 OUString sText = xTextRange->getString();
                 if (INetURLObject(sText) == INetURLObject(sHyperlink))
                 {
-                    svx::AccessibilityCheckResult aResult;
-                    aResult.m_aIssueText = sHyperlinkTextIsLink.replaceFirst("%LINK%", sHyperlink);
-                    m_rResultCollection.push_back(aResult);
+                    OUString sIssueText = sHyperlinkTextIsLink.replaceFirst("%LINK%", sHyperlink);
+                    lclAddIssue(m_rResultCollection, sIssueText);
                 }
             }
         }
     }
 
 public:
-    HyperlinkCheck(std::vector<svx::AccessibilityCheckResult>& rAccessibilityCheckResultCollection)
+    HyperlinkCheck(svx::AccessibilityCheckResultCollection& rAccessibilityCheckResultCollection)
         : NodeCheck(rAccessibilityCheckResultCollection)
     {
     }
@@ -366,16 +369,13 @@ private:
             double fContrastRatio = calculateContrastRatio(aForegroundColor, aBackgroundColor);
             if (fContrastRatio < 4.5)
             {
-                svx::AccessibilityCheckResult aResult;
-                aResult.m_aIssueText = sTextContrast;
-                m_rResultCollection.push_back(aResult);
+                lclAddIssue(m_rResultCollection, sTextContrast);
             }
         }
     }
 
 public:
-    TextContrastCheck(
-        std::vector<svx::AccessibilityCheckResult>& rAccessibilityCheckResultCollection)
+    TextContrastCheck(svx::AccessibilityCheckResultCollection& rAccessibilityCheckResultCollection)
         : NodeCheck(rAccessibilityCheckResultCollection)
     {
     }
@@ -417,16 +417,13 @@ private:
 
             if (bBlinking)
             {
-                svx::AccessibilityCheckResult aResult;
-                aResult.m_aIssueText = sTextBlinking;
-                m_rResultCollection.push_back(aResult);
+                lclAddIssue(m_rResultCollection, sTextBlinking);
             }
         }
     }
 
 public:
-    BlinkingTextCheck(
-        std::vector<svx::AccessibilityCheckResult>& rAccessibilityCheckResultCollection)
+    BlinkingTextCheck(svx::AccessibilityCheckResultCollection& rAccessibilityCheckResultCollection)
         : NodeCheck(rAccessibilityCheckResultCollection)
     {
     }
@@ -458,7 +455,7 @@ public:
 class DocumentCheck : public BaseCheck
 {
 public:
-    DocumentCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
+    DocumentCheck(svx::AccessibilityCheckResultCollection& rResultCollection)
         : BaseCheck(rResultCollection)
     {
     }
@@ -470,7 +467,7 @@ public:
 class DocumentDefaultLanguageCheck : public DocumentCheck
 {
 public:
-    DocumentDefaultLanguageCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
+    DocumentDefaultLanguageCheck(svx::AccessibilityCheckResultCollection& rResultCollection)
         : DocumentCheck(rResultCollection)
     {
     }
@@ -483,9 +480,8 @@ public:
         LanguageType eLanguage = rLang.GetLanguage();
         if (eLanguage == LANGUAGE_NONE)
         {
-            svx::AccessibilityCheckResult aResult(svx::AccessibilityIssueID::DOCUMENT_LANGUAGE);
-            aResult.m_aIssueText = sDocumentDefaultLanguage;
-            m_rResultCollection.push_back(aResult);
+            lclAddIssue(m_rResultCollection, sDocumentDefaultLanguage,
+                        svx::AccessibilityIssueID::DOCUMENT_LANGUAGE);
         }
         else
         {
@@ -494,11 +490,10 @@ public:
                 const SwAttrSet& rAttrSet = pTextFormatCollection->GetAttrSet();
                 if (rAttrSet.GetLanguage(false).GetLanguage() == LANGUAGE_NONE)
                 {
-                    svx::AccessibilityCheckResult aResult(
-                        svx::AccessibilityIssueID::STYLE_LANGUAGE);
                     OUString sName = pTextFormatCollection->GetName();
-                    aResult.m_aIssueText = sStyleNoLanguage.replaceAll("%STYLE_NAME%", sName);
-                    m_rResultCollection.push_back(aResult);
+                    OUString sIssueText = sStyleNoLanguage.replaceAll("%STYLE_NAME%", sName);
+                    lclAddIssue(m_rResultCollection, sIssueText,
+                                svx::AccessibilityIssueID::STYLE_LANGUAGE);
                 }
             }
         }
@@ -508,7 +503,7 @@ public:
 class DocumentTitleCheck : public DocumentCheck
 {
 public:
-    DocumentTitleCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
+    DocumentTitleCheck(svx::AccessibilityCheckResultCollection& rResultCollection)
         : DocumentCheck(rResultCollection)
     {
     }
@@ -525,9 +520,8 @@ public:
             OUString sTitle = xDocumentProperties->getTitle();
             if (sTitle.isEmpty())
             {
-                svx::AccessibilityCheckResult aResult(svx::AccessibilityIssueID::DOCUMENT_TITLE);
-                aResult.m_aIssueText = sDocumentTitle;
-                m_rResultCollection.push_back(aResult);
+                lclAddIssue(m_rResultCollection, sDocumentTitle,
+                            svx::AccessibilityIssueID::DOCUMENT_TITLE);
             }
         }
     }
@@ -536,7 +530,7 @@ public:
 class FootnoteEndnoteCheck : public DocumentCheck
 {
 public:
-    FootnoteEndnoteCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
+    FootnoteEndnoteCheck(svx::AccessibilityCheckResultCollection& rResultCollection)
         : DocumentCheck(rResultCollection)
     {
     }
@@ -548,15 +542,11 @@ public:
             SwFormatFootnote const& rFootnote = pTextFootnote->GetFootnote();
             if (rFootnote.IsEndNote())
             {
-                svx::AccessibilityCheckResult aResult;
-                aResult.m_aIssueText = sAvoidEndnotes;
-                m_rResultCollection.push_back(aResult);
+                lclAddIssue(m_rResultCollection, sAvoidEndnotes);
             }
             else
             {
-                svx::AccessibilityCheckResult aResult;
-                aResult.m_aIssueText = sAvoidFootnotes;
-                m_rResultCollection.push_back(aResult);
+                lclAddIssue(m_rResultCollection, sAvoidFootnotes);
             }
         }
     }
@@ -574,9 +564,8 @@ void AccessibilityCheck::checkObject(SdrObject* pObject)
         if (sAlternative.isEmpty())
         {
             OUString sName = pObject->GetName();
-            svx::AccessibilityCheckResult aResult;
-            aResult.m_aIssueText = sNoAlt.replaceAll("%OBJECT_NAME%", sName);
-            m_aResultCollection.push_back(aResult);
+            OUString sIssueText = sNoAlt.replaceAll("%OBJECT_NAME%", sName);
+            lclAddIssue(m_aResultCollection, sIssueText);
         }
     }
 }
diff --git a/sw/source/core/inc/AccessibilityCheck.hxx b/sw/source/core/inc/AccessibilityCheck.hxx
index 30bcb90e00a1..0ce80bf49f45 100644
--- a/sw/source/core/inc/AccessibilityCheck.hxx
+++ b/sw/source/core/inc/AccessibilityCheck.hxx
@@ -16,6 +16,16 @@
 
 namespace sw
 {
+class SW_DLLPUBLIC AccessibilityCheckResult final : public svx::AccessibilityCheckResult
+{
+public:
+    AccessibilityCheckResult(svx::AccessibilityIssueID eIssueID
+                             = svx::AccessibilityIssueID::UNSPECIFIED)
+        : svx::AccessibilityCheckResult(eIssueID)
+    {
+    }
+};
+
 class SW_DLLPUBLIC AccessibilityCheck final : public svx::AccessibilityCheck
 {
 private:
commit 7aa334e539c8df932ba328b1848309727f1b8eab
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Thu Dec 19 21:09:24 2019 +0100
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Wed Dec 25 13:39:18 2019 +0100

    pdf: support for PDF/UA in PDFWriter, write flag to the metadata
    
    This adds support for PDF/UA to the PDFWriter in form of a bool
    flag and writes into the XmpMetadata that the document is supposed
    to be PDF/UA compliant (even if it may not be).
    
    Change-Id: If187152d3860397fc629e272c5b3888fca34e790

diff --git a/vcl/inc/pdf/XmpMetadata.hxx b/vcl/inc/pdf/XmpMetadata.hxx
index d9f9cacc45b4..cc3f8da1a34c 100644
--- a/vcl/inc/pdf/XmpMetadata.hxx
+++ b/vcl/inc/pdf/XmpMetadata.hxx
@@ -31,6 +31,7 @@ public:
     OString msProducer;
     OString msKeywords;
     sal_Int32 mnPDF_A;
+    bool mbPDF_UA;
 
 public:
     XmpMetadata();
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 891d5db93a7b..e55efc180bb3 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -1307,6 +1307,7 @@ void PDFWriterImpl::PDFPage::appendWaveLine( sal_Int32 nWidth, sal_Int32 nY, sal
         m_nAccessPermissions(0),
         m_bIsPDF_A1( false ),
         m_bIsPDF_A2( false ),
+        m_bIsPDF_UA( false ),
         m_rOuterFace( i_rOuterFace )
 {
     m_aStructure.emplace_back( );
@@ -5225,7 +5226,7 @@ static void escapeStringXML( const OUString& rStr, OUString &rValue)
 // emits the document metadata
 sal_Int32 PDFWriterImpl::emitDocumentMetadata()
 {
-    if( !m_bIsPDF_A1 && !m_bIsPDF_A2 )
+    if (!m_bIsPDF_A1 && !m_bIsPDF_A2 && !m_bIsPDF_UA)
         return 0;
 
     //get the object number for all the destinations
@@ -5240,6 +5241,8 @@ sal_Int32 PDFWriterImpl::emitDocumentMetadata()
         else if (m_bIsPDF_A2)
             aMetadata.mnPDF_A = 2;
 
+        aMetadata.mbPDF_UA = m_bIsPDF_UA;
+
         if (!m_aContext.DocumentInfo.Title.isEmpty())
         {
             OUString aTempString;
diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx
index 6316b7daa92d..6c1dd623951e 100644
--- a/vcl/source/gdi/pdfwriter_impl.hxx
+++ b/vcl/source/gdi/pdfwriter_impl.hxx
@@ -982,6 +982,10 @@ i12626
     bool            m_bIsPDF_A1;
     /* true if PDF/A-2a is output */
     bool            m_bIsPDF_A2;
+
+    /* PDF/UA support enabled */
+    bool m_bIsPDF_UA;
+
     PDFWriter&      m_rOuterFace;
 
     /*
diff --git a/vcl/source/pdf/XmpMetadata.cxx b/vcl/source/pdf/XmpMetadata.cxx
index d9033f4875ae..281183c205e8 100644
--- a/vcl/source/pdf/XmpMetadata.cxx
+++ b/vcl/source/pdf/XmpMetadata.cxx
@@ -26,6 +26,7 @@ constexpr const char* constPadding = "                                        "
 XmpMetadata::XmpMetadata()
     : mbWritten(false)
     , mnPDF_A(0)
+    , mbPDF_UA(false)
 {
 }
 
@@ -107,6 +108,21 @@ void XmpMetadata::write()
             aXmlWriter.endElement();
         }
 
+        // PDF/UA
+        if (mbPDF_UA)
+        {
+            OString sPdfUaVersion = OString::number(1);
+            aXmlWriter.startElement("rdf:Description");
+            aXmlWriter.attribute("rdf:about", OString(""));
+            aXmlWriter.attribute("xmlns:pdfuaid", OString("http://www.aiim.org/pdfua/ns/id/"));
+
+            aXmlWriter.startElement("pdfuaid:part");
+            aXmlWriter.content(sPdfUaVersion);
+            aXmlWriter.endElement();
+
+            aXmlWriter.endElement();
+        }
+
         // PDF properties
         if (!msProducer.isEmpty() || !msKeywords.isEmpty())
         {
commit 2337bc712bc11ae8e11c500e439820b90dc22912
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Thu Dec 19 20:55:16 2019 +0100
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Wed Dec 25 13:39:18 2019 +0100

    pdf: extract XMP metadata writing and use XmlWriter
    
    Instead of writing XMP metadata with a string buffer, change to
    use XmlWriter instead. Extract XMP metadata writing into its own
    class vcl::pdf::XmpMetadata.
    
    This also needs a change to the XmlWriter to not write a classic
    XML header: '<?xml version="1.0" ... ?>'
    
    Change-Id: I95ea0e7ba58e7c43a0c707bf9c676994210ff104

diff --git a/include/tools/XmlWriter.hxx b/include/tools/XmlWriter.hxx
index da056c68a596..7efe3a57353a 100644
--- a/include/tools/XmlWriter.hxx
+++ b/include/tools/XmlWriter.hxx
@@ -40,7 +40,7 @@ public:
 
     ~XmlWriter();
 
-    bool startDocument(sal_Int32 nIndent = 2);
+    bool startDocument(sal_Int32 nIndent = 2, bool bWriteXmlHeader = true);
     void endDocument();
 
     void startElement(const OString& sName);
diff --git a/tools/source/xml/XmlWriter.cxx b/tools/source/xml/XmlWriter.cxx
index 3400a6e9d94b..a314eed6e940 100644
--- a/tools/source/xml/XmlWriter.cxx
+++ b/tools/source/xml/XmlWriter.cxx
@@ -36,11 +36,13 @@ struct XmlWriterImpl
     XmlWriterImpl(SvStream* pStream)
         : mpStream(pStream)
         , mpWriter(nullptr)
+        , mbWriteXmlHeader(true)
     {
     }
 
     SvStream* const mpStream;
     xmlTextWriterPtr mpWriter;
+    bool mbWriteXmlHeader;
 };
 
 XmlWriter::XmlWriter(SvStream* pStream)
@@ -54,21 +56,24 @@ XmlWriter::~XmlWriter()
         endDocument();
 }
 
-bool XmlWriter::startDocument(sal_Int32 nIndent)
+bool XmlWriter::startDocument(sal_Int32 nIndent, bool bWriteXmlHeader)
 {
+    mpImpl->mbWriteXmlHeader = bWriteXmlHeader;
     xmlOutputBufferPtr xmlOutBuffer
         = xmlOutputBufferCreateIO(funcWriteCallback, funcCloseCallback, mpImpl->mpStream, nullptr);
     mpImpl->mpWriter = xmlNewTextWriter(xmlOutBuffer);
     if (mpImpl->mpWriter == nullptr)
         return false;
     xmlTextWriterSetIndent(mpImpl->mpWriter, nIndent);
-    xmlTextWriterStartDocument(mpImpl->mpWriter, nullptr, "UTF-8", nullptr);
+    if (mpImpl->mbWriteXmlHeader)
+        xmlTextWriterStartDocument(mpImpl->mpWriter, nullptr, "UTF-8", nullptr);
     return true;
 }
 
 void XmlWriter::endDocument()
 {
-    xmlTextWriterEndDocument(mpImpl->mpWriter);
+    if (mpImpl->mbWriteXmlHeader)
+        xmlTextWriterEndDocument(mpImpl->mpWriter);
     xmlFreeTextWriter(mpImpl->mpWriter);
     mpImpl->mpWriter = nullptr;
 }
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index b401d811f596..0bc271576da7 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -448,6 +448,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
     vcl/source/fontsubset/sft \
     vcl/source/fontsubset/ttcr \
     vcl/source/fontsubset/xlat \
+    vcl/source/pdf/XmpMetadata \
     vcl/source/uitest/logger \
     vcl/source/uitest/uiobject \
     vcl/source/uitest/uitest \
diff --git a/vcl/inc/pdf/XmpMetadata.hxx b/vcl/inc/pdf/XmpMetadata.hxx
new file mode 100644
index 000000000000..d9f9cacc45b4
--- /dev/null
+++ b/vcl/inc/pdf/XmpMetadata.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#ifndef INCLUDED_VCL_INC_PDF_XMPMETADATA_HXX
+#define INCLUDED_VCL_INC_PDF_XMPMETADATA_HXX
+
+#include <vcl/dllapi.h>
+#include <rtl/string.hxx>
+#include <tools/stream.hxx>
+#include <memory>
+
+namespace vcl::pdf
+{
+class XmpMetadata
+{
+private:
+    bool mbWritten;
+    std::unique_ptr<SvMemoryStream> mpMemoryStream;
+
+public:
+    OString msTitle;
+    OString msAuthor;
+    OString msSubject;
+    OString msProducer;
+    OString msKeywords;
+    sal_Int32 mnPDF_A;
+
+public:
+    XmpMetadata();
+    sal_uInt64 getSize();
+    const void* getData();
+
+private:
+    void write();
+};
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index f5fb555b1f56..891d5db93a7b 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -74,6 +74,7 @@
 #include <textlineinfo.hxx>
 #include <bitmapwriteaccess.hxx>
 #include <impglyphitem.hxx>
+#include <pdf/XmpMetadata.hxx>
 
 #include "pdfwriter_impl.hxx"
 
@@ -5232,132 +5233,44 @@ sal_Int32 PDFWriterImpl::emitDocumentMetadata()
 
     if( updateObject( nObject ) )
     {
-        // the following string are written in UTF-8 unicode
-        OStringBuffer aMetadataStream( 8192 );
+        pdf::XmpMetadata aMetadata;
 
-        aMetadataStream.append( "<?xpacket begin=\"" );
-        // these lines write Unicode "zero width non-breaking space character" (U+FEFF)
-        // (aka byte-order mark ) used as a byte-order marker.
-        aMetadataStream.append( OUStringToOString( OUString( u'\xFEFF' ), RTL_TEXTENCODING_UTF8 ) );
-        aMetadataStream.append( "\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n" );
-        aMetadataStream.append( "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">\n" );
-        aMetadataStream.append( " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" );
-        //PDF/A part ( ISO 19005-1:2005 - 6.7.11 )
-        aMetadataStream.append( "  <rdf:Description rdf:about=\"\"\n" );
-        aMetadataStream.append( "      xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n" );
-        if( m_bIsPDF_A2 )
-        {
-            aMetadataStream.append( "   <pdfaid:part>2</pdfaid:part>\n" );
-            aMetadataStream.append( "   <pdfaid:conformance>B</pdfaid:conformance>\n" );
-        }
-        else
+        if (m_bIsPDF_A1)
+            aMetadata.mnPDF_A = 1;
+        else if (m_bIsPDF_A2)
+            aMetadata.mnPDF_A = 2;
+
+        if (!m_aContext.DocumentInfo.Title.isEmpty())
         {
-            aMetadataStream.append( "   <pdfaid:part>1</pdfaid:part>\n" );
-            aMetadataStream.append( "   <pdfaid:conformance>A</pdfaid:conformance>\n" );
+            OUString aTempString;
+            escapeStringXML(m_aContext.DocumentInfo.Title, aTempString);
+            aMetadata.msTitle = OUStringToOString(aTempString, RTL_TEXTENCODING_UTF8);
         }
-        aMetadataStream.append( "  </rdf:Description>\n" );
-        //... Dublin Core properties go here
-        if( !m_aContext.DocumentInfo.Title.isEmpty() ||
-            !m_aContext.DocumentInfo.Author.isEmpty() ||
-            !m_aContext.DocumentInfo.Subject.isEmpty() )
+        if (!m_aContext.DocumentInfo.Author.isEmpty())
         {
-            aMetadataStream.append( "  <rdf:Description rdf:about=\"\"\n" );
-            aMetadataStream.append( "      xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n" );
-            if( !m_aContext.DocumentInfo.Title.isEmpty() )
-            {
-                // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
-                aMetadataStream.append( "   <dc:title>\n" );
-                aMetadataStream.append( "    <rdf:Alt>\n" );
-                aMetadataStream.append( "     <rdf:li xml:lang=\"x-default\">" );
-                OUString aTitle;
-                escapeStringXML( m_aContext.DocumentInfo.Title, aTitle );
-                aMetadataStream.append( OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 )  );
-                aMetadataStream.append( "</rdf:li>\n" );
-                aMetadataStream.append( "    </rdf:Alt>\n" );
-                aMetadataStream.append( "   </dc:title>\n" );
-            }
-            if( !m_aContext.DocumentInfo.Author.isEmpty() )
-            {
-                aMetadataStream.append( "   <dc:creator>\n" );
-                aMetadataStream.append( "    <rdf:Seq>\n" );
-                aMetadataStream.append( "     <rdf:li>" );
-                OUString aAuthor;
-                escapeStringXML( m_aContext.DocumentInfo.Author, aAuthor );
-                aMetadataStream.append( OUStringToOString( aAuthor , RTL_TEXTENCODING_UTF8 )  );
-                aMetadataStream.append( "</rdf:li>\n" );
-                aMetadataStream.append( "    </rdf:Seq>\n" );
-                aMetadataStream.append( "   </dc:creator>\n" );
-            }
-            if( !m_aContext.DocumentInfo.Subject.isEmpty() )
-            {
-                // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
-                aMetadataStream.append( "   <dc:description>\n" );
-                aMetadataStream.append( "    <rdf:Alt>\n" );
-                aMetadataStream.append( "     <rdf:li xml:lang=\"x-default\">" );
-                OUString aSubject;
-                escapeStringXML( m_aContext.DocumentInfo.Subject, aSubject );
-                aMetadataStream.append( OUStringToOString( aSubject , RTL_TEXTENCODING_UTF8 )  );
-                aMetadataStream.append( "</rdf:li>\n" );
-                aMetadataStream.append( "    </rdf:Alt>\n" );
-                aMetadataStream.append( "   </dc:description>\n" );
-            }
-            aMetadataStream.append( "  </rdf:Description>\n" );
+            OUString aTempString;
+            escapeStringXML(m_aContext.DocumentInfo.Author, aTempString);
+            aMetadata.msAuthor = OUStringToOString(aTempString, RTL_TEXTENCODING_UTF8);
         }
-
-        //... PDF properties go here
-        if( !m_aContext.DocumentInfo.Producer.isEmpty() ||
-            !m_aContext.DocumentInfo.Keywords.isEmpty() )
+        if (!m_aContext.DocumentInfo.Subject.isEmpty())
         {
-            aMetadataStream.append( "  <rdf:Description rdf:about=\"\"\n" );
-            aMetadataStream.append( "     xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n" );
-            if( !m_aContext.DocumentInfo.Producer.isEmpty() )
-            {
-                aMetadataStream.append( "   <pdf:Producer>" );
-                OUString aProducer;
-                escapeStringXML( m_aContext.DocumentInfo.Producer, aProducer );
-                aMetadataStream.append( OUStringToOString( aProducer , RTL_TEXTENCODING_UTF8 )  );
-                aMetadataStream.append( "</pdf:Producer>\n" );
-            }
-            if( !m_aContext.DocumentInfo.Keywords.isEmpty() )
-            {
-                aMetadataStream.append( "   <pdf:Keywords>" );
-                OUString aKeywords;
-                escapeStringXML( m_aContext.DocumentInfo.Keywords, aKeywords );
-                aMetadataStream.append( OUStringToOString( aKeywords , RTL_TEXTENCODING_UTF8 )  );
-                aMetadataStream.append( "</pdf:Keywords>\n" );
-            }
-            aMetadataStream.append( "  </rdf:Description>\n" );
+            OUString aTempString;
+            escapeStringXML(m_aContext.DocumentInfo.Subject, aTempString);
+            aMetadata.msSubject = OUStringToOString(aTempString, RTL_TEXTENCODING_UTF8);
         }
-
-        aMetadataStream.append( "  <rdf:Description rdf:about=\"\"\n" );
-        aMetadataStream.append( "    xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\n" );
-        if( !m_aContext.DocumentInfo.Creator.isEmpty() )
+        if (!m_aContext.DocumentInfo.Producer.isEmpty())
         {
-            aMetadataStream.append( "   <xmp:CreatorTool>" );
-            OUString aCreator;
-            escapeStringXML( m_aContext.DocumentInfo.Creator, aCreator );
-            aMetadataStream.append( OUStringToOString( aCreator , RTL_TEXTENCODING_UTF8 )  );
-            aMetadataStream.append( "</xmp:CreatorTool>\n" );
+            OUString aTempString;
+            escapeStringXML(m_aContext.DocumentInfo.Producer, aTempString);
+            aMetadata.msProducer = OUStringToOString(aTempString, RTL_TEXTENCODING_UTF8);
         }
-        //creation date
-        aMetadataStream.append( "   <xmp:CreateDate>" );
-        aMetadataStream.append( m_aCreationMetaDateString );
-        aMetadataStream.append( "</xmp:CreateDate>\n" );
-
-        aMetadataStream.append( "  </rdf:Description>\n" );
-        aMetadataStream.append( " </rdf:RDF>\n" );
-        aMetadataStream.append( "</x:xmpmeta>\n" );
-
-        //add the padding
-        for( sal_Int32 nSpaces = 1; nSpaces <= 2100; nSpaces++ )
+        if (!m_aContext.DocumentInfo.Keywords.isEmpty())
         {
-            aMetadataStream.append( " " );
-            if( nSpaces % 100 == 0 )
-                aMetadataStream.append( "\n" );
+            OUString aTempString;
+            escapeStringXML(m_aContext.DocumentInfo.Keywords, aTempString);
+            aMetadata.msKeywords = OUStringToOString(aTempString, RTL_TEXTENCODING_UTF8);
         }
 
-        aMetadataStream.append( "<?xpacket end=\"w\"?>\n" );
-
         OStringBuffer aMetadataObj( 1024 );
 
         aMetadataObj.append( nObject );
@@ -5365,12 +5278,12 @@ sal_Int32 PDFWriterImpl::emitDocumentMetadata()
 
         aMetadataObj.append( "<</Type/Metadata/Subtype/XML/Length " );
 
-        aMetadataObj.append( aMetadataStream.getLength() );
+        aMetadataObj.append( sal_Int32(aMetadata.getSize()) );
         aMetadataObj.append( ">>\nstream\n" );
         if ( !writeBuffer( aMetadataObj.getStr(), aMetadataObj.getLength() ) )
             return 0;
         //emit the stream
-        if ( !writeBuffer( aMetadataStream.getStr(), aMetadataStream.getLength() ) )
+        if ( !writeBuffer( aMetadata.getData(), aMetadata.getSize() ) )
             return 0;
 
         aMetadataObj.setLength( 0 );
diff --git a/vcl/source/pdf/XmpMetadata.cxx b/vcl/source/pdf/XmpMetadata.cxx
new file mode 100644
index 000000000000..d9033f4875ae
--- /dev/null
+++ b/vcl/source/pdf/XmpMetadata.cxx
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <pdf/XmpMetadata.hxx>
+#include <tools/XmlWriter.hxx>
+
+namespace vcl::pdf
+{
+namespace
+{
+constexpr const char* constPadding = "                                        "
+                                     "                                        "
+                                     "                                        "
+                                     "                                        "
+                                     "                                        "
+                                     "\n";
+}
+
+XmpMetadata::XmpMetadata()
+    : mbWritten(false)
+    , mnPDF_A(0)
+{
+}
+
+void XmpMetadata::write()
+{
+    mpMemoryStream = std::make_unique<SvMemoryStream>(4096 /*Initial*/, 64 /*Resize*/);
+
+    // Header
+    mpMemoryStream->WriteOString("<?xpacket begin=\"");
+    mpMemoryStream->WriteOString(OUStringToOString(OUString(u'\xFEFF'), RTL_TEXTENCODING_UTF8));
+    mpMemoryStream->WriteOString("\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n");
+
+    {
+        tools::XmlWriter aXmlWriter(mpMemoryStream.get());
+        aXmlWriter.startDocument(2, false);
+        aXmlWriter.startElement("x", "xmpmeta", "adobe:ns:meta/");
+        aXmlWriter.startElement("rdf", "RDF", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
+
+        // PDF/A part ( ISO 19005-1:2005 - 6.7.11 )
+        if (mnPDF_A > 0)
+        {
+            OString sPdfVersion = OString::number(mnPDF_A);
+            OString sPdfConformance = (mnPDF_A == 1) ? "A" : "B";
+
+            aXmlWriter.startElement("rdf:Description");
+            aXmlWriter.attribute("rdf:about", OString(""));
+            aXmlWriter.attribute("xmlns:pdfaid", OString("http://www.aiim.org/pdfa/ns/id/"));
+
+            aXmlWriter.startElement("pdfaid:part");
+            aXmlWriter.content(sPdfVersion);
+            aXmlWriter.endElement();
+
+            aXmlWriter.startElement("pdfaid:conformance");
+            aXmlWriter.content(sPdfConformance);
+            aXmlWriter.endElement();
+
+            aXmlWriter.endElement();
+        }
+
+        // Dublin Core properties
+        if (!msTitle.isEmpty() || !msAuthor.isEmpty() || !msSubject.isEmpty())
+        {
+            aXmlWriter.startElement("rdf:Description");
+            aXmlWriter.attribute("rdf:about", OString(""));
+            aXmlWriter.attribute("xmlns:dc", OString("http://purl.org/dc/elements/1.1/"));
+            if (!msTitle.isEmpty())
+            {
+                // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
+                aXmlWriter.startElement("dc:title");
+                aXmlWriter.startElement("rdf:Alt");
+                aXmlWriter.startElement("rdf:li");
+                aXmlWriter.attribute("xml:lang", OString("x-default"));
+                aXmlWriter.content(msTitle);
+                aXmlWriter.endElement();
+                aXmlWriter.endElement();
+                aXmlWriter.endElement();
+            }
+            if (!msAuthor.isEmpty())
+            {
+                aXmlWriter.startElement("dc:creator");
+                aXmlWriter.startElement("rdf:Seq");
+                aXmlWriter.startElement("rdf:li");
+                aXmlWriter.content(msAuthor);
+                aXmlWriter.endElement();
+                aXmlWriter.endElement();
+                aXmlWriter.endElement();
+            }
+            if (!msSubject.isEmpty())
+            {
+                aXmlWriter.startElement("dc:description");
+                aXmlWriter.startElement("rdf:Alt");
+                aXmlWriter.startElement("rdf:li");
+                aXmlWriter.attribute("xml:lang", OString("x-default"));
+                aXmlWriter.content(msSubject);
+                aXmlWriter.endElement();
+                aXmlWriter.endElement();
+                aXmlWriter.endElement();
+            }
+            aXmlWriter.endElement();
+        }
+
+        // PDF properties
+        if (!msProducer.isEmpty() || !msKeywords.isEmpty())
+        {
+            aXmlWriter.startElement("rdf:Description");
+            aXmlWriter.attribute("rdf:about", OString(""));
+            aXmlWriter.attribute("xmlns:pdf", OString("http://ns.adobe.com/pdf/1.3/"));
+            if (!msProducer.isEmpty())
+            {
+                aXmlWriter.startElement("pdf:Producer");
+                aXmlWriter.content(msProducer);
+                aXmlWriter.endElement();
+            }
+            if (!msKeywords.isEmpty())
+            {
+                aXmlWriter.startElement("pdf:Keywords");
+                aXmlWriter.content(msKeywords);
+                aXmlWriter.endElement();
+            }
+            aXmlWriter.endElement();
+        }
+        aXmlWriter.endElement();
+        aXmlWriter.endElement();
+        aXmlWriter.endDocument();
+    }
+
+    // add padding (needed so the metadata can be changed in-place"
+    for (sal_Int32 nSpaces = 1; nSpaces <= 21; nSpaces++)
+        mpMemoryStream->WriteOString(constPadding);
+
+    mpMemoryStream->WriteOString("<?xpacket end=\"w\"?>\n");
+    mbWritten = true;
+}
+
+sal_uInt64 XmpMetadata::getSize()
+{
+    if (!mbWritten)
+        write();
+    return mpMemoryStream->GetSize();
+}
+
+const void* XmpMetadata::getData()
+{
+    if (!mbWritten)
+        write();
+    return mpMemoryStream->GetData();
+}
+
+} // end vcl::pdf
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 1f920dc79b48f0c0dc7d55049a9717818b71c7da
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun Dec 15 19:02:16 2019 +0100
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Wed Dec 25 13:39:18 2019 +0100

    acc. check: check for endnotes and footnotes
    
    Endnotes and footnotes cause problems for accessibility and should
    be avoided.
    
    Change-Id: Ibbce4d246f76feb8d389a7ba588836e2fef8f5d5

diff --git a/sw/source/core/access/AccessibilityCheck.cxx b/sw/source/core/access/AccessibilityCheck.cxx
index 90e1a6eb658c..c37f5975a04b 100644
--- a/sw/source/core/access/AccessibilityCheck.cxx
+++ b/sw/source/core/access/AccessibilityCheck.cxx
@@ -25,6 +25,8 @@
 #include <charatr.hxx>
 #include <svx/xfillit0.hxx>
 #include <svx/xflclit.hxx>
+#include <ftnidx.hxx>
+#include <txtftn.hxx>
 
 namespace sw
 {
@@ -40,6 +42,8 @@ OUString sStyleNoLanguage("Style '%STYLE_NAME%' has no language set");
 OUString sDocumentTitle("Document title is not set");
 OUString sTextContrast("Text contrast is too low.");
 OUString sTextBlinking("Blinking text.");
+OUString sAvoidFootnotes("Avoid footnotes.");
+OUString sAvoidEndnotes("Avoid endnotes.");
 }
 
 class BaseCheck
@@ -529,6 +533,35 @@ public:
     }
 };
 
+class FootnoteEndnoteCheck : public DocumentCheck
+{
+public:
+    FootnoteEndnoteCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
+        : DocumentCheck(rResultCollection)
+    {
+    }
+
+    void check(SwDoc* pDoc) override
+    {
+        for (SwTextFootnote const* pTextFootnote : pDoc->GetFootnoteIdxs())
+        {
+            SwFormatFootnote const& rFootnote = pTextFootnote->GetFootnote();
+            if (rFootnote.IsEndNote())
+            {
+                svx::AccessibilityCheckResult aResult;
+                aResult.m_aIssueText = sAvoidEndnotes;
+                m_rResultCollection.push_back(aResult);
+            }
+            else
+            {
+                svx::AccessibilityCheckResult aResult;
+                aResult.m_aIssueText = sAvoidFootnotes;
+                m_rResultCollection.push_back(aResult);
+            }
+        }
+    }
+};
+
 // Check Shapes, TextBox
 void AccessibilityCheck::checkObject(SdrObject* pObject)
 {
@@ -556,6 +589,7 @@ void AccessibilityCheck::check()
     std::vector<std::unique_ptr<DocumentCheck>> aDocumentChecks;
     aDocumentChecks.push_back(std::make_unique<DocumentDefaultLanguageCheck>(m_aResultCollection));
     aDocumentChecks.push_back(std::make_unique<DocumentTitleCheck>(m_aResultCollection));
+    aDocumentChecks.push_back(std::make_unique<FootnoteEndnoteCheck>(m_aResultCollection));
 
     for (std::unique_ptr<DocumentCheck>& rpDocumentCheck : aDocumentChecks)
     {
commit 9a1467416471a90c62e3385771ec5713e9fd6135
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun Dec 15 17:36:24 2019 +0100
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Wed Dec 25 13:39:18 2019 +0100

    acc. check: check for blinking text
    
    Change-Id: If023c9b6c6225a3889f2fd68b8ed62abb4365d48

diff --git a/sw/source/core/access/AccessibilityCheck.cxx b/sw/source/core/access/AccessibilityCheck.cxx
index 062bea8f18fb..90e1a6eb658c 100644
--- a/sw/source/core/access/AccessibilityCheck.cxx
+++ b/sw/source/core/access/AccessibilityCheck.cxx
@@ -39,6 +39,7 @@ OUString sDocumentDefaultLanguage("Document default language is not set");
 OUString sStyleNoLanguage("Style '%STYLE_NAME%' has no language set");
 OUString sDocumentTitle("Document title is not set");
 OUString sTextContrast("Text contrast is too low.");
+OUString sTextBlinking("Blinking text.");
 }
 
 class BaseCheck
@@ -399,6 +400,57 @@ public:
     }
 };
 
+class BlinkingTextCheck : public NodeCheck
+{
+private:
+    void checkTextRange(uno::Reference<text::XTextRange> const& xTextRange)
+    {
+        uno::Reference<beans::XPropertySet> xProperties(xTextRange, uno::UNO_QUERY);
+        if (xProperties.is() && xProperties->getPropertySetInfo()->hasPropertyByName("CharFlash"))
+        {
+            bool bBlinking = false;
+            xProperties->getPropertyValue("CharFlash") >>= bBlinking;
+
+            if (bBlinking)
+            {
+                svx::AccessibilityCheckResult aResult;
+                aResult.m_aIssueText = sTextBlinking;
+                m_rResultCollection.push_back(aResult);
+            }
+        }
+    }
+
+public:
+    BlinkingTextCheck(
+        std::vector<svx::AccessibilityCheckResult>& rAccessibilityCheckResultCollection)
+        : NodeCheck(rAccessibilityCheckResultCollection)
+    {
+    }
+
+    void check(SwNode* pCurrent) override
+    {
+        if (pCurrent->IsTextNode())
+        {
+            SwTextNode* pTextNode = pCurrent->GetTextNode();
+            uno::Reference<text::XTextContent> xParagraph;
+            xParagraph = SwXParagraph::CreateXParagraph(*pTextNode->GetDoc(), pTextNode);
+            if (xParagraph.is())
+            {
+                uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParagraph,
+                                                                             uno::UNO_QUERY);
+                uno::Reference<container::XEnumeration> xRunEnum
+                    = xRunEnumAccess->createEnumeration();
+                while (xRunEnum->hasMoreElements())
+                {
+                    uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
+                    if (xRun.is())
+                        checkTextRange(xRun);
+                }
+            }
+        }
+    }
+};
+
 class DocumentCheck : public BaseCheck
 {
 public:
@@ -516,6 +568,7 @@ void AccessibilityCheck::check()
     aNodeChecks.push_back(std::make_unique<NumberingCheck>(m_aResultCollection));
     aNodeChecks.push_back(std::make_unique<HyperlinkCheck>(m_aResultCollection));
     aNodeChecks.push_back(std::make_unique<TextContrastCheck>(m_aResultCollection));
+    aNodeChecks.push_back(std::make_unique<BlinkingTextCheck>(m_aResultCollection));
 
     auto const& pNodes = m_pDoc->GetNodes();
     SwNode* pNode = nullptr;
commit f9ba843c5dbecfc0ef79dac0a5f81a7f9fcca529
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun Dec 15 10:51:39 2019 +0100
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Wed Dec 25 13:39:17 2019 +0100

    acc. check: text vs. background contrast check
    
    Contrast between text and background shouldn't be too low (under
    4.5). The way how to calculate the contrast is defined by the
    WCAG21.
    
    Change-Id: Ic52ab68ba0ec6a4ab58e6b01afe74e8e7eeae104

diff --git a/sw/source/core/access/AccessibilityCheck.cxx b/sw/source/core/access/AccessibilityCheck.cxx
index ee3a0b52b0a0..062bea8f18fb 100644
--- a/sw/source/core/access/AccessibilityCheck.cxx
+++ b/sw/source/core/access/AccessibilityCheck.cxx
@@ -23,6 +23,8 @@
 #include <tools/urlobj.hxx>
 #include <editeng/langitem.hxx>
 #include <charatr.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
 
 namespace sw
 {
@@ -36,6 +38,7 @@ OUString sHyperlinkTextIsLink("Hyperlink text is the same as the link address '%
 OUString sDocumentDefaultLanguage("Document default language is not set");
 OUString sStyleNoLanguage("Style '%STYLE_NAME%' has no language set");
 OUString sDocumentTitle("Document title is not set");
+OUString sTextContrast("Text contrast is too low.");
 }
 
 class BaseCheck
@@ -262,6 +265,140 @@ public:
     }
 };
 
+namespace
+{
+// Based on https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
+double calculateRelativeLuminance(Color const& rColor)
+{
+    // Convert to BColor which has R, G, B colors components
+    // represented by a floating point number from [0.0, 1.0]
+    const basegfx::BColor aBColor = rColor.getBColor();
+
+    double r = aBColor.getRed();
+    double g = aBColor.getGreen();
+    double b = aBColor.getBlue();
+
+    // Calculate the values according to the described algorithm
+    r = (r <= 0.03928) ? r / 12.92 : std::pow((r + 0.055) / 1.055, 2.4);
+    g = (g <= 0.03928) ? g / 12.92 : std::pow((g + 0.055) / 1.055, 2.4);
+    b = (b <= 0.03928) ? b / 12.92 : std::pow((b + 0.055) / 1.055, 2.4);
+
+    return 0.2126 * r + 0.7152 * g + 0.0722 * b;
+}
+
+// TODO move to common color tools (BColorTools maybe)
+// Based on https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
+double calculateContrastRatio(Color const& rColor1, Color const& rColor2)
+{
+    const double fLuminance1 = calculateRelativeLuminance(rColor1);
+    const double fLuminance2 = calculateRelativeLuminance(rColor2);
+    const std::pair<const double, const double> aMinMax = std::minmax(fLuminance1, fLuminance2);
+
+    // (L1 + 0.05) / (L2 + 0.05)
+    // L1 is the lighter color (greater luminance value)
+    // L2 is the darker color (smaller luminance value)
+    return (aMinMax.second + 0.05) / (aMinMax.first + 0.05);
+}
+}
+
+class TextContrastCheck : public NodeCheck
+{
+private:
+    void checkTextRange(uno::Reference<text::XTextRange> const& xTextRange,
+                        uno::Reference<text::XTextContent> const& xParagraph, SwTextNode* pTextNode)
+    {
+        sal_Int32 nParaBackColor;
+        uno::Reference<beans::XPropertySet> xParagraphProperties(xParagraph, uno::UNO_QUERY);
+        xParagraphProperties->getPropertyValue("ParaBackColor") >>= nParaBackColor;
+
+        uno::Reference<beans::XPropertySet> xProperties(xTextRange, uno::UNO_QUERY);
+        if (xProperties.is())
+        {
+            // Forground color
+            sal_Int32 nCharColor;
+            xProperties->getPropertyValue("CharColor") >>= nCharColor;
+            Color aForegroundColor(nCharColor);
+            if (aForegroundColor == COL_AUTO)
+                return;
+
+            const SwPageDesc* pPageDescription = pTextNode->FindPageDesc();
+            const SwFrameFormat& rPageFormat = pPageDescription->GetMaster();
+            const SwAttrSet& rPageSet = rPageFormat.GetAttrSet();
+
+            const XFillStyleItem* pXFillStyleItem(
+                rPageSet.GetItem<XFillStyleItem>(XATTR_FILLSTYLE, false));
+            Color aPageBackground;
+
+            if (pXFillStyleItem->GetValue() == css::drawing::FillStyle_SOLID)
+            {
+                const XFillColorItem* rXFillColorItem
+                    = rPageSet.GetItem<XFillColorItem>(XATTR_FILLCOLOR, false);
+                aPageBackground = rXFillColorItem->GetColorValue();
+            }
+
+            sal_Int32 nCharBackColor;
+            sal_Int16 eRelief;
+
+            xProperties->getPropertyValue("CharBackColor") >>= nCharBackColor;
+            xProperties->getPropertyValue("CharRelief") >>= eRelief;
+
+            // Determine the background color
+            // Try Character background (highlight)
+            Color aBackgroundColor(nCharBackColor);
+
+            // If not character background color, try paragraph background color
+            if (aBackgroundColor == COL_AUTO)
+                aBackgroundColor = Color(nParaBackColor);
+
+            // If not paragraph background color, try page color
+            if (aBackgroundColor == COL_AUTO)
+                aBackgroundColor = aPageBackground;
+
+            // If not page color, assume white background color
+            if (aBackgroundColor == COL_AUTO)
+                aBackgroundColor = COL_WHITE;
+
+            double fContrastRatio = calculateContrastRatio(aForegroundColor, aBackgroundColor);
+            if (fContrastRatio < 4.5)
+            {
+                svx::AccessibilityCheckResult aResult;
+                aResult.m_aIssueText = sTextContrast;
+                m_rResultCollection.push_back(aResult);
+            }
+        }
+    }
+
+public:
+    TextContrastCheck(
+        std::vector<svx::AccessibilityCheckResult>& rAccessibilityCheckResultCollection)
+        : NodeCheck(rAccessibilityCheckResultCollection)
+    {
+    }
+
+    void check(SwNode* pCurrent) override
+    {
+        if (pCurrent->IsTextNode())
+        {
+            SwTextNode* pTextNode = pCurrent->GetTextNode();
+            uno::Reference<text::XTextContent> xParagraph;
+            xParagraph = SwXParagraph::CreateXParagraph(*pTextNode->GetDoc(), pTextNode);
+            if (xParagraph.is())
+            {
+                uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParagraph,
+                                                                             uno::UNO_QUERY);
+                uno::Reference<container::XEnumeration> xRunEnum
+                    = xRunEnumAccess->createEnumeration();
+                while (xRunEnum->hasMoreElements())
+                {
+                    uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
+                    if (xRun.is())
+                        checkTextRange(xRun, xParagraph, pTextNode);
+                }
+            }
+        }
+    }
+};
+
 class DocumentCheck : public BaseCheck
 {
 public:
@@ -378,6 +515,7 @@ void AccessibilityCheck::check()
     aNodeChecks.push_back(std::make_unique<TableNodeMergeSplitCheck>(m_aResultCollection));
     aNodeChecks.push_back(std::make_unique<NumberingCheck>(m_aResultCollection));
     aNodeChecks.push_back(std::make_unique<HyperlinkCheck>(m_aResultCollection));
+    aNodeChecks.push_back(std::make_unique<TextContrastCheck>(m_aResultCollection));
 
     auto const& pNodes = m_pDoc->GetNodes();
     SwNode* pNode = nullptr;
commit d0ce1d6d4b04d6bb3ffb1bf7f6a621480119df64
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun Dec 15 10:41:05 2019 +0100
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Wed Dec 25 13:39:17 2019 +0100

    acc. check: introduce AccessibilityCheckTest + document test
    
    This adds AccessibilityCheckTest to test that AccessibilityCheck
    returns correct issues for documents. This in addition adds 2
    tests for document title and document/style language.
    
    Change-Id: I71f3b0de0af7a08507f2b90b46847010948bc8cb

diff --git a/include/svx/AccessibilityCheck.hxx b/include/svx/AccessibilityCheck.hxx
index 66b18ab6386c..526082b42a4d 100644
--- a/include/svx/AccessibilityCheck.hxx
+++ b/include/svx/AccessibilityCheck.hxx
@@ -17,10 +17,24 @@
 
 namespace svx
 {
+enum class AccessibilityIssueID
+{
+    UNSPECIFIED, // TODO: remove - temporary
+    DOCUMENT_TITLE,
+    DOCUMENT_LANGUAGE,
+    STYLE_LANGUAGE
+};
+
 class SVX_DLLPUBLIC AccessibilityCheckResult final
 {
 public:
+    AccessibilityIssueID m_eIssueID;
     OUString m_aIssueText;
+
+    AccessibilityCheckResult(AccessibilityIssueID eIssueID = AccessibilityIssueID::UNSPECIFIED)
+        : m_eIssueID(eIssueID)
+    {
+    }
 };
 
 class SVX_DLLPUBLIC AccessibilityCheck
diff --git a/sw/CppunitTest_sw_core_accessibilitycheck.mk b/sw/CppunitTest_sw_core_accessibilitycheck.mk
new file mode 100644
index 000000000000..e8ca263bd26b
--- /dev/null
+++ b/sw/CppunitTest_sw_core_accessibilitycheck.mk
@@ -0,0 +1,68 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,sw_core_accessibilitycheck))
+
+$(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_core_accessibilitycheck))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sw_core_accessibilitycheck, \
+    sw/qa/core/accessibilitycheck/AccessibilityCheckTest \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,sw_core_accessibilitycheck, \
+    comphelper \
+    cppu \
+    cppuhelper \
+    sal \
+    sfx \
+    sw \
+    test \
+    unotest \
+    utl \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,sw_core_accessibilitycheck,\
+    boost_headers \
+    libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_set_include,sw_core_accessibilitycheck,\
+    -I$(SRCDIR)/sw/inc \
+    -I$(SRCDIR)/sw/source/core/inc \
+    -I$(SRCDIR)/sw/source/uibase/inc \
+    -I$(SRCDIR)/sw/qa/inc \
+    $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_api,sw_core_accessibilitycheck,\
+    udkapi \
+    offapi \
+    oovbaapi \
+))
+
+$(eval $(call gb_CppunitTest_use_ure,sw_core_accessibilitycheck))
+$(eval $(call gb_CppunitTest_use_vcl,sw_core_accessibilitycheck))
+
+$(eval $(call gb_CppunitTest_use_rdb,sw_core_accessibilitycheck,services))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,sw_core_accessibilitycheck,\
+    officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,sw_core_accessibilitycheck))
+
+$(eval $(call gb_CppunitTest_use_uiconfigs,sw_core_accessibilitycheck, \
+    modules/swriter \
+))
+
+$(eval $(call gb_CppunitTest_use_more_fonts,sw_core_accessibilitycheck))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sw/Module_sw.mk b/sw/Module_sw.mk
index 101d3b73921b..17b60a0eec14 100644
--- a/sw/Module_sw.mk
+++ b/sw/Module_sw.mk
@@ -105,6 +105,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\
     CppunitTest_sw_apitests \
     CppunitTest_sw_unowriter \
     CppunitTest_sw_core_text \
+    CppunitTest_sw_core_accessibilitycheck \
 ))
 
 ifneq ($(DISABLE_GUI),TRUE)
diff --git a/sw/qa/core/accessibilitycheck/AccessibilityCheckTest.cxx b/sw/qa/core/accessibilitycheck/AccessibilityCheckTest.cxx
new file mode 100644
index 000000000000..eff09430e92d
--- /dev/null
+++ b/sw/qa/core/accessibilitycheck/AccessibilityCheckTest.cxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swmodeltestbase.hxx>
+#include <wrtsh.hxx>
+#include <AccessibilityCheck.hxx>
+
+class AccessibilityCheckTest : public SwModelTestBase
+{
+public:
+    SwDoc* createDoc(const char* pName = nullptr)
+    {
+        load("/sw/qa/core/accessibilitycheck/data/", pName);
+        SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+        CPPUNIT_ASSERT(pTextDoc);
+        return pTextDoc->GetDocShell()->GetDoc();
+    }
+};
+
+CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testCheck)
+{
+    SwDoc* pDoc = createDoc("DocumentTest.odt");
+    CPPUNIT_ASSERT(pDoc);
+    sw::AccessibilityCheck aCheck(pDoc);
+    aCheck.check();
+    auto& aResults = aCheck.getResultCollecton();
+    CPPUNIT_ASSERT_EQUAL(size_t(2), aResults.size());
+    CPPUNIT_ASSERT_EQUAL(svx::AccessibilityIssueID::DOCUMENT_LANGUAGE, aResults[0].m_eIssueID);
+    CPPUNIT_ASSERT_EQUAL(svx::AccessibilityIssueID::DOCUMENT_TITLE, aResults[1].m_eIssueID);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/core/accessibilitycheck/data/DocumentTest.odt b/sw/qa/core/accessibilitycheck/data/DocumentTest.odt
new file mode 100644
index 000000000000..65b9a7c2fd46
Binary files /dev/null and b/sw/qa/core/accessibilitycheck/data/DocumentTest.odt differ
diff --git a/sw/source/core/access/AccessibilityCheck.cxx b/sw/source/core/access/AccessibilityCheck.cxx
index 498b4d968d9d..ee3a0b52b0a0 100644
--- a/sw/source/core/access/AccessibilityCheck.cxx
+++ b/sw/source/core/access/AccessibilityCheck.cxx
@@ -290,7 +290,7 @@ public:
         LanguageType eLanguage = rLang.GetLanguage();
         if (eLanguage == LANGUAGE_NONE)
         {
-            svx::AccessibilityCheckResult aResult;
+            svx::AccessibilityCheckResult aResult(svx::AccessibilityIssueID::DOCUMENT_LANGUAGE);
             aResult.m_aIssueText = sDocumentDefaultLanguage;
             m_rResultCollection.push_back(aResult);
         }
@@ -301,7 +301,8 @@ public:
                 const SwAttrSet& rAttrSet = pTextFormatCollection->GetAttrSet();
                 if (rAttrSet.GetLanguage(false).GetLanguage() == LANGUAGE_NONE)
                 {
-                    svx::AccessibilityCheckResult aResult;
+                    svx::AccessibilityCheckResult aResult(
+                        svx::AccessibilityIssueID::STYLE_LANGUAGE);
                     OUString sName = pTextFormatCollection->GetName();
                     aResult.m_aIssueText = sStyleNoLanguage.replaceAll("%STYLE_NAME%", sName);
                     m_rResultCollection.push_back(aResult);
@@ -331,7 +332,7 @@ public:
             OUString sTitle = xDocumentProperties->getTitle();
             if (sTitle.isEmpty())
             {
-                svx::AccessibilityCheckResult aResult;
+                svx::AccessibilityCheckResult aResult(svx::AccessibilityIssueID::DOCUMENT_TITLE);
                 aResult.m_aIssueText = sDocumentTitle;
                 m_rResultCollection.push_back(aResult);
             }
diff --git a/sw/source/core/inc/AccessibilityCheck.hxx b/sw/source/core/inc/AccessibilityCheck.hxx
index 9e77ca15e125..30bcb90e00a1 100644
--- a/sw/source/core/inc/AccessibilityCheck.hxx
+++ b/sw/source/core/inc/AccessibilityCheck.hxx
@@ -16,7 +16,7 @@
 
 namespace sw
 {
-class AccessibilityCheck final : public svx::AccessibilityCheck
+class SW_DLLPUBLIC AccessibilityCheck final : public svx::AccessibilityCheck
 {
 private:
     SwDoc* m_pDoc;
commit 4c559d38ad43bd345b9432ee24ee2661dc05f069
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun Dec 15 10:26:22 2019 +0100
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Wed Dec 25 13:39:17 2019 +0100

    acc. check: check document contains a document title (metadata)
    
    Change-Id: I09dd2143153e787730d1528de030d8777edcb05f

diff --git a/sw/source/core/access/AccessibilityCheck.cxx b/sw/source/core/access/AccessibilityCheck.cxx
index e342df2e5bd2..498b4d968d9d 100644
--- a/sw/source/core/access/AccessibilityCheck.cxx
+++ b/sw/source/core/access/AccessibilityCheck.cxx
@@ -12,11 +12,13 @@
 #include <ndgrf.hxx>
 #include <ndole.hxx>
 #include <ndtxt.hxx>
+#include <docsh.hxx>
 #include <IDocumentDrawModelAccess.hxx>
 #include <drawdoc.hxx>
 #include <svx/svdpage.hxx>
 #include <swtable.hxx>
 #include <com/sun/star/text/XTextContent.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
 #include <unoparagraph.hxx>
 #include <tools/urlobj.hxx>
 #include <editeng/langitem.hxx>
@@ -33,6 +35,7 @@ OUString sFakeNumbering("Fake numbering '%NUMBERING%'");
 OUString sHyperlinkTextIsLink("Hyperlink text is the same as the link address '%LINK%'");
 OUString sDocumentDefaultLanguage("Document default language is not set");
 OUString sStyleNoLanguage("Style '%STYLE_NAME%' has no language set");
+OUString sDocumentTitle("Document title is not set");
 }
 
 class BaseCheck
@@ -308,6 +311,34 @@ public:
     }
 };
 
+class DocumentTitleCheck : public DocumentCheck
+{
+public:
+    DocumentTitleCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
+        : DocumentCheck(rResultCollection)
+    {
+    }
+
+    void check(SwDoc* pDoc) override
+    {
+        SwDocShell* pShell = pDoc->GetDocShell();
+        if (pShell)
+        {
+            const uno::Reference<document::XDocumentPropertiesSupplier> xDPS(pShell->GetModel(),
+                                                                             uno::UNO_QUERY_THROW);
+            const uno::Reference<document::XDocumentProperties> xDocumentProperties(
+                xDPS->getDocumentProperties());
+            OUString sTitle = xDocumentProperties->getTitle();
+            if (sTitle.isEmpty())
+            {
+                svx::AccessibilityCheckResult aResult;
+                aResult.m_aIssueText = sDocumentTitle;
+                m_rResultCollection.push_back(aResult);
+            }
+        }
+    }
+};
+
 // Check Shapes, TextBox
 void AccessibilityCheck::checkObject(SdrObject* pObject)
 {
@@ -334,6 +365,7 @@ void AccessibilityCheck::check()
 
     std::vector<std::unique_ptr<DocumentCheck>> aDocumentChecks;
     aDocumentChecks.push_back(std::make_unique<DocumentDefaultLanguageCheck>(m_aResultCollection));
+    aDocumentChecks.push_back(std::make_unique<DocumentTitleCheck>(m_aResultCollection));
 
     for (std::unique_ptr<DocumentCheck>& rpDocumentCheck : aDocumentChecks)
     {
commit c173cce99f0226cd0f0d7a8be672110926972d85
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun Dec 15 10:19:24 2019 +0100
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Wed Dec 25 13:39:17 2019 +0100

    acc. check: check document default language and style language
    
    This checks hat the defualt language of the document is set and
    in addition that the used styles also have the default language
    set. Accessibility requires the language always be set.
    
    Change-Id: I6ea36e6e8b30289cdb35311da9470f856a847b38

diff --git a/sw/source/core/access/AccessibilityCheck.cxx b/sw/source/core/access/AccessibilityCheck.cxx
index 230a006a7294..e342df2e5bd2 100644
--- a/sw/source/core/access/AccessibilityCheck.cxx
+++ b/sw/source/core/access/AccessibilityCheck.cxx
@@ -19,6 +19,8 @@
 #include <com/sun/star/text/XTextContent.hpp>
 #include <unoparagraph.hxx>
 #include <tools/urlobj.hxx>
+#include <editeng/langitem.hxx>
+#include <charatr.hxx>
 
 namespace sw
 {
@@ -29,19 +31,31 @@ OUString sNoAlt("No alt text for graphic '%OBJECT_NAME%'");
 OUString sTableMergeSplit("Table '%OBJECT_NAME%' contains merges or splits");
 OUString sFakeNumbering("Fake numbering '%NUMBERING%'");
 OUString sHyperlinkTextIsLink("Hyperlink text is the same as the link address '%LINK%'");
+OUString sDocumentDefaultLanguage("Document default language is not set");
+OUString sStyleNoLanguage("Style '%STYLE_NAME%' has no language set");
 }
 
-class NodeCheck
+class BaseCheck
 {
 protected:
     std::vector<svx::AccessibilityCheckResult>& m_rResultCollection;
 
 public:
-    NodeCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
+    BaseCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
         : m_rResultCollection(rResultCollection)
     {
     }
-    virtual ~NodeCheck() {}
+    virtual ~BaseCheck() {}
+};
+
+class NodeCheck : public BaseCheck
+{
+public:
+    NodeCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
+        : BaseCheck(rResultCollection)
+    {
+    }
+
     virtual void check(SwNode* pCurrent) = 0;
 };
 
@@ -245,6 +259,55 @@ public:
     }
 };
 
+class DocumentCheck : public BaseCheck
+{
+public:
+    DocumentCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
+        : BaseCheck(rResultCollection)
+    {
+    }
+
+    virtual void check(SwDoc* pDoc) = 0;
+};
+
+// Check default language
+class DocumentDefaultLanguageCheck : public DocumentCheck
+{
+public:
+    DocumentDefaultLanguageCheck(std::vector<svx::AccessibilityCheckResult>& rResultCollection)
+        : DocumentCheck(rResultCollection)
+    {
+    }
+
+    void check(SwDoc* pDoc) override
+    {
+        // TODO maybe - also check RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CTL_LANGUAGE if CJK or CTL are enabled
+        const SvxLanguageItem& rLang
+            = static_cast<const SvxLanguageItem&>(pDoc->GetDefault(RES_CHRATR_LANGUAGE));
+        LanguageType eLanguage = rLang.GetLanguage();
+        if (eLanguage == LANGUAGE_NONE)
+        {
+            svx::AccessibilityCheckResult aResult;
+            aResult.m_aIssueText = sDocumentDefaultLanguage;
+            m_rResultCollection.push_back(aResult);
+        }
+        else
+        {
+            for (SwTextFormatColl* pTextFormatCollection : *pDoc->GetTextFormatColls())
+            {
+                const SwAttrSet& rAttrSet = pTextFormatCollection->GetAttrSet();
+                if (rAttrSet.GetLanguage(false).GetLanguage() == LANGUAGE_NONE)
+                {
+                    svx::AccessibilityCheckResult aResult;
+                    OUString sName = pTextFormatCollection->GetName();
+                    aResult.m_aIssueText = sStyleNoLanguage.replaceAll("%STYLE_NAME%", sName);
+                    m_rResultCollection.push_back(aResult);
+                }
+            }
+        }
+    }
+};
+
 // Check Shapes, TextBox

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list