Repository.mk                           |    2 
 include/sal/log-areas.dox               |    1 
 vcl/Library_vcl.mk                      |    2 
 vcl/Module_vcl.mk                       |    4 
 vcl/Package_skia_blacklist.mk           |   16 
 vcl/inc/driverblocklist.hxx             |  158 +++++++
 vcl/inc/opengl/win/WinDeviceInfo.hxx    |  113 -----
 vcl/inc/opengl/win/blocklist_parser.hxx |   42 -
 vcl/opengl/win/WinDeviceInfo.cxx        |  411 ------------------
 vcl/opengl/win/blocklist_parser.cxx     |  351 ---------------
 vcl/qa/cppunit/blocklistparsertest.cxx  |   94 ++--
 vcl/skia/SkiaHelper.cxx                 |   39 +
 vcl/skia/skia_blacklist_vulkan.xml      |   30 +
 vcl/source/helper/driverblocklist.cxx   |  711 ++++++++++++++++++++++++++++++++
 vcl/source/opengl/OpenGLHelper.cxx      |    4 
 15 files changed, 1007 insertions(+), 971 deletions(-)

New commits:
commit 2b702f7436acf6883b41508277441e5ea0a53d51
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Wed Feb 12 10:23:54 2020 +0100
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Thu Feb 13 15:44:39 2020 +0100

    make OpenGL blacklist file code generic and use it for Skia/Vulkan
    
    Change-Id: Icc150b853f5d2d06afedcb7878f6a031aff57c2b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88533
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/Repository.mk b/Repository.mk
index 7372a01319eb..864438ed63d2 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -951,6 +951,8 @@ $(eval $(call gb_Helper_register_packages_for_install,ooo,\
                vcl_opengl_blacklist \
        ) \
        $(if $(ENABLE_OPENGL_CANVAS),canvas_opengl_shader) \
+       $(if $(filter SKIA,$(BUILD_TYPE)), \
+               vcl_skia_blacklist ) \
        $(if $(DISABLE_PYTHON),,$(if $(filter-out AIX,$(OS)), \
                Pyuno/commonwizards \
                Pyuno/fax \
diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
index 3ebe47afd2b4..ea0c34e5223f 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -463,6 +463,7 @@ certain functionality.
 @li @c vcl.control
 @li @c vcl.ct - CoreText-using code for macOS and iOS
 @li @c vcl.debugevent
+@li @c vcl.driver Graphics driver handling
 @li @c vcl.emf - EMF/EMF+ processing
 @li @c vcl.eventtesting
 @li @c vcl.filter
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 1b5a6db8ec65..ca818e271c22 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -369,6 +369,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
     vcl/source/helper/canvastools \
     vcl/source/helper/commandinfoprovider \
     vcl/source/helper/displayconnectiondispatch \
+    vcl/source/helper/driverblocklist \
     vcl/source/helper/errcode \
     vcl/source/helper/evntpost \
     vcl/source/helper/lazydelete \
@@ -702,7 +703,6 @@ endif
 ifeq ($(OS),WNT)
 $(eval $(call gb_Library_add_exception_objects,vcl,\
     vcl/opengl/win/WinDeviceInfo \
-    vcl/opengl/win/blocklist_parser \
     vcl/source/app/salplug \
 ))
 
diff --git a/vcl/Module_vcl.mk b/vcl/Module_vcl.mk
index 5620f188c7f2..9736be35fedf 100644
--- a/vcl/Module_vcl.mk
+++ b/vcl/Module_vcl.mk
@@ -27,6 +27,8 @@ $(eval $(call gb_Module_add_targets,vcl,\
     UIConfig_vcl \
        $(if $(filter WNT,$(OS)), \
                Package_opengl_blacklist ) \
+       $(if $(filter SKIA,$(BUILD_TYPE)), \
+               Package_skia_blacklist ) \
     $(if $(filter DESKTOP,$(BUILD_TYPE)), \
         StaticLibrary_vclmain \
                $(if $(ENABLE_MACOSX_SANDBOX),, \
@@ -204,6 +206,7 @@ $(eval $(call gb_Module_add_check_targets,vcl,\
        CppunitTest_vcl_png_test \
        CppunitTest_vcl_widget_definition_reader_test \
        CppunitTest_vcl_backend_test \
+       CppunitTest_vcl_blocklistparser_test \
 ))
 
 ifeq ($(USING_X11),TRUE)
@@ -222,7 +225,6 @@ endif
 ifeq ($(OS),WNT)
 $(eval $(call gb_Module_add_check_targets,vcl,\
        CppunitTest_vcl_timer \
-       CppunitTest_vcl_blocklistparser_test \
 ))
 endif
 
diff --git a/vcl/Package_skia_blacklist.mk b/vcl/Package_skia_blacklist.mk
new file mode 100644
index 000000000000..611766eb7aa3
--- /dev/null
+++ b/vcl/Package_skia_blacklist.mk
@@ -0,0 +1,16 @@
+# -*- 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_Package_Package,vcl_skia_blacklist,$(SRCDIR)/vcl/skia))
+
+$(eval $(call 
gb_Package_add_files,vcl_skia_blacklist,$(LIBO_SHARE_FOLDER)/skia,\
+       skia_blacklist_vulkan.xml \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/vcl/inc/driverblocklist.hxx b/vcl/inc/driverblocklist.hxx
new file mode 100644
index 000000000000..e8f99378fa24
--- /dev/null
+++ b/vcl/inc/driverblocklist.hxx
@@ -0,0 +1,158 @@
+/* -*- 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_DRIVERBLOCKLIST_HXX
+#define INCLUDED_VCL_DRIVERBLOCKLIST_HXX
+
+#include <vcl/dllapi.h>
+#include <xmlreader/xmlreader.hxx>
+#include <vector>
+
+namespace DriverBlocklist
+{
+VCL_DLLPUBLIC bool IsDeviceBlocked(const OUString& blocklistURL, const 
OUString& driverVersion,
+                                   const OUString& vendorId, const OUString& 
deviceId);
+
+#ifdef _WIN32
+VCL_DLLPUBLIC int32_t GetWindowsVersion();
+#endif
+
+// The rest should be private (only for the unittest).
+
+struct InvalidFileException
+{
+};
+
+enum OperatingSystem
+{
+    DRIVER_OS_UNKNOWN = 0,
+    DRIVER_OS_WINDOWS_7,
+    DRIVER_OS_WINDOWS_8,
+    DRIVER_OS_WINDOWS_8_1,
+    DRIVER_OS_WINDOWS_10,
+    DRIVER_OS_LINUX,
+    DRIVER_OS_OSX_10_5,
+    DRIVER_OS_OSX_10_6,
+    DRIVER_OS_OSX_10_7,
+    DRIVER_OS_OSX_10_8,
+    DRIVER_OS_ANDROID,
+    DRIVER_OS_ALL
+};
+
+enum VersionComparisonOp
+{
+    DRIVER_LESS_THAN, // driver <  version
+    DRIVER_LESS_THAN_OR_EQUAL, // driver <= version
+    DRIVER_GREATER_THAN, // driver >  version
+    DRIVER_GREATER_THAN_OR_EQUAL, // driver >= version
+    DRIVER_EQUAL, // driver == version
+    DRIVER_NOT_EQUAL, // driver != version
+    DRIVER_BETWEEN_EXCLUSIVE, // driver > version && driver < versionMax
+    DRIVER_BETWEEN_INCLUSIVE, // driver >= version && driver <= versionMax
+    DRIVER_BETWEEN_INCLUSIVE_START, // driver >= version && driver < versionMax
+    DRIVER_COMPARISON_IGNORED
+};
+
+enum DeviceVendor
+{
+    VendorAll,
+    VendorIntel,
+    VendorNVIDIA,
+    VendorAMD,
+    VendorATI,
+    VendorMicrosoft,
+};
+const int DeviceVendorMax = VendorMicrosoft + 1;
+
+struct DriverInfo
+{
+    DriverInfo(OperatingSystem os, const OUString& vendor, VersionComparisonOp 
op,
+               uint64_t driverVersion, bool bWhiteListed = false,
+               const char* suggestedVersion = nullptr);
+
+    DriverInfo();
+
+    OperatingSystem meOperatingSystem;
+    OUString maAdapterVendor;
+    std::vector<OUString> maDevices;
+
+    bool mbWhitelisted;
+
+    VersionComparisonOp meComparisonOp;
+
+    /* versions are assumed to be A.B.C.D packed as 0xAAAABBBBCCCCDDDD */
+    uint64_t mnDriverVersion;
+    uint64_t mnDriverVersionMax;
+    static uint64_t allDriverVersions;
+
+    OUString maSuggestedVersion;
+    OUString maMsg;
+};
+
+class VCL_DLLPUBLIC Parser
+{
+public:
+    Parser(const OUString& rURL, std::vector<DriverInfo>& rDriverList);
+    bool parse();
+
+private:
+    void handleEntry(DriverInfo& rDriver, xmlreader::XmlReader& rReader);
+    void handleList(xmlreader::XmlReader& rReader);
+    void handleContent(xmlreader::XmlReader& rReader);
+    static void handleDevices(DriverInfo& rDriver, xmlreader::XmlReader& 
rReader);
+
+    enum class BlockType
+    {
+        WHITELIST,
+        BLACKLIST,
+        UNKNOWN
+    };
+
+    BlockType meBlockType;
+    std::vector<DriverInfo>& mrDriverList;
+    OUString maURL;
+};
+
+OUString VCL_DLLPUBLIC GetVendorId(DeviceVendor id);
+
+bool VCL_DLLPUBLIC FindBlocklistedDeviceInList(std::vector<DriverInfo>& 
aDeviceInfos,
+                                               OUString const& sDriverVersion,
+                                               OUString const& 
sAdapterVendorID,
+                                               OUString const& 
sAdapterDeviceID,
+                                               OperatingSystem system,
+                                               const OUString& blocklistURL = 
OUString());
+
+#define GFX_DRIVER_VERSION(a, b, c, d)                                         
                    \
+    ((uint64_t(a) << 48) | (uint64_t(b) << 32) | (uint64_t(c) << 16) | 
uint64_t(d))
+
+inline uint64_t V(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
+{
+    // We make sure every driver number is padded by 0s, this will allow us the
+    // easiest 'compare as if decimals' approach. See ParseDriverVersion for a
+    // more extensive explanation of this approach.
+    while (b > 0 && b < 1000)
+    {
+        b *= 10;
+    }
+    while (c > 0 && c < 1000)
+    {
+        c *= 10;
+    }
+    while (d > 0 && d < 1000)
+    {
+        d *= 10;
+    }
+    return GFX_DRIVER_VERSION(a, b, c, d);
+}
+
+} // namespace
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/opengl/win/WinDeviceInfo.hxx 
b/vcl/inc/opengl/win/WinDeviceInfo.hxx
index 773be7af0f7d..04d97406b54a 100644
--- a/vcl/inc/opengl/win/WinDeviceInfo.hxx
+++ b/vcl/inc/opengl/win/WinDeviceInfo.hxx
@@ -13,108 +13,12 @@
 #include <vcl/dllapi.h>
 
 #include <opengl/DeviceInfo.hxx>
+#include <driverblocklist.hxx>
 
 #include <rtl/ustring.hxx>
 #include <vector>
 #include <cstdint>
 
-namespace wgl {
-
-enum OperatingSystem {
-    DRIVER_OS_UNKNOWN = 0,
-    DRIVER_OS_WINDOWS_7,
-    DRIVER_OS_WINDOWS_8,
-    DRIVER_OS_WINDOWS_8_1,
-    DRIVER_OS_WINDOWS_10,
-    DRIVER_OS_LINUX,
-    DRIVER_OS_OS_X_10_5,
-    DRIVER_OS_OS_X_10_6,
-    DRIVER_OS_OS_X_10_7,
-    DRIVER_OS_OS_X_10_8,
-    DRIVER_OS_ANDROID,
-    DRIVER_OS_ALL
-};
-
-enum VersionComparisonOp {
-    DRIVER_LESS_THAN,             // driver <  version
-    DRIVER_LESS_THAN_OR_EQUAL,    // driver <= version
-    DRIVER_GREATER_THAN,          // driver >  version
-    DRIVER_GREATER_THAN_OR_EQUAL, // driver >= version
-    DRIVER_EQUAL,                 // driver == version
-    DRIVER_NOT_EQUAL,             // driver != version
-    DRIVER_BETWEEN_EXCLUSIVE,     // driver > version && driver < versionMax
-    DRIVER_BETWEEN_INCLUSIVE,     // driver >= version && driver <= versionMax
-    DRIVER_BETWEEN_INCLUSIVE_START, // driver >= version && driver < versionMax
-    DRIVER_COMPARISON_IGNORED
-};
-
-enum DeviceVendor {
-    VendorAll,
-    VendorIntel,
-    VendorNVIDIA,
-    VendorAMD,
-    VendorATI,
-    VendorMicrosoft,
-    DeviceVendorMax
-};
-
-bool ParseDriverVersion(const OUString& rString, uint64_t& rVersion);
-
-struct VCL_DLLPUBLIC DriverInfo
-{
-
-    DriverInfo(OperatingSystem os, const OUString& vendor, VersionComparisonOp 
op,
-            uint64_t driverVersion, bool bWhiteListed = false, const char 
*suggestedVersion = nullptr);
-
-    DriverInfo();
-    virtual ~DriverInfo();
-
-    OperatingSystem meOperatingSystem;
-    uint32_t mnOperatingSystemVersion;
-
-    OUString maAdapterVendor;
-
-    std::vector<OUString> maDevices;
-
-    // Whether the mDevices array should be deleted when this structure is
-    // deallocated. False by default.
-    bool mbDeleteDevices;
-
-    bool mbWhitelisted;
-
-    VersionComparisonOp meComparisonOp;
-
-    /* versions are assumed to be A.B.C.D packed as 0xAAAABBBBCCCCDDDD */
-    uint64_t mnDriverVersion;
-    uint64_t mnDriverVersionMax;
-    static uint64_t allDriverVersions;
-
-    OUString maSuggestedVersion;
-    OUString maMsg;
-};
-
-#define GFX_DRIVER_VERSION(a,b,c,d) \
-    ((uint64_t(a)<<48) | (uint64_t(b)<<32) | (uint64_t(c)<<16) | uint64_t(d))
-
-inline VCL_DLLPUBLIC uint64_t V(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
-{
-    // We make sure every driver number is padded by 0s, this will allow us the
-    // easiest 'compare as if decimals' approach. See ParseDriverVersion for a
-    // more extensive explanation of this approach.
-    while (b > 0 && b < 1000) {
-        b *= 10;
-    }
-    while (c > 0 && c < 1000) {
-        c *= 10;
-    }
-    while (d > 0 && d < 1000) {
-        d *= 10;
-    }
-    return GFX_DRIVER_VERSION(a, b, c, d);
-}
-
-}
-
 class VCL_DLLPUBLIC WinOpenGLDeviceInfo : public OpenGLDeviceInfo
 {
 private:
@@ -140,22 +44,16 @@ private:
 
     OUString maDeviceString;
     OUString maDeviceString2;
-    uint32_t mnWindowsVersion;
 
     bool mbHasDualGPU;
     bool mbRDP;
 
     void GetData();
-    static void FillBlacklist();
     bool FindBlocklistedDeviceInList();
 
-    static OUString* mpDeviceVendors[wgl::DeviceVendorMax];
-    static std::vector<wgl::DriverInfo> maDriverInfo;
-
 public:
     WinOpenGLDeviceInfo();
 
-    static OUString GetDeviceVendor(wgl::DeviceVendor eVendor);
     virtual ~WinOpenGLDeviceInfo() override;
 
     virtual bool isDeviceBlocked() override;
@@ -198,15 +96,6 @@ public:
     {
         return maDeviceString;
     }
-
-    sal_uInt32 GetWindowsVersion() const
-    {
-        return mnWindowsVersion;
-    }
-
-    static bool FindBlocklistedDeviceInList(std::vector<wgl::DriverInfo>& 
aDeviceInfos,
-                                            OUString const & sDriverVersion, 
OUString const & sAdapterVendorID,
-                                            OUString const & sAdapterDeviceID, 
uint32_t nWindowsVersion);
 };
 
 #endif
diff --git a/vcl/inc/opengl/win/blocklist_parser.hxx 
b/vcl/inc/opengl/win/blocklist_parser.hxx
deleted file mode 100644
index 1d1ea314d6f7..000000000000
--- a/vcl/inc/opengl/win/blocklist_parser.hxx
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- 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 <vcl/dllapi.h>
-#include <xmlreader/xmlreader.hxx>
-#include <vector>
-#include <opengl/win/WinDeviceInfo.hxx>
-
-class InvalidFileException
-{
-};
-
-class VCL_DLLPUBLIC WinBlocklistParser
-{
-public:
-    WinBlocklistParser(const OUString& rURL, std::vector<wgl::DriverInfo>& 
rDriverList);
-    void parse();
-
-private:
-    void handleEntry(wgl::DriverInfo& rDriver, xmlreader::XmlReader& rReader);
-    void handleList(xmlreader::XmlReader& rReader);
-    void handleContent(xmlreader::XmlReader& rReader);
-
-    enum class BlockType
-    {
-        WHITELIST,
-        BLACKLIST,
-        UNKNOWN
-    };
-
-    BlockType meBlockType;
-    std::vector<wgl::DriverInfo>& mrDriverList;
-    OUString maURL;
-};
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/win/WinDeviceInfo.cxx b/vcl/opengl/win/WinDeviceInfo.cxx
index 0e466ecd6d4e..3fb4035ec58c 100644
--- a/vcl/opengl/win/WinDeviceInfo.cxx
+++ b/vcl/opengl/win/WinDeviceInfo.cxx
@@ -9,7 +9,7 @@
 
 #include <opengl/win/WinDeviceInfo.hxx>
 
-#include <opengl/win/blocklist_parser.hxx>
+#include <driverblocklist.hxx>
 #include <config_folders.h>
 
 #if !defined WIN32_LEAN_AND_MEAN
@@ -31,23 +31,8 @@
 
 #include <desktop/crashreport.hxx>
 
-OUString* WinOpenGLDeviceInfo::mpDeviceVendors[wgl::DeviceVendorMax];
-std::vector<wgl::DriverInfo> WinOpenGLDeviceInfo::maDriverInfo;
-
 namespace {
 
-/*
- * Compute the length of an array with constant length.  (Use of this method
- * with a non-array pointer will not compile.)
- *
- * Beware of the implicit trailing '\0' when using this with string constants.
-*/
-template<typename T, size_t N>
-size_t ArrayLength(T (&)[N])
-{
-    return N;
-}
-
 bool GetKeyValue(const WCHAR* keyLocation, const WCHAR* keyName, OUString& 
destString, int type)
 {
     HKEY key;
@@ -146,142 +131,6 @@ uint32_t ParseIDFromDeviceID(const OUString &key, const 
char *prefix, int length
     return id.toUInt32(16);
 }
 
-// OS version in 16.16 major/minor form
-// based on http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx
-enum {
-    kWindowsUnknown    = 0,
-    kWindows7          = 0x00060001,
-    kWindows8          = 0x00060002,
-    kWindows8_1        = 0x00060003,
-    kWindows10         = 0x000A0000  // Major 10 Minor 0
-};
-
-
-wgl::OperatingSystem WindowsVersionToOperatingSystem(int32_t aWindowsVersion)
-{
-    switch(aWindowsVersion)
-    {
-        case kWindows7:
-            return wgl::DRIVER_OS_WINDOWS_7;
-        case kWindows8:
-            return wgl::DRIVER_OS_WINDOWS_8;
-        case kWindows8_1:
-            return wgl::DRIVER_OS_WINDOWS_8_1;
-        case kWindows10:
-            return wgl::DRIVER_OS_WINDOWS_10;
-        case kWindowsUnknown:
-        default:
-            return wgl::DRIVER_OS_UNKNOWN;
-    };
-}
-
-
-int32_t WindowsOSVersion()
-{
-    static int32_t winVersion = [&]()
-    {
-        // GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API 
are
-        // subject to manifest-based behavior since Windows 8.1, so give wrong 
results.
-        // Another approach would be to use NetWkstaGetInfo, but that has some 
small
-        // reported delays (some milliseconds), and might get slower in 
domains with
-        // poor network connections.
-        // So go with a solution described at 
https://msdn.microsoft.com/en-us/library/ms724429
-        HINSTANCE hLibrary = LoadLibraryW(L"kernel32.dll");
-        if (hLibrary != nullptr)
-        {
-            wchar_t szPath[MAX_PATH];
-            DWORD dwCount = GetModuleFileNameW(hLibrary, szPath, 
SAL_N_ELEMENTS(szPath));
-            FreeLibrary(hLibrary);
-            if (dwCount != 0 && dwCount < SAL_N_ELEMENTS(szPath))
-            {
-                dwCount = GetFileVersionInfoSizeW(szPath, nullptr);
-                if (dwCount != 0)
-                {
-                    std::unique_ptr<char[]> ver(new char[dwCount]);
-                    if (GetFileVersionInfoW(szPath, 0, dwCount, ver.get()) != 
FALSE)
-                    {
-                        void* pBlock = nullptr;
-                        UINT dwBlockSz = 0;
-                        if (VerQueryValueW(ver.get(), L"\\", &pBlock, 
&dwBlockSz) != FALSE && dwBlockSz >= sizeof(VS_FIXEDFILEINFO))
-                        {
-                            VS_FIXEDFILEINFO *vinfo = 
static_cast<VS_FIXEDFILEINFO *>(pBlock);
-                            return int32_t(vinfo->dwProductVersionMS);
-                        }
-                    }
-                }
-            }
-        }
-        return int32_t(kWindowsUnknown);
-    }();
-
-    return winVersion;
-}
-
-// This allows us to pad driver version 'substrings' with 0s, this
-// effectively allows us to treat the version numbers as 'decimals'. This is
-// a little strange but this method seems to do the right thing for all
-// different vendor's driver strings. i.e. .98 will become 9800, which is
-// larger than .978 which would become 9780.
-void PadDriverDecimal(char *aString)
-{
-    for (int i = 0; i < 4; i++)
-    {
-        if (!aString[i])
-        {
-            for (int c = i; c < 4; c++)
-            {
-                aString[c] = '0';
-            }
-            break;
-        }
-    }
-    aString[4] = 0;
-}
-
-// All destination string storage needs to have at least 5 bytes available.
-bool SplitDriverVersion(const char *aSource, char *aAStr, char *aBStr, char 
*aCStr, char *aDStr)
-{
-    // sscanf doesn't do what we want here to we parse this manually.
-    int len = strlen(aSource);
-    char *dest[4] = { aAStr, aBStr, aCStr, aDStr };
-    unsigned destIdx = 0;
-    unsigned destPos = 0;
-
-    for (int i = 0; i < len; i++)
-    {
-        if (destIdx >= ArrayLength(dest))
-        {
-            // Invalid format found. Ensure we don't access dest beyond bounds.
-            return false;
-        }
-
-        if (aSource[i] == '.')
-        {
-            dest[destIdx++][destPos] = 0;
-            destPos = 0;
-            continue;
-        }
-
-        if (destPos > 3)
-        {
-            // Ignore more than 4 chars. Ensure we never access dest[destIdx]
-            // beyond its bounds.
-            continue;
-        }
-
-        dest[destIdx][destPos++] = aSource[i];
-    }
-
-    // Add last terminator.
-    dest[destIdx][destPos] = 0;
-
-    if (destIdx != ArrayLength(dest) - 1)
-    {
-        return false;
-    }
-    return true;
-}
-
 /* Other interesting places for info:
  *   IDXGIAdapter::GetDesc()
  *   IDirectDraw7::GetAvailableVidMem()
@@ -306,202 +155,28 @@ template<typename T> void 
appendIntegerWithPadding(OUString& rString, T value, s
 #define DEVICE_KEY_PREFIX L"\\Registry\\Machine\\"
 }
 
-namespace wgl {
-
-bool ParseDriverVersion(const OUString& aVersion, uint64_t& rNumericVersion)
-{
-    rNumericVersion = 0;
-
-#if defined(_WIN32)
-    int a, b, c, d;
-    char aStr[8], bStr[8], cStr[8], dStr[8];
-    /* honestly, why do I even bother */
-    OString aOVersion = OUStringToOString(aVersion, RTL_TEXTENCODING_UTF8);
-    if (!SplitDriverVersion(aOVersion.getStr(), aStr, bStr, cStr, dStr))
-        return false;
-
-    PadDriverDecimal(bStr);
-    PadDriverDecimal(cStr);
-    PadDriverDecimal(dStr);
-
-    a = atoi(aStr);
-    b = atoi(bStr);
-    c = atoi(cStr);
-    d = atoi(dStr);
-
-    if (a < 0 || a > 0xffff) return false;
-    if (b < 0 || b > 0xffff) return false;
-    if (c < 0 || c > 0xffff) return false;
-    if (d < 0 || d > 0xffff) return false;
-
-    rNumericVersion = GFX_DRIVER_VERSION(a, b, c, d);
-    return true;
-#else
-    return false;
-#endif
-}
-
-uint64_t DriverInfo::allDriverVersions = ~(uint64_t(0));
-
-DriverInfo::DriverInfo()
-    : meOperatingSystem(wgl::DRIVER_OS_UNKNOWN),
-    mnOperatingSystemVersion(0),
-    maAdapterVendor(WinOpenGLDeviceInfo::GetDeviceVendor(VendorAll)),
-    mbWhitelisted(false),
-    meComparisonOp(DRIVER_COMPARISON_IGNORED),
-    mnDriverVersion(0),
-    mnDriverVersionMax(0)
-{}
-
-DriverInfo::DriverInfo(OperatingSystem os, const OUString& vendor,
-        VersionComparisonOp op,
-        uint64_t driverVersion,
-        bool bWhitelisted,
-        const char *suggestedVersion /* = nullptr */)
-    : meOperatingSystem(os),
-    mnOperatingSystemVersion(0),
-    maAdapterVendor(vendor),
-    mbWhitelisted(bWhitelisted),
-    meComparisonOp(op),
-    mnDriverVersion(driverVersion),
-    mnDriverVersionMax(0)
-{
-    if (suggestedVersion)
-        maSuggestedVersion = OStringToOUString(OString(suggestedVersion), 
RTL_TEXTENCODING_UTF8);
-}
-
-DriverInfo::~DriverInfo()
-{
-}
-
-}
-
 WinOpenGLDeviceInfo::WinOpenGLDeviceInfo():
     mbHasDualGPU(false),
     mbRDP(false)
 {
     GetData();
-    FillBlacklist();
 }
 
 WinOpenGLDeviceInfo::~WinOpenGLDeviceInfo()
 {
 }
 
-namespace {
-
-struct compareIgnoreAsciiCase
+static OUString getBlacklistFile()
 {
-    explicit compareIgnoreAsciiCase(const OUString& rString)
-        : maString(rString)
-    {
-    }
-
-    bool operator()(const OUString& rCompare)
-    {
-        return maString.equalsIgnoreAsciiCase(rCompare);
-    }
-
-private:
-    OUString maString;
-};
-
-}
-
-bool 
WinOpenGLDeviceInfo::FindBlocklistedDeviceInList(std::vector<wgl::DriverInfo>& 
aDeviceInfos,
-                                                      OUString const & 
sDriverVersion, OUString const & sAdapterVendorID,
-                                                      OUString const & 
sAdapterDeviceID, uint32_t nWindowsVersion)
-{
-    uint64_t driverVersion;
-    wgl::ParseDriverVersion(sDriverVersion, driverVersion);
-
-    wgl::OperatingSystem eOS = 
WindowsVersionToOperatingSystem(nWindowsVersion);
-    bool match = false;
-    for (std::vector<wgl::DriverInfo>::size_type i = 0; i < 
aDeviceInfos.size(); i++)
-    {
-        if (aDeviceInfos[i].meOperatingSystem != wgl::DRIVER_OS_ALL &&
-                aDeviceInfos[i].meOperatingSystem != eOS)
-        {
-            continue;
-        }
-
-        if (aDeviceInfos[i].mnOperatingSystemVersion && 
aDeviceInfos[i].mnOperatingSystemVersion != nWindowsVersion)
-        {
-            continue;
-        }
-
-        if 
(!aDeviceInfos[i].maAdapterVendor.equalsIgnoreAsciiCase(GetDeviceVendor(wgl::VendorAll))
 &&
-                
!aDeviceInfos[i].maAdapterVendor.equalsIgnoreAsciiCase(sAdapterVendorID))
-        {
-            continue;
-        }
-
-        if (std::none_of(aDeviceInfos[i].maDevices.begin(), 
aDeviceInfos[i].maDevices.end(), compareIgnoreAsciiCase("all")) &&
-            std::none_of(aDeviceInfos[i].maDevices.begin(), 
aDeviceInfos[i].maDevices.end(), compareIgnoreAsciiCase(sAdapterDeviceID)))
-        {
-            continue;
-        }
-
-        switch (aDeviceInfos[i].meComparisonOp)
-        {
-            case wgl::DRIVER_LESS_THAN:
-                match = driverVersion < aDeviceInfos[i].mnDriverVersion;
-                break;
-            case wgl::DRIVER_LESS_THAN_OR_EQUAL:
-                match = driverVersion <= aDeviceInfos[i].mnDriverVersion;
-                break;
-            case wgl::DRIVER_GREATER_THAN:
-                match = driverVersion > aDeviceInfos[i].mnDriverVersion;
-                break;
-            case wgl::DRIVER_GREATER_THAN_OR_EQUAL:
-                match = driverVersion >= aDeviceInfos[i].mnDriverVersion;
-                break;
-            case wgl::DRIVER_EQUAL:
-                match = driverVersion == aDeviceInfos[i].mnDriverVersion;
-                break;
-            case wgl::DRIVER_NOT_EQUAL:
-                match = driverVersion != aDeviceInfos[i].mnDriverVersion;
-                break;
-            case wgl::DRIVER_BETWEEN_EXCLUSIVE:
-                match = driverVersion > aDeviceInfos[i].mnDriverVersion && 
driverVersion < aDeviceInfos[i].mnDriverVersionMax;
-                break;
-            case wgl::DRIVER_BETWEEN_INCLUSIVE:
-                match = driverVersion >= aDeviceInfos[i].mnDriverVersion && 
driverVersion <= aDeviceInfos[i].mnDriverVersionMax;
-                break;
-            case wgl::DRIVER_BETWEEN_INCLUSIVE_START:
-                match = driverVersion >= aDeviceInfos[i].mnDriverVersion && 
driverVersion < aDeviceInfos[i].mnDriverVersionMax;
-                break;
-            case wgl::DRIVER_COMPARISON_IGNORED:
-                // We don't have a comparison op, so we match everything.
-                match = true;
-                break;
-            default:
-                SAL_WARN("vcl.opengl", "Bogus op in GfxDriverInfo");
-                break;
-        }
-
-        if (match || aDeviceInfos[i].mnDriverVersion == 
wgl::DriverInfo::allDriverVersions)
-        {
-            // white listed drivers
-            if (aDeviceInfos[i].mbWhitelisted)
-            {
-                SAL_WARN("vcl.opengl", "whitelisted driver");
-                return false;
-            }
-
-            match = true;
-            SAL_WARN("vcl.opengl", "use : " << 
aDeviceInfos[i].maSuggestedVersion);
-            break;
-        }
-    }
+    OUString url("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER);
+    rtl::Bootstrap::expandMacros(url);
 
-    SAL_INFO("vcl.opengl", (match ? "BLACKLISTED" : "not blacklisted"));
-    return match;
+    return url + "/opengl/opengl_blacklist_windows.xml";
 }
 
 bool WinOpenGLDeviceInfo::FindBlocklistedDeviceInList()
 {
-    return FindBlocklistedDeviceInList(maDriverInfo, maDriverVersion, 
maAdapterVendorID, maAdapterDeviceID, mnWindowsVersion);
+    return DriverBlocklist::IsDeviceBlocked( getBlacklistFile(), 
maDriverVersion, maAdapterVendorID, maAdapterDeviceID);
 }
 
 namespace {
@@ -573,7 +248,6 @@ void WinOpenGLDeviceInfo::GetData()
     DISPLAY_DEVICEW displayDevice;
     displayDevice.cb = sizeof(displayDevice);
 
-    mnWindowsVersion = WindowsOSVersion();
     int deviceIndex = 0;
 
     while (EnumDisplayDevicesW(nullptr, deviceIndex, &displayDevice, 0))
@@ -587,8 +261,8 @@ void WinOpenGLDeviceInfo::GetData()
 
     // make sure the string is null terminated
     // (using the term "null" here to mean a zero UTF-16 unit)
-    if (wcsnlen(displayDevice.DeviceKey, ArrayLength(displayDevice.DeviceKey))
-            == ArrayLength(displayDevice.DeviceKey))
+    if (wcsnlen(displayDevice.DeviceKey, 
SAL_N_ELEMENTS(displayDevice.DeviceKey))
+            == SAL_N_ELEMENTS(displayDevice.DeviceKey))
     {
         // we did not find a null
         SAL_WARN("vcl.opengl", "string not null terminated");
@@ -598,14 +272,14 @@ void WinOpenGLDeviceInfo::GetData()
     /* DeviceKey is "reserved" according to MSDN so we'll be careful with it */
     /* check that DeviceKey begins with DEVICE_KEY_PREFIX */
     /* some systems have a DeviceKey starting with \REGISTRY\Machine\ so we 
need to compare case insensitively */
-    if (_wcsnicmp(displayDevice.DeviceKey, DEVICE_KEY_PREFIX, 
ArrayLength(DEVICE_KEY_PREFIX)-1) != 0)
+    if (_wcsnicmp(displayDevice.DeviceKey, DEVICE_KEY_PREFIX, 
SAL_N_ELEMENTS(DEVICE_KEY_PREFIX)-1) != 0)
     {
         SAL_WARN("vcl.opengl", "incorrect DeviceKey");
         return;
     }
 
     // chop off DEVICE_KEY_PREFIX
-    maDeviceKey = o3tl::toU(displayDevice.DeviceKey) + 
ArrayLength(DEVICE_KEY_PREFIX)-1;
+    maDeviceKey = o3tl::toU(displayDevice.DeviceKey) + 
SAL_N_ELEMENTS(DEVICE_KEY_PREFIX)-1;
 
     maDeviceID = o3tl::toU(displayDevice.DeviceID);
     maDeviceString = o3tl::toU(displayDevice.DeviceString);
@@ -816,69 +490,4 @@ void WinOpenGLDeviceInfo::GetData()
     }
 }
 
-OUString WinOpenGLDeviceInfo::GetDeviceVendor(wgl::DeviceVendor id)
-{
-    assert(id >= 0 && id < wgl::DeviceVendorMax);
-
-    if (mpDeviceVendors[id])
-        return *mpDeviceVendors[id];
-
-    mpDeviceVendors[id] = new OUString();
-
-    switch (id)
-    {
-        case wgl::VendorAll:
-            *mpDeviceVendors[id] = "";
-        break;
-        case wgl::VendorIntel:
-            *mpDeviceVendors[id] = "0x8086";
-        break;
-        case wgl::VendorNVIDIA:
-            *mpDeviceVendors[id] = "0x10de";
-        break;
-        case wgl::VendorAMD:
-            *mpDeviceVendors[id] = "0x1022";
-        break;
-        case wgl::VendorATI:
-            *mpDeviceVendors[id] = "0x1002";
-        break;
-        case wgl::VendorMicrosoft:
-            *mpDeviceVendors[id] = "0x1414";
-        break;
-        case wgl::DeviceVendorMax: // Suppress a warning.
-        break;
-    }
-
-    return *mpDeviceVendors[id];
-}
-
-namespace {
-
-
-OUString getBlacklistFile()
-{
-    OUString url("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER);
-    rtl::Bootstrap::expandMacros(url);
-
-    return url + "/opengl/opengl_blacklist_windows.xml";
-}
-
-
-}
-
-void WinOpenGLDeviceInfo::FillBlacklist()
-{
-    OUString aURL = getBlacklistFile();
-    WinBlocklistParser aParser(aURL, maDriverInfo);
-    try {
-        aParser.parse();
-    }
-    catch (...)
-    {
-        SAL_WARN("vcl.opengl", "error parsing blacklist");
-        maDriverInfo.clear();
-    }
-}
-
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/win/blocklist_parser.cxx 
b/vcl/opengl/win/blocklist_parser.cxx
deleted file mode 100644
index 79e49f540028..000000000000
--- a/vcl/opengl/win/blocklist_parser.cxx
+++ /dev/null
@@ -1,351 +0,0 @@
-/* -*- 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 <opengl/win/blocklist_parser.hxx>
-
-#include <sal/log.hxx>
-
-WinBlocklistParser::WinBlocklistParser(const OUString& rURL,
-        std::vector<wgl::DriverInfo>& rDriverList)
-    : meBlockType(BlockType::UNKNOWN)
-    , mrDriverList(rDriverList)
-    , maURL(rURL)
-{
-}
-
-void WinBlocklistParser::parse()
-{
-    xmlreader::XmlReader aReader(maURL);
-    handleContent(aReader);
-}
-
-namespace {
-
-wgl::OperatingSystem getOperatingSystem(const OString& rString)
-{
-    if (rString == "all")
-    {
-        return wgl::DRIVER_OS_ALL;
-    }
-    else if (rString == "7")
-    {
-        return wgl::DRIVER_OS_WINDOWS_7;
-    }
-    else if (rString == "8")
-    {
-        return wgl::DRIVER_OS_WINDOWS_8;
-    }
-    else if (rString == "8_1")
-    {
-        return wgl::DRIVER_OS_WINDOWS_8_1;
-    }
-    else if (rString == "10")
-    {
-        return wgl::DRIVER_OS_WINDOWS_10;
-    }
-
-    return wgl::DRIVER_OS_UNKNOWN;
-}
-
-wgl::VersionComparisonOp getComparison(const OString& rString)
-{
-    if (rString == "less")
-    {
-        return wgl::DRIVER_LESS_THAN;
-    }
-    else if (rString == "less_equal")
-    {
-        return wgl::DRIVER_LESS_THAN_OR_EQUAL;
-    }
-    else if (rString == "greater")
-    {
-        return wgl::DRIVER_GREATER_THAN;
-    }
-    else if (rString == "greater_equal")
-    {
-        return wgl::DRIVER_GREATER_THAN_OR_EQUAL;
-    }
-    else if (rString == "equal")
-    {
-        return wgl::DRIVER_EQUAL;
-    }
-    else if (rString == "not_equal")
-    {
-        return wgl::DRIVER_NOT_EQUAL;
-    }
-    else if (rString == "between_exclusive")
-    {
-        return wgl::DRIVER_BETWEEN_EXCLUSIVE;
-    }
-    else if (rString == "between_inclusive")
-    {
-        return wgl::DRIVER_BETWEEN_INCLUSIVE;
-    }
-    else if (rString == "between_inclusive_start")
-    {
-        return wgl::DRIVER_BETWEEN_INCLUSIVE_START;
-    }
-
-    throw InvalidFileException();
-}
-
-OUString getVendor(const OString& rString)
-{
-    if (rString == "all")
-    {
-        return "";
-    }
-    else if (rString == "intel")
-    {
-        return "0x8086";
-    }
-    else if (rString == "nvidia")
-    {
-        return "0x10de";
-    }
-    else if (rString == "amd")
-    {
-        return "0x1022";
-    }
-    else if (rString == "ati")
-    {
-        return "0x1002";
-    }
-    else if (rString == "microsoft")
-    {
-        return "0x1414";
-    }
-    else
-    {
-        // Allow having simply the hex number as such there, too. After all, 
it's hex numbers that
-        // are output to opengl_device.log.
-        return OStringToOUString(rString, RTL_TEXTENCODING_UTF8);
-    }
-}
-
-uint64_t getVersion(const OString& rString)
-{
-    OUString aString = OStringToOUString(rString, RTL_TEXTENCODING_UTF8);
-    uint64_t nVersion;
-    bool bResult = wgl::ParseDriverVersion(aString, nVersion);
-
-    if (!bResult)
-    {
-        throw InvalidFileException();
-    }
-
-    return nVersion;
-}
-
-void handleDevices(wgl::DriverInfo& rDriver, xmlreader::XmlReader& rReader)
-{
-    int nLevel = 1;
-    bool bInMsg = false;
-
-    while(true)
-    {
-        xmlreader::Span name;
-        int nsId;
-
-        xmlreader::XmlReader::Result res = rReader.nextItem(
-                xmlreader::XmlReader::Text::Normalized, &name, &nsId);
-
-        if (res == xmlreader::XmlReader::Result::Begin)
-        {
-            ++nLevel;
-            if (nLevel > 2)
-                throw InvalidFileException();
-
-            if (name == "msg")
-            {
-                bInMsg = true;
-            }
-            else if (name == "device")
-            {
-                int nsIdDeveice;
-                while (rReader.nextAttribute(&nsIdDeveice, &name))
-                {
-                    if (name == "id")
-                    {
-                        name = rReader.getAttributeValue(false);
-                        OString aDeviceId(name.begin, name.length);
-                        
rDriver.maDevices.push_back(OStringToOUString(aDeviceId, 
RTL_TEXTENCODING_UTF8));
-                    }
-                }
-            }
-            else
-                throw InvalidFileException();
-        }
-        else if (res == xmlreader::XmlReader::Result::End)
-        {
-            --nLevel;
-            bInMsg = false;
-            if (!nLevel)
-                break;
-        }
-        else if (res == xmlreader::XmlReader::Result::Text)
-        {
-            if (bInMsg)
-            {
-                OString sMsg(name.begin, name.length);
-                rDriver.maMsg = OStringToOUString(sMsg, RTL_TEXTENCODING_UTF8);
-            }
-        }
-    }
-}
-
-}
-
-void WinBlocklistParser::handleEntry(wgl::DriverInfo& rDriver, 
xmlreader::XmlReader& rReader)
-{
-    if (meBlockType == BlockType::WHITELIST)
-    {
-        rDriver.mbWhitelisted = true;
-    }
-    else if (meBlockType == BlockType::BLACKLIST)
-    {
-        rDriver.mbWhitelisted = false;
-    }
-    else if (meBlockType == BlockType::UNKNOWN)
-    {
-        throw InvalidFileException();
-    }
-
-    xmlreader::Span name;
-    int nsId;
-
-    while (rReader.nextAttribute(&nsId, &name))
-    {
-        if (name == "os")
-        {
-            name = rReader.getAttributeValue(false);
-            OString sOS(name.begin, name.length);
-            rDriver.meOperatingSystem = getOperatingSystem(sOS);
-        }
-        else if (name == "vendor")
-        {
-            name = rReader.getAttributeValue(false);
-            OString sVendor(name.begin, name.length);
-            rDriver.maAdapterVendor = getVendor(sVendor);
-        }
-        else if (name == "compare")
-        {
-            name = rReader.getAttributeValue(false);
-            OString sCompare(name.begin, name.length);
-            rDriver.meComparisonOp = getComparison(sCompare);
-        }
-        else if (name == "version")
-        {
-            name = rReader.getAttributeValue(false);
-            OString sVersion(name.begin, name.length);
-            rDriver.mnDriverVersion = getVersion(sVersion);
-        }
-        else if (name == "minVersion")
-        {
-            name = rReader.getAttributeValue(false);
-            OString sMinVersion(name.begin, name.length);
-            rDriver.mnDriverVersion = getVersion(sMinVersion);
-        }
-        else if (name == "maxVersion")
-        {
-            name = rReader.getAttributeValue(false);
-            OString sMaxVersion(name.begin, name.length);
-            rDriver.mnDriverVersionMax = getVersion(sMaxVersion);
-        }
-        else
-        {
-            OString aAttrName(name.begin, name.length);
-            SAL_WARN("vcl.opengl", "unsupported attribute: " << aAttrName);
-        }
-    }
-
-    handleDevices(rDriver, rReader);
-}
-
-void WinBlocklistParser::handleList(xmlreader::XmlReader& rReader)
-{
-    xmlreader::Span name;
-    int nsId;
-
-    while (true)
-    {
-        xmlreader::XmlReader::Result res = rReader.nextItem(
-                xmlreader::XmlReader::Text::NONE, &name, &nsId);
-
-        if (res == xmlreader::XmlReader::Result::Begin)
-        {
-            if (name == "entry")
-            {
-                wgl::DriverInfo aDriver;
-                handleEntry(aDriver, rReader);
-                mrDriverList.push_back(aDriver);
-            }
-            else if (name == "entryRange")
-            {
-                wgl::DriverInfo aDriver;
-                handleEntry(aDriver, rReader);
-                mrDriverList.push_back(aDriver);
-            }
-            else
-            {
-                throw InvalidFileException();
-            }
-        }
-        else if (res == xmlreader::XmlReader::Result::End)
-        {
-            break;
-        }
-    }
-}
-
-void WinBlocklistParser::handleContent(xmlreader::XmlReader& rReader)
-{
-    while (true)
-    {
-        xmlreader::Span name;
-        int nsId;
-
-        xmlreader::XmlReader::Result res = rReader.nextItem(
-                xmlreader::XmlReader::Text::NONE, &name, &nsId);
-
-        if (res == xmlreader::XmlReader::Result::Begin)
-        {
-            if (name == "whitelist")
-            {
-                meBlockType = BlockType::WHITELIST;
-                handleList(rReader);
-            }
-            else if (name == "blacklist")
-            {
-                meBlockType = BlockType::BLACKLIST;
-                handleList(rReader);
-            }
-            else if (name == "root")
-            {
-            }
-            else
-            {
-                throw InvalidFileException();
-            }
-        }
-        else if (res == xmlreader::XmlReader::Result::End)
-        {
-            if (name == "whitelist" || name == "blacklist")
-            {
-                meBlockType = BlockType::UNKNOWN;
-            }
-        }
-        else if (res == xmlreader::XmlReader::Result::Done)
-        {
-            break;
-        }
-    }
-}
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/qa/cppunit/blocklistparsertest.cxx 
b/vcl/qa/cppunit/blocklistparsertest.cxx
index 7d99e87f3750..1a22d61e3577 100644
--- a/vcl/qa/cppunit/blocklistparsertest.cxx
+++ b/vcl/qa/cppunit/blocklistparsertest.cxx
@@ -16,7 +16,9 @@
 
 #include <unotest/bootstrapfixturebase.hxx>
 
-#include <opengl/win/blocklist_parser.hxx>
+#include <driverblocklist.hxx>
+
+using namespace DriverBlocklist;
 
 namespace
 {
@@ -34,9 +36,9 @@ class BlocklistParserTest : public test::BootstrapFixtureBase
 
 void BlocklistParserTest::testParse()
 {
-    std::vector<wgl::DriverInfo> aDriveInfos;
+    std::vector<DriverInfo> aDriveInfos;
 
-    WinBlocklistParser 
aBlocklistParser(m_directories.getURLFromSrc("vcl/qa/cppunit/") + 
"test_blocklist_parse.xml", aDriveInfos);
+    Parser aBlocklistParser(m_directories.getURLFromSrc("vcl/qa/cppunit/") + 
"test_blocklist_parse.xml", aDriveInfos);
     aBlocklistParser.parse();
 
     size_t const n = aDriveInfos.size();
@@ -46,91 +48,87 @@ void BlocklistParserTest::testParse()
 
     for (bool bIsWhitelisted : {true, false})
     {
-        wgl::DriverInfo& aDriveInfo = aDriveInfos[i++];
+        DriverInfo& aDriveInfo = aDriveInfos[i++];
         CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted);
-        
CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorAll), 
aDriveInfo.maAdapterVendor); // "all"
-        CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_LESS_THAN, 
aDriveInfo.meComparisonOp);
-        CPPUNIT_ASSERT_EQUAL(wgl::V(10,20,30,40), aDriveInfo.mnDriverVersion);
+        CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), 
aDriveInfo.maAdapterVendor); // "all"
+        CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_LESS_THAN, 
aDriveInfo.meComparisonOp);
+        CPPUNIT_ASSERT_EQUAL(V(10,20,30,40), aDriveInfo.mnDriverVersion);
 
         aDriveInfo = aDriveInfos[i++];
         CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted);
-        
CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorNVIDIA), 
aDriveInfo.maAdapterVendor);
-        CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_EQUAL, 
aDriveInfo.meComparisonOp);
+        CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorNVIDIA), 
aDriveInfo.maAdapterVendor);
+        CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_EQUAL, 
aDriveInfo.meComparisonOp);
 
         aDriveInfo = aDriveInfos[i++];
         CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted);
-        
CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorMicrosoft),
 aDriveInfo.maAdapterVendor);
-        CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_NOT_EQUAL, 
aDriveInfo.meComparisonOp);
+        CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorMicrosoft), 
aDriveInfo.maAdapterVendor);
+        CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_NOT_EQUAL, 
aDriveInfo.meComparisonOp);
 
         aDriveInfo = aDriveInfos[i++];
         CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted);
         CPPUNIT_ASSERT_EQUAL(OUString("0xcafe"), aDriveInfo.maAdapterVendor);
-        CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_NOT_EQUAL, 
aDriveInfo.meComparisonOp);
+        CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_NOT_EQUAL, 
aDriveInfo.meComparisonOp);
 
         aDriveInfo = aDriveInfos[i++];
         CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted);
-        
CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorAll), 
aDriveInfo.maAdapterVendor);
-        
CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_BETWEEN_EXCLUSIVE, 
aDriveInfo.meComparisonOp);
+        CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), 
aDriveInfo.maAdapterVendor);
+        CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_BETWEEN_EXCLUSIVE, 
aDriveInfo.meComparisonOp);
 
         aDriveInfo = aDriveInfos[i++];
         CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted);
-        
CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorAll), 
aDriveInfo.maAdapterVendor);
-        
CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_BETWEEN_INCLUSIVE, 
aDriveInfo.meComparisonOp);
+        CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), 
aDriveInfo.maAdapterVendor);
+        CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_BETWEEN_INCLUSIVE, 
aDriveInfo.meComparisonOp);
 
         aDriveInfo = aDriveInfos[i++];
         CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted);
-        
CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorAll), 
aDriveInfo.maAdapterVendor);
-        
CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_BETWEEN_INCLUSIVE_START, 
aDriveInfo.meComparisonOp);
+        CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), 
aDriveInfo.maAdapterVendor);
+        
CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_BETWEEN_INCLUSIVE_START, 
aDriveInfo.meComparisonOp);
 
         aDriveInfo = aDriveInfos[i++];
         CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted);
-        
CPPUNIT_ASSERT_EQUAL(WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorAll), 
aDriveInfo.maAdapterVendor);
-        
CPPUNIT_ASSERT_EQUAL(wgl::VersionComparisonOp::DRIVER_COMPARISON_IGNORED, 
aDriveInfo.meComparisonOp);
+        CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), 
aDriveInfo.maAdapterVendor);
+        CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_COMPARISON_IGNORED, 
aDriveInfo.meComparisonOp);
     }
 }
 
 void BlocklistParserTest::testEvaluate()
 {
-    std::vector<wgl::DriverInfo> aDriveInfos;
+    std::vector<DriverInfo> aDriveInfos;
 
-    WinBlocklistParser 
aBlocklistParser(m_directories.getURLFromSrc("vcl/qa/cppunit/") + 
"test_blocklist_evaluate.xml", aDriveInfos);
+    Parser aBlocklistParser(m_directories.getURLFromSrc("vcl/qa/cppunit/") + 
"test_blocklist_evaluate.xml", aDriveInfos);
     aBlocklistParser.parse();
 
-    OUString vendorAMD = WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorAMD);
-    OUString vendorNVIDIA = 
WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorNVIDIA);
-    OUString vendorIntel = 
WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorIntel);
-    OUString vendorMicrosoft = 
WinOpenGLDeviceInfo::GetDeviceVendor(wgl::VendorMicrosoft);
-
-    uint32_t const osWindows7 = 0x00060001;
-    uint32_t const osWindows8 = 0x00060002;
-    uint32_t const osWindows10 = 0x000A0000;
+    OUString vendorAMD = GetVendorId(VendorAMD);
+    OUString vendorNVIDIA = GetVendorId(VendorNVIDIA);
+    OUString vendorIntel = GetVendorId(VendorIntel);
+    OUString vendorMicrosoft = GetVendorId(VendorMicrosoft);
 
     // Check OS
-    CPPUNIT_ASSERT_EQUAL(false, 
WinOpenGLDeviceInfo::FindBlocklistedDeviceInList(
-                                    aDriveInfos, "10.20.30.40", vendorNVIDIA, 
"all", osWindows7));
-    CPPUNIT_ASSERT_EQUAL(false, 
WinOpenGLDeviceInfo::FindBlocklistedDeviceInList(
-                                    aDriveInfos, "10.20.30.40", vendorNVIDIA, 
"all", osWindows8));
-    CPPUNIT_ASSERT_EQUAL(false, 
WinOpenGLDeviceInfo::FindBlocklistedDeviceInList(
-                                    aDriveInfos, "10.20.30.40", vendorNVIDIA, 
"all", osWindows10));
+    CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList(
+                                    aDriveInfos, "10.20.30.40", vendorNVIDIA, 
"all", DRIVER_OS_WINDOWS_7));
+    CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList(
+                                    aDriveInfos, "10.20.30.40", vendorNVIDIA, 
"all", DRIVER_OS_WINDOWS_8));
+    CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList(
+                                    aDriveInfos, "10.20.30.40", vendorNVIDIA, 
"all", DRIVER_OS_WINDOWS_10));
 
 
     // Check Vendors
-    CPPUNIT_ASSERT_EQUAL(true, 
WinOpenGLDeviceInfo::FindBlocklistedDeviceInList(
-                                    aDriveInfos, "10.20.30.40", 
vendorMicrosoft, "all", osWindows7));
-    CPPUNIT_ASSERT_EQUAL(true, 
WinOpenGLDeviceInfo::FindBlocklistedDeviceInList(
-                                    aDriveInfos, "10.20.30.40", 
vendorMicrosoft, "all", osWindows10));
+    CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList(
+                                    aDriveInfos, "10.20.30.40", 
vendorMicrosoft, "all", DRIVER_OS_WINDOWS_7));
+    CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList(
+                                    aDriveInfos, "10.20.30.40", 
vendorMicrosoft, "all", DRIVER_OS_WINDOWS_10));
 
     // Check Versions
-    CPPUNIT_ASSERT_EQUAL(true, 
WinOpenGLDeviceInfo::FindBlocklistedDeviceInList(
-                                    aDriveInfos, "10.20.30.39", vendorAMD, 
"all", osWindows7));
-    CPPUNIT_ASSERT_EQUAL(false, 
WinOpenGLDeviceInfo::FindBlocklistedDeviceInList(
-                                    aDriveInfos, "10.20.30.40", vendorAMD, 
"all", osWindows7));
-    CPPUNIT_ASSERT_EQUAL(false, 
WinOpenGLDeviceInfo::FindBlocklistedDeviceInList(
-                                    aDriveInfos, "10.20.30.41", vendorAMD, 
"all", osWindows7));
+    CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList(
+                                    aDriveInfos, "10.20.30.39", vendorAMD, 
"all", DRIVER_OS_WINDOWS_7));
+    CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList(
+                                    aDriveInfos, "10.20.30.40", vendorAMD, 
"all", DRIVER_OS_WINDOWS_7));
+    CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList(
+                                    aDriveInfos, "10.20.30.41", vendorAMD, 
"all", DRIVER_OS_WINDOWS_7));
 
     // Check
-    CPPUNIT_ASSERT_EQUAL(true, 
WinOpenGLDeviceInfo::FindBlocklistedDeviceInList(
-                                    aDriveInfos, "9.17.10.4229", vendorIntel, 
"all", osWindows7));
+    CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList(
+                                    aDriveInfos, "9.17.10.4229", vendorIntel, 
"all", DRIVER_OS_WINDOWS_7));
 
 
 }
diff --git a/vcl/skia/SkiaHelper.cxx b/vcl/skia/SkiaHelper.cxx
index 0404a52f98cc..c305c5275ea5 100644
--- a/vcl/skia/SkiaHelper.cxx
+++ b/vcl/skia/SkiaHelper.cxx
@@ -9,13 +9,6 @@
 
 #include <vcl/skia/SkiaHelper.hxx>
 
-#include <vcl/svapp.hxx>
-#include <desktop/crashreport.hxx>
-#include <officecfg/Office/Common.hxx>
-#include <watchdog.hxx>
-#include <skia/zone.hxx>
-#include <sal/log.hxx>
-
 #if !HAVE_FEATURE_SKIA
 
 namespace SkiaHelper
@@ -26,7 +19,16 @@ bool isVCLSkiaEnabled() { return false; }
 
 #else
 
+#include <rtl/bootstrap.hxx>
+#include <vcl/svapp.hxx>
+#include <desktop/crashreport.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <watchdog.hxx>
+#include <skia/zone.hxx>
+#include <sal/log.hxx>
+#include <driverblocklist.hxx>
 #include <skia/utils.hxx>
+#include <config_folders.h>
 
 #include <SkSurface.h>
 
@@ -36,20 +38,31 @@ bool isVCLSkiaEnabled() { return false; }
 
 namespace SkiaHelper
 {
+static OUString getBlacklistFile()
+{
+    OUString url("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER);
+    rtl::Bootstrap::expandMacros(url);
+
+    return url + "/skia/skia_blacklist_vulkan.xml";
+}
+
 static bool isVulkanBlacklisted(const VkPhysicalDeviceProperties& props)
 {
     static const char* const types[]
         = { "other", "integrated", "discrete", "virtual", "cpu", "??" }; // 
VkPhysicalDeviceType
+    OUString driverVersion = OUString::number(props.driverVersion >> 22) + "."
+                             + OUString::number((props.driverVersion >> 12) & 
0x3ff) + "."
+                             + OUString::number(props.driverVersion & 0xfff);
+    OUString vendorId = "0x" + OUString::number(props.vendorID, 16);
+    OUString deviceId = "0x" + OUString::number(props.deviceID, 16);
     SAL_INFO("vcl.skia",
              "Vulkan API version: "
                  << (props.apiVersion >> 22) << "." << ((props.apiVersion >> 
12) & 0x3ff) << "."
-                 << (props.apiVersion & 0xfff) << ", driver version: "
-                 << (props.driverVersion >> 22) << "." << 
((props.driverVersion >> 12) & 0x3ff)
-                 << "." << (props.driverVersion & 0xfff) << std::hex << ", 
vendor: 0x"
-                 << props.vendorID << ", device: 0x" << props.deviceID << 
std::dec
-                 << ", type: " << types[std::min<unsigned>(props.deviceType, 
SAL_N_ELEMENTS(types))]
+                 << (props.apiVersion & 0xfff) << ", driver version: " << 
driverVersion
+                 << ", vendor: " << vendorId << ", device: " << deviceId << ", 
type: "
+                 << types[std::min<unsigned>(props.deviceType, 
SAL_N_ELEMENTS(types) - 1)]
                  << ", name: " << props.deviceName);
-    return false;
+    return DriverBlocklist::IsDeviceBlocked(getBlacklistFile(), driverVersion, 
vendorId, deviceId);
 }
 
 static void checkDeviceBlacklisted()
diff --git a/vcl/skia/skia_blacklist_vulkan.xml 
b/vcl/skia/skia_blacklist_vulkan.xml
new file mode 100644
index 000000000000..2c7714a38f8a
--- /dev/null
+++ b/vcl/skia/skia_blacklist_vulkan.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+* 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/.
+-->
+
+<!--
+    entry attributes:
+    os - "all", "7", "8", "8_1", "10", "linux"
+    vendor - "all", "intel", "ati", "amd", "nvidia", "microsoft"
+    compare - "less", "less_equal", "greater", "greater_equal", "equal", 
"not_equal", "between_exclusive", "between_inclusive", "between_inclusive_start"
+    version
+    minVersion
+    maxVersion
+-->
+
+<root>
+    <whitelist>
+    </whitelist>
+    <blacklist>
+<!-- example:
+        <entry os="all" vendor="ati" compare="equal" version="2.0.106">
+            <device id="all"/>
+        </entry>
+-->
+    </blacklist>
+</root>
diff --git a/vcl/source/helper/driverblocklist.cxx 
b/vcl/source/helper/driverblocklist.cxx
new file mode 100644
index 000000000000..a63fdc00cd30
--- /dev/null
+++ b/vcl/source/helper/driverblocklist.cxx
@@ -0,0 +1,711 @@
+/* -*- 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 <driverblocklist.hxx>
+
+#include <algorithm>
+
+#include <sal/log.hxx>
+
+#ifdef _WIN32
+#if !defined WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#endif
+
+namespace DriverBlocklist
+{
+static OperatingSystem getOperatingSystem(const OString& rString)
+{
+    if (rString == "all")
+        return DRIVER_OS_ALL;
+    else if (rString == "7")
+        return DRIVER_OS_WINDOWS_7;
+    else if (rString == "8")
+        return DRIVER_OS_WINDOWS_8;
+    else if (rString == "8_1")
+        return DRIVER_OS_WINDOWS_8_1;
+    else if (rString == "10")
+        return DRIVER_OS_WINDOWS_10;
+    else if (rString == "linux")
+        return DRIVER_OS_LINUX;
+    else if (rString == "osx_10_5")
+        return DRIVER_OS_OSX_10_5;
+    else if (rString == "osx_10_6")
+        return DRIVER_OS_OSX_10_6;
+    else if (rString == "osx_10_7")
+        return DRIVER_OS_OSX_10_7;
+    else if (rString == "osx_10_8")
+        return DRIVER_OS_OSX_10_8;
+    else if (rString == "android")
+        return DRIVER_OS_ANDROID;
+    return DRIVER_OS_UNKNOWN;
+}
+
+static VersionComparisonOp getComparison(const OString& rString)
+{
+    if (rString == "less")
+    {
+        return DRIVER_LESS_THAN;
+    }
+    else if (rString == "less_equal")
+    {
+        return DRIVER_LESS_THAN_OR_EQUAL;
+    }
+    else if (rString == "greater")
+    {
+        return DRIVER_GREATER_THAN;
+    }
+    else if (rString == "greater_equal")
+    {
+        return DRIVER_GREATER_THAN_OR_EQUAL;
+    }
+    else if (rString == "equal")
+    {
+        return DRIVER_EQUAL;
+    }
+    else if (rString == "not_equal")
+    {
+        return DRIVER_NOT_EQUAL;
+    }
+    else if (rString == "between_exclusive")
+    {
+        return DRIVER_BETWEEN_EXCLUSIVE;
+    }
+    else if (rString == "between_inclusive")
+    {
+        return DRIVER_BETWEEN_INCLUSIVE;
+    }
+    else if (rString == "between_inclusive_start")
+    {
+        return DRIVER_BETWEEN_INCLUSIVE_START;
+    }
+
+    throw InvalidFileException();
+}
+
+static OUString GetVendorId(const OString& rString)
+{
+    if (rString == "all")
+    {
+        return "";
+    }
+    else if (rString == "intel")
+    {
+        return "0x8086";
+    }
+    else if (rString == "nvidia")
+    {
+        return "0x10de";
+    }
+    else if (rString == "amd")
+    {
+        return "0x1022";
+    }
+    else if (rString == "ati")
+    {
+        return "0x1002";
+    }
+    else if (rString == "microsoft")
+    {
+        return "0x1414";
+    }
+    else
+    {
+        // Allow having simply the hex number as such there, too.
+        return OStringToOUString(rString, RTL_TEXTENCODING_UTF8);
+    }
+}
+
+OUString GetVendorId(DeviceVendor id)
+{
+    assert(id >= 0 && id < DeviceVendorMax);
+
+    switch (id)
+    {
+        case VendorAll:
+            return "";
+        case VendorIntel:
+            return "0x8086";
+        case VendorNVIDIA:
+            return "0x10de";
+        case VendorAMD:
+            return "0x1022";
+        case VendorATI:
+            return "0x1002";
+        case VendorMicrosoft:
+            return "0x1414";
+    }
+    abort();
+}
+
+Parser::Parser(const OUString& rURL, std::vector<DriverInfo>& rDriverList)
+    : meBlockType(BlockType::UNKNOWN)
+    , mrDriverList(rDriverList)
+    , maURL(rURL)
+{
+}
+
+bool Parser::parse()
+{
+    try
+    {
+        xmlreader::XmlReader aReader(maURL);
+        handleContent(aReader);
+    }
+    catch (...)
+    {
+        mrDriverList.clear();
+        return false;
+    }
+    return true;
+}
+
+// This allows us to pad driver version 'substrings' with 0s, this
+// effectively allows us to treat the version numbers as 'decimals'. This is
+// a little strange but this method seems to do the right thing for all
+// different vendor's driver strings. i.e. .98 will become 9800, which is
+// larger than .978 which would become 9780.
+static void PadDriverDecimal(char* aString)
+{
+    for (int i = 0; i < 4; i++)
+    {
+        if (!aString[i])
+        {
+            for (int c = i; c < 4; c++)
+            {
+                aString[c] = '0';
+            }
+            break;
+        }
+    }
+    aString[4] = 0;
+}
+
+// All destination string storage needs to have at least 5 bytes available.
+static bool SplitDriverVersion(const char* aSource, char* aAStr, char* aBStr, 
char* aCStr,
+                               char* aDStr)
+{
+    // sscanf doesn't do what we want here to we parse this manually.
+    int len = strlen(aSource);
+    char* dest[4] = { aAStr, aBStr, aCStr, aDStr };
+    unsigned destIdx = 0;
+    unsigned destPos = 0;
+
+    for (int i = 0; i < len; i++)
+    {
+        if (destIdx >= SAL_N_ELEMENTS(dest))
+        {
+            // Invalid format found. Ensure we don't access dest beyond bounds.
+            return false;
+        }
+
+        if (aSource[i] == '.')
+        {
+            dest[destIdx++][destPos] = 0;
+            destPos = 0;
+            continue;
+        }
+
+        if (destPos > 3)
+        {
+            // Ignore more than 4 chars. Ensure we never access dest[destIdx]
+            // beyond its bounds.
+            continue;
+        }
+
+        dest[destIdx][destPos++] = aSource[i];
+    }
+
+    // Add last terminator.
+    dest[destIdx][destPos] = 0;
+
+    // Vulkan version numbers have only 3 fields.
+    if (destIdx == SAL_N_ELEMENTS(dest) - 2)
+        dest[destIdx++][0] = '\0';
+    if (destIdx != SAL_N_ELEMENTS(dest) - 1)
+    {
+        return false;
+    }
+    return true;
+}
+
+static bool ParseDriverVersion(const OUString& aVersion, uint64_t& 
rNumericVersion)
+{
+    rNumericVersion = 0;
+
+    int a, b, c, d;
+    char aStr[8], bStr[8], cStr[8], dStr[8];
+    /* honestly, why do I even bother */
+    OString aOVersion = OUStringToOString(aVersion, RTL_TEXTENCODING_UTF8);
+    if (!SplitDriverVersion(aOVersion.getStr(), aStr, bStr, cStr, dStr))
+        return false;
+
+    PadDriverDecimal(bStr);
+    PadDriverDecimal(cStr);
+    PadDriverDecimal(dStr);
+
+    a = atoi(aStr);
+    b = atoi(bStr);
+    c = atoi(cStr);
+    d = atoi(dStr);
+
+    if (a < 0 || a > 0xffff)
+        return false;
+    if (b < 0 || b > 0xffff)
+        return false;
+    if (c < 0 || c > 0xffff)
+        return false;
+    if (d < 0 || d > 0xffff)
+        return false;
+
+    rNumericVersion = GFX_DRIVER_VERSION(a, b, c, d);
+    return true;
+}
+
+static uint64_t getVersion(const OString& rString)
+{
+    OUString aString = OStringToOUString(rString, RTL_TEXTENCODING_UTF8);
+    uint64_t nVersion;
+    bool bResult = ParseDriverVersion(aString, nVersion);
+
+    if (!bResult)
+    {
+        throw InvalidFileException();
+    }
+
+    return nVersion;
+}
+
+void Parser::handleDevices(DriverInfo& rDriver, xmlreader::XmlReader& rReader)
+{
+    int nLevel = 1;
+    bool bInMsg = false;
+
+    while (true)
+    {
+        xmlreader::Span name;
+        int nsId;
+
+        xmlreader::XmlReader::Result res
+            = rReader.nextItem(xmlreader::XmlReader::Text::Normalized, &name, 
&nsId);
+
+        if (res == xmlreader::XmlReader::Result::Begin)
+        {
+            ++nLevel;
+            if (nLevel > 2)
+                throw InvalidFileException();
+
+            if (name == "msg")
+            {
+                bInMsg = true;
+            }
+            else if (name == "device")
+            {
+                int nsIdDeveice;
+                while (rReader.nextAttribute(&nsIdDeveice, &name))
+                {
+                    if (name == "id")
+                    {
+                        name = rReader.getAttributeValue(false);
+                        OString aDeviceId(name.begin, name.length);
+                        rDriver.maDevices.push_back(
+                            OStringToOUString(aDeviceId, 
RTL_TEXTENCODING_UTF8));
+                    }
+                }
+            }
+            else
+                throw InvalidFileException();
+        }
+        else if (res == xmlreader::XmlReader::Result::End)
+        {
+            --nLevel;
+            bInMsg = false;
+            if (!nLevel)
+                break;
+        }
+        else if (res == xmlreader::XmlReader::Result::Text)
+        {
+            if (bInMsg)
+            {
+                OString sMsg(name.begin, name.length);
+                rDriver.maMsg = OStringToOUString(sMsg, RTL_TEXTENCODING_UTF8);
+            }
+        }
+    }
+}
+
+void Parser::handleEntry(DriverInfo& rDriver, xmlreader::XmlReader& rReader)
+{
+    if (meBlockType == BlockType::WHITELIST)
+    {
+        rDriver.mbWhitelisted = true;
+    }
+    else if (meBlockType == BlockType::BLACKLIST)
+    {
+        rDriver.mbWhitelisted = false;
+    }
+    else if (meBlockType == BlockType::UNKNOWN)
+    {
+        throw InvalidFileException();
+    }
+
+    xmlreader::Span name;
+    int nsId;
+
+    while (rReader.nextAttribute(&nsId, &name))
+    {
+        if (name == "os")
+        {
+            name = rReader.getAttributeValue(false);
+            OString sOS(name.begin, name.length);
+            rDriver.meOperatingSystem = getOperatingSystem(sOS);
+        }
+        else if (name == "vendor")
+        {
+            name = rReader.getAttributeValue(false);
+            OString sVendor(name.begin, name.length);
+            rDriver.maAdapterVendor = GetVendorId(sVendor);
+        }
+        else if (name == "compare")
+        {
+            name = rReader.getAttributeValue(false);
+            OString sCompare(name.begin, name.length);
+            rDriver.meComparisonOp = getComparison(sCompare);
+        }
+        else if (name == "version")
+        {
+            name = rReader.getAttributeValue(false);
+            OString sVersion(name.begin, name.length);
+            rDriver.mnDriverVersion = getVersion(sVersion);
+        }
+        else if (name == "minVersion")
+        {
+            name = rReader.getAttributeValue(false);
+            OString sMinVersion(name.begin, name.length);
+            rDriver.mnDriverVersion = getVersion(sMinVersion);
+        }
+        else if (name == "maxVersion")
+        {
+            name = rReader.getAttributeValue(false);
+            OString sMaxVersion(name.begin, name.length);
+            rDriver.mnDriverVersionMax = getVersion(sMaxVersion);
+        }
+        else
+        {
+            OString aAttrName(name.begin, name.length);
+            SAL_WARN("vcl.driver", "unsupported attribute: " << aAttrName);
+        }
+    }
+
+    handleDevices(rDriver, rReader);
+}
+
+void Parser::handleList(xmlreader::XmlReader& rReader)
+{
+    xmlreader::Span name;
+    int nsId;
+
+    while (true)
+    {
+        xmlreader::XmlReader::Result res
+            = rReader.nextItem(xmlreader::XmlReader::Text::NONE, &name, &nsId);
+
+        if (res == xmlreader::XmlReader::Result::Begin)
+        {
+            if (name == "entry")
+            {
+                DriverInfo aDriver;
+                handleEntry(aDriver, rReader);
+                mrDriverList.push_back(aDriver);
+            }
+            else if (name == "entryRange")
+            {
+                DriverInfo aDriver;
+                handleEntry(aDriver, rReader);
+                mrDriverList.push_back(aDriver);
+            }
+            else
+            {
+                throw InvalidFileException();
+            }
+        }
+        else if (res == xmlreader::XmlReader::Result::End)
+        {
+            break;
+        }
+    }
+}
+
+void Parser::handleContent(xmlreader::XmlReader& rReader)
+{
+    while (true)
+    {
+        xmlreader::Span name;
+        int nsId;
+
+        xmlreader::XmlReader::Result res
+            = rReader.nextItem(xmlreader::XmlReader::Text::NONE, &name, &nsId);
+
+        if (res == xmlreader::XmlReader::Result::Begin)
+        {
+            if (name == "whitelist")
+            {
+                meBlockType = BlockType::WHITELIST;
+                handleList(rReader);
+            }
+            else if (name == "blacklist")
+            {
+                meBlockType = BlockType::BLACKLIST;
+                handleList(rReader);
+            }
+            else if (name == "root")
+            {
+            }
+            else
+            {
+                throw InvalidFileException();
+            }
+        }
+        else if (res == xmlreader::XmlReader::Result::End)
+        {
+            if (name == "whitelist" || name == "blacklist")
+            {
+                meBlockType = BlockType::UNKNOWN;
+            }
+        }
+        else if (res == xmlreader::XmlReader::Result::Done)
+        {
+            break;
+        }
+    }
+}
+
+static OperatingSystem getOperatingSystem()
+{
+#ifdef _WIN32
+    // OS version in 16.16 major/minor form
+    // based on http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx
+    switch (DriverBlocklist::GetWindowsVersion())
+    {
+        case 0x00060001:
+            return DRIVER_OS_WINDOWS_7;
+        case 0x00060002:
+            return DRIVER_OS_WINDOWS_8;
+        case 0x00060003:
+            return DRIVER_OS_WINDOWS_8_1;
+        case 0x000A0000: // Major 10 Minor 0
+            return DRIVER_OS_WINDOWS_10;
+        default:
+            return DRIVER_OS_UNKNOWN;
+    }
+#elif defined LINUX
+    return DRIVER_OS_LINUX;
+#else
+    return DRIVER_OS_UNKNOWN;
+#endif
+}
+
+namespace
+{
+struct compareIgnoreAsciiCase
+{
+    explicit compareIgnoreAsciiCase(const OUString& rString)
+        : maString(rString)
+    {
+    }
+
+    bool operator()(const OUString& rCompare) { return 
maString.equalsIgnoreAsciiCase(rCompare); }
+
+private:
+    OUString maString;
+};
+}
+
+const uint64_t allDriverVersions = ~(uint64_t(0));
+
+DriverInfo::DriverInfo()
+    : meOperatingSystem(DRIVER_OS_UNKNOWN)
+    , maAdapterVendor(GetVendorId(VendorAll))
+    , mbWhitelisted(false)
+    , meComparisonOp(DRIVER_COMPARISON_IGNORED)
+    , mnDriverVersion(0)
+    , mnDriverVersionMax(0)
+{
+}
+
+DriverInfo::DriverInfo(OperatingSystem os, const OUString& vendor, 
VersionComparisonOp op,
+                       uint64_t driverVersion, bool bWhitelisted,
+                       const char* suggestedVersion /* = nullptr */)
+    : meOperatingSystem(os)
+    , maAdapterVendor(vendor)
+    , mbWhitelisted(bWhitelisted)
+    , meComparisonOp(op)
+    , mnDriverVersion(driverVersion)
+    , mnDriverVersionMax(0)
+{
+    if (suggestedVersion)
+        maSuggestedVersion = OStringToOUString(OString(suggestedVersion), 
RTL_TEXTENCODING_UTF8);
+}
+
+bool FindBlocklistedDeviceInList(std::vector<DriverInfo>& aDeviceInfos,
+                                 OUString const& sDriverVersion, OUString 
const& sAdapterVendorID,
+                                 OUString const& sAdapterDeviceID, 
OperatingSystem system,
+                                 const OUString& blocklistURL)
+{
+    uint64_t driverVersion;
+    ParseDriverVersion(sDriverVersion, driverVersion);
+
+    bool match = false;
+    for (std::vector<DriverInfo>::size_type i = 0; i < aDeviceInfos.size(); 
i++)
+    {
+        if (aDeviceInfos[i].meOperatingSystem != DRIVER_OS_ALL
+            && aDeviceInfos[i].meOperatingSystem != system)
+        {
+            continue;
+        }
+
+        if 
(!aDeviceInfos[i].maAdapterVendor.equalsIgnoreAsciiCase(GetVendorId(VendorAll))
+            && 
!aDeviceInfos[i].maAdapterVendor.equalsIgnoreAsciiCase(sAdapterVendorID))
+        {
+            continue;
+        }
+
+        if (std::none_of(aDeviceInfos[i].maDevices.begin(), 
aDeviceInfos[i].maDevices.end(),
+                         compareIgnoreAsciiCase("all"))
+            && std::none_of(aDeviceInfos[i].maDevices.begin(), 
aDeviceInfos[i].maDevices.end(),
+                            compareIgnoreAsciiCase(sAdapterDeviceID)))
+        {
+            continue;
+        }
+
+        switch (aDeviceInfos[i].meComparisonOp)
+        {
+            case DRIVER_LESS_THAN:
+                match = driverVersion < aDeviceInfos[i].mnDriverVersion;
+                break;
+            case DRIVER_LESS_THAN_OR_EQUAL:
+                match = driverVersion <= aDeviceInfos[i].mnDriverVersion;
+                break;
+            case DRIVER_GREATER_THAN:
+                match = driverVersion > aDeviceInfos[i].mnDriverVersion;
+                break;
+            case DRIVER_GREATER_THAN_OR_EQUAL:
+                match = driverVersion >= aDeviceInfos[i].mnDriverVersion;
+                break;
+            case DRIVER_EQUAL:
+                match = driverVersion == aDeviceInfos[i].mnDriverVersion;
+                break;
+            case DRIVER_NOT_EQUAL:
+                match = driverVersion != aDeviceInfos[i].mnDriverVersion;
+                break;
+            case DRIVER_BETWEEN_EXCLUSIVE:
+                match = driverVersion > aDeviceInfos[i].mnDriverVersion
+                        && driverVersion < aDeviceInfos[i].mnDriverVersionMax;
+                break;
+            case DRIVER_BETWEEN_INCLUSIVE:
+                match = driverVersion >= aDeviceInfos[i].mnDriverVersion
+                        && driverVersion <= aDeviceInfos[i].mnDriverVersionMax;
+                break;
+            case DRIVER_BETWEEN_INCLUSIVE_START:
+                match = driverVersion >= aDeviceInfos[i].mnDriverVersion
+                        && driverVersion < aDeviceInfos[i].mnDriverVersionMax;
+                break;
+            case DRIVER_COMPARISON_IGNORED:
+                // We don't have a comparison op, so we match everything.
+                match = true;
+                break;
+            default:
+                SAL_WARN("vcl.driver", "Bogus op in " << blocklistURL);
+                break;
+        }
+
+        if (match || aDeviceInfos[i].mnDriverVersion == allDriverVersions)
+        {
+            // white listed drivers
+            if (aDeviceInfos[i].mbWhitelisted)
+            {
+                SAL_INFO("vcl.driver", "whitelisted driver");
+                return false;
+            }
+
+            match = true;
+            if (!aDeviceInfos[i].maSuggestedVersion.isEmpty())
+            {
+                SAL_WARN("vcl.driver", "use : " << 
aDeviceInfos[i].maSuggestedVersion);
+            }
+            break;
+        }
+    }
+
+    SAL_INFO("vcl.driver", (match ? "blacklisted" : "not blacklisted") << " in 
" << blocklistURL);
+    return match;
+}
+
+bool IsDeviceBlocked(const OUString& blocklistURL, const OUString& 
driverVersion,
+                     const OUString& vendorId, const OUString& deviceId)
+{
+    std::vector<DriverInfo> driverList;
+    Parser parser(blocklistURL, driverList);
+    if (!parser.parse())
+    {
+        SAL_WARN("vcl.driver", "error parsing blacklist " << blocklistURL);
+        return false;
+    }
+    return FindBlocklistedDeviceInList(driverList, driverVersion, vendorId, 
deviceId,
+                                       getOperatingSystem(), blocklistURL);
+}
+
+#ifdef _WIN32
+int32_t GetWindowsVersion()
+{
+    static int32_t winVersion = [&]() {
+        // GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API 
are
+        // subject to manifest-based behavior since Windows 8.1, so give wrong 
results.
+        // Another approach would be to use NetWkstaGetInfo, but that has some 
small
+        // reported delays (some milliseconds), and might get slower in 
domains with
+        // poor network connections.
+        // So go with a solution described at 
https://msdn.microsoft.com/en-us/library/ms724429
+        HINSTANCE hLibrary = LoadLibraryW(L"kernel32.dll");
+        if (hLibrary != nullptr)
+        {
+            wchar_t szPath[MAX_PATH];
+            DWORD dwCount = GetModuleFileNameW(hLibrary, szPath, 
SAL_N_ELEMENTS(szPath));
+            FreeLibrary(hLibrary);
+            if (dwCount != 0 && dwCount < SAL_N_ELEMENTS(szPath))
+            {
+                dwCount = GetFileVersionInfoSizeW(szPath, nullptr);
+                if (dwCount != 0)
+                {
+                    std::unique_ptr<char[]> ver(new char[dwCount]);
+                    if (GetFileVersionInfoW(szPath, 0, dwCount, ver.get()) != 
FALSE)
+                    {
+                        void* pBlock = nullptr;
+                        UINT dwBlockSz = 0;
+                        if (VerQueryValueW(ver.get(), L"\\", &pBlock, 
&dwBlockSz) != FALSE
+                            && dwBlockSz >= sizeof(VS_FIXEDFILEINFO))
+                        {
+                            VS_FIXEDFILEINFO* vinfo = 
static_cast<VS_FIXEDFILEINFO*>(pBlock);
+                            return int32_t(vinfo->dwProductVersionMS);
+                        }
+                    }
+                }
+            }
+        }
+        return 0;
+    }();
+
+    return winVersion;
+}
+#endif
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/opengl/OpenGLHelper.cxx 
b/vcl/source/opengl/OpenGLHelper.cxx
index 081bf240cc8b..ece8e9d6c440 100644
--- a/vcl/source/opengl/OpenGLHelper.cxx
+++ b/vcl/source/opengl/OpenGLHelper.cxx
@@ -209,7 +209,7 @@ namespace
         return OUStringToOString(aInfo.GetAdapterVendorID(), 
RTL_TEXTENCODING_UTF8) +
             OUStringToOString(aInfo.GetAdapterDeviceID(), 
RTL_TEXTENCODING_UTF8) +
             OUStringToOString(aInfo.GetDriverVersion(), RTL_TEXTENCODING_UTF8) 
+
-            OString::number(aInfo.GetWindowsVersion());
+            OString::number(DriverBlocklist::GetWindowsVersion());
 #else
         return rtl::OStringView(reinterpret_cast<const 
char*>(glGetString(GL_VENDOR))) +
             reinterpret_cast<const char*>(glGetString(GL_RENDERER)) +
@@ -767,7 +767,7 @@ bool OpenGLHelper::isDeviceBlacklisted()
         WinOpenGLDeviceInfo aInfo;
         bBlacklisted = aInfo.isDeviceBlocked();
 
-        if (aInfo.GetWindowsVersion() == 0x00060001 && /* Windows 7 */
+        if (DriverBlocklist::GetWindowsVersion() == 0x00060001 && /* Windows 7 
*/
             (aInfo.GetAdapterVendorID() == "0x1002" || 
aInfo.GetAdapterVendorID() == "0x1022")) /* AMD */
         {
             SAL_INFO("vcl.opengl", "Relaxing watchdog timings.");
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to