104 {
105
106
107 QMap<QString, KoOpenTypeFeatureInfo>
featureInfo = previousFeatureInfo;
109 hb_tag_t table = gpos? HB_OT_TAG_GPOS: HB_OT_TAG_GSUB;
110 uint targetLanguage = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
111 uint targetScript = 0;
112
114 Q_FOREACH(const QString locale, locales) {
115 QLatin1String l(locale.split("_").join("-").toLatin1());
116 localeTags.append(hb_language_from_string(l.data(), l.size()));
117 }
118
119 hb_language_t languageTag = lang.isEmpty()? HB_LANGUAGE_INVALID: hb_language_from_string(lang.data(), lang.size());
120 uint scriptCount = hb_ot_layout_table_get_script_tags(hbFace.data(), table, 0,
nullptr,
nullptr);
122 for (
uint script = 0; script < scriptCount; script++) {
123 uint languageCount = hb_ot_layout_script_get_language_tags(hbFace.data(), table, script, 0,
nullptr,
nullptr);
124
125 for(
uint j = 0; j < languageCount; j++) {
126 hb_tag_t langTag;
128 hb_ot_layout_script_get_language_tags(hbFace.data(), table, script, j, &count, &langTag);
129 if (count < 1) continue;
130 if (hb_ot_tag_to_language(langTag) == languageTag) {
131 targetLanguage = j;
132 targetScript = script;
133 break;
134 }
135 }
136 }
137
138 uint featureCount = hb_ot_layout_language_get_feature_tags(hbFace.data(),
139 table,
140 targetScript,
141 targetLanguage,
142 0, nullptr, nullptr);
143 hb_ot_layout_language_get_feature_tags(hbFace.data(), table, targetScript,
144 targetLanguage,
145 0, nullptr, nullptr);
146 for(
uint k = 0; k < featureCount; k++) {
148 hb_tag_t features;
149 hb_ot_layout_language_get_feature_tags(hbFace.data(), table, targetScript,
150 targetLanguage,
151 k, &count, &features);
152 if (count < 1) continue;
153 tags.append(features);
154 }
155
156 QHash<quint32, int> glyphToCodepoint;
157 for (
int i = 0; i<
charMap.size(); i++) {
158 glyphToCodepoint.insert(
charMap.at(i).glyphIndex, i);
159 }
160
162 for (auto it = tags.begin(); it != tags.end(); it++) {
163 char c[4];
164 hb_tag_to_string(*it, c);
165 const QLatin1String tagName(c, 4);
167
169 bool found = hb_ot_layout_language_find_feature (hbFace.data(), table,
170 targetScript,
171 targetLanguage,
172 *it,
173 &featureIndex );
174
175 if (!found) {
176 continue;
177 }
178
179 hb_ot_name_id_t labelId = HB_OT_NAME_ID_INVALID;
180 hb_ot_name_id_t toolTipId = HB_OT_NAME_ID_INVALID;
181 hb_ot_name_id_t sampleId = HB_OT_NAME_ID_INVALID;
182 uint namedParameters;
183 hb_ot_name_id_t firstParamId = HB_OT_NAME_ID_INVALID;
185 if (hb_ot_layout_feature_get_name_ids(hbFace.data(), table, featureIndex, &labelId, &toolTipId, &sampleId, &namedParameters, &firstParamId)) {
187 if (firstParamId != HB_OT_NAME_ID_INVALID) {
188 for (
uint i = 0; i < namedParameters; i++) {
189 nameIds += firstParamId + i;
190 }
191 }
192
193 for(auto nameId = nameIds.begin(); nameId != nameIds.end(); nameId++) {
194 if (*nameId == HB_OT_NAME_ID_INVALID) {
195 continue;
196 }
199 if (*nameId == sampleId) {
200 testLang.append(languageTag);
201 } else {
202 testLang = localeTags;
203 }
204 testLang.append(HB_LANGUAGE_INVALID);
205 for (auto tag = testLang.begin(); tag != testLang.end(); tag++) {
206 length = hb_ot_name_get_utf8(hbFace.data(), *nameId, *tag,
nullptr,
nullptr);
209 break;
210 }
211 }
212
213 std::vector<char> buff(
length);
214 hb_ot_name_get_utf8(hbFace.data(), *nameId, languageTag, &
length, buff.data());
216 const QString nameString = QString::fromUtf8(buff.data(),
length);
217 if (*nameId == labelId) {
218 info.
name = nameString;
219 } else if (*nameId == toolTipId) {
221 } else if (*nameId == sampleId) {
223 } else {
225 }
226 }
227 }
228 }
229
232 continue;
233 }
234
236 int lookupCount = hb_ot_layout_feature_get_lookups (hbFace.data(), table,
237 featureIndex,
238 0,
239 nullptr,
240 nullptr );
241 for (int i = 0; i < lookupCount; ++i) {
243 uint lookUpIndex = 0;
244 hb_ot_layout_feature_get_lookups (hbFace.data(), table,
245 featureIndex,
246 i,
247 &maxCount,
248 &lookUpIndex );
249 if (maxCount < 1 || lookUpsProcessed.contains(lookUpIndex)) {
250 continue;
251 }
252
253
254
255
256
261
262 hb_ot_layout_lookup_collect_glyphs (hbFace.data(), table,
263 lookUpIndex,
264 glyphsBefore.data(),
265 glyphsInput.data(),
266 glyphsAfter.data(),
267 glyphsOutput.data() );
268
269 GlyphInfo gci;
271 gci.baseString = tagName;
272
273 hb_codepoint_t currentGlyph = HB_SET_VALUE_INVALID;
274 while(hb_set_next(glyphsInput.data(), ¤tGlyph)) {
275 if (!glyphToCodepoint.contains(currentGlyph)) continue;
276 const int codePointLocation = glyphToCodepoint.value(currentGlyph);
277 CodePointInfo codePointInfo =
charMap.at(codePointLocation);
278 gci.ucs = codePointInfo.ucs;
279 bool addSample = false;
280
281 uint alt_count = hb_ot_layout_lookup_get_glyph_alternates (hbFace.data(),
282 lookUpIndex, currentGlyph,
283 0,
284 nullptr, nullptr);
285
286 if (alt_count > 0) {
287
288 for(
uint j = 1; j < alt_count; ++j) {
289 gci.featureIndex = j;
290 codePointInfo.glyphs.append(gci);
291 }
293 addSample = true;
294 } else {
295 gci.featureIndex = 1;
296 codePointInfo.glyphs.append(gci);
297 addSample = true;
298 }
299 charMap[codePointLocation] = codePointInfo;
300 if (samples.size() < 6 && addSample) {
301 samples.append(QString::fromUcs4(&gci.ucs, 1));
302 }
303 if (samples.size() >= 6 && samplesOnly) {
304 break;
305 }
306 }
307
308 lookUpsProcessed.append(lookUpIndex);
309 if (info.
sample.isEmpty() && !samples.isEmpty()) {
310 info.
sample = samples.join(
" ");
311 }
313
314 }
315
316 }
317
318
320 }
qreal length(const QPointF &vec)
QMap< QString, KoOpenTypeFeatureInfo > featureInfo() const
featureInfo
static QVector< CodePointInfo > charMap(FT_FaceSP face)
The KoOpenTypeFeatureInfoFactory class.
KoOpenTypeFeatureInfo infoByTag(const QLatin1String &tag) const
infoByTag
QString description
Description of the feature.
QString name
User-friendly name.
bool glyphPalette
Whether the feature should be visible in the glyph palette.
QStringList namedParameters
QString sample
Sample of the feature, if any. Only used by CVXX features and retrieved from the font.
int maxValue
The maximum value possible, this is by default 1 (on), but for alternate substitution(gsub 3),...