LCOV - code coverage report
Current view: top level - gfx/graphite2/src - Face.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 149 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 19 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*  GRAPHITE2 LICENSING
       2             : 
       3             :     Copyright 2010, SIL International
       4             :     All rights reserved.
       5             : 
       6             :     This library is free software; you can redistribute it and/or modify
       7             :     it under the terms of the GNU Lesser General Public License as published
       8             :     by the Free Software Foundation; either version 2.1 of License, or
       9             :     (at your option) any later version.
      10             : 
      11             :     This program is distributed in the hope that it will be useful,
      12             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :     Lesser General Public License for more details.
      15             : 
      16             :     You should also have received a copy of the GNU Lesser General Public
      17             :     License along with this library in the file named "LICENSE".
      18             :     If not, write to the Free Software Foundation, 51 Franklin Street, 
      19             :     Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
      20             :     internet at http://www.fsf.org/licenses/lgpl.html.
      21             : 
      22             : Alternatively, the contents of this file may be used under the terms of the
      23             : Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
      24             : License, as published by the Free Software Foundation, either version 2
      25             : of the License or (at your option) any later version.
      26             : */
      27             : #include <cstring>
      28             : #include "graphite2/Segment.h"
      29             : #include "inc/CmapCache.h"
      30             : #include "inc/debug.h"
      31             : #include "inc/Decompressor.h"
      32             : #include "inc/Endian.h"
      33             : #include "inc/Face.h"
      34             : #include "inc/FileFace.h"
      35             : #include "inc/GlyphFace.h"
      36             : #include "inc/json.h"
      37             : #include "inc/SegCacheStore.h"
      38             : #include "inc/Segment.h"
      39             : #include "inc/NameTable.h"
      40             : #include "inc/Error.h"
      41             : 
      42             : using namespace graphite2;
      43             : 
      44             : namespace
      45             : {
      46             : enum compression
      47             : {
      48             :     NONE,
      49             :     LZ4
      50             : };
      51             : 
      52             : }
      53             : 
      54           0 : Face::Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops)
      55             : : m_appFaceHandle(appFaceHandle),
      56             :   m_pFileFace(NULL),
      57             :   m_pGlyphFaceCache(NULL),
      58             :   m_cmap(NULL),
      59             :   m_pNames(NULL),
      60             :   m_logger(NULL),
      61             :   m_error(0), m_errcntxt(0),
      62             :   m_silfs(NULL),
      63             :   m_numSilf(0),
      64             :   m_ascent(0),
      65           0 :   m_descent(0)
      66             : {
      67           0 :     memset(&m_ops, 0, sizeof m_ops);
      68           0 :     memcpy(&m_ops, &ops, min(sizeof m_ops, ops.size));
      69           0 : }
      70             : 
      71             : 
      72           0 : Face::~Face()
      73             : {
      74           0 :     setLogger(0);
      75           0 :     delete m_pGlyphFaceCache;
      76           0 :     delete m_cmap;
      77           0 :     delete[] m_silfs;
      78             : #ifndef GRAPHITE2_NFILEFACE
      79             :     delete m_pFileFace;
      80             : #endif
      81           0 :     delete m_pNames;
      82           0 : }
      83             : 
      84           0 : float Face::default_glyph_advance(const void* font_ptr, gr_uint16 glyphid)
      85             : {
      86           0 :     const Font & font = *reinterpret_cast<const Font *>(font_ptr);
      87             : 
      88           0 :     return font.face().glyphs().glyph(glyphid)->theAdvance().x * font.scale();
      89             : }
      90             : 
      91           0 : bool Face::readGlyphs(uint32 faceOptions)
      92             : {
      93           0 :     Error e;
      94             : #ifdef GRAPHITE2_TELEMETRY
      95             :     telemetry::category _glyph_cat(tele.glyph);
      96             : #endif
      97           0 :     error_context(EC_READGLYPHS);
      98           0 :     m_pGlyphFaceCache = new GlyphCache(*this, faceOptions);
      99             : 
     100           0 :     if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM)
     101           0 :         || e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS)
     102           0 :         || e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM))
     103             :     {
     104           0 :         return error(e);
     105             :     }
     106             : 
     107           0 :     if (faceOptions & gr_face_cacheCmap)
     108           0 :         m_cmap = new CachedCmap(*this);
     109             :     else
     110           0 :         m_cmap = new DirectCmap(*this);
     111           0 :     if (e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
     112           0 :         return error(e);
     113             : 
     114           0 :     if (faceOptions & gr_face_preloadGlyphs)
     115           0 :         nameTable();        // preload the name table along with the glyphs.
     116             : 
     117           0 :     return true;
     118             : }
     119             : 
     120           0 : bool Face::readGraphite(const Table & silf)
     121             : {
     122             : #ifdef GRAPHITE2_TELEMETRY
     123             :     telemetry::category _silf_cat(tele.silf);
     124             : #endif
     125           0 :     Error e;
     126           0 :     error_context(EC_READSILF);
     127           0 :     const byte * p = silf;
     128           0 :     if (e.test(!p, E_NOSILF) || e.test(silf.size() < 20, E_BADSIZE)) return error(e);
     129             : 
     130           0 :     const uint32 version = be::read<uint32>(p);
     131           0 :     if (e.test(version < 0x00020000, E_TOOOLD)) return error(e);
     132           0 :     if (version >= 0x00030000)
     133           0 :         be::skip<uint32>(p);        // compilerVersion
     134           0 :     m_numSilf = be::read<uint16>(p);
     135             : 
     136           0 :     be::skip<uint16>(p);            // reserved
     137             : 
     138           0 :     bool havePasses = false;
     139           0 :     m_silfs = new Silf[m_numSilf];
     140           0 :     if (e.test(!m_silfs, E_OUTOFMEM)) return error(e);
     141           0 :     for (int i = 0; i < m_numSilf; i++)
     142             :     {
     143           0 :         error_context(EC_ASILF + (i << 8));
     144           0 :         const uint32 offset = be::read<uint32>(p),
     145           0 :                      next   = i == m_numSilf - 1 ? silf.size() : be::peek<uint32>(p);
     146           0 :         if (e.test(next > silf.size() || offset >= next, E_BADSIZE))
     147           0 :             return error(e);
     148             : 
     149           0 :         if (!m_silfs[i].readGraphite(silf + offset, next - offset, *this, version))
     150           0 :             return false;
     151             : 
     152           0 :         if (m_silfs[i].numPasses())
     153           0 :             havePasses = true;
     154             :     }
     155             : 
     156           0 :     return havePasses;
     157             : }
     158             : 
     159           0 : bool Face::readFeatures()
     160             : {
     161           0 :     return m_Sill.readFace(*this);
     162             : }
     163             : 
     164           0 : bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
     165             : {
     166             : #if !defined GRAPHITE2_NTRACING
     167             :     json * dbgout = logger();
     168             :     if (dbgout)
     169             :     {
     170             :         *dbgout << json::object
     171             :                     << "id"         << objectid(seg)
     172             :                     << "passes"     << json::array;
     173             :     }
     174             : #endif
     175             : 
     176             : //    if ((seg->dir() & 1) != aSilf->dir())
     177             : //        seg->reverseSlots();
     178           0 :     if ((seg->dir() & 3) == 3 && aSilf->bidiPass() == 0xFF)
     179           0 :         seg->doMirror(aSilf->aMirror());
     180           0 :     bool res = aSilf->runGraphite(seg, 0, aSilf->positionPass(), true);
     181           0 :     if (res)
     182             :     {
     183           0 :         seg->associateChars(0, seg->charInfoCount());
     184           0 :         if (aSilf->flags() & 0x20)
     185           0 :             res &= seg->initCollisions();
     186           0 :         if (res)
     187           0 :             res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
     188             :     }
     189             : 
     190             : #if !defined GRAPHITE2_NTRACING
     191             :     if (dbgout)
     192             : {
     193             :         seg->positionSlots(0, 0, 0, seg->currdir());
     194             :         *dbgout             << json::item
     195             :                             << json::close // Close up the passes array
     196             :                 << "outputdir" << (seg->currdir() ? "rtl" : "ltr")
     197             :                 << "output" << json::array;
     198             :         for(Slot * s = seg->first(); s; s = s->next())
     199             :             *dbgout     << dslot(seg, s);
     200             :         *dbgout         << json::close
     201             :                 << "advance" << seg->advance()
     202             :                 << "chars"   << json::array;
     203             :         for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i)
     204             :             *dbgout     << json::flat << *seg->charinfo(i);
     205             :         *dbgout         << json::close  // Close up the chars array
     206             :                     << json::close;     // Close up the segment object
     207             :     }
     208             : #endif
     209             : 
     210           0 :     return res;
     211             : }
     212             : 
     213           0 : void Face::setLogger(FILE * log_file GR_MAYBE_UNUSED)
     214             : {
     215             : #if !defined GRAPHITE2_NTRACING
     216             :     delete m_logger;
     217             :     m_logger = log_file ? new json(log_file) : 0;
     218             : #endif
     219           0 : }
     220             : 
     221           0 : const Silf *Face::chooseSilf(uint32 script) const
     222             : {
     223           0 :     if (m_numSilf == 0)
     224           0 :         return NULL;
     225           0 :     else if (m_numSilf == 1 || script == 0)
     226           0 :         return m_silfs;
     227             :     else // do more work here
     228           0 :         return m_silfs;
     229             : }
     230             : 
     231           0 : uint16 Face::findPseudo(uint32 uid) const
     232             : {
     233           0 :     return (m_numSilf) ? m_silfs[0].findPseudo(uid) : 0;
     234             : }
     235             : 
     236           0 : int32 Face::getGlyphMetric(uint16 gid, uint8 metric) const
     237             : {
     238           0 :     switch (metrics(metric))
     239             :     {
     240           0 :         case kgmetAscent : return m_ascent;
     241           0 :         case kgmetDescent : return m_descent;
     242             :         default: 
     243           0 :             if (gid >= glyphs().numGlyphs()) return 0;
     244           0 :             return glyphs().glyph(gid)->getMetric(metric);
     245             :     }
     246             : }
     247             : 
     248           0 : void Face::takeFileFace(FileFace* pFileFace GR_MAYBE_UNUSED/*takes ownership*/)
     249             : {
     250             : #ifndef GRAPHITE2_NFILEFACE
     251             :     if (m_pFileFace==pFileFace)
     252             :       return;
     253             :     
     254             :     delete m_pFileFace;
     255             :     m_pFileFace = pFileFace;
     256             : #endif
     257           0 : }
     258             : 
     259           0 : NameTable * Face::nameTable() const
     260             : {
     261           0 :     if (m_pNames) return m_pNames;
     262           0 :     const Table name(*this, Tag::name);
     263           0 :     if (name)
     264           0 :         m_pNames = new NameTable(name, name.size());
     265           0 :     return m_pNames;
     266             : }
     267             : 
     268           0 : uint16 Face::languageForLocale(const char * locale) const
     269             : {
     270           0 :     nameTable();
     271           0 :     if (m_pNames)
     272           0 :         return m_pNames->getLanguageId(locale);
     273           0 :     return 0;
     274             : }
     275             : 
     276             : 
     277             : 
     278           0 : Face::Table::Table(const Face & face, const Tag n, uint32 version) throw()
     279           0 : : _f(&face), _compressed(false)
     280             : {
     281           0 :     size_t sz = 0;
     282           0 :     _p = static_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &sz));
     283           0 :     _sz = uint32(sz);
     284             : 
     285           0 :     if (!TtfUtil::CheckTable(n, _p, _sz))
     286             :     {
     287           0 :         releaseBuffers();     // Make sure we release the table buffer even if the table failed it's checks
     288           0 :         return;
     289             :     }
     290             : 
     291           0 :     if (be::peek<uint32>(_p) >= version)
     292           0 :         decompress();
     293             : }
     294             : 
     295           0 : void Face::Table::releaseBuffers()
     296             : {
     297           0 :     if (_compressed)
     298           0 :         free(const_cast<byte *>(_p));
     299           0 :     else if (_p && _f->m_ops.release_table)
     300           0 :         (*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
     301           0 :     _p = 0; _sz = 0;
     302           0 : }
     303             : 
     304           0 : Face::Table & Face::Table::operator = (const Table & rhs) throw()
     305             : {
     306           0 :     if (_p == rhs._p)   return *this;
     307             : 
     308           0 :     this->~Table();
     309           0 :     new (this) Table(rhs);
     310           0 :     return *this;
     311             : }
     312             : 
     313           0 : Error Face::Table::decompress()
     314             : {
     315           0 :     Error e;
     316           0 :     if (e.test(_sz < 5 * sizeof(uint32), E_BADSIZE))
     317           0 :         return e;
     318           0 :     byte * uncompressed_table = 0;
     319           0 :     size_t uncompressed_size = 0;
     320             : 
     321           0 :     const byte * p = _p;
     322           0 :     const uint32 version = be::read<uint32>(p);    // Table version number.
     323             : 
     324             :     // The scheme is in the top 5 bits of the 1st uint32.
     325           0 :     const uint32 hdr = be::read<uint32>(p);
     326           0 :     switch(compression(hdr >> 27))
     327             :     {
     328           0 :     case NONE: return e;
     329             : 
     330             :     case LZ4:
     331             :     {
     332           0 :         uncompressed_size  = hdr & 0x07ffffff;
     333           0 :         uncompressed_table = gralloc<byte>(uncompressed_size);
     334           0 :         if (!e.test(!uncompressed_table || uncompressed_size < 4, E_OUTOFMEM))
     335             :         {
     336           0 :             memset(uncompressed_table, 0, 4);   // make sure version number is initialised
     337             :             // coverity[forward_null : FALSE] - uncompressed_table has been checked so can't be null
     338             :             // coverity[checked_return : FALSE] - we test e later
     339           0 :             e.test(lz4::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
     340             :         }
     341           0 :         break;
     342             :     }
     343             : 
     344             :     default:
     345           0 :         e.error(E_BADSCHEME);
     346             :     };
     347             : 
     348             :     // Check the uncompressed version number against the original.
     349           0 :     if (!e)
     350             :         // coverity[forward_null : FALSE] - uncompressed_table has already been tested so can't be null
     351             :         // coverity[checked_return : FALSE] - we test e later
     352           0 :         e.test(be::peek<uint32>(uncompressed_table) != version, E_SHRINKERFAILED);
     353             : 
     354             :     // Tell the provider to release the compressed form since were replacing
     355             :     //   it anyway.
     356           0 :     releaseBuffers();
     357             : 
     358           0 :     if (e)
     359             :     {
     360           0 :         free(uncompressed_table);
     361           0 :         uncompressed_table = 0;
     362           0 :         uncompressed_size  = 0;
     363             :     }
     364             : 
     365           0 :     _p = uncompressed_table;
     366           0 :     _sz = uncompressed_size;
     367           0 :     _compressed = true;
     368             : 
     369           0 :     return e;
     370             : }

Generated by: LCOV version 1.13