summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2018-06-15 18:50:00 +0200
committerTomaž Vajngerl <quikee@gmail.com>2018-06-16 14:28:40 +0200
commitbda33ba2ce4d53214e1bd9ee62b05ced0525e8db (patch)
tree2668d78510ba316a40478b629d87009610d9e19c
parent8dacd42f3af903ac3daeef8f4dd444ffc7e1a99c (diff)
tdf#58941 implement retrieving font features and structures
This adds the following: - Retrieving of features using HarfBuzz - Retrieving of feature definitions from graphite fonts - Adds description texts of OpenType features - Tests for retrieving features (Linux Libertine G graphite font) and making sure the features and definitions are what we expect. Change-Id: I51573fe086e59c6228cb546bbfac95ac53824c47 Reviewed-on: https://gerrit.libreoffice.org/55892 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
-rw-r--r--include/vcl/font/Feature.hxx99
-rw-r--r--include/vcl/outdev.hxx6
-rw-r--r--vcl/CppunitTest_vcl_fontfeature.mk49
-rw-r--r--vcl/Library_vcl.mk3
-rw-r--r--vcl/Module_vcl.mk1
-rw-r--r--vcl/inc/font/FeatureCollector.hxx52
-rw-r--r--vcl/inc/font/OpenTypeFeatureDefinitonList.hxx47
-rw-r--r--vcl/inc/font/OpenTypeFeatureStrings.hrc184
-rw-r--r--vcl/qa/cppunit/FontFeatureTest.cxx110
-rw-r--r--vcl/source/font/Feature.cxx119
-rw-r--r--vcl/source/font/FeatureCollector.cxx141
-rw-r--r--vcl/source/font/OpenTypeFeatureDefinitonList.cxx199
-rw-r--r--vcl/source/outdev/font.cxx34
13 files changed, 1044 insertions, 0 deletions
diff --git a/include/vcl/font/Feature.hxx b/include/vcl/font/Feature.hxx
new file mode 100644
index 000000000000..0fa8f6d5bb70
--- /dev/null
+++ b/include/vcl/font/Feature.hxx
@@ -0,0 +1,99 @@
+/* -*- 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_FONT_FEATURE_HXX
+#define INCLUDED_VCL_FONT_FEATURE_HXX
+
+#include <vcl/dllapi.h>
+#include <rtl/ustring.hxx>
+#include <rtl/string.hxx>
+#include <memory>
+#include <vector>
+#include <unordered_map>
+
+namespace vcl
+{
+namespace font
+{
+constexpr sal_uInt32 featureCode(const char sFeature[4])
+{
+ return sFeature[0] << 24 | sFeature[1] << 16 | sFeature[2] << 8 | sFeature[3] << 0;
+}
+
+VCL_DLLPUBLIC OUString featureCodeAsString(sal_uInt32 nFeature);
+
+enum class FeatureParameterType
+{
+ BOOL,
+ ENUM
+};
+
+struct VCL_DLLPUBLIC FeatureParameter
+{
+private:
+ sal_uInt32 m_nCode;
+ OUString m_sDescription;
+ const char* m_pDescriptionID;
+
+public:
+ FeatureParameter(sal_uInt32 nCode, OUString aDescription);
+ FeatureParameter(sal_uInt32 nCode, const char* pDescriptionID);
+
+ sal_uInt32 getCode() const;
+ OUString getDescription() const;
+};
+
+class VCL_DLLPUBLIC FeatureDefinition
+{
+private:
+ sal_uInt32 m_nCode;
+ OUString m_sDescription;
+ const char* m_pDescriptionID;
+ FeatureParameterType m_eType;
+ // the index of the parameter defines the enum value, string is the description
+ std::vector<FeatureParameter> m_aEnumParameters;
+
+public:
+ FeatureDefinition();
+ FeatureDefinition(sal_uInt32 nCode, OUString const& rDescription,
+ FeatureParameterType eType = FeatureParameterType::BOOL,
+ std::vector<FeatureParameter> const& rEnumParameters
+ = std::vector<FeatureParameter>{});
+ FeatureDefinition(sal_uInt32 nCode, const char* pDescriptionID);
+ FeatureDefinition(sal_uInt32 nCode, const char* pDescriptionID,
+ std::vector<FeatureParameter> aEnumParameters);
+
+ const std::vector<FeatureParameter>& getEnumParameters() const;
+ OUString getDescription() const;
+ sal_uInt32 getCode() const;
+ FeatureParameterType getType() const;
+
+ operator bool() const;
+};
+
+struct VCL_DLLPUBLIC FeatureID
+{
+ sal_uInt32 m_aFeatureCode;
+ sal_uInt32 m_aScriptCode;
+ sal_uInt32 m_aLanguageCode;
+};
+
+struct VCL_DLLPUBLIC Feature
+{
+ FeatureID m_aID;
+ FeatureDefinition m_aDefinition;
+};
+
+} // end font namespace
+
+} // end vcl namespace
+
+#endif // INCLUDED_VCL_FONT_FEATURE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index 5cff1915b602..96fd4246a070 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -101,6 +101,9 @@ namespace vcl
class TextLayoutCache;
class Window;
class FontInfo;
+ namespace font {
+ struct Feature;
+ }
}
namespace com { namespace sun { namespace star { namespace rendering {
@@ -1218,6 +1221,9 @@ public:
bool GetFontCharMap( FontCharMapRef& rxFontCharMap ) const;
bool GetFontCapabilities( vcl::FontCapabilities& rFontCapabilities ) const;
+ bool GetFontFeatures(std::vector<vcl::font::Feature>& rFontFeatures) const;
+
+
/** Retrieve detailed font information in platform independent structure
@param nFallbacklevel Fallback font level (0 = best matching font)
diff --git a/vcl/CppunitTest_vcl_fontfeature.mk b/vcl/CppunitTest_vcl_fontfeature.mk
new file mode 100644
index 000000000000..bb3b97106de1
--- /dev/null
+++ b/vcl/CppunitTest_vcl_fontfeature.mk
@@ -0,0 +1,49 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,vcl_fontfeature))
+
+$(eval $(call gb_CppunitTest_set_include,vcl_fontfeature,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/vcl/inc \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,vcl_fontfeature, \
+ vcl/qa/cppunit/FontFeatureTest \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,vcl_fontfeature,boost_headers))
+
+$(eval $(call gb_CppunitTest_use_libraries,vcl_fontfeature, \
+ comphelper \
+ cppu \
+ cppuhelper \
+ sal \
+ svt \
+ test \
+ tl \
+ tk \
+ unotest \
+ vcl \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,vcl_fontfeature))
+
+$(eval $(call gb_CppunitTest_use_ure,vcl_fontfeature))
+$(eval $(call gb_CppunitTest_use_vcl,vcl_fontfeature))
+
+$(eval $(call gb_CppunitTest_use_components,vcl_fontfeature,\
+ configmgr/source/configmgr \
+ i18npool/util/i18npool \
+ ucb/source/core/ucb1 \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,vcl_fontfeature))
+
+# vim: set noet sw=4 ts=4:
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index fd99be295c98..58fbfaaa8b56 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -403,6 +403,9 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/filter/wmf/wmf \
vcl/source/filter/wmf/wmfexternal \
vcl/source/filter/wmf/wmfwr \
+ vcl/source/font/Feature \
+ vcl/source/font/FeatureCollector \
+ vcl/source/font/OpenTypeFeatureDefinitonList \
vcl/source/font/PhysicalFontCollection \
vcl/source/font/PhysicalFontFace \
vcl/source/font/PhysicalFontFamily \
diff --git a/vcl/Module_vcl.mk b/vcl/Module_vcl.mk
index a739d5988716..f2dfff71d862 100644
--- a/vcl/Module_vcl.mk
+++ b/vcl/Module_vcl.mk
@@ -192,6 +192,7 @@ $(eval $(call gb_Module_add_check_targets,vcl,\
CppunitTest_vcl_graphic_test \
CppunitTest_vcl_fontcharmap \
CppunitTest_vcl_font \
+ CppunitTest_vcl_fontfeature \
CppunitTest_vcl_fontmetric \
CppunitTest_vcl_complextext \
CppunitTest_vcl_filters_test \
diff --git a/vcl/inc/font/FeatureCollector.hxx b/vcl/inc/font/FeatureCollector.hxx
new file mode 100644
index 000000000000..4e918c48e334
--- /dev/null
+++ b/vcl/inc/font/FeatureCollector.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#ifndef INCLUDED_VCL_INC_FONT_FEATURECOLLECTOR_HXX
+#define INCLUDED_VCL_INC_FONT_FEATURECOLLECTOR_HXX
+
+#include <vcl/font/Feature.hxx>
+#include <o3tl/make_unique.hxx>
+#include <hb.h>
+
+namespace vcl
+{
+namespace font
+{
+class FeatureCollector
+{
+private:
+ hb_face_t* m_pHbFace;
+ std::vector<vcl::font::Feature>& m_rFontFeatures;
+
+public:
+ FeatureCollector(hb_face_t* pHbFace, std::vector<vcl::font::Feature>& rFontFeatures)
+ : m_pHbFace(pHbFace)
+ , m_rFontFeatures(rFontFeatures)
+ {
+ }
+
+private:
+ bool collectGraphiteFeatureDefinition(vcl::font::Feature& rFeature);
+
+ void collectForLanguage(hb_tag_t aTableTag, sal_uInt32 nScript, hb_tag_t aScriptTag,
+ sal_uInt32 nLanguage, hb_tag_t aLanguageTag);
+
+ void collectForScript(hb_tag_t aTableTag, sal_uInt32 nScript, hb_tag_t aScriptTag);
+
+public:
+ void collectForTable(hb_tag_t aTableTag);
+};
+
+} // end namespace font
+} // end namespace vcl
+
+#endif // INCLUDED_VCL_INC_FONT_FEATURECOLLECTOR_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/font/OpenTypeFeatureDefinitonList.hxx b/vcl/inc/font/OpenTypeFeatureDefinitonList.hxx
new file mode 100644
index 000000000000..f606017d7412
--- /dev/null
+++ b/vcl/inc/font/OpenTypeFeatureDefinitonList.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_VCL_INC_FONT_OPENTYPEFEATUREDEFINITONLIST_HXX
+#define INCLUDED_VCL_INC_FONT_OPENTYPEFEATUREDEFINITONLIST_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/font/Feature.hxx>
+#include <rtl/instance.hxx>
+#include <memory>
+#include <vector>
+#include <unordered_map>
+
+namespace vcl
+{
+namespace font
+{
+class VCL_DLLPUBLIC OpenTypeFeatureDefinitonListPrivate
+{
+private:
+ std::vector<FeatureDefinition> m_aFeatureDefinition;
+ std::unordered_map<sal_uInt32, size_t> m_aCodeToIndex;
+
+ void init();
+
+public:
+ OpenTypeFeatureDefinitonListPrivate();
+ FeatureDefinition getDefinition(sal_uInt32 nFeatureCode);
+};
+
+class VCL_DLLPUBLIC OpenTypeFeatureDefinitonList
+ : public rtl::Static<OpenTypeFeatureDefinitonListPrivate, OpenTypeFeatureDefinitonList>
+{
+};
+
+} // end font namespace
+} // end vcl namespace
+
+#endif // INCLUDED_VCL_INC_FONT_OPENTYPEFEATUREDEFINITONLIST_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/font/OpenTypeFeatureStrings.hrc b/vcl/inc/font/OpenTypeFeatureStrings.hrc
new file mode 100644
index 000000000000..379a013b9f89
--- /dev/null
+++ b/vcl/inc/font/OpenTypeFeatureStrings.hrc
@@ -0,0 +1,184 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_VCL_INC_FONT_OPENTYPEFEATRESTRINGS_HRC
+#define INCLUDED_VCL_INC_FONT_OPENTYPEFEATRESTRINGS_HRC
+
+#define NC_(Context, String) (Context "\004" u8##String)
+
+#define STR_FONT_FEATURE_ID_AALT NC_("STR_FONT_FEATURE_ID_AALT", "Access All Alternates")
+#define STR_FONT_FEATURE_ID_ABVF NC_("STR_FONT_FEATURE_ID_ABVF", "Above Base Forms")
+#define STR_FONT_FEATURE_ID_ABVM NC_("STR_FONT_FEATURE_ID_ABVM", "Above Base Mark Positioning")
+#define STR_FONT_FEATURE_ID_ABVS NC_("STR_FONT_FEATURE_ID_ABVS", "Above Base Substitutions")
+#define STR_FONT_FEATURE_ID_AFRC NC_("STR_FONT_FEATURE_ID_AFRC", "Alternative (Vertical) Fractions")
+#define STR_FONT_FEATURE_ID_AKHN NC_("STR_FONT_FEATURE_ID_AKHN", "Akhands")
+#define STR_FONT_FEATURE_ID_ALIG NC_("STR_FONT_FEATURE_ID_ALIG", "Ancient Ligatures")
+#define STR_FONT_FEATURE_ID_BLWF NC_("STR_FONT_FEATURE_ID_BLWF", "Below Base Forms")
+#define STR_FONT_FEATURE_ID_BLWM NC_("STR_FONT_FEATURE_ID_BLWM", "Below Base Mark Positioning")
+#define STR_FONT_FEATURE_ID_BLWS NC_("STR_FONT_FEATURE_ID_BLWS", "Below Base Substitutions")
+#define STR_FONT_FEATURE_ID_C2PC NC_("STR_FONT_FEATURE_ID_C2PC", "Capitals to Petite Capitals")
+#define STR_FONT_FEATURE_ID_C2SC NC_("STR_FONT_FEATURE_ID_C2SC", "Capitals to Small Capitals")
+#define STR_FONT_FEATURE_ID_CALT NC_("STR_FONT_FEATURE_ID_CALT", "Contextual Alternates")
+#define STR_FONT_FEATURE_ID_CASE NC_("STR_FONT_FEATURE_ID_CASE", "Case-Sensitive Forms")
+#define STR_FONT_FEATURE_ID_CCMP NC_("STR_FONT_FEATURE_ID_CCMP", "Glyph Composition / Decomposition")
+#define STR_FONT_FEATURE_ID_CFAR NC_("STR_FONT_FEATURE_ID_CFAR", "Conjunct Form After Ro")
+#define STR_FONT_FEATURE_ID_CJCT NC_("STR_FONT_FEATURE_ID_CJCT", "Conjunct Forms")
+#define STR_FONT_FEATURE_ID_CLIG NC_("STR_FONT_FEATURE_ID_CLIG", "Contextual Ligatures")
+#define STR_FONT_FEATURE_ID_CPCT NC_("STR_FONT_FEATURE_ID_CPCT", "Centered CJK Punctuation")
+#define STR_FONT_FEATURE_ID_CPSP NC_("STR_FONT_FEATURE_ID_CPSP", "Capital Spacing")
+#define STR_FONT_FEATURE_ID_CSWH NC_("STR_FONT_FEATURE_ID_CSWH", "Contextual Swash")
+#define STR_FONT_FEATURE_ID_CURS NC_("STR_FONT_FEATURE_ID_CURS", "Cursive Attachment")
+#define STR_FONT_FEATURE_ID_CV01 NC_("STR_FONT_FEATURE_ID_CV01", "Character Variant 1")
+#define STR_FONT_FEATURE_ID_CV02 NC_("STR_FONT_FEATURE_ID_CV02", "Character Variant 2")
+#define STR_FONT_FEATURE_ID_CV03 NC_("STR_FONT_FEATURE_ID_CV03", "Character Variant 3")
+#define STR_FONT_FEATURE_ID_CV04 NC_("STR_FONT_FEATURE_ID_CV04", "Character Variant 4")
+#define STR_FONT_FEATURE_ID_CV05 NC_("STR_FONT_FEATURE_ID_CV05", "Character Variant 5")
+#define STR_FONT_FEATURE_ID_CV06 NC_("STR_FONT_FEATURE_ID_CV06", "Character Variant 6")
+#define STR_FONT_FEATURE_ID_CV07 NC_("STR_FONT_FEATURE_ID_CV07", "Character Variant 7")
+#define STR_FONT_FEATURE_ID_CV08 NC_("STR_FONT_FEATURE_ID_CV08", "Character Variant 8")
+#define STR_FONT_FEATURE_ID_CV09 NC_("STR_FONT_FEATURE_ID_CV09", "Character Variant 9")
+#define STR_FONT_FEATURE_ID_CV10 NC_("STR_FONT_FEATURE_ID_CV10", "Character Variant 10")
+#define STR_FONT_FEATURE_ID_CV11 NC_("STR_FONT_FEATURE_ID_CV11", "Character Variant 11")
+#define STR_FONT_FEATURE_ID_DCAP NC_("STR_FONT_FEATURE_ID_DCAP", "Drop Caps")
+#define STR_FONT_FEATURE_ID_DIST NC_("STR_FONT_FEATURE_ID_DIST", "Distances")
+#define STR_FONT_FEATURE_ID_DLIG NC_("STR_FONT_FEATURE_ID_DLIG", "Discretionary Ligatures")
+#define STR_FONT_FEATURE_ID_DNOM NC_("STR_FONT_FEATURE_ID_DNOM", "Denominators")
+#define STR_FONT_FEATURE_ID_DPNG NC_("STR_FONT_FEATURE_ID_DPNG", "Dipthongs (Obsolete)")
+#define STR_FONT_FEATURE_ID_DTLS NC_("STR_FONT_FEATURE_ID_DTLS", "Dotless Forms")
+#define STR_FONT_FEATURE_ID_EXPT NC_("STR_FONT_FEATURE_ID_EXPT", "Expert Forms")
+#define STR_FONT_FEATURE_ID_FALT NC_("STR_FONT_FEATURE_ID_FALT", "Final Glyph on Line Alternates")
+#define STR_FONT_FEATURE_ID_FIN2 NC_("STR_FONT_FEATURE_ID_FIN2", "Terminal Forms #2")
+#define STR_FONT_FEATURE_ID_FIN3 NC_("STR_FONT_FEATURE_ID_FIN3", "Terminal Forms #3")
+#define STR_FONT_FEATURE_ID_FINA NC_("STR_FONT_FEATURE_ID_FINA", "Terminal Forms")
+#define STR_FONT_FEATURE_ID_FLAC NC_("STR_FONT_FEATURE_ID_FLAC", "Flattened Accent Over Capitals")
+#define STR_FONT_FEATURE_ID_FRAC NC_("STR_FONT_FEATURE_ID_FRAC", "DIagonal Fractions")
+#define STR_FONT_FEATURE_ID_FRAC_PARAM_1 NC_("STR_FONT_FEATURE_ID_FRAC_PARAM_1", "Diagonal Fractions")
+#define STR_FONT_FEATURE_ID_FRAC_PARAM_2 NC_("STR_FONT_FEATURE_ID_FRAC_PARAM_2", "Nut Fractions")
+#define STR_FONT_FEATURE_ID_FWID NC_("STR_FONT_FEATURE_ID_FWID", "Full Widths")
+#define STR_FONT_FEATURE_ID_HALF NC_("STR_FONT_FEATURE_ID_HALF", "Half Forms")
+#define STR_FONT_FEATURE_ID_HALN NC_("STR_FONT_FEATURE_ID_HALN", "Halant Forms")
+#define STR_FONT_FEATURE_ID_HALT NC_("STR_FONT_FEATURE_ID_HALT", "Alternate Half Widths")
+#define STR_FONT_FEATURE_ID_HIST NC_("STR_FONT_FEATURE_ID_HIST", "Historical Forms")
+#define STR_FONT_FEATURE_ID_HKNA NC_("STR_FONT_FEATURE_ID_HKNA", "Horizontal Kana Alternates")
+#define STR_FONT_FEATURE_ID_HLIG NC_("STR_FONT_FEATURE_ID_HLIG", "Historical Ligatures")
+#define STR_FONT_FEATURE_ID_HNGL NC_("STR_FONT_FEATURE_ID_HNGL", "Hanja to Hangul")
+#define STR_FONT_FEATURE_ID_HOJO NC_("STR_FONT_FEATURE_ID_HOJO", "Hojo Kanji Forms (JIS X 0212-1990 Kanji Forms)")
+#define STR_FONT_FEATURE_ID_HWID NC_("STR_FONT_FEATURE_ID_HWID", "Half Widths")
+#define STR_FONT_FEATURE_ID_INIT NC_("STR_FONT_FEATURE_ID_INIT", "Initial Forms")
+#define STR_FONT_FEATURE_ID_ISOL NC_("STR_FONT_FEATURE_ID_ISOL", "Isolated Forms")
+#define STR_FONT_FEATURE_ID_ITAL NC_("STR_FONT_FEATURE_ID_ITAL", "Italics")
+#define STR_FONT_FEATURE_ID_JALT NC_("STR_FONT_FEATURE_ID_JALT", "Justification Alternates")
+#define STR_FONT_FEATURE_ID_JP04 NC_("STR_FONT_FEATURE_ID_JP04", "JIS2004 Forms")
+#define STR_FONT_FEATURE_ID_JP78 NC_("STR_FONT_FEATURE_ID_JP78", "JIS78 Forms")
+#define STR_FONT_FEATURE_ID_JP83 NC_("STR_FONT_FEATURE_ID_JP83", "JIS83 Forms")
+#define STR_FONT_FEATURE_ID_JP90 NC_("STR_FONT_FEATURE_ID_JP90", "JIS90 Forms")
+#define STR_FONT_FEATURE_ID_KERN NC_("STR_FONT_FEATURE_ID_KERN", "Horizontal Kerning")
+#define STR_FONT_FEATURE_ID_LFBD NC_("STR_FONT_FEATURE_ID_LFBD", "Left Bounds")
+#define STR_FONT_FEATURE_ID_LIGA NC_("STR_FONT_FEATURE_ID_LIGA", "Standard Ligatures")
+#define STR_FONT_FEATURE_ID_LJMO NC_("STR_FONT_FEATURE_ID_LJMO", "Leading Jamo Forms")
+#define STR_FONT_FEATURE_ID_LNUM NC_("STR_FONT_FEATURE_ID_LNUM", "Lining Figures")
+#define STR_FONT_FEATURE_ID_LOCL NC_("STR_FONT_FEATURE_ID_LOCL", "Localized Forms")
+#define STR_FONT_FEATURE_ID_LTRA NC_("STR_FONT_FEATURE_ID_LTRA", "Left to Right Alternates")
+#define STR_FONT_FEATURE_ID_LTRM NC_("STR_FONT_FEATURE_ID_LTRM", "Left to Right Mirrored Forms")
+#define STR_FONT_FEATURE_ID_MARK NC_("STR_FONT_FEATURE_ID_MARK", "Mark Positioning")
+#define STR_FONT_FEATURE_ID_MED2 NC_("STR_FONT_FEATURE_ID_MED2", "Medial Forms #2")
+#define STR_FONT_FEATURE_ID_MEDI NC_("STR_FONT_FEATURE_ID_MEDI", "Medial Forms")
+#define STR_FONT_FEATURE_ID_MGRK NC_("STR_FONT_FEATURE_ID_MGRK", "Mathematical Greek")
+#define STR_FONT_FEATURE_ID_MKMK NC_("STR_FONT_FEATURE_ID_MKMK", "Mark to Mark Positioning")
+#define STR_FONT_FEATURE_ID_MSET NC_("STR_FONT_FEATURE_ID_MSET", "Mark Positioning via Substitution")
+#define STR_FONT_FEATURE_ID_NALT NC_("STR_FONT_FEATURE_ID_NALT", "Alternate Annotation Forms")
+#define STR_FONT_FEATURE_ID_NLCK NC_("STR_FONT_FEATURE_ID_NLCK", "NLC Kanji Forms")
+#define STR_FONT_FEATURE_ID_NUKT NC_("STR_FONT_FEATURE_ID_NUKT", "Nukta Forms")
+#define STR_FONT_FEATURE_ID_NUMR NC_("STR_FONT_FEATURE_ID_NUMR", "Numerators")
+#define STR_FONT_FEATURE_ID_ONUM NC_("STR_FONT_FEATURE_ID_ONUM", "Oldstyle Figures")
+#define STR_FONT_FEATURE_ID_OPBD NC_("STR_FONT_FEATURE_ID_OPBD", "Optical Bounds")
+#define STR_FONT_FEATURE_ID_ORDN NC_("STR_FONT_FEATURE_ID_ORDN", "Ordinals")
+#define STR_FONT_FEATURE_ID_ORNM NC_("STR_FONT_FEATURE_ID_ORNM", "Ornaments")
+#define STR_FONT_FEATURE_ID_PALT NC_("STR_FONT_FEATURE_ID_PALT", "Proportional Alternate Metrics")
+#define STR_FONT_FEATURE_ID_PCAP NC_("STR_FONT_FEATURE_ID_PCAP", "Lowercase to Petite Capitals")
+#define STR_FONT_FEATURE_ID_PKNA NC_("STR_FONT_FEATURE_ID_PKNA", "Proportional Kana")
+#define STR_FONT_FEATURE_ID_PNUM NC_("STR_FONT_FEATURE_ID_PNUM", "Proportional Numbers")
+#define STR_FONT_FEATURE_ID_PREF NC_("STR_FONT_FEATURE_ID_PREF", "Pre Base Forms")
+#define STR_FONT_FEATURE_ID_PRES NC_("STR_FONT_FEATURE_ID_PRES", "Pre Base Substitutions")
+#define STR_FONT_FEATURE_ID_PSTF NC_("STR_FONT_FEATURE_ID_PSTF", "Post Base Forms")
+#define STR_FONT_FEATURE_ID_PSTS NC_("STR_FONT_FEATURE_ID_PSTS", "Post Base Substitutions")
+#define STR_FONT_FEATURE_ID_PWID NC_("STR_FONT_FEATURE_ID_PWID", "Proportional Widths")
+#define STR_FONT_FEATURE_ID_QWID NC_("STR_FONT_FEATURE_ID_QWID", "Quarter Widths")
+#define STR_FONT_FEATURE_ID_RAND NC_("STR_FONT_FEATURE_ID_RAND", "Randomize")
+#define STR_FONT_FEATURE_ID_RCLT NC_("STR_FONT_FEATURE_ID_RCLT", "Required Contextual Alternates")
+#define STR_FONT_FEATURE_ID_RKRF NC_("STR_FONT_FEATURE_ID_RKRF", "Rakar Forms")
+#define STR_FONT_FEATURE_ID_RLIG NC_("STR_FONT_FEATURE_ID_RLIG", "Required Ligatures")
+#define STR_FONT_FEATURE_ID_RPHF NC_("STR_FONT_FEATURE_ID_RPHF", "Reph Forms")
+#define STR_FONT_FEATURE_ID_RTBD NC_("STR_FONT_FEATURE_ID_RTBD", "Right Bounds")
+#define STR_FONT_FEATURE_ID_RTLA NC_("STR_FONT_FEATURE_ID_RTLA", "Right to Left Alternates")
+#define STR_FONT_FEATURE_ID_RTLM NC_("STR_FONT_FEATURE_ID_RTLM", "Right to Left Mirrored Forms")
+#define STR_FONT_FEATURE_ID_RUBY NC_("STR_FONT_FEATURE_ID_RUBY", "Ruby Notation Forms")
+#define STR_FONT_FEATURE_ID_RVRN NC_("STR_FONT_FEATURE_ID_RVRN", "Required Variation Alternates")
+#define STR_FONT_FEATURE_ID_SALT NC_("STR_FONT_FEATURE_ID_SALT", "Stylistic Alternates")
+#define STR_FONT_FEATURE_ID_SINF NC_("STR_FONT_FEATURE_ID_SINF", "Scientific Inferiors")
+#define STR_FONT_FEATURE_ID_SIZE NC_("STR_FONT_FEATURE_ID_SIZE", "Optical Size")
+#define STR_FONT_FEATURE_ID_SMCP NC_("STR_FONT_FEATURE_ID_SMCP", "Lowercase to Small Capitals")
+#define STR_FONT_FEATURE_ID_SMPL NC_("STR_FONT_FEATURE_ID_SMPL", "Simplified Forms")
+#define STR_FONT_FEATURE_ID_SS01 NC_("STR_FONT_FEATURE_ID_SS01", "Stylistic Set 1")
+#define STR_FONT_FEATURE_ID_SS02 NC_("STR_FONT_FEATURE_ID_SS02", "Stylistic Set 2")
+#define STR_FONT_FEATURE_ID_SS03 NC_("STR_FONT_FEATURE_ID_SS03", "Stylistic Set 3")
+#define STR_FONT_FEATURE_ID_SS04 NC_("STR_FONT_FEATURE_ID_SS04", "Stylistic Set 4")
+#define STR_FONT_FEATURE_ID_SS05 NC_("STR_FONT_FEATURE_ID_SS05", "Stylistic Set 5")
+#define STR_FONT_FEATURE_ID_SS06 NC_("STR_FONT_FEATURE_ID_SS06", "Stylistic Set 6")
+#define STR_FONT_FEATURE_ID_SS07 NC_("STR_FONT_FEATURE_ID_SS07", "Stylistic Set 7")
+#define STR_FONT_FEATURE_ID_SS08 NC_("STR_FONT_FEATURE_ID_SS08", "Stylistic Set 8")
+#define STR_FONT_FEATURE_ID_SS09 NC_("STR_FONT_FEATURE_ID_SS09", "Stylistic Set 9")
+#define STR_FONT_FEATURE_ID_SS10 NC_("STR_FONT_FEATURE_ID_SS10", "Stylistic Set 10")
+#define STR_FONT_FEATURE_ID_SS11 NC_("STR_FONT_FEATURE_ID_SS11", "Stylistic Set 11")
+#define STR_FONT_FEATURE_ID_SS12 NC_("STR_FONT_FEATURE_ID_SS12", "Stylistic Set 12")
+#define STR_FONT_FEATURE_ID_SS13 NC_("STR_FONT_FEATURE_ID_SS13", "Stylistic Set 13")
+#define STR_FONT_FEATURE_ID_SS14 NC_("STR_FONT_FEATURE_ID_SS14", "Stylistic Set 14")
+#define STR_FONT_FEATURE_ID_SS15 NC_("STR_FONT_FEATURE_ID_SS15", "Stylistic Set 15")
+#define STR_FONT_FEATURE_ID_SS16 NC_("STR_FONT_FEATURE_ID_SS16", "Stylistic Set 16")
+#define STR_FONT_FEATURE_ID_SS17 NC_("STR_FONT_FEATURE_ID_SS17", "Stylistic Set 17")
+#define STR_FONT_FEATURE_ID_SS18 NC_("STR_FONT_FEATURE_ID_SS18", "Stylistic Set 18")
+#define STR_FONT_FEATURE_ID_SS19 NC_("STR_FONT_FEATURE_ID_SS19", "Stylistic Set 19")
+#define STR_FONT_FEATURE_ID_SS20 NC_("STR_FONT_FEATURE_ID_SS20", "Stylistic Set 20")
+#define STR_FONT_FEATURE_ID_SSTY NC_("STR_FONT_FEATURE_ID_SSTY", "Script Style")
+#define STR_FONT_FEATURE_ID_STCH NC_("STR_FONT_FEATURE_ID_STCH", "Stretching Glyph Decomposition")
+#define STR_FONT_FEATURE_ID_SUBS NC_("STR_FONT_FEATURE_ID_SUBS", "Subscript")
+#define STR_FONT_FEATURE_ID_SUPS NC_("STR_FONT_FEATURE_ID_SUPS", "Superscript")
+#define STR_FONT_FEATURE_ID_SWSH NC_("STR_FONT_FEATURE_ID_SWSH", "Swash")
+#define STR_FONT_FEATURE_ID_TITL NC_("STR_FONT_FEATURE_ID_TITL", "Titling")
+#define STR_FONT_FEATURE_ID_TJMO NC_("STR_FONT_FEATURE_ID_TJMO", "Trailing Jamo Forms")
+#define STR_FONT_FEATURE_ID_TNAM NC_("STR_FONT_FEATURE_ID_TNAM", "Traditional Name Forms")
+#define STR_FONT_FEATURE_ID_TNUM NC_("STR_FONT_FEATURE_ID_TNUM", "Tabular Numbers")
+#define STR_FONT_FEATURE_ID_TRAD NC_("STR_FONT_FEATURE_ID_TRAD", "Traditional Forms")
+#define STR_FONT_FEATURE_ID_TWID NC_("STR_FONT_FEATURE_ID_TWID", "Third Widths")
+#define STR_FONT_FEATURE_ID_UNIC NC_("STR_FONT_FEATURE_ID_UNIC", "Unicase")
+#define STR_FONT_FEATURE_ID_VALT NC_("STR_FONT_FEATURE_ID_VALT", "Alternate Vertical Metrics")
+#define STR_FONT_FEATURE_ID_VATU NC_("STR_FONT_FEATURE_ID_VATU", "Vattu Variants")
+#define STR_FONT_FEATURE_ID_VERT NC_("STR_FONT_FEATURE_ID_VERT", "Vertical Alternatives")
+#define STR_FONT_FEATURE_ID_VHAL NC_("STR_FONT_FEATURE_ID_VHAL", "Alternate Vertical Half Metrics")
+#define STR_FONT_FEATURE_ID_VJMO NC_("STR_FONT_FEATURE_ID_VJMO", "Vowel Jamo Forms")
+#define STR_FONT_FEATURE_ID_VKNA NC_("STR_FONT_FEATURE_ID_VKNA", "Vertical Kana Alternates")
+#define STR_FONT_FEATURE_ID_VKRN NC_("STR_FONT_FEATURE_ID_VKRN", "Vertical Kerning")
+#define STR_FONT_FEATURE_ID_VPAL NC_("STR_FONT_FEATURE_ID_VPAL", "Proportional Alternate Vertical Metrics")
+#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")
+
+#endif // INCLUDED_VCL_INC_STRINGS_HRC
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/qa/cppunit/FontFeatureTest.cxx b/vcl/qa/cppunit/FontFeatureTest.cxx
new file mode 100644
index 000000000000..0bb28e306139
--- /dev/null
+++ b/vcl/qa/cppunit/FontFeatureTest.cxx
@@ -0,0 +1,110 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <vcl/font/Feature.hxx>
+
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+
+class FontFeatureTest : public test::BootstrapFixture
+{
+public:
+ FontFeatureTest()
+ : BootstrapFixture(true, false)
+ {
+ }
+
+ void testGetFontFeatures();
+
+ CPPUNIT_TEST_SUITE(FontFeatureTest);
+ CPPUNIT_TEST(testGetFontFeatures);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+void FontFeatureTest::testGetFontFeatures()
+{
+ ScopedVclPtrInstance<VirtualDevice> aVDev(*Application::GetDefaultDevice(),
+ DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
+ aVDev->SetOutputSizePixel(Size(10, 10));
+
+ vcl::Font aFont = aVDev->GetFont();
+ aFont.SetFamilyName("Linux Libertine G");
+ aVDev->SetFont(aFont);
+
+ std::vector<vcl::font::Feature> rFontFeatures;
+ CPPUNIT_ASSERT(aVDev->GetFontFeatures(rFontFeatures));
+
+ // We're interested only in defaults here
+ std::vector<vcl::font::Feature> rDefaultFontFeatures;
+ OUString aFeaturesString;
+ for (vcl::font::Feature const& rFeature : rFontFeatures)
+ {
+ if (rFeature.m_aID.m_aScriptCode == vcl::font::featureCode("DFLT")
+ && rFeature.m_aID.m_aLanguageCode == vcl::font::featureCode("dflt"))
+ {
+ rDefaultFontFeatures.push_back(rFeature);
+ aFeaturesString += vcl::font::featureCodeAsString(rFeature.m_aID.m_aFeatureCode) + " ";
+ }
+ }
+
+ CPPUNIT_ASSERT_EQUAL(size_t(31), rDefaultFontFeatures.size());
+
+ OUString aExpectedFeaturesString = "aalt c2sc case ccmp dlig fina frac hlig "
+ "liga lnum nalt onum pnum salt sinf smcp "
+ "ss01 ss02 ss03 ss04 ss05 ss06 sups tnum "
+ "zero cpsp kern lfbd mark mkmk rtbd ";
+ CPPUNIT_ASSERT_EQUAL(aExpectedFeaturesString, aFeaturesString);
+
+ // Check C2SC feature
+ {
+ vcl::font::Feature& rFeature = rDefaultFontFeatures[1];
+ CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("c2sc"), rFeature.m_aID.m_aFeatureCode);
+
+ vcl::font::FeatureDefinition& rFracFeatureDefinition = rFeature.m_aDefinition;
+ CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("c2sc"), rFracFeatureDefinition.getCode());
+ CPPUNIT_ASSERT(!rFracFeatureDefinition.getDescription().isEmpty());
+ CPPUNIT_ASSERT_EQUAL(vcl::font::FeatureParameterType::BOOL,
+ rFracFeatureDefinition.getType());
+
+ CPPUNIT_ASSERT_EQUAL(size_t(0), rFracFeatureDefinition.getEnumParameters().size());
+ }
+
+ // Check FRAC feature
+ {
+ vcl::font::Feature& rFeature = rDefaultFontFeatures[6];
+ CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("frac"), rFeature.m_aID.m_aFeatureCode);
+
+ vcl::font::FeatureDefinition& rFracFeatureDefinition = rFeature.m_aDefinition;
+ CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("frac"), rFracFeatureDefinition.getCode());
+ CPPUNIT_ASSERT(!rFracFeatureDefinition.getDescription().isEmpty());
+ CPPUNIT_ASSERT_EQUAL(vcl::font::FeatureParameterType::ENUM,
+ rFracFeatureDefinition.getType());
+
+ CPPUNIT_ASSERT_EQUAL(size_t(2), rFracFeatureDefinition.getEnumParameters().size());
+
+ vcl::font::FeatureParameter const& rParameter1
+ = rFracFeatureDefinition.getEnumParameters()[0];
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(1), rParameter1.getCode());
+ CPPUNIT_ASSERT(!rParameter1.getDescription().isEmpty());
+
+ vcl::font::FeatureParameter const& rParameter2
+ = rFracFeatureDefinition.getEnumParameters()[1];
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(2), rParameter2.getCode());
+ CPPUNIT_ASSERT(!rParameter2.getDescription().isEmpty());
+ }
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(FontFeatureTest);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/font/Feature.cxx b/vcl/source/font/Feature.cxx
new file mode 100644
index 000000000000..1b7545b560b9
--- /dev/null
+++ b/vcl/source/font/Feature.cxx
@@ -0,0 +1,119 @@
+/* -*- 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/font/Feature.hxx>
+#include <strings.hrc>
+#include <svdata.hxx>
+
+namespace vcl
+{
+namespace font
+{
+OUString featureCodeAsString(sal_uInt32 nFeature)
+{
+ std::vector<sal_Char> aString(5, 0);
+ aString[0] = sal_Char(nFeature >> 24 & 0xff);
+ aString[1] = sal_Char(nFeature >> 16 & 0xff);
+ aString[2] = sal_Char(nFeature >> 8 & 0xff);
+ aString[3] = sal_Char(nFeature >> 0 & 0xff);
+
+ return OStringToOUString(aString.data(), RTL_TEXTENCODING_ASCII_US);
+}
+
+// FeatureParameter
+
+FeatureParameter::FeatureParameter(sal_uInt32 nCode, OUString aDescription)
+ : m_nCode(nCode)
+ , m_sDescription(aDescription)
+ , m_pDescriptionID(nullptr)
+{
+}
+
+FeatureParameter::FeatureParameter(sal_uInt32 nCode, const char* pDescriptionID)
+ : m_nCode(nCode)
+ , m_pDescriptionID(pDescriptionID)
+{
+}
+
+OUString FeatureParameter::getDescription() const
+{
+ OUString aReturnString;
+
+ if (m_pDescriptionID)
+ aReturnString = VclResId(m_pDescriptionID);
+ else if (!m_sDescription.isEmpty())
+ aReturnString = m_sDescription;
+
+ return aReturnString;
+}
+
+sal_uInt32 FeatureParameter::getCode() const { return m_nCode; }
+
+// FeatureDefinition
+
+FeatureDefinition::FeatureDefinition()
+ : m_nCode(0)
+ , m_pDescriptionID(nullptr)
+ , m_eType(FeatureParameterType::BOOL)
+{
+}
+
+FeatureDefinition::FeatureDefinition(sal_uInt32 nCode, OUString const& rDescription,
+ FeatureParameterType eType,
+ std::vector<FeatureParameter> const& rEnumParameters)
+ : m_nCode(nCode)
+ , m_sDescription(rDescription)
+ , m_pDescriptionID(nullptr)
+ , m_eType(eType)
+ , m_aEnumParameters(rEnumParameters)
+{
+}
+
+FeatureDefinition::FeatureDefinition(sal_uInt32 nCode, const char* pDescriptionID)
+ : m_nCode(nCode)
+ , m_pDescriptionID(pDescriptionID)
+ , m_eType(FeatureParameterType::BOOL)
+{
+}
+
+FeatureDefinition::FeatureDefinition(sal_uInt32 nCode, const char* pDescriptionID,
+ std::vector<FeatureParameter> aEnumParameters)
+ : m_nCode(nCode)
+ , m_pDescriptionID(pDescriptionID)
+ , m_eType(FeatureParameterType::ENUM)
+ , m_aEnumParameters(aEnumParameters)
+{
+}
+
+const std::vector<FeatureParameter>& FeatureDefinition::getEnumParameters() const
+{
+ return m_aEnumParameters;
+}
+
+OUString FeatureDefinition::getDescription() const
+{
+ if (m_pDescriptionID)
+ return VclResId(m_pDescriptionID);
+ else if (!m_sDescription.isEmpty())
+ return m_sDescription;
+ else
+ return vcl::font::featureCodeAsString(m_nCode);
+}
+
+sal_uInt32 FeatureDefinition::getCode() const { return m_nCode; }
+
+FeatureParameterType FeatureDefinition::getType() const { return m_eType; }
+
+FeatureDefinition::operator bool() const { return m_nCode != 0; }
+
+} // end font namespace
+} // end vcl namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/font/FeatureCollector.cxx b/vcl/source/font/FeatureCollector.cxx
new file mode 100644
index 000000000000..1087a9311daf
--- /dev/null
+++ b/vcl/source/font/FeatureCollector.cxx
@@ -0,0 +1,141 @@
+/* -*- 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 <font/FeatureCollector.hxx>
+#include <font/OpenTypeFeatureDefinitonList.hxx>
+#include <o3tl/make_unique.hxx>
+
+#include <hb-ot.h>
+#include <hb-graphite2.h>
+
+namespace vcl
+{
+namespace font
+{
+bool FeatureCollector::collectGraphiteFeatureDefinition(vcl::font::Feature& rFeature)
+{
+ gr_face* grFace = hb_graphite2_face_get_gr_face(m_pHbFace);
+ if (grFace == nullptr)
+ return false;
+
+ bool bFound = false;
+
+ gr_uint16 nUILanguage = 0x0409;
+
+ gr_uint16 nNumberOfFeatures = gr_face_n_fref(grFace);
+ gr_feature_val* pFeatures = gr_face_featureval_for_lang(grFace, rFeature.m_aID.m_aLanguageCode);
+
+ if (pFeatures)
+ {
+ for (gr_uint16 i = 0; i < nNumberOfFeatures; ++i)
+ {
+ const gr_feature_ref* pFeatureRef = gr_face_fref(grFace, i);
+ gr_uint32 nFeatureCode = gr_fref_id(pFeatureRef);
+
+ if (nFeatureCode == rFeature.m_aID.m_aFeatureCode)
+ {
+ gr_uint32 nLabelLength = 0;
+ void* pLabel = gr_fref_label(pFeatureRef, &nUILanguage, gr_utf8, &nLabelLength);
+ OUString sLabel(OUString::createFromAscii(static_cast<char*>(pLabel)));
+ gr_label_destroy(pLabel);
+
+ std::vector<vcl::font::FeatureParameter> aParameters;
+ gr_uint16 nNumberOfValues = gr_fref_n_values(pFeatureRef);
+ for (gr_uint16 j = 0; j < nNumberOfValues; ++j)
+ {
+ if (gr_fref_value(pFeatureRef, j))
+ {
+ gr_uint32 nValueLabelLength = 0;
+ void* pValueLabel = gr_fref_value_label(pFeatureRef, j, &nUILanguage,
+ gr_utf8, &nValueLabelLength);
+ OUString sValueLabel(
+ OUString::createFromAscii(static_cast<char*>(pValueLabel)));
+ aParameters.emplace_back(sal_uInt32(j), sValueLabel);
+ gr_label_destroy(pValueLabel);
+ }
+ }
+
+ auto eFeatureParameterType = vcl::font::FeatureParameterType::ENUM;
+
+ // Check if the parameters are boolean
+ if (aParameters.size() == 1 && aParameters[0].getDescription() == "True")
+ {
+ eFeatureParameterType = vcl::font::FeatureParameterType::BOOL;
+ aParameters.clear();
+ }
+ rFeature.m_aDefinition = vcl::font::FeatureDefinition(
+ rFeature.m_aID.m_aFeatureCode, sLabel, eFeatureParameterType, aParameters);
+ bFound = true;
+ }
+ }
+ }
+ gr_featureval_destroy(pFeatures);
+ return bFound;
+}
+
+void FeatureCollector::collectForLanguage(hb_tag_t aTableTag, sal_uInt32 nScript,
+ hb_tag_t aScriptTag, sal_uInt32 nLanguage,
+ hb_tag_t aLanguageTag)
+{
+ unsigned int nFeatureCount = hb_ot_layout_language_get_feature_tags(
+ m_pHbFace, aTableTag, nScript, nLanguage, 0, nullptr, nullptr);
+ std::vector<hb_tag_t> aFeatureTags(nFeatureCount);
+ hb_ot_layout_language_get_feature_tags(m_pHbFace, aTableTag, nScript, nLanguage, 0,
+ &nFeatureCount, aFeatureTags.data());
+ aFeatureTags.resize(nFeatureCount);
+
+ for (hb_tag_t aFeatureTag : aFeatureTags)
+ {
+ m_rFontFeatures.emplace_back();
+ vcl::font::Feature& rFeature = m_rFontFeatures.back();
+ rFeature.m_aID = { aFeatureTag, aScriptTag, aLanguageTag };
+ bool bResult = collectGraphiteFeatureDefinition(rFeature);
+ if (!bResult)
+ {
+ FeatureDefinition aDefinition
+ = OpenTypeFeatureDefinitonList::get().getDefinition(aFeatureTag);
+ if (aDefinition)
+ {
+ rFeature.m_aDefinition = vcl::font::FeatureDefinition(aDefinition);
+ }
+ }
+ }
+}
+
+void FeatureCollector::collectForScript(hb_tag_t aTableTag, sal_uInt32 nScript, hb_tag_t aScriptTag)
+{
+ collectForLanguage(aTableTag, nScript, aScriptTag, HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
+ HB_OT_TAG_DEFAULT_LANGUAGE);
+
+ unsigned int nLanguageCount
+ = hb_ot_layout_script_get_language_tags(m_pHbFace, aTableTag, nScript, 0, nullptr, nullptr);
+ std::vector<hb_tag_t> aLanguageTags(nLanguageCount);
+ hb_ot_layout_script_get_language_tags(m_pHbFace, aTableTag, nScript, 0, &nLanguageCount,
+ aLanguageTags.data());
+ aLanguageTags.resize(nLanguageCount);
+ for (sal_uInt32 nLanguage = 0; nLanguage < sal_uInt32(nLanguageCount); ++nLanguage)
+ collectForLanguage(aTableTag, nScript, aScriptTag, nLanguage, aLanguageTags[nLanguage]);
+}
+
+void FeatureCollector::collectForTable(hb_tag_t aTableTag)
+{
+ unsigned int nScriptCount
+ = hb_ot_layout_table_get_script_tags(m_pHbFace, aTableTag, 0, nullptr, nullptr);
+ std::vector<hb_tag_t> aScriptTags(nScriptCount);
+ hb_ot_layout_table_get_script_tags(m_pHbFace, aTableTag, 0, &nScriptCount, aScriptTags.data());
+ aScriptTags.resize(nScriptCount);
+
+ for (sal_uInt32 nScript = 0; nScript < sal_uInt32(nScriptCount); ++nScript)
+ collectForScript(aTableTag, nScript, aScriptTags[nScript]);
+}
+
+} // end namespace font
+} // end namespace vcl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/font/OpenTypeFeatureDefinitonList.cxx b/vcl/source/font/OpenTypeFeatureDefinitonList.cxx
new file mode 100644
index 000000000000..17ee8268c741
--- /dev/null
+++ b/vcl/source/font/OpenTypeFeatureDefinitonList.cxx
@@ -0,0 +1,199 @@
+/* -*- 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 <font/OpenTypeFeatureDefinitonList.hxx>
+#include <font/OpenTypeFeatureStrings.hrc>
+#include <svdata.hxx>
+
+namespace vcl
+{
+namespace font
+{
+OpenTypeFeatureDefinitonListPrivate::OpenTypeFeatureDefinitonListPrivate() { init(); }
+
+void OpenTypeFeatureDefinitonListPrivate::init()
+{
+ m_aFeatureDefinition.assign({
+ { featureCode("aalt"), STR_FONT_FEATURE_ID_AALT },
+ { featureCode("abvf"), STR_FONT_FEATURE_ID_ABVF },
+ { featureCode("abvm"), STR_FONT_FEATURE_ID_ABVM },
+ { featureCode("abvs"), STR_FONT_FEATURE_ID_ABVS },
+ { featureCode("afrc"), STR_FONT_FEATURE_ID_AFRC },
+ { featureCode("akhn"), STR_FONT_FEATURE_ID_AKHN },
+ { featureCode("alig"), STR_FONT_FEATURE_ID_ALIG },
+ { featureCode("blwf"), STR_FONT_FEATURE_ID_BLWF },
+ { featureCode("blwm"), STR_FONT_FEATURE_ID_BLWM },
+ { featureCode("blws"), STR_FONT_FEATURE_ID_BLWS },
+ { featureCode("c2pc"), STR_FONT_FEATURE_ID_C2PC },
+ { featureCode("c2sc"), STR_FONT_FEATURE_ID_C2SC },
+ { featureCode("calt"), STR_FONT_FEATURE_ID_CALT },
+ { featureCode("case"), STR_FONT_FEATURE_ID_CASE },
+ { featureCode("ccmp"), STR_FONT_FEATURE_ID_CCMP },
+ { featureCode("cfar"), STR_FONT_FEATURE_ID_CFAR },
+ { featureCode("cjct"), STR_FONT_FEATURE_ID_CJCT },
+ { featureCode("clig"), STR_FONT_FEATURE_ID_CLIG },
+ { featureCode("cpct"), STR_FONT_FEATURE_ID_CPCT },
+ { featureCode("cpsp"), STR_FONT_FEATURE_ID_CPSP },
+ { featureCode("cswh"), STR_FONT_FEATURE_ID_CSWH },
+ { featureCode("curs"), STR_FONT_FEATURE_ID_CURS },
+ { featureCode("cv01"), STR_FONT_FEATURE_ID_CV01 },
+ { featureCode("cv02"), STR_FONT_FEATURE_ID_CV02 },
+ { featureCode("cv03"), STR_FONT_FEATURE_ID_CV03 },
+ { featureCode("cv04"), STR_FONT_FEATURE_ID_CV04 },
+ { featureCode("cv05"), STR_FONT_FEATURE_ID_CV05 },
+ { featureCode("cv06"), STR_FONT_FEATURE_ID_CV06 },
+ { featureCode("cv07"), STR_FONT_FEATURE_ID_CV07 },
+ { featureCode("cv08"), STR_FONT_FEATURE_ID_CV08 },
+ { featureCode("cv09"), STR_FONT_FEATURE_ID_CV09 },
+ { featureCode("dcap"), STR_FONT_FEATURE_ID_DCAP },
+ { featureCode("dist"), STR_FONT_FEATURE_ID_DIST },
+ { featureCode("dlig"), STR_FONT_FEATURE_ID_DLIG },
+ { featureCode("dnom"), STR_FONT_FEATURE_ID_DNOM },
+ { featureCode("dpng"), STR_FONT_FEATURE_ID_DPNG },
+ { featureCode("dtls"), STR_FONT_FEATURE_ID_DTLS },
+ { featureCode("expt"), STR_FONT_FEATURE_ID_EXPT },
+ { featureCode("falt"), STR_FONT_FEATURE_ID_FALT },
+ { featureCode("fin2"), STR_FONT_FEATURE_ID_FIN2 },
+ { featureCode("fin3"), STR_FONT_FEATURE_ID_FIN3 },
+ { featureCode("fina"), STR_FONT_FEATURE_ID_FINA },
+ { featureCode("flac"), STR_FONT_FEATURE_ID_FLAC },
+ { featureCode("frac"), STR_FONT_FEATURE_ID_FRAC,
+ std::vector<FeatureParameter>{ { 1, STR_FONT_FEATURE_ID_FRAC_PARAM_1 },
+ { 2, STR_FONT_FEATURE_ID_FRAC_PARAM_2 } } },
+ { featureCode("fwid"), STR_FONT_FEATURE_ID_FWID },
+ { featureCode("half"), STR_FONT_FEATURE_ID_HALF },
+ { featureCode("haln"), STR_FONT_FEATURE_ID_HALN },
+ { featureCode("halt"), STR_FONT_FEATURE_ID_HALT },
+ { featureCode("hist"), STR_FONT_FEATURE_ID_HIST },
+ { featureCode("hkna"), STR_FONT_FEATURE_ID_HKNA },
+ { featureCode("hlig"), STR_FONT_FEATURE_ID_HLIG },
+ { featureCode("hngl"), STR_FONT_FEATURE_ID_HNGL },
+ { featureCode("hojo"), STR_FONT_FEATURE_ID_HOJO },
+ { featureCode("hwid"), STR_FONT_FEATURE_ID_HWID },
+ { featureCode("init"), STR_FONT_FEATURE_ID_INIT },
+ { featureCode("isol"), STR_FONT_FEATURE_ID_ISOL },
+ { featureCode("ital"), STR_FONT_FEATURE_ID_ITAL },
+ { featureCode("jalt"), STR_FONT_FEATURE_ID_JALT },
+ { featureCode("jp78"), STR_FONT_FEATURE_ID_JP78 },
+ { featureCode("jp83"), STR_FONT_FEATURE_ID_JP83 },
+ { featureCode("jp90"), STR_FONT_FEATURE_ID_JP90 },
+ { featureCode("jp04"), STR_FONT_FEATURE_ID_JP04 },
+ { featureCode("kern"), STR_FONT_FEATURE_ID_KERN },
+ { featureCode("lfbd"), STR_FONT_FEATURE_ID_LFBD },
+ { featureCode("liga"), STR_FONT_FEATURE_ID_LIGA },
+ { featureCode("ljmo"), STR_FONT_FEATURE_ID_LJMO },
+ { featureCode("lnum"), STR_FONT_FEATURE_ID_LNUM },
+ { featureCode("locl"), STR_FONT_FEATURE_ID_LOCL },
+ { featureCode("ltra"), STR_FONT_FEATURE_ID_LTRA },
+ { featureCode("ltrm"), STR_FONT_FEATURE_ID_LTRM },
+ { featureCode("mark"), STR_FONT_FEATURE_ID_MARK },
+ { featureCode("med2"), STR_FONT_FEATURE_ID_MED2 },
+ { featureCode("medi"), STR_FONT_FEATURE_ID_MEDI },
+ { featureCode("mgrk"), STR_FONT_FEATURE_ID_MGRK },
+ { featureCode("mkmk"), STR_FONT_FEATURE_ID_MKMK },
+ { featureCode("mset"), STR_FONT_FEATURE_ID_MSET },
+ { featureCode("nalt"), STR_FONT_FEATURE_ID_NALT },
+ { featureCode("nlck"), STR_FONT_FEATURE_ID_NLCK },
+ { featureCode("nukt"), STR_FONT_FEATURE_ID_NUKT },
+ { featureCode("numr"), STR_FONT_FEATURE_ID_NUMR },
+ { featureCode("onum"), STR_FONT_FEATURE_ID_ONUM },
+ { featureCode("opbd"), STR_FONT_FEATURE_ID_OPBD },
+ { featureCode("ordn"), STR_FONT_FEATURE_ID_ORDN },
+ { featureCode("ornm"), STR_FONT_FEATURE_ID_ORNM },
+ { featureCode("palt"), STR_FONT_FEATURE_ID_PALT },
+ { featureCode("pcap"), STR_FONT_FEATURE_ID_PCAP },
+ { featureCode("pkna"), STR_FONT_FEATURE_ID_PKNA },
+ { featureCode("pnum"), STR_FONT_FEATURE_ID_PNUM },
+ { featureCode("pref"), STR_FONT_FEATURE_ID_PREF },
+ { featureCode("pres"), STR_FONT_FEATURE_ID_PRES },
+ { featureCode("pstf"), STR_FONT_FEATURE_ID_PSTF },
+ { featureCode("psts"), STR_FONT_FEATURE_ID_PSTS },
+ { featureCode("pwid"), STR_FONT_FEATURE_ID_PWID },
+ { featureCode("qwid"), STR_FONT_FEATURE_ID_QWID },
+ { featureCode("rand"), STR_FONT_FEATURE_ID_RAND },
+ { featureCode("rclt"), STR_FONT_FEATURE_ID_RCLT },
+ { featureCode("rkrf"), STR_FONT_FEATURE_ID_RKRF },
+ { featureCode("rlig"), STR_FONT_FEATURE_ID_RLIG },
+ { featureCode("rphf"), STR_FONT_FEATURE_ID_RPHF },
+ { featureCode("rtbd"), STR_FONT_FEATURE_ID_RTBD },
+ { featureCode("rtla"), STR_FONT_FEATURE_ID_RTLA },
+ { featureCode("rtlm"), STR_FONT_FEATURE_ID_RTLM },
+ { featureCode("ruby"), STR_FONT_FEATURE_ID_RUBY },
+ { featureCode("rvrn"), STR_FONT_FEATURE_ID_RVRN },
+ { featureCode("salt"), STR_FONT_FEATURE_ID_SALT },
+ { featureCode("sinf"), STR_FONT_FEATURE_ID_SINF },
+ { featureCode("size"), STR_FONT_FEATURE_ID_SIZE },
+ { featureCode("smcp"), STR_FONT_FEATURE_ID_SMCP },
+ { featureCode("smpl"), STR_FONT_FEATURE_ID_SMPL },
+ { featureCode("ss01"), STR_FONT_FEATURE_ID_SS01 },
+ { featureCode("ss02"), STR_FONT_FEATURE_ID_SS02 },
+ { featureCode("ss03"), STR_FONT_FEATURE_ID_SS03 },
+ { featureCode("ss04"), STR_FONT_FEATURE_ID_SS04 },
+ { featureCode("ss05"), STR_FONT_FEATURE_ID_SS05 },
+ { featureCode("ss06"), STR_FONT_FEATURE_ID_SS06 },
+ { featureCode("ss07"), STR_FONT_FEATURE_ID_SS07 },
+ { featureCode("ss08"), STR_FONT_FEATURE_ID_SS08 },
+ { featureCode("ss09"), STR_FONT_FEATURE_ID_SS09 },
+ { featureCode("ss10"), STR_FONT_FEATURE_ID_SS10 },
+ { featureCode("ss11"), STR_FONT_FEATURE_ID_SS11 },
+ { featureCode("ss12"), STR_FONT_FEATURE_ID_SS12 },
+ { featureCode("ss13"), STR_FONT_FEATURE_ID_SS13 },
+ { featureCode("ss14"), STR_FONT_FEATURE_ID_SS14 },
+ { featureCode("ss15"), STR_FONT_FEATURE_ID_SS15 },
+ { featureCode("ss16"), STR_FONT_FEATURE_ID_SS16 },
+ { featureCode("ss17"), STR_FONT_FEATURE_ID_SS17 },
+ { featureCode("ss18"), STR_FONT_FEATURE_ID_SS18 },
+ { featureCode("ss19"), STR_FONT_FEATURE_ID_SS19 },
+ { featureCode("ss20"), STR_FONT_FEATURE_ID_SS20 },
+ { featureCode("ssty"), STR_FONT_FEATURE_ID_SSTY },
+ { featureCode("stch"), STR_FONT_FEATURE_ID_STCH },
+ { featureCode("subs"), STR_FONT_FEATURE_ID_SUBS },
+ { featureCode("sups"), STR_FONT_FEATURE_ID_SUPS },
+ { featureCode("swsh"), STR_FONT_FEATURE_ID_SWSH },
+ { featureCode("titl"), STR_FONT_FEATURE_ID_TITL },
+ { featureCode("tjmo"), STR_FONT_FEATURE_ID_TJMO },
+ { featureCode("tnam"), STR_FONT_FEATURE_ID_TNAM },
+ { featureCode("tnum"), STR_FONT_FEATURE_ID_TNUM },
+ { featureCode("trad"), STR_FONT_FEATURE_ID_TRAD },
+ { featureCode("twid"), STR_FONT_FEATURE_ID_TWID },
+ { featureCode("unic"), STR_FONT_FEATURE_ID_UNIC },
+ { featureCode("valt"), STR_FONT_FEATURE_ID_VALT },
+ { featureCode("vatu"), STR_FONT_FEATURE_ID_VATU },
+ { featureCode("vert"), STR_FONT_FEATURE_ID_VERT },
+ { featureCode("vhal"), STR_FONT_FEATURE_ID_VHAL },
+ { featureCode("vjmo"), STR_FONT_FEATURE_ID_VJMO },
+ { featureCode("vkna"), STR_FONT_FEATURE_ID_VKNA },
+ { featureCode("vkrn"), STR_FONT_FEATURE_ID_VKRN },
+ { featureCode("vpal"), STR_FONT_FEATURE_ID_VPAL },
+ { featureCode("vrt2"), STR_FONT_FEATURE_ID_VRT2 },
+ { featureCode("vrtr"), STR_FONT_FEATURE_ID_VRTR },
+ { featureCode("zero"), STR_FONT_FEATURE_ID_ZERO },
+ });
+
+ for (size_t i = 0; i < m_aFeatureDefinition.size(); ++i)
+ {
+ m_aCodeToIndex.emplace(m_aFeatureDefinition[i].getCode(), i);
+ }
+}
+
+FeatureDefinition OpenTypeFeatureDefinitonListPrivate::getDefinition(sal_uInt32 nFeatureCode)
+{
+ if (m_aCodeToIndex.find(nFeatureCode) != m_aCodeToIndex.end())
+ {
+ size_t nIndex = m_aCodeToIndex.at(nFeatureCode);
+ return m_aFeatureDefinition[nIndex];
+ }
+ return FeatureDefinition();
+}
+
+} // end font namespace
+} // end vcl namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx
index 439a3df75c5b..2f9a7f7df570 100644
--- a/vcl/source/outdev/font.cxx
+++ b/vcl/source/outdev/font.cxx
@@ -24,6 +24,7 @@
#include <vcl/print.hxx>
#include <vcl/sysdata.hxx>
#include <vcl/fontcharmap.hxx>
+#include <font/FeatureCollector.hxx>
#include <sallayout.hxx>
#include <salgdi.hxx>
@@ -162,6 +163,39 @@ bool OutputDevice::AddTempDevFont( const OUString& rFileURL, const OUString& rFo
return true;
}
+bool OutputDevice::GetFontFeatures(std::vector<vcl::font::Feature>& rFontFeatures) const
+{
+ if (mbNewFont)
+ ImplNewFont();
+
+ if (mbInitFont)
+ InitFont();
+
+ if (!mpFontInstance)
+ return false;
+
+ LogicalFontInstance* pFontInstance = mpFontInstance;
+
+ if (!pFontInstance)
+ return false;
+
+ hb_font_t* pHbFont = pFontInstance->GetHbFont();
+
+ if (!pHbFont)
+ return false;
+
+ hb_face_t* pHbFace = hb_font_get_face(pHbFont);
+
+ if (!pHbFace)
+ return false;
+
+ vcl::font::FeatureCollector aFeatureCollector(pHbFace, rFontFeatures);
+ aFeatureCollector.collectForTable(HB_OT_TAG_GSUB); // substitution
+ aFeatureCollector.collectForTable(HB_OT_TAG_GPOS); // positioning
+
+ return true;
+}
+
FontMetric OutputDevice::GetFontMetric() const
{
FontMetric aMetric;