LCOV - code coverage report
Current view: directory - gfx/graphite2/src - Silf.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 190 0 0.0 %
Date: 2012-06-02 Functions: 11 0 0.0 %

       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 <cstdlib>
      28                 : #include "graphite2/Segment.h"
      29                 : #include "inc/debug.h"
      30                 : #include "inc/Endian.h"
      31                 : #include "inc/Silf.h"
      32                 : #include "inc/Segment.h"
      33                 : #include "inc/Rule.h"
      34                 : 
      35                 : 
      36                 : using namespace graphite2;
      37                 : 
      38                 : 
      39               0 : Silf::Silf() throw()
      40                 : : m_passes(0), m_pseudos(0), m_classOffsets(0), m_classData(0), m_justs(0),
      41                 :   m_numPasses(0), m_sPass(0), m_pPass(0), m_jPass(0), m_bPass(0), m_flags(0),
      42                 :   m_aBreak(0), m_aUser(0), m_iMaxComp(0),
      43               0 :   m_aLig(0), m_numPseudo(0), m_nClass(0), m_nLinear(0)
      44                 : {
      45               0 : }
      46                 : 
      47               0 : Silf::~Silf() throw()
      48                 : {
      49               0 :     releaseBuffers();
      50               0 : }
      51                 : 
      52               0 : void Silf::releaseBuffers() throw()
      53                 : {
      54               0 :     delete [] m_passes;
      55               0 :     delete [] m_pseudos;
      56               0 :     free(m_classOffsets);
      57               0 :     free(m_classData);
      58               0 :     free(m_justs);
      59               0 :     m_passes= 0;
      60               0 :     m_pseudos = 0;
      61               0 :     m_classOffsets = 0;
      62               0 :     m_classData = 0;
      63               0 :     m_justs = 0;
      64               0 : }
      65                 : 
      66                 : 
      67               0 : bool Silf::readGraphite(const void* pSilf, size_t lSilf, const Face& face, uint32 version)
      68                 : {
      69               0 :     const byte * p = (byte *)pSilf,
      70               0 :                    * const eSilf = p + lSilf;
      71                 : 
      72               0 :     if (version >= 0x00030000)
      73                 :     {
      74               0 :         if (lSilf < 27)              { releaseBuffers(); return false; }
      75               0 :         p += 8;
      76                 :     }
      77               0 :     else if (lSilf < 19)     { releaseBuffers(); return false; }
      78               0 :     p += 2;     // maxGlyphID
      79               0 :     p += 4;     // extra ascent/descent
      80               0 :     m_numPasses = uint8(*p++);
      81               0 :     if (m_numPasses > 128)
      82               0 :         return false;
      83               0 :     m_passes = new Pass[m_numPasses];
      84               0 :     m_sPass = uint8(*p++);
      85               0 :     m_pPass = uint8(*p++);
      86               0 :     if (m_pPass < m_sPass) {
      87               0 :         releaseBuffers();
      88               0 :         return false;
      89                 :     }
      90               0 :     m_jPass = uint8(*p++);
      91               0 :     if (m_jPass < m_pPass) {
      92               0 :         releaseBuffers();
      93               0 :         return false;
      94                 :     }
      95               0 :     m_bPass = uint8(*p++);     // when do we reorder?
      96               0 :     if (m_bPass != 0xFF && (m_bPass < m_jPass || m_bPass > m_numPasses)) {
      97               0 :         releaseBuffers();
      98               0 :         return false;
      99                 :     }
     100               0 :     m_flags = uint8(*p++);
     101               0 :     p += 2;     // ignore line end contextuals for now
     102               0 :     m_aPseudo = uint8(*p++);
     103               0 :     m_aBreak = uint8(*p++);
     104               0 :     m_aBidi = uint8(*p++);
     105               0 :     m_aMirror = uint8(*p++);
     106               0 :     p += 1;     // skip reserved stuff
     107               0 :     m_numJusts = uint8(*p++);
     108               0 :     m_justs = gralloc<Justinfo>(m_numJusts);
     109               0 :     for (uint8 i = 0; i < m_numJusts; i++)
     110                 :     {
     111               0 :         ::new(m_justs + i) Justinfo(p[0], p[1], p[2], p[3]);
     112               0 :         p += 8;
     113                 :     }
     114                 : //    p += uint8(*p) * 8 + 1;     // ignore justification for now
     115               0 :     if (p + 9 >= eSilf) { releaseBuffers(); return false; }
     116               0 :     m_aLig = be::read<uint16>(p);
     117               0 :     if (m_aLig > 127) {
     118               0 :         releaseBuffers();
     119               0 :         return false;
     120                 :     }
     121               0 :     m_aUser = uint8(*p++);
     122               0 :     m_iMaxComp = uint8(*p++);
     123               0 :     p += 5;     // skip direction and reserved
     124               0 :     p += uint8(*p) * 2 + 1;        // don't need critical features yet
     125               0 :     p++;        // reserved
     126               0 :     if (p >= eSilf) 
     127                 :     {
     128               0 :         releaseBuffers();
     129               0 :         return false;
     130                 :     }
     131               0 :     p += uint8(*p) * 4 + 1;        // skip scripts
     132               0 :     p += 2;     // skip lbGID
     133                 :     
     134               0 :     if (p + 4 * (m_numPasses + 1) + 6 >= eSilf) 
     135                 :     {
     136               0 :         releaseBuffers(); 
     137               0 :         return false;
     138                 :     }
     139               0 :     const byte * pPasses = p;
     140               0 :     p += 4 * (m_numPasses + 1);
     141               0 :     m_numPseudo = be::read<uint16>(p);
     142               0 :     p += 6;
     143               0 :     if (p + m_numPseudo * 6 >= eSilf) 
     144                 :     {
     145               0 :         releaseBuffers();
     146               0 :         return false;
     147                 :     }
     148               0 :     m_pseudos = new Pseudo[m_numPseudo];
     149               0 :     for (int i = 0; i < m_numPseudo; i++)
     150                 :     {
     151               0 :         m_pseudos[i].uid = be::read<uint32>(p);
     152               0 :         m_pseudos[i].gid = be::read<uint16>(p);
     153                 :     }
     154               0 :     if (p >= eSilf) 
     155                 :     {
     156               0 :         releaseBuffers();
     157               0 :         return false;
     158                 :     }
     159                 : 
     160               0 :     int clen = readClassMap(p, be::peek<uint32>(pPasses) - (p - (byte *)pSilf), version);
     161               0 :     if (clen < 0) {
     162               0 :         releaseBuffers();
     163               0 :         return false;
     164                 :     }
     165               0 :     p += clen;
     166                 : 
     167               0 :     for (size_t i = 0; i < m_numPasses; ++i)
     168                 :     {
     169               0 :         uint32 pOffset = be::read<uint32>(pPasses);
     170               0 :         uint32 pEnd = be::peek<uint32>(pPasses);
     171               0 :         if ((uint8 *)pSilf + pEnd > eSilf || pOffset > pEnd)
     172                 :         {
     173               0 :             releaseBuffers();
     174               0 :             return false;
     175                 :         }
     176               0 :         m_passes[i].init(this);
     177               0 :         if (!m_passes[i].readPass((char *)pSilf + pOffset, pEnd - pOffset, pOffset, face))
     178                 :         {
     179               0 :                 releaseBuffers();
     180               0 :                 return false;
     181                 :         }
     182                 :     }
     183               0 :     return true;
     184                 : }
     185                 : 
     186               0 : template<typename T> inline uint32 Silf::readClassOffsets(const byte *&p, size_t data_len)
     187                 : {
     188               0 :         const T cls_off = 2*sizeof(uint16) + sizeof(T)*(m_nClass+1);
     189               0 :         const uint32 max_off = (be::peek<T>(p + sizeof(T)*m_nClass) - cls_off)/sizeof(uint16);
     190                 :         // Check that the last+1 offset is less than or equal to the class map length.
     191               0 :         if (be::peek<T>(p) != cls_off || max_off > (data_len - cls_off)/sizeof(uint16))
     192               0 :                 return 0;
     193                 : 
     194                 :         // Read in all the offsets.
     195               0 :         m_classOffsets = gralloc<uint32>(m_nClass+1);
     196               0 :         for (uint32 * o = m_classOffsets, * const o_end = o + m_nClass + 1; o != o_end; ++o)
     197                 :         {
     198               0 :                 *o = (be::read<T>(p) - cls_off)/sizeof(uint16);
     199               0 :                 if (*o > max_off)
     200               0 :                         return 0;
     201                 :         }
     202               0 :     return max_off;
     203                 : }
     204                 : 
     205               0 : size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version)
     206                 : {
     207               0 :         if (data_len < sizeof(uint16)*2)     return -1;
     208                 : 
     209               0 :         m_nClass  = be::read<uint16>(p);
     210               0 :         m_nLinear = be::read<uint16>(p);
     211                 : 
     212                 :         // Check that numLinear < numClass,
     213                 :         // that there is at least enough data for numClasses offsets.
     214               0 :         if (m_nLinear > m_nClass
     215                 :          || (m_nClass + 1) * (version >= 0x00040000 ? sizeof(uint32) : sizeof(uint16))> (data_len - 4))
     216               0 :                 return -1;
     217                 : 
     218                 :     
     219                 :     uint32 max_off;
     220               0 :     if (version >= 0x00040000)
     221               0 :         max_off = readClassOffsets<uint32>(p, data_len);
     222                 :     else
     223               0 :         max_off = readClassOffsets<uint16>(p, data_len);
     224                 : 
     225               0 :     if (max_off == 0) return -1;
     226                 : 
     227                 :         // Check the linear offsets are sane, these must be monotonically increasing.
     228               0 :         for (const uint32 *o = m_classOffsets, * const o_end = o + m_nLinear; o != o_end; ++o)
     229               0 :                 if (o[0] > o[1])
     230               0 :                         return -1;
     231                 : 
     232                 :         // Fortunately the class data is all uint16s so we can decode these now
     233               0 :     m_classData = gralloc<uint16>(max_off);
     234               0 :     for (uint16 *d = m_classData, * const d_end = d + max_off; d != d_end; ++d)
     235               0 :         *d = be::read<uint16>(p);
     236                 : 
     237                 :         // Check the lookup class invariants for each non-linear class
     238               0 :         for (const uint32 *o = m_classOffsets + m_nLinear, * const o_end = m_classOffsets + m_nClass; o != o_end; ++o)
     239                 :         {
     240               0 :                 const uint16 * lookup = m_classData + *o;
     241               0 :                 if (lookup[0] == 0                                                      // A LookupClass with no looks is a suspicious thing ...
     242               0 :                  || lookup[0] > (max_off - *o - 4)/2             // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off]
     243               0 :                  || lookup[3] != lookup[0] - lookup[1])         // rangeShift:   numIDs  - searchRange
     244               0 :                         return -1;
     245                 :         }
     246                 : 
     247               0 :         return max_off;
     248                 : }
     249                 : 
     250               0 : uint16 Silf::findPseudo(uint32 uid) const
     251                 : {
     252               0 :     for (int i = 0; i < m_numPseudo; i++)
     253               0 :         if (m_pseudos[i].uid == uid) return m_pseudos[i].gid;
     254               0 :     return 0;
     255                 : }
     256                 : 
     257               0 : uint16 Silf::findClassIndex(uint16 cid, uint16 gid) const
     258                 : {
     259               0 :     if (cid > m_nClass) return -1;
     260                 : 
     261               0 :     const uint16 * cls = m_classData + m_classOffsets[cid];
     262               0 :     if (cid < m_nLinear)        // output class being used for input, shouldn't happen
     263                 :     {
     264               0 :         for (unsigned int i = 0, n = m_classOffsets[cid + 1]; i < n; ++i, ++cls)
     265               0 :             if (*cls == gid) return i;
     266               0 :         return -1;
     267                 :     }
     268                 :     else
     269                 :     {
     270               0 :         const uint16 *  min = cls + 4,          // lookups array
     271               0 :                                  *      max = min + cls[0]*2; // lookups aray is numIDs (cls[0]) uint16 pairs long
     272               0 :         do
     273                 :         {
     274               0 :                 const uint16 * p = min + (-2U & ((max-min)/2));
     275               0 :                 if      (p[0] > gid) max = p;
     276               0 :                 else                            min = p;
     277                 :         }
     278                 :         while (max - min > 2);
     279               0 :         return min[0] == gid ? min[1] : -1;
     280                 :     }
     281                 : }
     282                 : 
     283               0 : uint16 Silf::getClassGlyph(uint16 cid, unsigned int index) const
     284                 : {
     285               0 :     if (cid > m_nClass) return 0;
     286                 : 
     287               0 :     uint32 loc = m_classOffsets[cid];
     288               0 :     if (cid < m_nLinear)
     289                 :     {
     290               0 :         if (index < m_classOffsets[cid + 1] - loc)
     291               0 :             return m_classData[index + loc];
     292                 :     }
     293                 :     else        // input class being used for output. Shouldn't happen
     294                 :     {
     295               0 :         for (unsigned int i = loc + 4; i < m_classOffsets[cid + 1]; i += 2)
     296               0 :             if (m_classData[i + 1] == index) return m_classData[i];
     297                 :     }
     298               0 :     return 0;
     299                 : }
     300                 : 
     301                 : 
     302               0 : bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass) const
     303                 : {
     304               0 :     assert(seg != 0);
     305               0 :     SlotMap            map(*seg);
     306               0 :     FiniteStateMachine fsm(map);
     307               0 :     vm::Machine        m(map);
     308               0 :     unsigned int       initSize = seg->slotCount();
     309                 : 
     310               0 :     if (lastPass == 0)
     311                 :     {
     312               0 :         if (firstPass == lastPass)
     313               0 :             return true;
     314               0 :         lastPass = m_numPasses;
     315                 :     }
     316                 : 
     317                 : #if !defined GRAPHITE2_NTRACING
     318                 :     if (dbgout)
     319                 :     {
     320                 :         char version[64];
     321                 :         sprintf(version, "%d.%d.%d",
     322                 :                         GR2_VERSION_MAJOR, GR2_VERSION_MINOR, GR2_VERSION_BUGFIX);
     323                 :         *dbgout << json::object
     324                 :                                 << "version"    << version
     325                 :                                 << "passes"             << json::array;
     326                 :     }
     327                 : #endif
     328                 : 
     329               0 :     for (size_t i = firstPass; i < lastPass; ++i)
     330                 :     {
     331                 :         // bidi and mirroring
     332               0 :         if (i == m_bPass)
     333                 :         {
     334                 : #if !defined GRAPHITE2_NTRACING
     335                 :                 if (dbgout)
     336                 :                 {
     337                 :                         *dbgout << json::item << json::object
     338                 :                                                 << "id"         << -1
     339                 :                                                 << "slots"      << json::array;
     340                 :                         seg->positionSlots(0);
     341                 :                         for(Slot * s = seg->first(); s; s = s->next())
     342                 :                                 *dbgout         << dslot(seg, s);
     343                 :                         *dbgout                 << json::close
     344                 :                                                 << "rules"      << json::array << json::close
     345                 :                                                 << json::close;
     346                 :                 }
     347                 : #endif
     348                 : 
     349               0 :                 if (!(seg->dir() & 2))
     350               0 :                 seg->bidiPass(m_aBidi, seg->dir() & 1, m_aMirror);
     351               0 :                 else if (m_aMirror)
     352                 :             {
     353                 :                 Slot * s;
     354               0 :                 for (s = seg->first(); s; s = s->next())
     355                 :                 {
     356               0 :                     unsigned short g = seg->glyphAttr(s->gid(), m_aMirror);
     357               0 :                     if (g && (!(seg->dir() & 4) || !seg->glyphAttr(s->gid(), m_aMirror + 1)))
     358               0 :                         s->setGlyph(seg, g);
     359                 :                 }
     360                 :             }
     361                 :         }
     362                 : 
     363                 : #if !defined GRAPHITE2_NTRACING
     364                 :         if (dbgout)
     365                 :         {
     366                 :                 *dbgout << json::item << json::object
     367                 :                                         << "id"         << i+1
     368                 :                                         << "slots"      << json::array;
     369                 :                 seg->positionSlots(0);
     370                 :                 for(Slot * s = seg->first(); s; s = s->next())
     371                 :                         *dbgout         << dslot(seg, s);
     372                 :                 *dbgout                 << json::close;
     373                 :         }
     374                 : #endif
     375                 : 
     376                 :         // test whether to reorder, prepare for positioning
     377               0 :         m_passes[i].runGraphite(m, fsm);
     378                 :         // only subsitution passes can change segment length, cached subsegments are short for their text
     379               0 :         if (m.status() != vm::Machine::finished
     380               0 :                 || (i < m_pPass && (seg->slotCount() > initSize * MAX_SEG_GROWTH_FACTOR
     381               0 :             || (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize))))
     382               0 :             return false;
     383                 :     }
     384                 : #if !defined GRAPHITE2_NTRACING
     385                 :         if (dbgout)
     386                 :         {
     387                 :                 *dbgout                         << json::item
     388                 :                                                         << json::close // Close up the passes array
     389                 :                                 << "output" << json::array;
     390                 :                 for(Slot * s = seg->first(); s; s = s->next())
     391                 :                         *dbgout         << dslot(seg, s);
     392                 :                 seg->finalise(0);                                    // Call this here to fix up charinfo back indexes.
     393                 :                 *dbgout                 << json::close
     394                 :                                 << "advance" << seg->advance()
     395                 :                                 << "chars"       << json::array;
     396                 :                 for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i)
     397                 :                         *dbgout         << json::flat << *seg->charinfo(i);
     398                 :                 *dbgout                 << json::close    // Close up the chars array
     399                 :                                         << json::close;           // Clsoe up the segment object
     400                 :         }
     401                 : #endif
     402               0 :     return true;
     403                 : }

Generated by: LCOV version 1.7