gfx/graphite2/src/GlyphCache.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 2012, 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 "graphite2/Font.h"
michael@0 28
michael@0 29 #include "inc/Main.h"
michael@0 30 #include "inc/Face.h" //for the tags
michael@0 31 #include "inc/GlyphCache.h"
michael@0 32 #include "inc/GlyphFace.h"
michael@0 33 #include "inc/Endian.h"
michael@0 34
michael@0 35 using namespace graphite2;
michael@0 36
michael@0 37 namespace
michael@0 38 {
michael@0 39 // Iterator over version 1 or 2 glat entries which consist of a series of
michael@0 40 // +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+
michael@0 41 // v1 |k|n|v1 |v2 |...|vN | or v2 | k | n |v1 |v2 |...|vN |
michael@0 42 // +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+
michael@0 43 // variable length structures.
michael@0 44
michael@0 45 template<typename W>
michael@0 46 class _glat_iterator : public std::iterator<std::input_iterator_tag, std::pair<sparse::key_type, sparse::mapped_type> >
michael@0 47 {
michael@0 48 unsigned short key() const { return be::peek<W>(_e) + _n; }
michael@0 49 unsigned int run() const { return be::peek<W>(_e+sizeof(W)); }
michael@0 50 void advance_entry() { _n = 0; _e = _v; be::skip<W>(_v,2); }
michael@0 51 public:
michael@0 52 _glat_iterator(const void * glat=0) : _e(reinterpret_cast<const byte *>(glat)), _v(_e+2*sizeof(W)), _n(0) {}
michael@0 53
michael@0 54 _glat_iterator<W> & operator ++ () {
michael@0 55 ++_n; be::skip<uint16>(_v);
michael@0 56 if (_n == run()) advance_entry();
michael@0 57 return *this;
michael@0 58 }
michael@0 59 _glat_iterator<W> operator ++ (int) { _glat_iterator<W> tmp(*this); operator++(); return tmp; }
michael@0 60
michael@0 61 // This is strictly a >= operator. A true == operator could be
michael@0 62 // implemented that test for overlap but it would be more expensive a
michael@0 63 // test.
michael@0 64 bool operator == (const _glat_iterator<W> & rhs) { return _v >= rhs._e; }
michael@0 65 bool operator != (const _glat_iterator<W> & rhs) { return !operator==(rhs); }
michael@0 66
michael@0 67 value_type operator * () const {
michael@0 68 return value_type(key(), be::peek<uint16>(_v));
michael@0 69 }
michael@0 70
michael@0 71 protected:
michael@0 72 const byte * _e, * _v;
michael@0 73 ptrdiff_t _n;
michael@0 74 };
michael@0 75
michael@0 76 typedef _glat_iterator<uint8> glat_iterator;
michael@0 77 typedef _glat_iterator<uint16> glat2_iterator;
michael@0 78 }
michael@0 79
michael@0 80
michael@0 81 class GlyphCache::Loader
michael@0 82 {
michael@0 83 public:
michael@0 84 Loader(const Face & face, const bool dumb_font); //return result indicates success. Do not use if failed.
michael@0 85
michael@0 86 operator bool () const throw();
michael@0 87 unsigned short int units_per_em() const throw();
michael@0 88 unsigned short int num_glyphs() const throw();
michael@0 89 unsigned short int num_attrs() const throw();
michael@0 90
michael@0 91 const GlyphFace * read_glyph(unsigned short gid, GlyphFace &) const throw();
michael@0 92
michael@0 93 CLASS_NEW_DELETE;
michael@0 94 private:
michael@0 95 Face::Table _head,
michael@0 96 _hhea,
michael@0 97 _hmtx,
michael@0 98 _glyf,
michael@0 99 _loca,
michael@0 100 m_pGlat,
michael@0 101 m_pGloc;
michael@0 102
michael@0 103 bool _long_fmt;
michael@0 104 unsigned short _num_glyphs_graphics, //i.e. boundary box and advance
michael@0 105 _num_glyphs_attributes,
michael@0 106 _num_attrs; // number of glyph attributes per glyph
michael@0 107 };
michael@0 108
michael@0 109
michael@0 110
michael@0 111 GlyphCache::GlyphCache(const Face & face, const uint32 face_options)
michael@0 112 : _glyph_loader(new Loader(face, bool(face_options & gr_face_dumbRendering))),
michael@0 113 _glyphs(_glyph_loader && *_glyph_loader ? grzeroalloc<const GlyphFace *>(_glyph_loader->num_glyphs()) : 0),
michael@0 114 _num_glyphs(_glyphs ? _glyph_loader->num_glyphs() : 0),
michael@0 115 _num_attrs(_glyphs ? _glyph_loader->num_attrs() : 0),
michael@0 116 _upem(_glyphs ? _glyph_loader->units_per_em() : 0)
michael@0 117 {
michael@0 118 if ((face_options & gr_face_preloadGlyphs) && _glyph_loader && _glyphs)
michael@0 119 {
michael@0 120 GlyphFace * const glyphs = new GlyphFace [_num_glyphs];
michael@0 121 if (!glyphs)
michael@0 122 return;
michael@0 123
michael@0 124 // The 0 glyph is definately required.
michael@0 125 _glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0]);
michael@0 126
michael@0 127 // glyphs[0] has the same address as the glyphs array just allocated,
michael@0 128 // thus assigning the &glyphs[0] to _glyphs[0] means _glyphs[0] points
michael@0 129 // to the entire array.
michael@0 130 const GlyphFace * loaded = _glyphs[0];
michael@0 131 for (uint16 gid = 1; loaded && gid != _num_glyphs; ++gid)
michael@0 132 _glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid]);
michael@0 133
michael@0 134 if (!loaded)
michael@0 135 {
michael@0 136 _glyphs[0] = 0;
michael@0 137 delete [] glyphs;
michael@0 138 }
michael@0 139 delete _glyph_loader;
michael@0 140 _glyph_loader = 0;
michael@0 141 }
michael@0 142
michael@0 143 if (_glyphs && glyph(0) == 0)
michael@0 144 {
michael@0 145 free(_glyphs);
michael@0 146 _glyphs = 0;
michael@0 147 _num_glyphs = _num_attrs = _upem = 0;
michael@0 148 }
michael@0 149 }
michael@0 150
michael@0 151
michael@0 152 GlyphCache::~GlyphCache()
michael@0 153 {
michael@0 154 if (_glyphs)
michael@0 155 {
michael@0 156 if (_glyph_loader)
michael@0 157 {
michael@0 158 const GlyphFace * * g = _glyphs;
michael@0 159 for(unsigned short n = _num_glyphs; n; --n, ++g)
michael@0 160 delete *g;
michael@0 161 }
michael@0 162 else
michael@0 163 delete [] _glyphs[0];
michael@0 164 free(_glyphs);
michael@0 165 }
michael@0 166 delete _glyph_loader;
michael@0 167 }
michael@0 168
michael@0 169 const GlyphFace *GlyphCache::glyph(unsigned short glyphid) const //result may be changed by subsequent call with a different glyphid
michael@0 170 {
michael@0 171 const GlyphFace * & p = _glyphs[glyphid];
michael@0 172 if (p == 0 && _glyph_loader)
michael@0 173 {
michael@0 174 GlyphFace * g = new GlyphFace();
michael@0 175 if (g) p = _glyph_loader->read_glyph(glyphid, *g);
michael@0 176 if (!p)
michael@0 177 {
michael@0 178 delete g;
michael@0 179 return *_glyphs;
michael@0 180 }
michael@0 181 }
michael@0 182 return p;
michael@0 183 }
michael@0 184
michael@0 185
michael@0 186
michael@0 187 GlyphCache::Loader::Loader(const Face & face, const bool dumb_font)
michael@0 188 : _head(face, Tag::head),
michael@0 189 _hhea(face, Tag::hhea),
michael@0 190 _hmtx(face, Tag::hmtx),
michael@0 191 _glyf(face, Tag::glyf),
michael@0 192 _loca(face, Tag::loca),
michael@0 193 _long_fmt(false),
michael@0 194 _num_glyphs_graphics(0),
michael@0 195 _num_glyphs_attributes(0),
michael@0 196 _num_attrs(0)
michael@0 197 {
michael@0 198 if (!operator bool())
michael@0 199 return;
michael@0 200
michael@0 201 const Face::Table maxp = Face::Table(face, Tag::maxp);
michael@0 202 if (!maxp) { _head = Face::Table(); return; }
michael@0 203
michael@0 204 _num_glyphs_graphics = TtfUtil::GlyphCount(maxp);
michael@0 205 // This will fail if the number of glyphs is wildly out of range.
michael@0 206 if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-1))
michael@0 207 {
michael@0 208 _head = Face::Table();
michael@0 209 return;
michael@0 210 }
michael@0 211
michael@0 212 if (!dumb_font)
michael@0 213 {
michael@0 214 if ((m_pGlat = Face::Table(face, Tag::Glat)) == NULL
michael@0 215 || (m_pGloc = Face::Table(face, Tag::Gloc)) == NULL
michael@0 216 || m_pGloc.size() < 6)
michael@0 217 {
michael@0 218 _head = Face::Table();
michael@0 219 return;
michael@0 220 }
michael@0 221 const byte * p = m_pGloc;
michael@0 222 const int version = be::read<uint32>(p);
michael@0 223 const uint16 flags = be::read<uint16>(p);
michael@0 224 _num_attrs = be::read<uint16>(p);
michael@0 225 // We can accurately calculate the number of attributed glyphs by
michael@0 226 // subtracting the length of the attribids array (numAttribs long if present)
michael@0 227 // and dividing by either 2 or 4 depending on shor or lonf format
michael@0 228 _long_fmt = flags & 1;
michael@0 229 _num_glyphs_attributes = (m_pGloc.size()
michael@0 230 - (p - m_pGloc)
michael@0 231 - sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0))
michael@0 232 / (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1;
michael@0 233
michael@0 234 if (version != 0x00010000
michael@0 235 || _num_attrs == 0 || _num_attrs > 0x3000 // is this hard limit appropriate?
michael@0 236 || _num_glyphs_graphics > _num_glyphs_attributes)
michael@0 237 {
michael@0 238 _head = Face::Table();
michael@0 239 return;
michael@0 240 }
michael@0 241 }
michael@0 242 }
michael@0 243
michael@0 244 inline
michael@0 245 GlyphCache::Loader::operator bool () const throw()
michael@0 246 {
michael@0 247 return _head && _hhea && _hmtx && !(bool(_glyf) != bool(_loca));
michael@0 248 }
michael@0 249
michael@0 250 inline
michael@0 251 unsigned short int GlyphCache::Loader::units_per_em() const throw()
michael@0 252 {
michael@0 253 return _head ? TtfUtil::DesignUnits(_head) : 0;
michael@0 254 }
michael@0 255
michael@0 256 inline
michael@0 257 unsigned short int GlyphCache::Loader::num_glyphs() const throw()
michael@0 258 {
michael@0 259 return max(_num_glyphs_graphics, _num_glyphs_attributes);
michael@0 260 }
michael@0 261
michael@0 262 inline
michael@0 263 unsigned short int GlyphCache::Loader::num_attrs() const throw()
michael@0 264 {
michael@0 265 return _num_attrs;
michael@0 266 }
michael@0 267
michael@0 268 const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph) const throw()
michael@0 269 {
michael@0 270 Rect bbox;
michael@0 271 Position advance;
michael@0 272
michael@0 273 if (glyphid < _num_glyphs_graphics)
michael@0 274 {
michael@0 275 int nLsb;
michael@0 276 unsigned int nAdvWid;
michael@0 277 if (_glyf)
michael@0 278 {
michael@0 279 int xMin, yMin, xMax, yMax;
michael@0 280 size_t locidx = TtfUtil::LocaLookup(glyphid, _loca, _loca.size(), _head);
michael@0 281 void *pGlyph = TtfUtil::GlyfLookup(_glyf, locidx, _glyf.size());
michael@0 282
michael@0 283 if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax))
michael@0 284 bbox = Rect(Position(static_cast<float>(xMin), static_cast<float>(yMin)),
michael@0 285 Position(static_cast<float>(xMax), static_cast<float>(yMax)));
michael@0 286 }
michael@0 287 if (TtfUtil::HorMetrics(glyphid, _hmtx, _hmtx.size(), _hhea, nLsb, nAdvWid))
michael@0 288 advance = Position(static_cast<float>(nAdvWid), 0);
michael@0 289 }
michael@0 290
michael@0 291 if (glyphid < _num_glyphs_attributes)
michael@0 292 {
michael@0 293 const byte * gloc = m_pGloc;
michael@0 294 size_t glocs = 0, gloce = 0;
michael@0 295
michael@0 296 be::skip<uint32>(gloc);
michael@0 297 be::skip<uint16>(gloc,2);
michael@0 298 if (_long_fmt)
michael@0 299 {
michael@0 300 be::skip<uint32>(gloc, glyphid);
michael@0 301 glocs = be::read<uint32>(gloc);
michael@0 302 gloce = be::peek<uint32>(gloc);
michael@0 303 }
michael@0 304 else
michael@0 305 {
michael@0 306 be::skip<uint16>(gloc, glyphid);
michael@0 307 glocs = be::read<uint16>(gloc);
michael@0 308 gloce = be::peek<uint16>(gloc);
michael@0 309 }
michael@0 310
michael@0 311 if (glocs >= m_pGlat.size() || gloce > m_pGlat.size())
michael@0 312 return 0;
michael@0 313
michael@0 314 const uint32 glat_version = be::peek<uint32>(m_pGlat);
michael@0 315 if (glat_version < 0x00020000)
michael@0 316 {
michael@0 317 if (gloce - glocs < 2*sizeof(byte)+sizeof(uint16)
michael@0 318 || gloce - glocs > _num_attrs*(2*sizeof(byte)+sizeof(uint16)))
michael@0 319 {
michael@0 320 return 0;
michael@0 321 }
michael@0 322
michael@0 323 new (&glyph) GlyphFace(bbox, advance, glat_iterator(m_pGlat + glocs), glat_iterator(m_pGlat + gloce));
michael@0 324 }
michael@0 325 else
michael@0 326 {
michael@0 327 if (gloce - glocs < 3*sizeof(uint16)
michael@0 328 || gloce - glocs > _num_attrs*3*sizeof(uint16))
michael@0 329 {
michael@0 330 return 0;
michael@0 331 }
michael@0 332
michael@0 333 new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce));
michael@0 334 }
michael@0 335
michael@0 336 if (!glyph.attrs() || glyph.attrs().capacity() > _num_attrs)
michael@0 337 return 0;
michael@0 338 }
michael@0 339
michael@0 340 return &glyph;
michael@0 341 }

mercurial