gfx/graphite2/src/Face.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 #include "graphite2/Segment.h"
michael@0 29 #include "inc/CmapCache.h"
michael@0 30 #include "inc/debug.h"
michael@0 31 #include "inc/Endian.h"
michael@0 32 #include "inc/Face.h"
michael@0 33 #include "inc/FileFace.h"
michael@0 34 #include "inc/GlyphFace.h"
michael@0 35 #include "inc/json.h"
michael@0 36 #include "inc/SegCacheStore.h"
michael@0 37 #include "inc/Segment.h"
michael@0 38 #include "inc/NameTable.h"
michael@0 39 #include "inc/Error.h"
michael@0 40
michael@0 41 using namespace graphite2;
michael@0 42
michael@0 43 Face::Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops)
michael@0 44 : m_appFaceHandle(appFaceHandle),
michael@0 45 m_pFileFace(NULL),
michael@0 46 m_pGlyphFaceCache(NULL),
michael@0 47 m_cmap(NULL),
michael@0 48 m_pNames(NULL),
michael@0 49 m_logger(NULL),
michael@0 50 m_error(0), m_errcntxt(0),
michael@0 51 m_silfs(NULL),
michael@0 52 m_numSilf(0),
michael@0 53 m_ascent(0),
michael@0 54 m_descent(0)
michael@0 55 {
michael@0 56 memset(&m_ops, 0, sizeof m_ops);
michael@0 57 memcpy(&m_ops, &ops, min(sizeof m_ops, ops.size));
michael@0 58 }
michael@0 59
michael@0 60
michael@0 61 Face::~Face()
michael@0 62 {
michael@0 63 setLogger(0);
michael@0 64 delete m_pGlyphFaceCache;
michael@0 65 delete m_cmap;
michael@0 66 delete[] m_silfs;
michael@0 67 #ifndef GRAPHITE2_NFILEFACE
michael@0 68 delete m_pFileFace;
michael@0 69 #endif
michael@0 70 delete m_pNames;
michael@0 71 }
michael@0 72
michael@0 73 float Face::default_glyph_advance(const void* font_ptr, gr_uint16 glyphid)
michael@0 74 {
michael@0 75 const Font & font = *reinterpret_cast<const Font *>(font_ptr);
michael@0 76
michael@0 77 return font.face().glyphs().glyph(glyphid)->theAdvance().x * font.scale();
michael@0 78 }
michael@0 79
michael@0 80 bool Face::readGlyphs(uint32 faceOptions)
michael@0 81 {
michael@0 82 Error e;
michael@0 83 #ifdef GRAPHITE2_TELEMETRY
michael@0 84 telemetry::category _glyph_cat(tele.glyph);
michael@0 85 #endif
michael@0 86 error_context(EC_READGLYPHS);
michael@0 87 if (faceOptions & gr_face_cacheCmap)
michael@0 88 m_cmap = new CachedCmap(*this);
michael@0 89 else
michael@0 90 m_cmap = new DirectCmap(*this);
michael@0 91
michael@0 92 m_pGlyphFaceCache = new GlyphCache(*this, faceOptions);
michael@0 93 if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM)
michael@0 94 || e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS)
michael@0 95 || e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM)
michael@0 96 || e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
michael@0 97 {
michael@0 98 return error(e);
michael@0 99 }
michael@0 100
michael@0 101 if (faceOptions & gr_face_preloadGlyphs)
michael@0 102 nameTable(); // preload the name table along with the glyphs.
michael@0 103
michael@0 104 return true;
michael@0 105 }
michael@0 106
michael@0 107 bool Face::readGraphite(const Table & silf)
michael@0 108 {
michael@0 109 #ifdef GRAPHITE2_TELEMETRY
michael@0 110 telemetry::category _silf_cat(tele.silf);
michael@0 111 #endif
michael@0 112 Error e;
michael@0 113 error_context(EC_READSILF);
michael@0 114 const byte * p = silf;
michael@0 115 if (e.test(!p, E_NOSILF)) return error(e);
michael@0 116
michael@0 117 const uint32 version = be::read<uint32>(p);
michael@0 118 if (e.test(version < 0x00020000, E_TOOOLD)) return error(e);
michael@0 119 if (version >= 0x00030000)
michael@0 120 be::skip<uint32>(p); // compilerVersion
michael@0 121 m_numSilf = be::read<uint16>(p);
michael@0 122 be::skip<uint16>(p); // reserved
michael@0 123
michael@0 124 bool havePasses = false;
michael@0 125 m_silfs = new Silf[m_numSilf];
michael@0 126 for (int i = 0; i < m_numSilf; i++)
michael@0 127 {
michael@0 128 error_context(EC_ASILF + (i << 8));
michael@0 129 const uint32 offset = be::read<uint32>(p),
michael@0 130 next = i == m_numSilf - 1 ? silf.size() : be::peek<uint32>(p);
michael@0 131 if (e.test(next > silf.size() || offset >= next, E_BADSIZE))
michael@0 132 return error(e);
michael@0 133
michael@0 134 if (!m_silfs[i].readGraphite(silf + offset, next - offset, *this, version))
michael@0 135 return false;
michael@0 136
michael@0 137 if (m_silfs[i].numPasses())
michael@0 138 havePasses = true;
michael@0 139 }
michael@0 140
michael@0 141 return havePasses;
michael@0 142 }
michael@0 143
michael@0 144 bool Face::readFeatures()
michael@0 145 {
michael@0 146 return m_Sill.readFace(*this);
michael@0 147 }
michael@0 148
michael@0 149 bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
michael@0 150 {
michael@0 151 #if !defined GRAPHITE2_NTRACING
michael@0 152 json * dbgout = logger();
michael@0 153 if (dbgout)
michael@0 154 {
michael@0 155 *dbgout << json::object
michael@0 156 << "id" << objectid(seg)
michael@0 157 << "passes" << json::array;
michael@0 158 }
michael@0 159 #endif
michael@0 160
michael@0 161 bool res = aSilf->runGraphite(seg, 0, aSilf->justificationPass(), true);
michael@0 162 if (res)
michael@0 163 res = aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
michael@0 164
michael@0 165 #if !defined GRAPHITE2_NTRACING
michael@0 166 if (dbgout)
michael@0 167 {
michael@0 168 *dbgout << json::item
michael@0 169 << json::close // Close up the passes array
michael@0 170 << "output" << json::array;
michael@0 171 for(Slot * s = seg->first(); s; s = s->next())
michael@0 172 *dbgout << dslot(seg, s);
michael@0 173 seg->finalise(0); // Call this here to fix up charinfo back indexes.
michael@0 174 *dbgout << json::close
michael@0 175 << "advance" << seg->advance()
michael@0 176 << "chars" << json::array;
michael@0 177 for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i)
michael@0 178 *dbgout << json::flat << *seg->charinfo(i);
michael@0 179 *dbgout << json::close // Close up the chars array
michael@0 180 << json::close; // Close up the segment object
michael@0 181 }
michael@0 182 #endif
michael@0 183
michael@0 184 return res;
michael@0 185 }
michael@0 186
michael@0 187 void Face::setLogger(FILE * log_file GR_MAYBE_UNUSED)
michael@0 188 {
michael@0 189 #if !defined GRAPHITE2_NTRACING
michael@0 190 delete m_logger;
michael@0 191 m_logger = log_file ? new json(log_file) : 0;
michael@0 192 #endif
michael@0 193 }
michael@0 194
michael@0 195 const Silf *Face::chooseSilf(uint32 script) const
michael@0 196 {
michael@0 197 if (m_numSilf == 0)
michael@0 198 return NULL;
michael@0 199 else if (m_numSilf == 1 || script == 0)
michael@0 200 return m_silfs;
michael@0 201 else // do more work here
michael@0 202 return m_silfs;
michael@0 203 }
michael@0 204
michael@0 205 uint16 Face::findPseudo(uint32 uid) const
michael@0 206 {
michael@0 207 return (m_numSilf) ? m_silfs[0].findPseudo(uid) : 0;
michael@0 208 }
michael@0 209
michael@0 210 uint16 Face::getGlyphMetric(uint16 gid, uint8 metric) const
michael@0 211 {
michael@0 212 switch (metrics(metric))
michael@0 213 {
michael@0 214 case kgmetAscent : return m_ascent;
michael@0 215 case kgmetDescent : return m_descent;
michael@0 216 default: return glyphs().glyph(gid)->getMetric(metric);
michael@0 217 }
michael@0 218 }
michael@0 219
michael@0 220 void Face::takeFileFace(FileFace* pFileFace GR_MAYBE_UNUSED/*takes ownership*/)
michael@0 221 {
michael@0 222 #ifndef GRAPHITE2_NFILEFACE
michael@0 223 if (m_pFileFace==pFileFace)
michael@0 224 return;
michael@0 225
michael@0 226 delete m_pFileFace;
michael@0 227 m_pFileFace = pFileFace;
michael@0 228 #endif
michael@0 229 }
michael@0 230
michael@0 231 NameTable * Face::nameTable() const
michael@0 232 {
michael@0 233 if (m_pNames) return m_pNames;
michael@0 234 const Table name(*this, Tag::name);
michael@0 235 if (name)
michael@0 236 m_pNames = new NameTable(name, name.size());
michael@0 237 return m_pNames;
michael@0 238 }
michael@0 239
michael@0 240 uint16 Face::languageForLocale(const char * locale) const
michael@0 241 {
michael@0 242 nameTable();
michael@0 243 if (m_pNames)
michael@0 244 return m_pNames->getLanguageId(locale);
michael@0 245 return 0;
michael@0 246 }
michael@0 247
michael@0 248 Face::Table::Table(const Face & face, const Tag n) throw()
michael@0 249 : _f(&face)
michael@0 250 {
michael@0 251 size_t sz = 0;
michael@0 252 _p = reinterpret_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &sz));
michael@0 253 _sz = uint32(sz);
michael@0 254 if (!TtfUtil::CheckTable(n, _p, _sz))
michael@0 255 {
michael@0 256 this->~Table(); // Make sure we release the table buffer even if the table filed it's checks
michael@0 257 _p = 0; _sz = 0;
michael@0 258 }
michael@0 259 }
michael@0 260
michael@0 261 Face::Table & Face::Table::operator = (const Table & rhs) throw()
michael@0 262 {
michael@0 263 if (_p == rhs._p) return *this;
michael@0 264
michael@0 265 this->~Table();
michael@0 266 new (this) Table(rhs);
michael@0 267 return *this;
michael@0 268 }
michael@0 269

mercurial