LibreOffice Module vcl (master) 1
FeatureCollector.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 */
9
13
14#include <font/OpenTypeFeatureStrings.hrc>
15#include <svdata.hxx>
16
17#include <hb-ot.h>
18#include <hb-graphite2.h>
19
20namespace vcl::font
21{
23{
24 gr_face* grFace = hb_graphite2_face_get_gr_face(m_pHbFace);
25
26 if (grFace == nullptr)
27 return false;
28
29 gr_uint16 nUILanguage = gr_uint16(m_rLanguageTag.getLanguageType());
30
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
34
35 for (gr_uint16 i = 0; i < nNumberOfFeatures; ++i)
36 {
37 const gr_feature_ref* pFeatureRef = gr_face_fref(grFace, i);
38 gr_uint32 nFeatureCode = gr_fref_id(pFeatureRef);
39
40 if (nFeatureCode == 0) // illegal feature code - skip
41 continue;
42
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);
48
49 std::vector<vcl::font::FeatureParameter> aParameters;
50 gr_uint16 nNumberOfValues = gr_fref_n_values(pFeatureRef);
51
52 if (nNumberOfValues > 0)
53 {
54 for (gr_uint16 j = 0; j < nNumberOfValues; ++j)
55 {
56 gr_uint32 nValueLabelLength = 0;
57 void* pValueLabel = gr_fref_value_label(pFeatureRef, j, &nUILanguage, gr_utf8,
58 &nValueLabelLength);
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);
63 }
64
65 auto eFeatureParameterType = vcl::font::FeatureParameterType::ENUM;
66
67 // Check if the parameters are boolean
68 if (aParameters.size() == 2
69 && (aParameters[0].getDescription() == "True"
70 || aParameters[0].getDescription() == "False"))
71 {
72 eFeatureParameterType = vcl::font::FeatureParameterType::BOOL;
73 aParameters.clear();
74 }
75
76 m_rFontFeatures.emplace_back(nFeatureCode, vcl::font::FeatureType::Graphite);
77 vcl::font::Feature& rFeature = m_rFontFeatures.back();
78 rFeature.m_aDefinition
79 = vcl::font::FeatureDefinition(nFeatureCode, sLabel, eFeatureParameterType,
80 std::move(aParameters), int32_t(nValue));
81 }
82 }
83 gr_featureval_destroy(pfeatureValues);
84 return true;
85}
86
87void FeatureCollector::collectForTable(hb_tag_t aTableTag)
88{
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,
93 aFeatureTags.data());
94 aFeatureTags.resize(nFeatureCount);
95
96 for (hb_tag_t aFeatureTag : aFeatureTags)
97 {
98 if (OpenTypeFeatureDefinitionList().isRequired(aFeatureTag))
99 continue;
100
101 m_rFontFeatures.emplace_back();
102 vcl::font::Feature& rFeature = m_rFontFeatures.back();
103 rFeature.m_nCode = aFeatureTag;
104
106 std::vector<vcl::font::FeatureParameter> aParameters{
107 { 0, VclResId(STR_FONT_FEATURE_PARAM_NONE) }
108 };
109
110 unsigned int nFeatureIdx;
111 if (hb_ot_layout_language_find_feature(m_pHbFace, aTableTag, 0,
112 HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, aFeatureTag,
113 &nFeatureIdx))
114 {
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,
122 &aFirstParameterID))
123 {
124 OUString sLabel = m_pFace->GetName(NameID(aLabelID), m_rLanguageTag);
125 if (!sLabel.isEmpty())
126 aDefinition = vcl::font::FeatureDefinition(aFeatureTag, sLabel);
127
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++)
131 {
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);
136 else
137 aParameters.emplace_back(uint32_t(i + 1), OUString::number(i + 1));
138 }
139 }
140
141 unsigned int nAlternates = 0;
142 if (aTableTag == HB_OT_TAG_GSUB)
143 {
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,
150 aLookups.data());
151
152 hb_set_t* pGlyphs = hb_set_create();
153 for (unsigned int nLookupIdx : aLookups)
154 {
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))
160 {
161 nAlternates
162 = std::max(nAlternates,
163 hb_ot_layout_lookup_get_glyph_alternates(
164 m_pHbFace, nLookupIdx, nGlyphIdx, 0, nullptr, nullptr));
165 }
166 }
167 hb_set_destroy(pGlyphs);
168 }
169
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));
174
175 if (aParameters.size() > 1)
176 {
177 aDefinition = vcl::font::FeatureDefinition(
178 aFeatureTag, aDefinition.getDescription(),
179 vcl::font::FeatureParameterType::ENUM, std::move(aParameters), 0);
180 }
181 }
182
183 if (aDefinition)
184 rFeature.m_aDefinition = aDefinition;
185 }
186}
187
189{
190 gr_face* grFace = hb_graphite2_face_get_gr_face(m_pHbFace);
191
192 if (grFace)
193 {
194 return collectGraphite();
195 }
196 else
197 {
198 collectForTable(HB_OT_TAG_GSUB); // substitution
199 collectForTable(HB_OT_TAG_GPOS); // positioning
200 return true;
201 }
202}
203
204} // end namespace vcl::font
205
206/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
LanguageType getLanguageType(bool bResolveSystem=true) const
std::vector< vcl::font::Feature > & m_rFontFeatures
const PhysicalFontFace * m_pFace
void collectForTable(hb_tag_t aTableTag)
const LanguageTag & m_rLanguageTag
OUString getDescription() const
Definition: Feature.cxx:134
FeatureDefinition getDefinition(vcl::font::Feature &rFeature)
OUString GetName(NameID, const LanguageTag &) const
sal_Int16 nValue
OUString sName
int i
A PhysicalFontFaceCollection is created by a PhysicalFontCollection and becomes invalid when original...
OpenTypeFeatureDefinitionListPrivate & OpenTypeFeatureDefinitionList()
FeatureDefinition m_aDefinition
Definition: Feature.hxx:110
uint32_t m_nCode
Definition: Feature.hxx:108
OUString VclResId(TranslateId aId)
Definition: svdata.cxx:261