tdf#123304: Allow the full feature syntax as pre 6.2

Fix regression from:

commit dc9ee533dc707cc10b99d537eaccc3ee5aa555fe
Author: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Date:   Fri Jun 15 19:32:15 2018 +0200

    vcl: parser of font features included in the font name

Where hb_feature_from_string() was replaced by a simple parser that supports
avery limited subset of the syntax it supports (as documented in
https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-feature-from-string)

Reviewed-on: https://gerrit.libreoffice.org/69062
Reviewed-by: Khaled Hosny <khaledhosny@eglug.org>
Tested-by: Khaled Hosny <khaledhosny@eglug.org>
(cherry picked from commit 45deb5b714d2d011eb2a5ad91721a9c2c508a426)

Change-Id: I613190a677d24183e8c718fcfcaf9cf9b37a1e8f
Reviewed-on: https://gerrit.libreoffice.org/69068
Reviewed-by: Khaled Hosny <khaledhosny@eglug.org>
Tested-by: Khaled Hosny <khaledhosny@eglug.org>
diff --git a/cui/source/dialogs/FontFeaturesDialog.cxx b/cui/source/dialogs/FontFeaturesDialog.cxx
index 8da13ed..f927644 100644
--- a/cui/source/dialogs/FontFeaturesDialog.cxx
+++ b/cui/source/dialogs/FontFeaturesDialog.cxx
@@ -74,7 +74,7 @@ void FontFeaturesDialog::initialize()
void FontFeaturesDialog::fillGrid(std::vector<vcl::font::Feature> const& rFontFeatures)
{
    vcl::font::FeatureParser aParser(m_sFontName);
    std::unordered_map<sal_uInt32, sal_uInt32> aExistingFeatures = aParser.getFeaturesMap();
    auto aExistingFeatures = aParser.getFeaturesMap();

    sal_Int32 i = 0;
    for (vcl::font::Feature const& rFontFeature : rFontFeatures)
@@ -89,7 +89,7 @@ void FontFeaturesDialog::fillGrid(std::vector<vcl::font::Feature> const& rFontFe

        m_aFeatureItems.emplace_back(m_xContentGrid.get());

        sal_uInt32 nValue = 0;
        uint32_t nValue = 0;
        if (aExistingFeatures.find(nFontFeatureCode) != aExistingFeatures.end())
            nValue = aExistingFeatures.at(nFontFeatureCode);

diff --git a/include/vcl/font/Feature.hxx b/include/vcl/font/Feature.hxx
index 299d0a5..76ba597 100644
--- a/include/vcl/font/Feature.hxx
+++ b/include/vcl/font/Feature.hxx
@@ -21,13 +21,13 @@ namespace vcl
{
namespace font
{
constexpr sal_uInt32 featureCode(const char sFeature[4])
constexpr uint32_t featureCode(const char sFeature[4])
{
    return static_cast<sal_uInt32>(sFeature[0]) << 24U | static_cast<sal_uInt32>(sFeature[1]) << 16U
           | static_cast<sal_uInt32>(sFeature[2]) << 8U | static_cast<sal_uInt32>(sFeature[3]);
    return static_cast<uint32_t>(sFeature[0]) << 24U | static_cast<uint32_t>(sFeature[1]) << 16U
           | static_cast<uint32_t>(sFeature[2]) << 8U | static_cast<uint32_t>(sFeature[3]);
}

VCL_DLLPUBLIC OUString featureCodeAsString(sal_uInt32 nFeature);
VCL_DLLPUBLIC OUString featureCodeAsString(uint32_t nFeature);

enum class FeatureParameterType
{
@@ -44,22 +44,22 @@ enum class FeatureType
struct VCL_DLLPUBLIC FeatureParameter
{
private:
    sal_uInt32 m_nCode;
    uint32_t m_nCode;
    OUString m_sDescription;
    const char* m_pDescriptionID;

public:
    FeatureParameter(sal_uInt32 nCode, OUString aDescription);
    FeatureParameter(sal_uInt32 nCode, const char* pDescriptionID);
    FeatureParameter(uint32_t nCode, OUString aDescription);
    FeatureParameter(uint32_t nCode, const char* pDescriptionID);

    sal_uInt32 getCode() const;
    uint32_t getCode() const;
    OUString getDescription() const;
};

class VCL_DLLPUBLIC FeatureDefinition
{
private:
    sal_uInt32 m_nCode;
    uint32_t m_nCode;
    OUString m_sDescription;
    const char* m_pDescriptionID;
    OUString m_sNumericPart;
@@ -69,18 +69,18 @@ private:

public:
    FeatureDefinition();
    FeatureDefinition(sal_uInt32 nCode, OUString const& rDescription,
    FeatureDefinition(uint32_t nCode, OUString const& rDescription,
                      FeatureParameterType eType = FeatureParameterType::BOOL,
                      std::vector<FeatureParameter> const& rEnumParameters
                      = std::vector<FeatureParameter>{});
    FeatureDefinition(sal_uInt32 nCode, const char* pDescriptionID,
    FeatureDefinition(uint32_t nCode, const char* pDescriptionID,
                      OUString const& rNumericPart = OUString());
    FeatureDefinition(sal_uInt32 nCode, const char* pDescriptionID,
    FeatureDefinition(uint32_t nCode, const char* pDescriptionID,
                      std::vector<FeatureParameter> aEnumParameters);

    const std::vector<FeatureParameter>& getEnumParameters() const;
    OUString getDescription() const;
    sal_uInt32 getCode() const;
    uint32_t getCode() const;
    FeatureParameterType getType() const;

    operator bool() const;
@@ -88,9 +88,9 @@ public:

struct VCL_DLLPUBLIC FeatureID
{
    sal_uInt32 m_aFeatureCode;
    sal_uInt32 m_aScriptCode;
    sal_uInt32 m_aLanguageCode;
    uint32_t m_aFeatureCode;
    uint32_t m_aScriptCode;
    uint32_t m_aLanguageCode;
};

struct VCL_DLLPUBLIC Feature
@@ -103,6 +103,18 @@ struct VCL_DLLPUBLIC Feature
    FeatureDefinition m_aDefinition;
};

// This is basically duplicates hb_feature_t to avoid including HarfBuzz
// headers here, so the member types should remain compatible.
struct VCL_DLLPUBLIC FeatureSetting
{
    FeatureSetting(OString feature);

    uint32_t m_nTag;
    uint32_t m_nValue;
    unsigned int m_nStart;
    unsigned int m_nEnd;
};

} // end font namespace

} // end vcl namespace
diff --git a/include/vcl/font/FeatureParser.hxx b/include/vcl/font/FeatureParser.hxx
old mode 100644
new mode 100755
index 3adc5fc..65de3ea
--- a/include/vcl/font/FeatureParser.hxx
+++ b/include/vcl/font/FeatureParser.hxx
@@ -18,6 +18,8 @@
#include <unordered_map>
#include <vcl/font/Feature.hxx>

#include <vcl/font/Feature.hxx>

namespace vcl
{
namespace font
@@ -32,19 +34,16 @@ class VCL_DLLPUBLIC FeatureParser
{
private:
    OUString m_sLanguage;
    std::vector<std::pair<sal_uInt32, sal_uInt32>> m_aFeatures;
    std::vector<FeatureSetting> m_aFeatures;

public:
    FeatureParser(OUString const& sFontName);

    OUString const& getLanguage() const { return m_sLanguage; }

    std::vector<std::pair<sal_uInt32, sal_uInt32>> const& getFeatures() const
    {
        return m_aFeatures;
    }
    std::vector<FeatureSetting> const& getFeatures() const { return m_aFeatures; }

    std::unordered_map<sal_uInt32, sal_uInt32> getFeaturesMap() const;
    std::unordered_map<uint32_t, uint32_t> getFeaturesMap() const;
};

} // end font namespace
diff --git a/vcl/qa/cppunit/FontFeatureTest.cxx b/vcl/qa/cppunit/FontFeatureTest.cxx
index 6a66eb1..47e610f 100644
--- a/vcl/qa/cppunit/FontFeatureTest.cxx
+++ b/vcl/qa/cppunit/FontFeatureTest.cxx
@@ -119,17 +119,17 @@ void FontFeatureTest::testGetFontFeatures()

        vcl::font::FeatureParameter const& rParameter1
            = rFracFeatureDefinition.getEnumParameters()[0];
        CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), rParameter1.getCode());
        CPPUNIT_ASSERT_EQUAL(uint32_t(0), rParameter1.getCode());
        CPPUNIT_ASSERT(!rParameter1.getDescription().isEmpty());

        vcl::font::FeatureParameter const& rParameter2
            = rFracFeatureDefinition.getEnumParameters()[1];
        CPPUNIT_ASSERT_EQUAL(sal_uInt32(1), rParameter2.getCode());
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), rParameter2.getCode());
        CPPUNIT_ASSERT(!rParameter2.getDescription().isEmpty());

        vcl::font::FeatureParameter const& rParameter3
            = rFracFeatureDefinition.getEnumParameters()[2];
        CPPUNIT_ASSERT_EQUAL(sal_uInt32(2), rParameter3.getCode());
        CPPUNIT_ASSERT_EQUAL(uint32_t(2), rParameter3.getCode());
        CPPUNIT_ASSERT(!rParameter2.getDescription().isEmpty());
    }
#endif // HAVE_MORE_FONTS
@@ -146,44 +146,184 @@ void FontFeatureTest::testParseFeature()
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].first);
        CPPUNIT_ASSERT_EQUAL(sal_uInt32(1), aFeatures[0].second);
        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue);
    }
    { // One feature specified, explicit value
        vcl::font::FeatureParser aParser("Font name:abcd=5");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].first);
        CPPUNIT_ASSERT_EQUAL(sal_uInt32(5), aFeatures[0].second);
        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(5), aFeatures[0].m_nValue);
    }
    { // One feature specified, explicit zero value
        vcl::font::FeatureParser aParser("Font name:abcd=0");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue);
    }
    { // One feature specified, using plus prefix
        vcl::font::FeatureParser aParser("Font name:+abcd");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue);
    }
    { // One feature specified, using minus prefix
        vcl::font::FeatureParser aParser("Font name:-abcd");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue);
    }
    { // One feature specified, with empty character range
        vcl::font::FeatureParser aParser("Font name:abcd[]");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(0), aFeatures[0].m_nStart);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(-1), aFeatures[0].m_nEnd);
    }
    { // One feature specified, with empty character range
        vcl::font::FeatureParser aParser("Font name:abcd[:]");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(0), aFeatures[0].m_nStart);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(-1), aFeatures[0].m_nEnd);
    }
    { // One feature specified, with start character range
        vcl::font::FeatureParser aParser("Font name:abcd[3:]");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nStart);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(-1), aFeatures[0].m_nEnd);
    }
    { // One feature specified, with end character range
        vcl::font::FeatureParser aParser("Font name:abcd[:3]");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(0), aFeatures[0].m_nStart);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nEnd);
    }
    { // One feature specified, with character range
        vcl::font::FeatureParser aParser("Font name:abcd[3:6]");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nStart);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(6), aFeatures[0].m_nEnd);
    }
    { // One feature specified, with character range
        vcl::font::FeatureParser aParser("Font name:abcd[3]");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nStart);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(4), aFeatures[0].m_nEnd);
    }
    { // One feature specified, with character range and value
        vcl::font::FeatureParser aParser("Font name:abcd[3:6]=2");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(2), aFeatures[0].m_nValue);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nStart);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(6), aFeatures[0].m_nEnd);
    }
    { // One feature specified, with character range and 0 value
        vcl::font::FeatureParser aParser("Font name:abcd[3:6]=0");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nStart);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(6), aFeatures[0].m_nEnd);
    }
    { // One feature specified, with character range and minus prefix
        vcl::font::FeatureParser aParser("Font name:-abcd[3:6]");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nStart);
        CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(6), aFeatures[0].m_nEnd);
    }
    { // One feature specified, with CSS on
        vcl::font::FeatureParser aParser("Font name:\"abcd\" on");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue);
    }
    { // One feature specified, with CSS off
        vcl::font::FeatureParser aParser("Font name:'abcd' off");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue);
    }
    { // One feature specified, with CSS value
        vcl::font::FeatureParser aParser("Font name:\"abcd\" 2");
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(2), aFeatures[0].m_nValue);
    }
    { // Multiple features specified, no values
        vcl::font::FeatureParser aParser("Font name:abcd&bcde&efgh");
        CPPUNIT_ASSERT_EQUAL(size_t(3), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].first);
        CPPUNIT_ASSERT_EQUAL(sal_uInt32(1), aFeatures[0].second);
        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue);

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("bcde"), aFeatures[1].first);
        CPPUNIT_ASSERT_EQUAL(sal_uInt32(1), aFeatures[1].second);
        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("bcde"), aFeatures[1].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[1].m_nValue);

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("efgh"), aFeatures[2].first);
        CPPUNIT_ASSERT_EQUAL(sal_uInt32(1), aFeatures[2].second);
        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("efgh"), aFeatures[2].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[2].m_nValue);
    }
    {
        // Multiple features specified, explicit values
        // Only 4 char parameter names supported - "toolong" is too long and ignored
        // If value is 0, it should be also ignored
        vcl::font::FeatureParser aParser("Font name:abcd=1&bcde=0&toolong=1&cdef=3");
        CPPUNIT_ASSERT_EQUAL(size_t(2), aParser.getFeatures().size());
        CPPUNIT_ASSERT_EQUAL(size_t(3), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].first);
        CPPUNIT_ASSERT_EQUAL(sal_uInt32(1), aFeatures[0].second);
        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue);

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("cdef"), aFeatures[1].first);
        CPPUNIT_ASSERT_EQUAL(sal_uInt32(3), aFeatures[1].second);
        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("bcde"), aFeatures[1].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[1].m_nValue);

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("cdef"), aFeatures[2].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(3), aFeatures[2].m_nValue);
    }
    {
        // Special case - "lang" is parsed specially and access separately not as a feature.
@@ -192,8 +332,8 @@ void FontFeatureTest::testParseFeature()
        CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size());
        auto aFeatures = aParser.getFeatures();

        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].first);
        CPPUNIT_ASSERT_EQUAL(sal_uInt32(1), aFeatures[0].second);
        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag);
        CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue);

        CPPUNIT_ASSERT_EQUAL(OUString("slo"), aParser.getLanguage());
    }
diff --git a/vcl/source/font/Feature.cxx b/vcl/source/font/Feature.cxx
index 07810c1..3a809cb 100644
--- a/vcl/source/font/Feature.cxx
+++ b/vcl/source/font/Feature.cxx
@@ -13,11 +13,13 @@
#include <strings.hrc>
#include <svdata.hxx>

#include <hb.h>

namespace vcl
{
namespace font
{
OUString featureCodeAsString(sal_uInt32 nFeature)
OUString featureCodeAsString(uint32_t nFeature)
{
    std::vector<sal_Char> aString(5, 0);
    aString[0] = sal_Char(nFeature >> 24 & 0xff);
@@ -41,16 +43,33 @@ Feature::Feature(FeatureID const& rID, FeatureType eType)
{
}

// FeatureSetting
FeatureSetting::FeatureSetting(OString feature)
    : m_nTag(0)
    , m_nValue(0)
    , m_nStart(0)
    , m_nEnd(0)
{
    hb_feature_t aFeat;
    if (hb_feature_from_string(feature.getStr(), feature.getLength(), &aFeat))
    {
        m_nTag = aFeat.tag;
        m_nValue = aFeat.value;
        m_nStart = aFeat.start;
        m_nEnd = aFeat.end;
    }
}

// FeatureParameter

FeatureParameter::FeatureParameter(sal_uInt32 nCode, OUString aDescription)
FeatureParameter::FeatureParameter(uint32_t nCode, OUString aDescription)
    : m_nCode(nCode)
    , m_sDescription(std::move(aDescription))
    , m_pDescriptionID(nullptr)
{
}

FeatureParameter::FeatureParameter(sal_uInt32 nCode, const char* pDescriptionID)
FeatureParameter::FeatureParameter(uint32_t nCode, const char* pDescriptionID)
    : m_nCode(nCode)
    , m_pDescriptionID(pDescriptionID)
{
@@ -68,7 +87,7 @@ OUString FeatureParameter::getDescription() const
    return aReturnString;
}

sal_uInt32 FeatureParameter::getCode() const { return m_nCode; }
uint32_t FeatureParameter::getCode() const { return m_nCode; }

// FeatureDefinition

@@ -79,7 +98,7 @@ FeatureDefinition::FeatureDefinition()
{
}

FeatureDefinition::FeatureDefinition(sal_uInt32 nCode, OUString const& rDescription,
FeatureDefinition::FeatureDefinition(uint32_t nCode, OUString const& rDescription,
                                     FeatureParameterType eType,
                                     std::vector<FeatureParameter> const& rEnumParameters)
    : m_nCode(nCode)
@@ -90,7 +109,7 @@ FeatureDefinition::FeatureDefinition(sal_uInt32 nCode, OUString const& rDescript
{
}

FeatureDefinition::FeatureDefinition(sal_uInt32 nCode, const char* pDescriptionID,
FeatureDefinition::FeatureDefinition(uint32_t nCode, const char* pDescriptionID,
                                     OUString const& rNumericPart)
    : m_nCode(nCode)
    , m_pDescriptionID(pDescriptionID)
@@ -99,7 +118,7 @@ FeatureDefinition::FeatureDefinition(sal_uInt32 nCode, const char* pDescriptionI
{
}

FeatureDefinition::FeatureDefinition(sal_uInt32 nCode, const char* pDescriptionID,
FeatureDefinition::FeatureDefinition(uint32_t nCode, const char* pDescriptionID,
                                     std::vector<FeatureParameter> aEnumParameters)
    : m_nCode(nCode)
    , m_pDescriptionID(pDescriptionID)
@@ -132,7 +151,7 @@ OUString FeatureDefinition::getDescription() const
    }
}

sal_uInt32 FeatureDefinition::getCode() const { return m_nCode; }
uint32_t FeatureDefinition::getCode() const { return m_nCode; }

FeatureParameterType FeatureDefinition::getType() const { return m_eType; }

diff --git a/vcl/source/font/FeatureParser.cxx b/vcl/source/font/FeatureParser.cxx
index 7085b94..adafbaa 100644
--- a/vcl/source/font/FeatureParser.cxx
+++ b/vcl/source/font/FeatureParser.cxx
@@ -26,43 +26,39 @@ OUString trimFontNameFeatures(OUString const& rFontName)

FeatureParser::FeatureParser(OUString const& rFontName)
{
    if (rFontName.indexOf(vcl::font::FeaturePrefix) < 0)
    sal_Int32 nPrefixIdx{ rFontName.indexOf(vcl::font::FeaturePrefix) };
    if (nPrefixIdx < 0)
        return;

    OUString sName = rFontName.getToken(1, vcl::font::FeaturePrefix);
    OUString sName = rFontName.copy(++nPrefixIdx);
    sal_Int32 nIndex = 0;
    do
    {
        OUString sToken = sName.getToken(0, vcl::font::FeatureSeparator, nIndex);

        OUString sID = sToken.getToken(0, '=');
        OUString sValue = sToken.getToken(1, '=');

        if (sID.getLength() == 4 && sValue != "0")
        if (sID == "lang")
        {
            if (sID == "lang")
            {
                m_sLanguage = sValue;
            }
            else
            {
                OString sFeatureCodeAscii = OUStringToOString(sID, RTL_TEXTENCODING_ASCII_US);
                sal_uInt32 nCode = vcl::font::featureCode(sFeatureCodeAscii.getStr());
                sal_uInt32 nValue = sValue.isEmpty() ? 1 : sValue.toUInt32();

                if (nValue != 0)
                    m_aFeatures.emplace_back(nCode, nValue);
            }
            m_sLanguage = sToken.getToken(1, '=');
        }
        else
        {
            OString sFeature = OUStringToOString(sToken, RTL_TEXTENCODING_ASCII_US);
            FeatureSetting aFeature(sFeature);
            if (aFeature.m_nTag != 0)
                m_aFeatures.push_back(aFeature);
        }
    } while (nIndex >= 0);
}

std::unordered_map<sal_uInt32, sal_uInt32> FeatureParser::getFeaturesMap() const
std::unordered_map<uint32_t, uint32_t> FeatureParser::getFeaturesMap() const
{
    std::unordered_map<sal_uInt32, sal_uInt32> aResultMap;
    for (auto const& rPair : m_aFeatures)
    std::unordered_map<uint32_t, uint32_t> aResultMap;
    for (auto const& rFeat : m_aFeatures)
    {
        aResultMap.emplace(rPair);
        if (rFeat.m_nValue != 0)
            aResultMap.emplace(rFeat.m_nTag, rFeat.m_nValue);
    }
    return aResultMap;
}
diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index 21d4d1c..9a63866 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -74,9 +74,9 @@ void GenericSalLayout::ParseFeatures(const OUString& aName)
    if (!sLanguage.isEmpty())
        msLanguage = OUStringToOString(sLanguage, RTL_TEXTENCODING_ASCII_US);

    for (std::pair<sal_uInt32, sal_uInt32> const & rPair : aParser.getFeatures())
    for (auto const &rFeat : aParser.getFeatures())
    {
        hb_feature_t aFeature { rPair.first, rPair.second, 0, SAL_MAX_UINT32 };
        hb_feature_t aFeature { rFeat.m_nTag, rFeat.m_nValue, rFeat.m_nStart, rFeat.m_nEnd };
        maFeatures.push_back(aFeature);
    }
}