summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vcl/inc/font/OpenTypeFeatureStrings.hrc1
-rw-r--r--vcl/qa/cppunit/FontFeatureTest.cxx61
-rw-r--r--vcl/source/font/FeatureCollector.cxx69
3 files changed, 124 insertions, 7 deletions
diff --git a/vcl/inc/font/OpenTypeFeatureStrings.hrc b/vcl/inc/font/OpenTypeFeatureStrings.hrc
index a8bb5473fafb..aebdda1d2743 100644
--- a/vcl/inc/font/OpenTypeFeatureStrings.hrc
+++ b/vcl/inc/font/OpenTypeFeatureStrings.hrc
@@ -97,6 +97,7 @@
#define STR_FONT_FEATURE_ID_VRT2 NC_("STR_FONT_FEATURE_ID_VRT2", "Vertical Alternates and Rotation")
#define STR_FONT_FEATURE_ID_VRTR NC_("STR_FONT_FEATURE_ID_VRTR", "Vertical Alternates for Rotation")
#define STR_FONT_FEATURE_ID_ZERO NC_("STR_FONT_FEATURE_ID_ZERO", "Slashed Zero")
+#define STR_FONT_FEATURE_PARAM_NONE NC_("STR_FONT_FEATURE_PARAM_NONE", "None")
#endif // INCLUDED_VCL_INC_STRINGS_HRC
diff --git a/vcl/qa/cppunit/FontFeatureTest.cxx b/vcl/qa/cppunit/FontFeatureTest.cxx
index 103870306bcf..9858c96e0a9f 100644
--- a/vcl/qa/cppunit/FontFeatureTest.cxx
+++ b/vcl/qa/cppunit/FontFeatureTest.cxx
@@ -27,11 +27,13 @@ public:
void testGetFontFeaturesGraphite();
void testGetFontFeaturesOpenType();
+ void testGetFontFeaturesOpenTypeEnum();
void testParseFeature();
CPPUNIT_TEST_SUITE(FontFeatureTest);
CPPUNIT_TEST(testGetFontFeaturesGraphite);
CPPUNIT_TEST(testGetFontFeaturesOpenType);
+ CPPUNIT_TEST(testGetFontFeaturesOpenTypeEnum);
CPPUNIT_TEST(testParseFeature);
CPPUNIT_TEST_SUITE_END();
};
@@ -169,6 +171,65 @@ void FontFeatureTest::testGetFontFeaturesOpenType()
#endif // HAVE_MORE_FONTS
}
+void FontFeatureTest::testGetFontFeaturesOpenTypeEnum()
+{
+#if HAVE_MORE_FONTS
+ ScopedVclPtrInstance<VirtualDevice> aVDev(*Application::GetDefaultDevice(),
+ DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
+ aVDev->SetOutputSizePixel(Size(10, 10));
+
+ OUString aFontName("Reem Kufi");
+ 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(10), rFontFeatures.size());
+
+ CPPUNIT_ASSERT_EQUAL(OUString("aalt case cv01 cv02 cv03 frac ordn sups "
+ "zero kern "),
+ aFeaturesString);
+
+ // Check aalt feature
+ {
+ vcl::font::Feature& rFeature = rFontFeatures[0];
+ CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("aalt"), rFeature.m_nCode);
+
+ vcl::font::FeatureDefinition& rFeatureDefinition = rFeature.m_aDefinition;
+ CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("aalt"), rFeatureDefinition.getCode());
+ CPPUNIT_ASSERT(!rFeatureDefinition.getDescription().isEmpty());
+ CPPUNIT_ASSERT_EQUAL(vcl::font::FeatureParameterType::ENUM, rFeatureDefinition.getType());
+
+ CPPUNIT_ASSERT_EQUAL(size_t(3), rFeatureDefinition.getEnumParameters().size());
+
+ vcl::font::FeatureParameter const& rParameter1 = rFeatureDefinition.getEnumParameters()[0];
+ CPPUNIT_ASSERT_EQUAL(uint32_t(0), rParameter1.getCode());
+ CPPUNIT_ASSERT(!rParameter1.getDescription().isEmpty());
+
+ vcl::font::FeatureParameter const& rParameter2 = rFeatureDefinition.getEnumParameters()[1];
+ CPPUNIT_ASSERT_EQUAL(uint32_t(1), rParameter2.getCode());
+ CPPUNIT_ASSERT(!rParameter2.getDescription().isEmpty());
+
+ vcl::font::FeatureParameter const& rParameter3 = rFeatureDefinition.getEnumParameters()[2];
+ CPPUNIT_ASSERT_EQUAL(uint32_t(2), rParameter3.getCode());
+ CPPUNIT_ASSERT(!rParameter2.getDescription().isEmpty());
+ }
+
+ 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 8b506f7dfd47..c792d50d7e17 100644
--- a/vcl/source/font/FeatureCollector.cxx
+++ b/vcl/source/font/FeatureCollector.cxx
@@ -11,6 +11,9 @@
#include <font/OpenTypeFeatureDefinitionList.hxx>
#include <i18nlangtag/languagetag.hxx>
+#include <font/OpenTypeFeatureStrings.hrc>
+#include <svdata.hxx>
+
#include <hb-ot.h>
#include <hb-graphite2.h>
@@ -123,24 +126,76 @@ void FeatureCollector::collectForTable(hb_tag_t aTableTag)
rFeature.m_nCode = aFeatureTag;
FeatureDefinition aDefinition = OpenTypeFeatureDefinitionList().getDefinition(aFeatureTag);
-
- if (OpenTypeFeatureDefinitionListPrivate::isSpecialFeatureCode(aFeatureTag))
+ std::vector<vcl::font::FeatureParameter> aParameters{
+ { 0, VclResId(STR_FONT_FEATURE_PARAM_NONE) }
+ };
+
+ unsigned int nFeatureIdx;
+ if (hb_ot_layout_language_find_feature(m_pHbFace, aTableTag, 0,
+ HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, aFeatureTag,
+ &nFeatureIdx))
{
- unsigned int nFeatureIdx;
- if (hb_ot_layout_language_find_feature(m_pHbFace, aTableTag, 0,
- HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, aFeatureTag,
- &nFeatureIdx))
+ if (OpenTypeFeatureDefinitionListPrivate::isSpecialFeatureCode(aFeatureTag))
{
+ // ssXX and cvXX can have name ID defined for them, check for
+ // them and use as appropriate.
hb_ot_name_id_t aLabelID;
+ hb_ot_name_id_t aFirstParameterID;
+ unsigned nNamedParameters;
if (hb_ot_layout_feature_get_name_ids(m_pHbFace, aTableTag, nFeatureIdx, &aLabelID,
- nullptr, nullptr, nullptr, nullptr))
+ nullptr, nullptr, &nNamedParameters,
+ &aFirstParameterID))
{
OString sLanguage = m_rLanguageTag.getBcp47().toUtf8();
OUString sLabel = getName(m_pHbFace, aLabelID, sLanguage);
if (!sLabel.isEmpty())
aDefinition = vcl::font::FeatureDefinition(aFeatureTag, sLabel);
+
+ // cvXX features can have parameters name IDs, check for
+ // them and populate feature parameters as appropriate.
+ for (unsigned i = 0; i < nNamedParameters; i++)
+ {
+ hb_ot_name_id_t aNameID = aFirstParameterID + i;
+ OUString sName = getName(m_pHbFace, aNameID, sLanguage);
+ if (!sName.isEmpty())
+ aParameters.emplace_back(uint32_t(i), sName);
+ }
+ }
+ }
+
+ // Collect lookups in this feature, and input glyphs for each
+ // lookup, and calculate the max number of alternates they have.
+ unsigned int nLookups = hb_ot_layout_feature_get_lookups(
+ m_pHbFace, aTableTag, nFeatureIdx, 0, nullptr, nullptr);
+ std::vector<unsigned int> aLookups(nLookups);
+ hb_ot_layout_feature_get_lookups(m_pHbFace, aTableTag, nFeatureIdx, 0, &nLookups,
+ aLookups.data());
+ unsigned int nAlternates = 0;
+ for (unsigned int nLookupIdx : aLookups)
+ {
+ hb_set_t* aGlyphs = hb_set_create();
+ hb_ot_layout_lookup_collect_glyphs(m_pHbFace, aTableTag, nLookupIdx, nullptr,
+ aGlyphs, nullptr, nullptr);
+ hb_codepoint_t nGlyphIdx = HB_SET_VALUE_INVALID;
+ while (hb_set_next(aGlyphs, &nGlyphIdx))
+ {
+ nAlternates = std::max(
+ nAlternates, hb_ot_layout_lookup_get_glyph_alternates(
+ m_pHbFace, nLookupIdx, nGlyphIdx, 0, nullptr, nullptr));
}
}
+
+ // Append the alternates to the feature parameters, keeping any
+ // existing ones calculated from cvXX features above.
+ for (unsigned int i = aParameters.size() - 1; i < nAlternates; i++)
+ aParameters.emplace_back(uint32_t(i + 1), OUString::number(i + 1));
+
+ if (aParameters.size() > 1)
+ {
+ aDefinition = vcl::font::FeatureDefinition(
+ aFeatureTag, aDefinition.getDescription(),
+ vcl::font::FeatureParameterType::ENUM, std::move(aParameters), 0);
+ }
}
if (aDefinition)