vcl/inc/font/FeatureCollector.hxx              |    6 +-
 vcl/inc/font/OpenTypeFeatureDefinitionList.hxx |    2 
 vcl/qa/cppunit/FontFeatureTest.cxx             |   57 +++++++++++++++++++++++--
 vcl/source/font/FeatureCollector.cxx           |   46 +++++++++++++++++++-
 vcl/source/outdev/font.cxx                     |    4 -
 5 files changed, 105 insertions(+), 10 deletions(-)

New commits:
commit 19787042b1f139cb9c366801d283c6c0227e85e6
Author:     Khaled Hosny <kha...@aliftype.com>
AuthorDate: Wed Aug 24 00:26:10 2022 +0200
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Thu Aug 25 13:03:55 2022 +0200

    FeatureCollector: Get feature labels for ssXX/cvXX features from the font
    
    If the font provides feature labels for ssXX/cvXX features, fetch and
    use them.
    
    Switches also to using the UI language not locale for finding labels as
    the UI language is what controls the UI localization.
    
    Change-Id: Ic7eeae9df25692e7f2924b2db65905666999c904
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138748
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/vcl/inc/font/FeatureCollector.hxx 
b/vcl/inc/font/FeatureCollector.hxx
index 976a89fc8d86..ae784474e06d 100644
--- a/vcl/inc/font/FeatureCollector.hxx
+++ b/vcl/inc/font/FeatureCollector.hxx
@@ -22,14 +22,14 @@ class FeatureCollector
 private:
     hb_face_t* m_pHbFace;
     std::vector<vcl::font::Feature>& m_rFontFeatures;
-    LanguageType m_eLanguageType;
+    const LanguageTag& m_rLanguageTag;
 
 public:
     FeatureCollector(hb_face_t* pHbFace, std::vector<vcl::font::Feature>& 
rFontFeatures,
-                     LanguageType eLanguageType)
+                     const LanguageTag& rLanguageTag)
         : m_pHbFace(pHbFace)
         , m_rFontFeatures(rFontFeatures)
-        , m_eLanguageType(eLanguageType)
+        , m_rLanguageTag(rLanguageTag)
     {
     }
 
diff --git a/vcl/inc/font/OpenTypeFeatureDefinitionList.hxx 
b/vcl/inc/font/OpenTypeFeatureDefinitionList.hxx
index 52dbcfb5b9f0..aaa89ebe5d48 100644
--- a/vcl/inc/font/OpenTypeFeatureDefinitionList.hxx
+++ b/vcl/inc/font/OpenTypeFeatureDefinitionList.hxx
@@ -25,12 +25,12 @@ private:
 
     void init();
 
-    static bool isSpecialFeatureCode(sal_uInt32 nFeatureCode);
     static FeatureDefinition handleSpecialFeatureCode(sal_uInt32 nFeatureCode);
 
 public:
     OpenTypeFeatureDefinitionListPrivate();
     FeatureDefinition getDefinition(sal_uInt32 nFeatureCode);
+    static bool isSpecialFeatureCode(sal_uInt32 nFeatureCode);
     bool isRequired(sal_uInt32 nFeatureCode);
 };
 
diff --git a/vcl/qa/cppunit/FontFeatureTest.cxx 
b/vcl/qa/cppunit/FontFeatureTest.cxx
index 91bcda29b74f..103870306bcf 100644
--- a/vcl/qa/cppunit/FontFeatureTest.cxx
+++ b/vcl/qa/cppunit/FontFeatureTest.cxx
@@ -25,16 +25,18 @@ public:
     {
     }
 
-    void testGetFontFeatures();
+    void testGetFontFeaturesGraphite();
+    void testGetFontFeaturesOpenType();
     void testParseFeature();
 
     CPPUNIT_TEST_SUITE(FontFeatureTest);
-    CPPUNIT_TEST(testGetFontFeatures);
+    CPPUNIT_TEST(testGetFontFeaturesGraphite);
+    CPPUNIT_TEST(testGetFontFeaturesOpenType);
     CPPUNIT_TEST(testParseFeature);
     CPPUNIT_TEST_SUITE_END();
 };
 
-void FontFeatureTest::testGetFontFeatures()
+void FontFeatureTest::testGetFontFeaturesGraphite()
 {
 #if HAVE_MORE_FONTS
     ScopedVclPtrInstance<VirtualDevice> aVDev(*Application::GetDefaultDevice(),
@@ -118,6 +120,55 @@ void FontFeatureTest::testGetFontFeatures()
 #endif // HAVE_MORE_FONTS
 }
 
+void FontFeatureTest::testGetFontFeaturesOpenType()
+{
+#if HAVE_MORE_FONTS
+    ScopedVclPtrInstance<VirtualDevice> aVDev(*Application::GetDefaultDevice(),
+                                              DeviceFormat::DEFAULT, 
DeviceFormat::DEFAULT);
+    aVDev->SetOutputSizePixel(Size(10, 10));
+
+    OUString aFontName("Amiri");
+    CPPUNIT_ASSERT(aVDev->IsFontAvailable(aFontName));
+
+    vcl::Font aFont = aVDev->GetFont();
+    aFont.SetFamilyName(aFontName);
+    aFont.SetWeight(FontWeight::WEIGHT_NORMAL);
+    aFont.SetItalic(FontItalic::ITALIC_NORMAL);
+    aFont.SetWidthType(FontWidth::WIDTH_NORMAL);
+    aVDev->SetFont(aFont);
+
+    std::vector<vcl::font::Feature> rFontFeatures;
+    CPPUNIT_ASSERT(aVDev->GetFontFeatures(rFontFeatures));
+
+    OUString aFeaturesString;
+    for (vcl::font::Feature const& rFeature : rFontFeatures)
+        aFeaturesString += vcl::font::featureCodeAsString(rFeature.m_nCode) + 
" ";
+
+    CPPUNIT_ASSERT_EQUAL(size_t(17), rFontFeatures.size());
+
+    CPPUNIT_ASSERT_EQUAL(OUString("calt calt dnom liga numr pnum ss01 ss02 "
+                                  "ss03 ss04 ss05 ss06 ss07 ss08 kern kern "
+                                  "ss05 "),
+                         aFeaturesString);
+
+    // Check ss01 feature
+    {
+        vcl::font::Feature& rFeature = rFontFeatures[6];
+        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("ss01"), rFeature.m_nCode);
+
+        vcl::font::FeatureDefinition& rFeatureDefinition = 
rFeature.m_aDefinition;
+        CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("ss01"), 
rFeatureDefinition.getCode());
+        CPPUNIT_ASSERT_EQUAL(OUString("Low Baa dot following a Raa or Waw"),
+                             rFeatureDefinition.getDescription());
+        CPPUNIT_ASSERT_EQUAL(vcl::font::FeatureParameterType::BOOL, 
rFeatureDefinition.getType());
+
+        CPPUNIT_ASSERT_EQUAL(size_t(0), 
rFeatureDefinition.getEnumParameters().size());
+    }
+
+    aVDev.disposeAndClear();
+#endif // HAVE_MORE_FONTS
+}
+
 void FontFeatureTest::testParseFeature()
 {
     { // No font features specified
diff --git a/vcl/source/font/FeatureCollector.cxx 
b/vcl/source/font/FeatureCollector.cxx
index 20f47dfdc502..8b506f7dfd47 100644
--- a/vcl/source/font/FeatureCollector.cxx
+++ b/vcl/source/font/FeatureCollector.cxx
@@ -9,6 +9,7 @@
 
 #include <font/FeatureCollector.hxx>
 #include <font/OpenTypeFeatureDefinitionList.hxx>
+#include <i18nlangtag/languagetag.hxx>
 
 #include <hb-ot.h>
 #include <hb-graphite2.h>
@@ -22,7 +23,7 @@ bool FeatureCollector::collectGraphite()
     if (grFace == nullptr)
         return false;
 
-    gr_uint16 nUILanguage = gr_uint16(m_eLanguageType);
+    gr_uint16 nUILanguage = gr_uint16(m_rLanguageTag.getLanguageType());
 
     gr_uint16 nNumberOfFeatures = gr_face_n_fref(grFace);
     gr_feature_val* pfeatureValues
@@ -80,6 +81,29 @@ bool FeatureCollector::collectGraphite()
     return true;
 }
 
+static OUString getName(hb_face_t* pHbFace, hb_ot_name_id_t aNameID, OString& 
rLanguage)
+{
+    auto aHbLang = hb_language_from_string(rLanguage.getStr(), 
rLanguage.getLength());
+    auto nName = hb_ot_name_get_utf16(pHbFace, aNameID, aHbLang, nullptr, 
nullptr);
+
+    if (!nName)
+    {
+        // Fallback to English if localized name is missing.
+        aHbLang = hb_language_from_string("en", 2);
+        nName = hb_ot_name_get_utf16(pHbFace, aNameID, aHbLang, nullptr, 
nullptr);
+    }
+
+    OUString sName;
+    if (nName)
+    {
+        std::vector<uint16_t> aBuf(++nName); // make space for terminating NUL.
+        hb_ot_name_get_utf16(pHbFace, aNameID, aHbLang, &nName, aBuf.data());
+        sName = OUString(reinterpret_cast<sal_Unicode*>(aBuf.data()), nName);
+    }
+
+    return sName;
+}
+
 void FeatureCollector::collectForTable(hb_tag_t aTableTag)
 {
     unsigned int nFeatureCount
@@ -99,6 +123,26 @@ void FeatureCollector::collectForTable(hb_tag_t aTableTag)
         rFeature.m_nCode = aFeatureTag;
 
         FeatureDefinition aDefinition = 
OpenTypeFeatureDefinitionList().getDefinition(aFeatureTag);
+
+        if 
(OpenTypeFeatureDefinitionListPrivate::isSpecialFeatureCode(aFeatureTag))
+        {
+            unsigned int nFeatureIdx;
+            if (hb_ot_layout_language_find_feature(m_pHbFace, aTableTag, 0,
+                                                   
HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, aFeatureTag,
+                                                   &nFeatureIdx))
+            {
+                hb_ot_name_id_t aLabelID;
+                if (hb_ot_layout_feature_get_name_ids(m_pHbFace, aTableTag, 
nFeatureIdx, &aLabelID,
+                                                      nullptr, nullptr, 
nullptr, nullptr))
+                {
+                    OString sLanguage = m_rLanguageTag.getBcp47().toUtf8();
+                    OUString sLabel = getName(m_pHbFace, aLabelID, sLanguage);
+                    if (!sLabel.isEmpty())
+                        aDefinition = 
vcl::font::FeatureDefinition(aFeatureTag, sLabel);
+                }
+            }
+        }
+
         if (aDefinition)
             rFeature.m_aDefinition = aDefinition;
     }
diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx
index e24d6ac014db..dc5ca50abaf9 100644
--- a/vcl/source/outdev/font.cxx
+++ b/vcl/source/outdev/font.cxx
@@ -170,9 +170,9 @@ bool 
OutputDevice::GetFontFeatures(std::vector<vcl::font::Feature>& rFontFeature
     if (!pHbFace)
         return false;
 
-    const LanguageType eOfficeLanguage = 
Application::GetSettings().GetLanguageTag().getLanguageType();
+    const LanguageTag& rOfficeLanguage = 
Application::GetSettings().GetUILanguageTag();
 
-    vcl::font::FeatureCollector aFeatureCollector(pHbFace, rFontFeatures, 
eOfficeLanguage);
+    vcl::font::FeatureCollector aFeatureCollector(pHbFace, rFontFeatures, 
rOfficeLanguage);
     aFeatureCollector.collect();
 
     return true;

Reply via email to