1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <font/FeatureCollector.hxx>
11 #include <font/OpenTypeFeatureDefinitionList.hxx>
12 #include <i18nlangtag/languagetag.hxx>
14 #include <font/OpenTypeFeatureStrings.hrc>
18 #include <hb-graphite2.h>
22 bool FeatureCollector::collectGraphite()
24 gr_face
* grFace
= hb_graphite2_face_get_gr_face(m_pHbFace
);
26 if (grFace
== nullptr)
29 gr_uint16 nUILanguage
= gr_uint16(m_rLanguageTag
.getLanguageType());
31 gr_uint16 nNumberOfFeatures
= gr_face_n_fref(grFace
);
32 gr_feature_val
* pfeatureValues
33 = gr_face_featureval_for_lang(grFace
, 0); // shame we don't know which lang
35 for (gr_uint16 i
= 0; i
< nNumberOfFeatures
; ++i
)
37 const gr_feature_ref
* pFeatureRef
= gr_face_fref(grFace
, i
);
38 gr_uint32 nFeatureCode
= gr_fref_id(pFeatureRef
);
40 if (nFeatureCode
== 0) // illegal feature code - skip
43 gr_uint16 nValue
= gr_fref_feature_value(pFeatureRef
, pfeatureValues
);
44 gr_uint32 nLabelLength
= 0;
45 void* pLabel
= gr_fref_label(pFeatureRef
, &nUILanguage
, gr_utf8
, &nLabelLength
);
46 OUString
sLabel(OUString::createFromAscii(static_cast<char*>(pLabel
)));
47 gr_label_destroy(pLabel
);
49 std::vector
<vcl::font::FeatureParameter
> aParameters
;
50 gr_uint16 nNumberOfValues
= gr_fref_n_values(pFeatureRef
);
52 if (nNumberOfValues
> 0)
54 for (gr_uint16 j
= 0; j
< nNumberOfValues
; ++j
)
56 gr_uint32 nValueLabelLength
= 0;
57 void* pValueLabel
= gr_fref_value_label(pFeatureRef
, j
, &nUILanguage
, gr_utf8
,
59 OUString
sValueLabel(OUString::createFromAscii(static_cast<char*>(pValueLabel
)));
60 gr_uint16 nParamValue
= gr_fref_value(pFeatureRef
, j
);
61 aParameters
.emplace_back(sal_uInt32(nParamValue
), sValueLabel
);
62 gr_label_destroy(pValueLabel
);
65 auto eFeatureParameterType
= vcl::font::FeatureParameterType::ENUM
;
67 // Check if the parameters are boolean
68 if (aParameters
.size() == 2
69 && (aParameters
[0].getDescription() == "True"
70 || aParameters
[0].getDescription() == "False"))
72 eFeatureParameterType
= vcl::font::FeatureParameterType::BOOL
;
76 m_rFontFeatures
.emplace_back(nFeatureCode
, vcl::font::FeatureType::Graphite
);
77 vcl::font::Feature
& rFeature
= m_rFontFeatures
.back();
78 rFeature
.m_aDefinition
= vcl::font::FeatureDefinition(
79 nFeatureCode
, std::move(sLabel
), eFeatureParameterType
, std::move(aParameters
),
83 gr_featureval_destroy(pfeatureValues
);
87 void FeatureCollector::collectForTable(hb_tag_t aTableTag
)
89 unsigned int nFeatureCount
90 = hb_ot_layout_table_get_feature_tags(m_pHbFace
, aTableTag
, 0, nullptr, nullptr);
91 std::vector
<hb_tag_t
> aFeatureTags(nFeatureCount
);
92 hb_ot_layout_table_get_feature_tags(m_pHbFace
, aTableTag
, 0, &nFeatureCount
,
94 aFeatureTags
.resize(nFeatureCount
);
96 for (hb_tag_t aFeatureTag
: aFeatureTags
)
98 if (OpenTypeFeatureDefinitionList().isRequired(aFeatureTag
))
101 m_rFontFeatures
.emplace_back();
102 vcl::font::Feature
& rFeature
= m_rFontFeatures
.back();
103 rFeature
.m_nCode
= aFeatureTag
;
105 FeatureDefinition aDefinition
= OpenTypeFeatureDefinitionList().getDefinition(rFeature
);
106 std::vector
<vcl::font::FeatureParameter
> aParameters
{
107 { 0, VclResId(STR_FONT_FEATURE_PARAM_NONE
) }
110 unsigned int nFeatureIdx
;
111 if (hb_ot_layout_language_find_feature(m_pHbFace
, aTableTag
, 0,
112 HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX
, aFeatureTag
,
115 // ssXX and cvXX can have name ID defined for them, check for
116 // them and use as appropriate.
117 hb_ot_name_id_t aLabelID
;
118 hb_ot_name_id_t aFirstParameterID
;
119 unsigned nNamedParameters
;
120 if (hb_ot_layout_feature_get_name_ids(m_pHbFace
, aTableTag
, nFeatureIdx
, &aLabelID
,
121 nullptr, nullptr, &nNamedParameters
,
124 OUString sLabel
= m_pFace
->GetName(NameID(aLabelID
), m_rLanguageTag
);
125 if (!sLabel
.isEmpty())
126 aDefinition
= vcl::font::FeatureDefinition(aFeatureTag
, sLabel
);
128 // cvXX features can have parameters name IDs, check for
129 // them and populate feature parameters as appropriate.
130 for (unsigned i
= 0; i
< nNamedParameters
; i
++)
132 hb_ot_name_id_t aNameID
= aFirstParameterID
+ i
;
133 OUString sName
= m_pFace
->GetName(NameID(aNameID
), m_rLanguageTag
);
134 if (!sName
.isEmpty())
135 aParameters
.emplace_back(uint32_t(i
+ 1), sName
);
137 aParameters
.emplace_back(uint32_t(i
+ 1), OUString::number(i
+ 1));
141 unsigned int nAlternates
= 0;
142 if (aTableTag
== HB_OT_TAG_GSUB
)
144 // Collect lookups in this feature, and input glyphs for each
145 // lookup, and calculate the max number of alternates they have.
146 unsigned int nLookups
= hb_ot_layout_feature_get_lookups(
147 m_pHbFace
, aTableTag
, nFeatureIdx
, 0, nullptr, nullptr);
148 std::vector
<unsigned int> aLookups(nLookups
);
149 hb_ot_layout_feature_get_lookups(m_pHbFace
, aTableTag
, nFeatureIdx
, 0, &nLookups
,
152 hb_set_t
* pGlyphs
= hb_set_create();
153 for (unsigned int nLookupIdx
: aLookups
)
155 hb_set_clear(pGlyphs
);
156 hb_ot_layout_lookup_collect_glyphs(m_pHbFace
, aTableTag
, nLookupIdx
, nullptr,
157 pGlyphs
, nullptr, nullptr);
158 hb_codepoint_t nGlyphIdx
= HB_SET_VALUE_INVALID
;
159 while (hb_set_next(pGlyphs
, &nGlyphIdx
))
162 = std::max(nAlternates
,
163 hb_ot_layout_lookup_get_glyph_alternates(
164 m_pHbFace
, nLookupIdx
, nGlyphIdx
, 0, nullptr, nullptr));
167 hb_set_destroy(pGlyphs
);
170 // Append the alternates to the feature parameters, keeping any
171 // existing ones calculated from cvXX features above.
172 for (unsigned int i
= aParameters
.size() - 1; i
< nAlternates
; i
++)
173 aParameters
.emplace_back(uint32_t(i
+ 1), OUString::number(i
+ 1));
175 if (aParameters
.size() > 1)
177 aDefinition
= vcl::font::FeatureDefinition(
178 aFeatureTag
, aDefinition
.getDescription(),
179 vcl::font::FeatureParameterType::ENUM
, std::move(aParameters
), 0);
184 rFeature
.m_aDefinition
= std::move(aDefinition
);
188 bool FeatureCollector::collect()
190 gr_face
* grFace
= hb_graphite2_face_get_gr_face(m_pHbFace
);
194 return collectGraphite();
198 collectForTable(HB_OT_TAG_GSUB
); // substitution
199 collectForTable(HB_OT_TAG_GPOS
); // positioning
204 } // end namespace vcl::font
206 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */