Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/graphite/src/FeatureMap.cpp
Line
Count
Source
1
// SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later
2
// Copyright 2010, SIL International, All rights reserved.
3
4
#include <cstring>
5
6
#include "inc/Main.h"
7
#include "inc/bits.h"
8
#include "inc/Endian.h"
9
#include "inc/FeatureMap.h"
10
#include "inc/FeatureVal.h"
11
#include "graphite2/Font.h"
12
#include "inc/TtfUtil.h"
13
#include <cstdlib>
14
#include "inc/Face.h"
15
16
17
using namespace graphite2;
18
19
namespace
20
{
21
    static int cmpNameAndFeatures(const void *ap, const void *bp)
22
0
    {
23
0
        const NameAndFeatureRef & a = *static_cast<const NameAndFeatureRef *>(ap),
24
0
                                & b = *static_cast<const NameAndFeatureRef *>(bp);
25
0
        return (a < b ? -1 : (b < a ? 1 : 0));
26
0
    }
27
28
    const size_t    FEAT_HEADER     = sizeof(uint32) + 2*sizeof(uint16) + sizeof(uint32),
29
                    FEATURE_SIZE    = sizeof(uint32)
30
                                    + 2*sizeof(uint16)
31
                                    + sizeof(uint32)
32
                                    + 2*sizeof(uint16),
33
                    FEATURE_SETTING_SIZE = sizeof(int16) + sizeof(uint16);
34
35
    uint16 readFeatureSettings(const byte * p, FeatureSetting * s, size_t num_settings)
36
0
    {
37
0
        uint16 max_val = 0;
38
0
        for (FeatureSetting * const end = s + num_settings; s != end; ++s)
39
0
        {
40
0
            const int16 value = be::read<int16>(p);
41
0
            ::new (s) FeatureSetting(value, be::read<uint16>(p));
42
0
            if (uint16(value) > max_val)    max_val = value;
43
0
        }
44
45
0
        return max_val;
46
0
    }
47
}
48
49
FeatureRef::FeatureRef(const Face & face,
50
    unsigned short & bits_offset, uint32 max_val,
51
    uint32 name, uint16 uiName, flags_t flags,
52
    FeatureSetting *settings, uint16 num_set) throw()
53
0
: m_face(&face),
54
0
  m_nameValues(settings),
55
0
  m_mask(mask_over_val(max_val)),
56
0
  m_max(max_val),
57
0
  m_id(name),
58
0
  m_nameid(uiName),
59
0
  m_numSet(num_set),
60
0
  m_flags(flags)
61
0
{
62
0
    const uint8 need_bits = bit_set_count(m_mask);
63
0
    m_index = (bits_offset + need_bits) / SIZEOF_CHUNK;
64
0
    if (m_index > bits_offset / SIZEOF_CHUNK)
65
0
        bits_offset = m_index*SIZEOF_CHUNK;
66
0
    m_bits = bits_offset % SIZEOF_CHUNK;
67
0
    bits_offset += need_bits;
68
0
    m_mask <<= m_bits;
69
0
}
70
71
FeatureRef::~FeatureRef() throw()
72
0
{
73
0
    free(m_nameValues);
74
0
}
75
76
bool FeatureMap::readFeats(const Face & face)
77
0
{
78
0
    const Face::Table feat(face, TtfUtil::Tag::Feat);
79
0
    const byte * p = feat;
80
0
    if (!p) return true;
81
0
    if (feat.size() < FEAT_HEADER) return false;
82
83
0
    const byte *const feat_start = p,
84
0
               *const feat_end = p + feat.size();
85
86
0
    const uint32 version = be::read<uint32>(p);
87
0
    m_numFeats = be::read<uint16>(p);
88
0
    be::skip<uint16>(p);
89
0
    be::skip<uint32>(p);
90
91
    // Sanity checks
92
0
    if (m_numFeats == 0)    return true;
93
0
    if (version < 0x00010000 ||
94
0
        p + m_numFeats*FEATURE_SIZE > feat_end)
95
0
    {   //defensive
96
0
        m_numFeats = 0;
97
0
        return false;
98
0
    }
99
100
0
    m_feats = new FeatureRef [m_numFeats];
101
0
    uint16 * const  defVals = gralloc<uint16>(m_numFeats);
102
0
    if (!defVals || !m_feats) return false;
103
0
    unsigned short bits = 0;     //to cause overflow on first Feature
104
105
0
    for (int i = 0, ie = m_numFeats; i != ie; i++)
106
0
    {
107
0
        const uint32    label   = version < 0x00020000 ? be::read<uint16>(p) : be::read<uint32>(p);
108
0
        const uint16    num_settings = be::read<uint16>(p);
109
0
        if (version >= 0x00020000)
110
0
            be::skip<uint16>(p);
111
0
        const uint32    settings_offset = be::read<uint32>(p);
112
0
        const uint16    flags  = be::read<uint16>(p),
113
0
                        uiName = be::read<uint16>(p);
114
115
0
        if (settings_offset > size_t(feat_end - feat_start)
116
0
            || settings_offset + num_settings * FEATURE_SETTING_SIZE > size_t(feat_end - feat_start))
117
0
        {
118
0
            free(defVals);
119
0
            return false;
120
0
        }
121
122
0
        FeatureSetting *uiSet;
123
0
        uint32 maxVal;
124
0
        if (num_settings != 0)
125
0
        {
126
0
            uiSet = gralloc<FeatureSetting>(num_settings);
127
0
            if (!uiSet)
128
0
            {
129
0
                free(defVals);
130
0
                return false;
131
0
            }
132
0
            maxVal = readFeatureSettings(feat_start + settings_offset, uiSet, num_settings);
133
0
            defVals[i] = uiSet[0].value();
134
0
        }
135
0
        else
136
0
        {
137
0
            uiSet = 0;
138
0
            maxVal = 0xffffffff;
139
0
            defVals[i] = 0;
140
0
        }
141
142
0
        ::new (m_feats + i) FeatureRef (face, bits, maxVal,
143
0
                                       label, uiName, 
144
0
                                       FeatureRef::flags_t(flags),
145
0
                                       uiSet, num_settings);
146
0
    }
147
0
    new (&m_defaultFeatures) Features(bits/(sizeof(uint32)*8) + 1, *this);
148
0
    m_pNamedFeats = new NameAndFeatureRef[m_numFeats];
149
0
    if (!m_pNamedFeats)
150
0
    {
151
0
        free(defVals);
152
0
        return false;
153
0
    }
154
0
    for (int i = 0; i < m_numFeats; ++i)
155
0
    {
156
0
        m_feats[i].applyValToFeature(defVals[i], m_defaultFeatures);
157
0
        m_pNamedFeats[i] = m_feats[i];
158
0
    }
159
160
0
    free(defVals);
161
162
0
    qsort(m_pNamedFeats, m_numFeats, sizeof(NameAndFeatureRef), &cmpNameAndFeatures);
163
164
0
    return true;
165
0
}
166
167
bool SillMap::readFace(const Face & face)
168
0
{
169
0
    if (!m_FeatureMap.readFeats(face)) return false;
170
0
    if (!readSill(face)) return false;
171
0
    return true;
172
0
}
173
174
175
bool SillMap::readSill(const Face & face)
176
0
{
177
0
    const Face::Table sill(face, TtfUtil::Tag::Sill);
178
0
    const byte *p = sill;
179
180
0
    if (!p) return true;
181
0
    if (sill.size() < 12) return false;
182
0
    if (be::read<uint32>(p) != 0x00010000UL) return false;
183
0
    m_numLanguages = be::read<uint16>(p);
184
0
    m_langFeats = new LangFeaturePair[m_numLanguages];
185
0
    if (!m_langFeats || !m_FeatureMap.m_numFeats) { m_numLanguages = 0; return true; }        //defensive
186
187
0
    p += 6;     // skip the fast search
188
0
    if (sill.size() < m_numLanguages * 8U + 12) return false;
189
190
0
    for (int i = 0; i < m_numLanguages; i++)
191
0
    {
192
0
        uint32 langid = be::read<uint32>(p);
193
0
        uint16 numSettings = be::read<uint16>(p);
194
0
        uint16 offset = be::read<uint16>(p);
195
0
        if (offset + 8U * numSettings > sill.size() && numSettings > 0) return false;
196
0
        Features* feats = new Features(m_FeatureMap.m_defaultFeatures);
197
0
        if (!feats) return false;
198
0
        const byte *pLSet = sill + offset;
199
200
        // Apply langauge specific settings
201
0
        for (int j = 0; j < numSettings; j++)
202
0
        {
203
0
            uint32 name = be::read<uint32>(pLSet);
204
0
            uint16 val = be::read<uint16>(pLSet);
205
0
            pLSet += 2;
206
0
            const FeatureRef* pRef = m_FeatureMap.findFeatureRef(name);
207
0
            if (pRef)   pRef->applyValToFeature(val, *feats);
208
0
        }
209
        // Add the language id feature which is always feature id 1
210
0
        const FeatureRef* pRef = m_FeatureMap.findFeatureRef(1);
211
0
        if (pRef)   pRef->applyValToFeature(langid, *feats);
212
213
0
        m_langFeats[i].m_lang = langid;
214
0
        m_langFeats[i].m_pFeatures = feats;
215
0
    }
216
0
    return true;
217
0
}
218
219
220
Features* SillMap::cloneFeatures(uint32 langname/*0 means default*/) const
221
0
{
222
0
    if (langname)
223
0
    {
224
        // the number of languages in a font is usually small e.g. 8 in Doulos
225
        // so this loop is not very expensive
226
0
        for (uint16 i = 0; i < m_numLanguages; i++)
227
0
        {
228
0
            if (m_langFeats[i].m_lang == langname)
229
0
                return new Features(*m_langFeats[i].m_pFeatures);
230
0
        }
231
0
    }
232
0
    return new Features (m_FeatureMap.m_defaultFeatures);
233
0
}
234
235
236
237
const FeatureRef *FeatureMap::findFeatureRef(uint32 name) const
238
0
{
239
0
    NameAndFeatureRef *it;
240
241
0
    for (it = m_pNamedFeats; it < m_pNamedFeats + m_numFeats; ++it)
242
0
        if (it->m_name == name)
243
0
            return it->m_pFRef;
244
0
    return NULL;
245
0
}
246
247
bool FeatureRef::applyValToFeature(uint32 val, Features & pDest) const
248
0
{
249
0
    if (val>maxVal() || !m_face)
250
0
      return false;
251
0
    if (pDest.m_pMap==NULL)
252
0
      pDest.m_pMap = &m_face->theSill().theFeatureMap();
253
0
    else
254
0
      if (pDest.m_pMap!=&m_face->theSill().theFeatureMap())
255
0
        return false;       //incompatible
256
0
    if (m_index >= pDest.size())
257
0
        pDest.resize(m_index+1);
258
0
    pDest[m_index] &= ~m_mask;
259
0
    pDest[m_index] |= (uint32(val) << m_bits);
260
0
    return true;
261
0
}
262
263
uint32 FeatureRef::getFeatureVal(const Features& feats) const
264
0
{
265
0
  if (m_index < feats.size() && m_face
266
0
      && &m_face->theSill().theFeatureMap()==feats.m_pMap)
267
0
    return (feats[m_index] & m_mask) >> m_bits;
268
0
  else
269
0
    return 0;
270
0
}