1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/graphite2/src/GlyphCache.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,341 @@ 1.4 +/* GRAPHITE2 LICENSING 1.5 + 1.6 + Copyright 2012, 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 "graphite2/Font.h" 1.31 + 1.32 +#include "inc/Main.h" 1.33 +#include "inc/Face.h" //for the tags 1.34 +#include "inc/GlyphCache.h" 1.35 +#include "inc/GlyphFace.h" 1.36 +#include "inc/Endian.h" 1.37 + 1.38 +using namespace graphite2; 1.39 + 1.40 +namespace 1.41 +{ 1.42 + // Iterator over version 1 or 2 glat entries which consist of a series of 1.43 + // +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ 1.44 + // v1 |k|n|v1 |v2 |...|vN | or v2 | k | n |v1 |v2 |...|vN | 1.45 + // +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ 1.46 + // variable length structures. 1.47 + 1.48 + template<typename W> 1.49 + class _glat_iterator : public std::iterator<std::input_iterator_tag, std::pair<sparse::key_type, sparse::mapped_type> > 1.50 + { 1.51 + unsigned short key() const { return be::peek<W>(_e) + _n; } 1.52 + unsigned int run() const { return be::peek<W>(_e+sizeof(W)); } 1.53 + void advance_entry() { _n = 0; _e = _v; be::skip<W>(_v,2); } 1.54 + public: 1.55 + _glat_iterator(const void * glat=0) : _e(reinterpret_cast<const byte *>(glat)), _v(_e+2*sizeof(W)), _n(0) {} 1.56 + 1.57 + _glat_iterator<W> & operator ++ () { 1.58 + ++_n; be::skip<uint16>(_v); 1.59 + if (_n == run()) advance_entry(); 1.60 + return *this; 1.61 + } 1.62 + _glat_iterator<W> operator ++ (int) { _glat_iterator<W> tmp(*this); operator++(); return tmp; } 1.63 + 1.64 + // This is strictly a >= operator. A true == operator could be 1.65 + // implemented that test for overlap but it would be more expensive a 1.66 + // test. 1.67 + bool operator == (const _glat_iterator<W> & rhs) { return _v >= rhs._e; } 1.68 + bool operator != (const _glat_iterator<W> & rhs) { return !operator==(rhs); } 1.69 + 1.70 + value_type operator * () const { 1.71 + return value_type(key(), be::peek<uint16>(_v)); 1.72 + } 1.73 + 1.74 + protected: 1.75 + const byte * _e, * _v; 1.76 + ptrdiff_t _n; 1.77 + }; 1.78 + 1.79 + typedef _glat_iterator<uint8> glat_iterator; 1.80 + typedef _glat_iterator<uint16> glat2_iterator; 1.81 +} 1.82 + 1.83 + 1.84 +class GlyphCache::Loader 1.85 +{ 1.86 +public: 1.87 + Loader(const Face & face, const bool dumb_font); //return result indicates success. Do not use if failed. 1.88 + 1.89 + operator bool () const throw(); 1.90 + unsigned short int units_per_em() const throw(); 1.91 + unsigned short int num_glyphs() const throw(); 1.92 + unsigned short int num_attrs() const throw(); 1.93 + 1.94 + const GlyphFace * read_glyph(unsigned short gid, GlyphFace &) const throw(); 1.95 + 1.96 + CLASS_NEW_DELETE; 1.97 +private: 1.98 + Face::Table _head, 1.99 + _hhea, 1.100 + _hmtx, 1.101 + _glyf, 1.102 + _loca, 1.103 + m_pGlat, 1.104 + m_pGloc; 1.105 + 1.106 + bool _long_fmt; 1.107 + unsigned short _num_glyphs_graphics, //i.e. boundary box and advance 1.108 + _num_glyphs_attributes, 1.109 + _num_attrs; // number of glyph attributes per glyph 1.110 +}; 1.111 + 1.112 + 1.113 + 1.114 +GlyphCache::GlyphCache(const Face & face, const uint32 face_options) 1.115 +: _glyph_loader(new Loader(face, bool(face_options & gr_face_dumbRendering))), 1.116 + _glyphs(_glyph_loader && *_glyph_loader ? grzeroalloc<const GlyphFace *>(_glyph_loader->num_glyphs()) : 0), 1.117 + _num_glyphs(_glyphs ? _glyph_loader->num_glyphs() : 0), 1.118 + _num_attrs(_glyphs ? _glyph_loader->num_attrs() : 0), 1.119 + _upem(_glyphs ? _glyph_loader->units_per_em() : 0) 1.120 +{ 1.121 + if ((face_options & gr_face_preloadGlyphs) && _glyph_loader && _glyphs) 1.122 + { 1.123 + GlyphFace * const glyphs = new GlyphFace [_num_glyphs]; 1.124 + if (!glyphs) 1.125 + return; 1.126 + 1.127 + // The 0 glyph is definately required. 1.128 + _glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0]); 1.129 + 1.130 + // glyphs[0] has the same address as the glyphs array just allocated, 1.131 + // thus assigning the &glyphs[0] to _glyphs[0] means _glyphs[0] points 1.132 + // to the entire array. 1.133 + const GlyphFace * loaded = _glyphs[0]; 1.134 + for (uint16 gid = 1; loaded && gid != _num_glyphs; ++gid) 1.135 + _glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid]); 1.136 + 1.137 + if (!loaded) 1.138 + { 1.139 + _glyphs[0] = 0; 1.140 + delete [] glyphs; 1.141 + } 1.142 + delete _glyph_loader; 1.143 + _glyph_loader = 0; 1.144 + } 1.145 + 1.146 + if (_glyphs && glyph(0) == 0) 1.147 + { 1.148 + free(_glyphs); 1.149 + _glyphs = 0; 1.150 + _num_glyphs = _num_attrs = _upem = 0; 1.151 + } 1.152 +} 1.153 + 1.154 + 1.155 +GlyphCache::~GlyphCache() 1.156 +{ 1.157 + if (_glyphs) 1.158 + { 1.159 + if (_glyph_loader) 1.160 + { 1.161 + const GlyphFace * * g = _glyphs; 1.162 + for(unsigned short n = _num_glyphs; n; --n, ++g) 1.163 + delete *g; 1.164 + } 1.165 + else 1.166 + delete [] _glyphs[0]; 1.167 + free(_glyphs); 1.168 + } 1.169 + delete _glyph_loader; 1.170 +} 1.171 + 1.172 +const GlyphFace *GlyphCache::glyph(unsigned short glyphid) const //result may be changed by subsequent call with a different glyphid 1.173 +{ 1.174 + const GlyphFace * & p = _glyphs[glyphid]; 1.175 + if (p == 0 && _glyph_loader) 1.176 + { 1.177 + GlyphFace * g = new GlyphFace(); 1.178 + if (g) p = _glyph_loader->read_glyph(glyphid, *g); 1.179 + if (!p) 1.180 + { 1.181 + delete g; 1.182 + return *_glyphs; 1.183 + } 1.184 + } 1.185 + return p; 1.186 +} 1.187 + 1.188 + 1.189 + 1.190 +GlyphCache::Loader::Loader(const Face & face, const bool dumb_font) 1.191 +: _head(face, Tag::head), 1.192 + _hhea(face, Tag::hhea), 1.193 + _hmtx(face, Tag::hmtx), 1.194 + _glyf(face, Tag::glyf), 1.195 + _loca(face, Tag::loca), 1.196 + _long_fmt(false), 1.197 + _num_glyphs_graphics(0), 1.198 + _num_glyphs_attributes(0), 1.199 + _num_attrs(0) 1.200 +{ 1.201 + if (!operator bool()) 1.202 + return; 1.203 + 1.204 + const Face::Table maxp = Face::Table(face, Tag::maxp); 1.205 + if (!maxp) { _head = Face::Table(); return; } 1.206 + 1.207 + _num_glyphs_graphics = TtfUtil::GlyphCount(maxp); 1.208 + // This will fail if the number of glyphs is wildly out of range. 1.209 + if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-1)) 1.210 + { 1.211 + _head = Face::Table(); 1.212 + return; 1.213 + } 1.214 + 1.215 + if (!dumb_font) 1.216 + { 1.217 + if ((m_pGlat = Face::Table(face, Tag::Glat)) == NULL 1.218 + || (m_pGloc = Face::Table(face, Tag::Gloc)) == NULL 1.219 + || m_pGloc.size() < 6) 1.220 + { 1.221 + _head = Face::Table(); 1.222 + return; 1.223 + } 1.224 + const byte * p = m_pGloc; 1.225 + const int version = be::read<uint32>(p); 1.226 + const uint16 flags = be::read<uint16>(p); 1.227 + _num_attrs = be::read<uint16>(p); 1.228 + // We can accurately calculate the number of attributed glyphs by 1.229 + // subtracting the length of the attribids array (numAttribs long if present) 1.230 + // and dividing by either 2 or 4 depending on shor or lonf format 1.231 + _long_fmt = flags & 1; 1.232 + _num_glyphs_attributes = (m_pGloc.size() 1.233 + - (p - m_pGloc) 1.234 + - sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0)) 1.235 + / (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1; 1.236 + 1.237 + if (version != 0x00010000 1.238 + || _num_attrs == 0 || _num_attrs > 0x3000 // is this hard limit appropriate? 1.239 + || _num_glyphs_graphics > _num_glyphs_attributes) 1.240 + { 1.241 + _head = Face::Table(); 1.242 + return; 1.243 + } 1.244 + } 1.245 +} 1.246 + 1.247 +inline 1.248 +GlyphCache::Loader::operator bool () const throw() 1.249 +{ 1.250 + return _head && _hhea && _hmtx && !(bool(_glyf) != bool(_loca)); 1.251 +} 1.252 + 1.253 +inline 1.254 +unsigned short int GlyphCache::Loader::units_per_em() const throw() 1.255 +{ 1.256 + return _head ? TtfUtil::DesignUnits(_head) : 0; 1.257 +} 1.258 + 1.259 +inline 1.260 +unsigned short int GlyphCache::Loader::num_glyphs() const throw() 1.261 +{ 1.262 + return max(_num_glyphs_graphics, _num_glyphs_attributes); 1.263 +} 1.264 + 1.265 +inline 1.266 +unsigned short int GlyphCache::Loader::num_attrs() const throw() 1.267 +{ 1.268 + return _num_attrs; 1.269 +} 1.270 + 1.271 +const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph) const throw() 1.272 +{ 1.273 + Rect bbox; 1.274 + Position advance; 1.275 + 1.276 + if (glyphid < _num_glyphs_graphics) 1.277 + { 1.278 + int nLsb; 1.279 + unsigned int nAdvWid; 1.280 + if (_glyf) 1.281 + { 1.282 + int xMin, yMin, xMax, yMax; 1.283 + size_t locidx = TtfUtil::LocaLookup(glyphid, _loca, _loca.size(), _head); 1.284 + void *pGlyph = TtfUtil::GlyfLookup(_glyf, locidx, _glyf.size()); 1.285 + 1.286 + if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax)) 1.287 + bbox = Rect(Position(static_cast<float>(xMin), static_cast<float>(yMin)), 1.288 + Position(static_cast<float>(xMax), static_cast<float>(yMax))); 1.289 + } 1.290 + if (TtfUtil::HorMetrics(glyphid, _hmtx, _hmtx.size(), _hhea, nLsb, nAdvWid)) 1.291 + advance = Position(static_cast<float>(nAdvWid), 0); 1.292 + } 1.293 + 1.294 + if (glyphid < _num_glyphs_attributes) 1.295 + { 1.296 + const byte * gloc = m_pGloc; 1.297 + size_t glocs = 0, gloce = 0; 1.298 + 1.299 + be::skip<uint32>(gloc); 1.300 + be::skip<uint16>(gloc,2); 1.301 + if (_long_fmt) 1.302 + { 1.303 + be::skip<uint32>(gloc, glyphid); 1.304 + glocs = be::read<uint32>(gloc); 1.305 + gloce = be::peek<uint32>(gloc); 1.306 + } 1.307 + else 1.308 + { 1.309 + be::skip<uint16>(gloc, glyphid); 1.310 + glocs = be::read<uint16>(gloc); 1.311 + gloce = be::peek<uint16>(gloc); 1.312 + } 1.313 + 1.314 + if (glocs >= m_pGlat.size() || gloce > m_pGlat.size()) 1.315 + return 0; 1.316 + 1.317 + const uint32 glat_version = be::peek<uint32>(m_pGlat); 1.318 + if (glat_version < 0x00020000) 1.319 + { 1.320 + if (gloce - glocs < 2*sizeof(byte)+sizeof(uint16) 1.321 + || gloce - glocs > _num_attrs*(2*sizeof(byte)+sizeof(uint16))) 1.322 + { 1.323 + return 0; 1.324 + } 1.325 + 1.326 + new (&glyph) GlyphFace(bbox, advance, glat_iterator(m_pGlat + glocs), glat_iterator(m_pGlat + gloce)); 1.327 + } 1.328 + else 1.329 + { 1.330 + if (gloce - glocs < 3*sizeof(uint16) 1.331 + || gloce - glocs > _num_attrs*3*sizeof(uint16)) 1.332 + { 1.333 + return 0; 1.334 + } 1.335 + 1.336 + new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce)); 1.337 + } 1.338 + 1.339 + if (!glyph.attrs() || glyph.attrs().capacity() > _num_attrs) 1.340 + return 0; 1.341 + } 1.342 + 1.343 + return &glyph; 1.344 +}