1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/graphite2/src/Face.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,269 @@ 1.4 +/* GRAPHITE2 LICENSING 1.5 + 1.6 + Copyright 2010, SIL International 1.7 + All rights reserved. 1.8 + 1.9 + This library is free software; you can redistribute it and/or modify 1.10 + it under the terms of the GNU Lesser General Public License as published 1.11 + by the Free Software Foundation; either version 2.1 of License, or 1.12 + (at your option) any later version. 1.13 + 1.14 + This program is distributed in the hope that it will be useful, 1.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of 1.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.17 + Lesser General Public License for more details. 1.18 + 1.19 + You should also have received a copy of the GNU Lesser General Public 1.20 + License along with this library in the file named "LICENSE". 1.21 + If not, write to the Free Software Foundation, 51 Franklin Street, 1.22 + Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 1.23 + internet at http://www.fsf.org/licenses/lgpl.html. 1.24 + 1.25 +Alternatively, the contents of this file may be used under the terms of the 1.26 +Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public 1.27 +License, as published by the Free Software Foundation, either version 2 1.28 +of the License or (at your option) any later version. 1.29 +*/ 1.30 +#include <cstring> 1.31 +#include "graphite2/Segment.h" 1.32 +#include "inc/CmapCache.h" 1.33 +#include "inc/debug.h" 1.34 +#include "inc/Endian.h" 1.35 +#include "inc/Face.h" 1.36 +#include "inc/FileFace.h" 1.37 +#include "inc/GlyphFace.h" 1.38 +#include "inc/json.h" 1.39 +#include "inc/SegCacheStore.h" 1.40 +#include "inc/Segment.h" 1.41 +#include "inc/NameTable.h" 1.42 +#include "inc/Error.h" 1.43 + 1.44 +using namespace graphite2; 1.45 + 1.46 +Face::Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops) 1.47 +: m_appFaceHandle(appFaceHandle), 1.48 + m_pFileFace(NULL), 1.49 + m_pGlyphFaceCache(NULL), 1.50 + m_cmap(NULL), 1.51 + m_pNames(NULL), 1.52 + m_logger(NULL), 1.53 + m_error(0), m_errcntxt(0), 1.54 + m_silfs(NULL), 1.55 + m_numSilf(0), 1.56 + m_ascent(0), 1.57 + m_descent(0) 1.58 +{ 1.59 + memset(&m_ops, 0, sizeof m_ops); 1.60 + memcpy(&m_ops, &ops, min(sizeof m_ops, ops.size)); 1.61 +} 1.62 + 1.63 + 1.64 +Face::~Face() 1.65 +{ 1.66 + setLogger(0); 1.67 + delete m_pGlyphFaceCache; 1.68 + delete m_cmap; 1.69 + delete[] m_silfs; 1.70 +#ifndef GRAPHITE2_NFILEFACE 1.71 + delete m_pFileFace; 1.72 +#endif 1.73 + delete m_pNames; 1.74 +} 1.75 + 1.76 +float Face::default_glyph_advance(const void* font_ptr, gr_uint16 glyphid) 1.77 +{ 1.78 + const Font & font = *reinterpret_cast<const Font *>(font_ptr); 1.79 + 1.80 + return font.face().glyphs().glyph(glyphid)->theAdvance().x * font.scale(); 1.81 +} 1.82 + 1.83 +bool Face::readGlyphs(uint32 faceOptions) 1.84 +{ 1.85 + Error e; 1.86 +#ifdef GRAPHITE2_TELEMETRY 1.87 + telemetry::category _glyph_cat(tele.glyph); 1.88 +#endif 1.89 + error_context(EC_READGLYPHS); 1.90 + if (faceOptions & gr_face_cacheCmap) 1.91 + m_cmap = new CachedCmap(*this); 1.92 + else 1.93 + m_cmap = new DirectCmap(*this); 1.94 + 1.95 + m_pGlyphFaceCache = new GlyphCache(*this, faceOptions); 1.96 + if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM) 1.97 + || e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS) 1.98 + || e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM) 1.99 + || e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP)) 1.100 + { 1.101 + return error(e); 1.102 + } 1.103 + 1.104 + if (faceOptions & gr_face_preloadGlyphs) 1.105 + nameTable(); // preload the name table along with the glyphs. 1.106 + 1.107 + return true; 1.108 +} 1.109 + 1.110 +bool Face::readGraphite(const Table & silf) 1.111 +{ 1.112 +#ifdef GRAPHITE2_TELEMETRY 1.113 + telemetry::category _silf_cat(tele.silf); 1.114 +#endif 1.115 + Error e; 1.116 + error_context(EC_READSILF); 1.117 + const byte * p = silf; 1.118 + if (e.test(!p, E_NOSILF)) return error(e); 1.119 + 1.120 + const uint32 version = be::read<uint32>(p); 1.121 + if (e.test(version < 0x00020000, E_TOOOLD)) return error(e); 1.122 + if (version >= 0x00030000) 1.123 + be::skip<uint32>(p); // compilerVersion 1.124 + m_numSilf = be::read<uint16>(p); 1.125 + be::skip<uint16>(p); // reserved 1.126 + 1.127 + bool havePasses = false; 1.128 + m_silfs = new Silf[m_numSilf]; 1.129 + for (int i = 0; i < m_numSilf; i++) 1.130 + { 1.131 + error_context(EC_ASILF + (i << 8)); 1.132 + const uint32 offset = be::read<uint32>(p), 1.133 + next = i == m_numSilf - 1 ? silf.size() : be::peek<uint32>(p); 1.134 + if (e.test(next > silf.size() || offset >= next, E_BADSIZE)) 1.135 + return error(e); 1.136 + 1.137 + if (!m_silfs[i].readGraphite(silf + offset, next - offset, *this, version)) 1.138 + return false; 1.139 + 1.140 + if (m_silfs[i].numPasses()) 1.141 + havePasses = true; 1.142 + } 1.143 + 1.144 + return havePasses; 1.145 +} 1.146 + 1.147 +bool Face::readFeatures() 1.148 +{ 1.149 + return m_Sill.readFace(*this); 1.150 +} 1.151 + 1.152 +bool Face::runGraphite(Segment *seg, const Silf *aSilf) const 1.153 +{ 1.154 +#if !defined GRAPHITE2_NTRACING 1.155 + json * dbgout = logger(); 1.156 + if (dbgout) 1.157 + { 1.158 + *dbgout << json::object 1.159 + << "id" << objectid(seg) 1.160 + << "passes" << json::array; 1.161 + } 1.162 +#endif 1.163 + 1.164 + bool res = aSilf->runGraphite(seg, 0, aSilf->justificationPass(), true); 1.165 + if (res) 1.166 + res = aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false); 1.167 + 1.168 +#if !defined GRAPHITE2_NTRACING 1.169 + if (dbgout) 1.170 +{ 1.171 + *dbgout << json::item 1.172 + << json::close // Close up the passes array 1.173 + << "output" << json::array; 1.174 + for(Slot * s = seg->first(); s; s = s->next()) 1.175 + *dbgout << dslot(seg, s); 1.176 + seg->finalise(0); // Call this here to fix up charinfo back indexes. 1.177 + *dbgout << json::close 1.178 + << "advance" << seg->advance() 1.179 + << "chars" << json::array; 1.180 + for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i) 1.181 + *dbgout << json::flat << *seg->charinfo(i); 1.182 + *dbgout << json::close // Close up the chars array 1.183 + << json::close; // Close up the segment object 1.184 + } 1.185 +#endif 1.186 + 1.187 + return res; 1.188 +} 1.189 + 1.190 +void Face::setLogger(FILE * log_file GR_MAYBE_UNUSED) 1.191 +{ 1.192 +#if !defined GRAPHITE2_NTRACING 1.193 + delete m_logger; 1.194 + m_logger = log_file ? new json(log_file) : 0; 1.195 +#endif 1.196 +} 1.197 + 1.198 +const Silf *Face::chooseSilf(uint32 script) const 1.199 +{ 1.200 + if (m_numSilf == 0) 1.201 + return NULL; 1.202 + else if (m_numSilf == 1 || script == 0) 1.203 + return m_silfs; 1.204 + else // do more work here 1.205 + return m_silfs; 1.206 +} 1.207 + 1.208 +uint16 Face::findPseudo(uint32 uid) const 1.209 +{ 1.210 + return (m_numSilf) ? m_silfs[0].findPseudo(uid) : 0; 1.211 +} 1.212 + 1.213 +uint16 Face::getGlyphMetric(uint16 gid, uint8 metric) const 1.214 +{ 1.215 + switch (metrics(metric)) 1.216 + { 1.217 + case kgmetAscent : return m_ascent; 1.218 + case kgmetDescent : return m_descent; 1.219 + default: return glyphs().glyph(gid)->getMetric(metric); 1.220 + } 1.221 +} 1.222 + 1.223 +void Face::takeFileFace(FileFace* pFileFace GR_MAYBE_UNUSED/*takes ownership*/) 1.224 +{ 1.225 +#ifndef GRAPHITE2_NFILEFACE 1.226 + if (m_pFileFace==pFileFace) 1.227 + return; 1.228 + 1.229 + delete m_pFileFace; 1.230 + m_pFileFace = pFileFace; 1.231 +#endif 1.232 +} 1.233 + 1.234 +NameTable * Face::nameTable() const 1.235 +{ 1.236 + if (m_pNames) return m_pNames; 1.237 + const Table name(*this, Tag::name); 1.238 + if (name) 1.239 + m_pNames = new NameTable(name, name.size()); 1.240 + return m_pNames; 1.241 +} 1.242 + 1.243 +uint16 Face::languageForLocale(const char * locale) const 1.244 +{ 1.245 + nameTable(); 1.246 + if (m_pNames) 1.247 + return m_pNames->getLanguageId(locale); 1.248 + return 0; 1.249 +} 1.250 + 1.251 +Face::Table::Table(const Face & face, const Tag n) throw() 1.252 +: _f(&face) 1.253 +{ 1.254 + size_t sz = 0; 1.255 + _p = reinterpret_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &sz)); 1.256 + _sz = uint32(sz); 1.257 + if (!TtfUtil::CheckTable(n, _p, _sz)) 1.258 + { 1.259 + this->~Table(); // Make sure we release the table buffer even if the table filed it's checks 1.260 + _p = 0; _sz = 0; 1.261 + } 1.262 +} 1.263 + 1.264 +Face::Table & Face::Table::operator = (const Table & rhs) throw() 1.265 +{ 1.266 + if (_p == rhs._p) return *this; 1.267 + 1.268 + this->~Table(); 1.269 + new (this) Table(rhs); 1.270 + return *this; 1.271 +} 1.272 +