gfx/graphite2/src/FeatureMap.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* GRAPHITE2 LICENSING
michael@0 2
michael@0 3 Copyright 2010, SIL International
michael@0 4 All rights reserved.
michael@0 5
michael@0 6 This library is free software; you can redistribute it and/or modify
michael@0 7 it under the terms of the GNU Lesser General Public License as published
michael@0 8 by the Free Software Foundation; either version 2.1 of License, or
michael@0 9 (at your option) any later version.
michael@0 10
michael@0 11 This program is distributed in the hope that it will be useful,
michael@0 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
michael@0 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
michael@0 14 Lesser General Public License for more details.
michael@0 15
michael@0 16 You should also have received a copy of the GNU Lesser General Public
michael@0 17 License along with this library in the file named "LICENSE".
michael@0 18 If not, write to the Free Software Foundation, 51 Franklin Street,
michael@0 19 Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
michael@0 20 internet at http://www.fsf.org/licenses/lgpl.html.
michael@0 21
michael@0 22 Alternatively, the contents of this file may be used under the terms of the
michael@0 23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
michael@0 24 License, as published by the Free Software Foundation, either version 2
michael@0 25 of the License or (at your option) any later version.
michael@0 26 */
michael@0 27 #include <cstring>
michael@0 28
michael@0 29 #include "inc/Main.h"
michael@0 30 #include "inc/bits.h"
michael@0 31 #include "inc/Endian.h"
michael@0 32 #include "inc/FeatureMap.h"
michael@0 33 #include "inc/FeatureVal.h"
michael@0 34 #include "graphite2/Font.h"
michael@0 35 #include "inc/TtfUtil.h"
michael@0 36 #include <cstdlib>
michael@0 37 #include "inc/Face.h"
michael@0 38
michael@0 39
michael@0 40 using namespace graphite2;
michael@0 41
michael@0 42 namespace
michael@0 43 {
michael@0 44 static int cmpNameAndFeatures(const void *ap, const void *bp)
michael@0 45 {
michael@0 46 const NameAndFeatureRef & a = *static_cast<const NameAndFeatureRef *>(ap),
michael@0 47 & b = *static_cast<const NameAndFeatureRef *>(bp);
michael@0 48 return (a < b ? -1 : (b < a ? 1 : 0));
michael@0 49 }
michael@0 50
michael@0 51 const size_t FEAT_HEADER = sizeof(uint32) + 2*sizeof(uint16) + sizeof(uint32),
michael@0 52 FEATURE_SIZE = sizeof(uint32)
michael@0 53 + 2*sizeof(uint16)
michael@0 54 + sizeof(uint32)
michael@0 55 + 2*sizeof(uint16),
michael@0 56 FEATURE_SETTING_SIZE = sizeof(int16) + sizeof(uint16);
michael@0 57
michael@0 58 uint16 readFeatureSettings(const byte * p, FeatureSetting * s, size_t num_settings)
michael@0 59 {
michael@0 60 uint16 max_val = 0;
michael@0 61 for (FeatureSetting * const end = s + num_settings; s != end; ++s)
michael@0 62 {
michael@0 63 const int16 value = be::read<int16>(p);
michael@0 64 ::new (s) FeatureSetting(value, be::read<uint16>(p));
michael@0 65 if (uint16(value) > max_val) max_val = value;
michael@0 66 }
michael@0 67
michael@0 68 return max_val;
michael@0 69 }
michael@0 70 }
michael@0 71
michael@0 72 FeatureRef::FeatureRef(const Face & face,
michael@0 73 unsigned short & bits_offset, uint32 max_val,
michael@0 74 uint32 name, uint16 uiName, uint16 flags,
michael@0 75 FeatureSetting *settings, uint16 num_set) throw()
michael@0 76 : m_pFace(&face),
michael@0 77 m_nameValues(settings),
michael@0 78 m_mask(mask_over_val(max_val)),
michael@0 79 m_max(max_val),
michael@0 80 m_id(name),
michael@0 81 m_nameid(uiName),
michael@0 82 m_flags(flags),
michael@0 83 m_numSet(num_set)
michael@0 84 {
michael@0 85 const uint8 need_bits = bit_set_count(m_mask);
michael@0 86 m_index = (bits_offset + need_bits) / SIZEOF_CHUNK;
michael@0 87 if (m_index > bits_offset / SIZEOF_CHUNK)
michael@0 88 bits_offset = m_index*SIZEOF_CHUNK;
michael@0 89 m_bits = bits_offset % SIZEOF_CHUNK;
michael@0 90 bits_offset += need_bits;
michael@0 91 m_mask <<= m_bits;
michael@0 92 }
michael@0 93
michael@0 94 FeatureRef::~FeatureRef() throw()
michael@0 95 {
michael@0 96 free(m_nameValues);
michael@0 97 }
michael@0 98
michael@0 99 bool FeatureMap::readFeats(const Face & face)
michael@0 100 {
michael@0 101 const Face::Table feat(face, TtfUtil::Tag::Feat);
michael@0 102 const byte * p = feat;
michael@0 103 if (!p) return true;
michael@0 104 if (feat.size() < FEAT_HEADER) return false;
michael@0 105
michael@0 106 const byte *const feat_start = p,
michael@0 107 *const feat_end = p + feat.size();
michael@0 108
michael@0 109 const uint32 version = be::read<uint32>(p);
michael@0 110 m_numFeats = be::read<uint16>(p);
michael@0 111 be::skip<uint16>(p);
michael@0 112 be::skip<uint32>(p);
michael@0 113
michael@0 114 // Sanity checks
michael@0 115 if (m_numFeats == 0) return true;
michael@0 116 if (version < 0x00010000 ||
michael@0 117 p + m_numFeats*FEATURE_SIZE > feat_end)
michael@0 118 { //defensive
michael@0 119 m_numFeats = 0;
michael@0 120 return false;
michael@0 121 }
michael@0 122
michael@0 123 m_feats = new FeatureRef [m_numFeats];
michael@0 124 uint16 * const defVals = gralloc<uint16>(m_numFeats);
michael@0 125 if (!defVals || !m_feats) return false;
michael@0 126 unsigned short bits = 0; //to cause overflow on first Feature
michael@0 127
michael@0 128 for (int i = 0, ie = m_numFeats; i != ie; i++)
michael@0 129 {
michael@0 130 const uint32 label = version < 0x00020000 ? be::read<uint16>(p) : be::read<uint32>(p);
michael@0 131 const uint16 num_settings = be::read<uint16>(p);
michael@0 132 if (version >= 0x00020000)
michael@0 133 be::skip<uint16>(p);
michael@0 134 const byte * const feat_setts = feat_start + be::read<uint32>(p);
michael@0 135 const uint16 flags = be::read<uint16>(p),
michael@0 136 uiName = be::read<uint16>(p);
michael@0 137
michael@0 138 if (feat_setts + num_settings * FEATURE_SETTING_SIZE > feat_end)
michael@0 139 {
michael@0 140 free(defVals);
michael@0 141 return false;
michael@0 142 }
michael@0 143
michael@0 144 FeatureSetting *uiSet;
michael@0 145 uint32 maxVal;
michael@0 146 if (num_settings != 0)
michael@0 147 {
michael@0 148 uiSet = gralloc<FeatureSetting>(num_settings);
michael@0 149 if (!uiSet)
michael@0 150 {
michael@0 151 free(defVals);
michael@0 152 return false;
michael@0 153 }
michael@0 154 maxVal = readFeatureSettings(feat_setts, uiSet, num_settings);
michael@0 155 defVals[i] = uiSet[0].value();
michael@0 156 }
michael@0 157 else
michael@0 158 {
michael@0 159 uiSet = 0;
michael@0 160 maxVal = 0xffffffff;
michael@0 161 defVals[i] = 0;
michael@0 162 }
michael@0 163
michael@0 164 ::new (m_feats + i) FeatureRef (face, bits, maxVal,
michael@0 165 label, uiName, flags,
michael@0 166 uiSet, num_settings);
michael@0 167 }
michael@0 168 m_defaultFeatures = new Features(bits/(sizeof(uint32)*8) + 1, *this);
michael@0 169 m_pNamedFeats = new NameAndFeatureRef[m_numFeats];
michael@0 170 if (!m_defaultFeatures || !m_pNamedFeats)
michael@0 171 {
michael@0 172 free(defVals);
michael@0 173 return false;
michael@0 174 }
michael@0 175 for (int i = 0; i < m_numFeats; ++i)
michael@0 176 {
michael@0 177 m_feats[i].applyValToFeature(defVals[i], *m_defaultFeatures);
michael@0 178 m_pNamedFeats[i] = m_feats+i;
michael@0 179 }
michael@0 180
michael@0 181 free(defVals);
michael@0 182
michael@0 183 qsort(m_pNamedFeats, m_numFeats, sizeof(NameAndFeatureRef), &cmpNameAndFeatures);
michael@0 184
michael@0 185 return true;
michael@0 186 }
michael@0 187
michael@0 188 bool SillMap::readFace(const Face & face)
michael@0 189 {
michael@0 190 if (!m_FeatureMap.readFeats(face)) return false;
michael@0 191 if (!readSill(face)) return false;
michael@0 192 return true;
michael@0 193 }
michael@0 194
michael@0 195
michael@0 196 bool SillMap::readSill(const Face & face)
michael@0 197 {
michael@0 198 const Face::Table sill(face, TtfUtil::Tag::Sill);
michael@0 199 const byte *p = sill;
michael@0 200
michael@0 201 if (!p) return true;
michael@0 202 if (sill.size() < 12) return false;
michael@0 203 if (be::read<uint32>(p) != 0x00010000UL) return false;
michael@0 204 m_numLanguages = be::read<uint16>(p);
michael@0 205 m_langFeats = new LangFeaturePair[m_numLanguages];
michael@0 206 if (!m_langFeats || !m_FeatureMap.m_numFeats) { m_numLanguages = 0; return true; } //defensive
michael@0 207
michael@0 208 p += 6; // skip the fast search
michael@0 209 if (sill.size() < m_numLanguages * 8U + 12) return false;
michael@0 210
michael@0 211 for (int i = 0; i < m_numLanguages; i++)
michael@0 212 {
michael@0 213 uint32 langid = be::read<uint32>(p);
michael@0 214 uint16 numSettings = be::read<uint16>(p);
michael@0 215 uint16 offset = be::read<uint16>(p);
michael@0 216 if (offset + 8U * numSettings > sill.size() && numSettings > 0) return false;
michael@0 217 Features* feats = new Features(*m_FeatureMap.m_defaultFeatures);
michael@0 218 if (!feats) return false;
michael@0 219 const byte *pLSet = sill + offset;
michael@0 220
michael@0 221 // Apply langauge specific settings
michael@0 222 for (int j = 0; j < numSettings; j++)
michael@0 223 {
michael@0 224 uint32 name = be::read<uint32>(pLSet);
michael@0 225 uint16 val = be::read<uint16>(pLSet);
michael@0 226 pLSet += 2;
michael@0 227 const FeatureRef* pRef = m_FeatureMap.findFeatureRef(name);
michael@0 228 if (pRef) pRef->applyValToFeature(val, *feats);
michael@0 229 }
michael@0 230 // Add the language id feature which is always feature id 1
michael@0 231 const FeatureRef* pRef = m_FeatureMap.findFeatureRef(1);
michael@0 232 if (pRef) pRef->applyValToFeature(langid, *feats);
michael@0 233
michael@0 234 m_langFeats[i].m_lang = langid;
michael@0 235 m_langFeats[i].m_pFeatures = feats;
michael@0 236 }
michael@0 237 return true;
michael@0 238 }
michael@0 239
michael@0 240
michael@0 241 Features* SillMap::cloneFeatures(uint32 langname/*0 means default*/) const
michael@0 242 {
michael@0 243 if (langname)
michael@0 244 {
michael@0 245 // the number of languages in a font is usually small e.g. 8 in Doulos
michael@0 246 // so this loop is not very expensive
michael@0 247 for (uint16 i = 0; i < m_numLanguages; i++)
michael@0 248 {
michael@0 249 if (m_langFeats[i].m_lang == langname)
michael@0 250 return new Features(*m_langFeats[i].m_pFeatures);
michael@0 251 }
michael@0 252 }
michael@0 253 return new Features (*m_FeatureMap.m_defaultFeatures);
michael@0 254 }
michael@0 255
michael@0 256
michael@0 257
michael@0 258 const FeatureRef *FeatureMap::findFeatureRef(uint32 name) const
michael@0 259 {
michael@0 260 NameAndFeatureRef *it;
michael@0 261
michael@0 262 for (it = m_pNamedFeats; it < m_pNamedFeats + m_numFeats; ++it)
michael@0 263 if (it->m_name == name)
michael@0 264 return it->m_pFRef;
michael@0 265 return NULL;
michael@0 266 }
michael@0 267
michael@0 268 bool FeatureRef::applyValToFeature(uint32 val, Features & pDest) const
michael@0 269 {
michael@0 270 if (val>maxVal() || !m_pFace)
michael@0 271 return false;
michael@0 272 if (pDest.m_pMap==NULL)
michael@0 273 pDest.m_pMap = &m_pFace->theSill().theFeatureMap();
michael@0 274 else
michael@0 275 if (pDest.m_pMap!=&m_pFace->theSill().theFeatureMap())
michael@0 276 return false; //incompatible
michael@0 277 pDest.reserve(m_index);
michael@0 278 pDest[m_index] &= ~m_mask;
michael@0 279 pDest[m_index] |= (uint32(val) << m_bits);
michael@0 280 return true;
michael@0 281 }
michael@0 282
michael@0 283 uint32 FeatureRef::getFeatureVal(const Features& feats) const
michael@0 284 {
michael@0 285 if (m_index < feats.size() && &m_pFace->theSill().theFeatureMap()==feats.m_pMap)
michael@0 286 return (feats[m_index] & m_mask) >> m_bits;
michael@0 287 else
michael@0 288 return 0;
michael@0 289 }
michael@0 290
michael@0 291

mercurial