gfx/graphite2/src/TtfUtil.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/graphite2/src/TtfUtil.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1979 @@
     1.4 +/*  GRAPHITE2 LICENSING
     1.5 +
     1.6 +    Copyright 2010, 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 +/*--------------------------------------------------------------------*//*:Ignore this sentence.
    1.31 +
    1.32 +File: TtfUtil.cpp
    1.33 +Responsibility: Alan Ward
    1.34 +Last reviewed: Not yet.
    1.35 +
    1.36 +Description
    1.37 +    Implements the methods for TtfUtil class. This file should remain portable to any C++ 
    1.38 +    environment by only using standard C++ and the TTF structurs defined in Tt.h.
    1.39 +-------------------------------------------------------------------------------*//*:End Ignore*/
    1.40 +
    1.41 +
    1.42 +/***********************************************************************************************
    1.43 +    Include files
    1.44 +***********************************************************************************************/
    1.45 +// Language headers
    1.46 +//#include <algorithm>
    1.47 +#include <cassert>
    1.48 +#include <cstddef>
    1.49 +#include <cstring>
    1.50 +#include <climits>
    1.51 +#include <cwchar>
    1.52 +//#include <stdexcept>
    1.53 +// Platform headers
    1.54 +// Module headers
    1.55 +#include "inc/TtfUtil.h"
    1.56 +#include "inc/TtfTypes.h"
    1.57 +#include "inc/Endian.h"
    1.58 +
    1.59 +/***********************************************************************************************
    1.60 +    Forward declarations
    1.61 +***********************************************************************************************/
    1.62 +
    1.63 +/***********************************************************************************************
    1.64 +    Local Constants and static variables
    1.65 +***********************************************************************************************/
    1.66 +namespace 
    1.67 +{
    1.68 +    // max number of components allowed in composite glyphs
    1.69 +    const int kMaxGlyphComponents = 8;
    1.70 +
    1.71 +    template <int R, typename T>
    1.72 +    inline float fixed_to_float(const T f) {
    1.73 +        return float(f)/float(2^R);
    1.74 +    }
    1.75 +
    1.76 +/*----------------------------------------------------------------------------------------------
    1.77 +    Table of standard Postscript glyph names. From Martin Hosken. Disagress with ttfdump.exe
    1.78 +---------------------------------------------------------------------------------------------*/
    1.79 +#ifdef ALL_TTFUTILS
    1.80 +    const int kcPostNames = 258;
    1.81 +
    1.82 +    const char * rgPostName[kcPostNames] = {
    1.83 +        ".notdef", ".null", "nonmarkingreturn", "space", "exclam", "quotedbl", "numbersign", 
    1.84 +        "dollar", "percent", "ampersand", "quotesingle", "parenleft", 
    1.85 +        "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", 
    1.86 +        "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", 
    1.87 +        "nine", "colon", "semicolon", "less", "equal", "greater", "question", 
    1.88 +        "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", 
    1.89 +        "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 
    1.90 +        "bracketleft", "backslash", "bracketright", "asciicircum", 
    1.91 +        "underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i", 
    1.92 +        "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", 
    1.93 +        "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", 
    1.94 +        "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis", 
    1.95 +        "Udieresis", "aacute", "agrave", "acircumflex", "adieresis", "atilde", 
    1.96 +        "aring", "ccedilla", "eacute", "egrave", "ecircumflex", "edieresis", 
    1.97 +        "iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute", 
    1.98 +        "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", 
    1.99 +        "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling", 
   1.100 +        "section", "bullet", "paragraph", "germandbls", "registered", 
   1.101 +        "copyright", "trademark", "acute", "dieresis", "notequal", "AE", 
   1.102 +        "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen", 
   1.103 +        "mu", "partialdiff", "summation", "product", "pi", "integral", 
   1.104 +        "ordfeminine", "ordmasculine", "Omega", "ae", "oslash", "questiondown", 
   1.105 +        "exclamdown", "logicalnot", "radical", "florin", "approxequal", 
   1.106 +        "Delta", "guillemotleft", "guillemotright", "ellipsis", "nonbreakingspace", 
   1.107 +        "Agrave", "Atilde", "Otilde", "OE", "oe", "endash", "emdash", 
   1.108 +        "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", 
   1.109 +        "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", 
   1.110 +        "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered", 
   1.111 +        "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", 
   1.112 +        "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", 
   1.113 +        "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", 
   1.114 +        "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi", 
   1.115 +        "circumflex", "tilde", "macron", "breve", "dotaccent", "ring", 
   1.116 +        "cedilla", "hungarumlaut", "ogonek", "caron", "Lslash", "lslash", 
   1.117 +        "Scaron", "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth", 
   1.118 +        "Yacute", "yacute", "Thorn", "thorn", "minus", "multiply", 
   1.119 +        "onesuperior", "twosuperior", "threesuperior", "onehalf", "onequarter", 
   1.120 +        "threequarters", "franc", "Gbreve", "gbreve", "Idotaccent", "Scedilla", 
   1.121 +        "scedilla", "Cacute", "cacute", "Ccaron", "ccaron", 
   1.122 +        "dcroat" };
   1.123 +#endif
   1.124 +
   1.125 +} // end of namespace
   1.126 +
   1.127 +/***********************************************************************************************
   1.128 +    Methods
   1.129 +***********************************************************************************************/
   1.130 +
   1.131 +/* Note on error processing: The code guards against bad glyph ids being used to look up data
   1.132 +in open ended tables (loca, hmtx). If the glyph id comes from a cmap this shouldn't happen 
   1.133 +but it seems prudent to check for user errors here. The code does assume that data obtained 
   1.134 +from the TTF file is valid otherwise (though the CheckTable method seeks to check for 
   1.135 +obvious problems that might accompany a change in table versions). For example an invalid 
   1.136 +offset in the loca table which could exceed the size of the glyf table is NOT trapped.
   1.137 +Likewise if numberOf_LongHorMetrics in the hhea table is wrong, this will NOT be trapped, 
   1.138 +which could cause a lookup in the hmtx table to exceed the table length. Of course, TTF tables
   1.139 +that are completely corrupt will cause unpredictable results. */
   1.140 +
   1.141 +/* Note on composite glyphs: Glyphs that have components that are themselves composites
   1.142 +are not supported. IsDeepComposite can be used to test for this. False is returned from many 
   1.143 +of the methods in this cases. It is unclear how to build composite glyphs in some cases, 
   1.144 +so this code represents my best guess until test cases can be found. See notes on the high-
   1.145 +level GlyfPoints method. */
   1.146 +namespace graphite2
   1.147 +{
   1.148 +namespace TtfUtil
   1.149 +{
   1.150 +
   1.151 +
   1.152 +/*----------------------------------------------------------------------------------------------
   1.153 +    Get offset and size of the offset table needed to find table directory.
   1.154 +    Return true if success, false otherwise.
   1.155 +    lSize excludes any table directory entries.
   1.156 +----------------------------------------------------------------------------------------------*/
   1.157 +bool GetHeaderInfo(size_t & lOffset, size_t & lSize)
   1.158 +{
   1.159 +    lOffset = 0;
   1.160 +    lSize   = offsetof(Sfnt::OffsetSubTable, table_directory);
   1.161 +    assert(sizeof(uint32) + 4*sizeof (uint16) == lSize);
   1.162 +    return true;
   1.163 +}
   1.164 +
   1.165 +/*----------------------------------------------------------------------------------------------
   1.166 +    Check the offset table for expected data.
   1.167 +    Return true if success, false otherwise.
   1.168 +----------------------------------------------------------------------------------------------*/
   1.169 +bool CheckHeader(const void * pHdr)
   1.170 +{
   1.171 +    const Sfnt::OffsetSubTable * pOffsetTable  
   1.172 +        = reinterpret_cast<const Sfnt::OffsetSubTable *>(pHdr);
   1.173 +
   1.174 +    return pHdr && be::swap(pOffsetTable->scaler_type) == Sfnt::OffsetSubTable::TrueTypeWin;
   1.175 +}
   1.176 +
   1.177 +/*----------------------------------------------------------------------------------------------
   1.178 +    Get offset and size of the table directory.
   1.179 +    Return true if successful, false otherwise.
   1.180 +----------------------------------------------------------------------------------------------*/
   1.181 +bool GetTableDirInfo(const void * pHdr, size_t & lOffset, size_t & lSize)
   1.182 +{
   1.183 +    const Sfnt::OffsetSubTable * pOffsetTable
   1.184 +        = reinterpret_cast<const Sfnt::OffsetSubTable *>(pHdr);
   1.185 +
   1.186 +    lOffset = offsetof(Sfnt::OffsetSubTable, table_directory);
   1.187 +    lSize   = be::swap(pOffsetTable->num_tables)
   1.188 +        * sizeof(Sfnt::OffsetSubTable::Entry);
   1.189 +    
   1.190 +    return true;
   1.191 +}
   1.192 +
   1.193 +
   1.194 +/*----------------------------------------------------------------------------------------------
   1.195 +    Get offset and size of the specified table.
   1.196 +    Return true if successful, false otherwise. On false, offset and size will be 0.
   1.197 +----------------------------------------------------------------------------------------------*/
   1.198 +bool GetTableInfo(const Tag TableTag, const void * pHdr, const void * pTableDir,
   1.199 +                           size_t & lOffset, size_t & lSize)
   1.200 +{
   1.201 +    const Sfnt::OffsetSubTable * pOffsetTable 
   1.202 +        = reinterpret_cast<const Sfnt::OffsetSubTable *>(pHdr);
   1.203 +    const size_t num_tables = be::swap(pOffsetTable->num_tables);
   1.204 +    const Sfnt::OffsetSubTable::Entry 
   1.205 +        * entry_itr = reinterpret_cast<const Sfnt::OffsetSubTable::Entry *>(
   1.206 +            pTableDir),
   1.207 +        * const  dir_end = entry_itr + num_tables;
   1.208 +
   1.209 +    if (num_tables > 40)
   1.210 +        return false;
   1.211 +
   1.212 +    for (;entry_itr != dir_end; ++entry_itr) // 40 - safe guard
   1.213 +    {
   1.214 +        if (be::swap(entry_itr->tag) == TableTag)
   1.215 +        {
   1.216 +            lOffset = be::swap(entry_itr->offset);
   1.217 +            lSize   = be::swap(entry_itr->length);
   1.218 +            return true;
   1.219 +        }
   1.220 +    }
   1.221 +
   1.222 +    return false;
   1.223 +}
   1.224 +
   1.225 +/*----------------------------------------------------------------------------------------------
   1.226 +    Check the specified table. Tests depend on the table type.
   1.227 +    Return true if successful, false otherwise.
   1.228 +----------------------------------------------------------------------------------------------*/
   1.229 +bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
   1.230 +{
   1.231 +    using namespace Sfnt;
   1.232 +    
   1.233 +    if (pTable == 0) return false;
   1.234 +
   1.235 +    switch(TableId)
   1.236 +    {
   1.237 +    case Tag::cmap: // cmap
   1.238 +    {
   1.239 +        const Sfnt::CharacterCodeMap * const pCmap 
   1.240 +            = reinterpret_cast<const Sfnt::CharacterCodeMap *>(pTable);
   1.241 +        return be::swap(pCmap->version) == 0;
   1.242 +    }
   1.243 +
   1.244 +    case Tag::head: // head
   1.245 +    {
   1.246 +        const Sfnt::FontHeader * const pHead 
   1.247 +            = reinterpret_cast<const Sfnt::FontHeader *>(pTable);
   1.248 +        bool r = be::swap(pHead->version) == OneFix
   1.249 +            && be::swap(pHead->magic_number) == FontHeader::MagicNumber
   1.250 +            && be::swap(pHead->glyph_data_format)
   1.251 +                    == FontHeader::GlypDataFormat 
   1.252 +            && (be::swap(pHead->index_to_loc_format)
   1.253 +                    == FontHeader::ShortIndexLocFormat 
   1.254 +                || be::swap(pHead->index_to_loc_format)
   1.255 +                    == FontHeader::LongIndexLocFormat) 
   1.256 +            && sizeof(FontHeader) <= lTableSize;
   1.257 +        return r;
   1.258 +    }
   1.259 +
   1.260 +    case Tag::post: // post
   1.261 +    {
   1.262 +        const Sfnt::PostScriptGlyphName * const pPost 
   1.263 +            = reinterpret_cast<const Sfnt::PostScriptGlyphName *>(pTable);
   1.264 +        const fixed format = be::swap(pPost->format);
   1.265 +        bool r = format == PostScriptGlyphName::Format1 
   1.266 +            || format == PostScriptGlyphName::Format2 
   1.267 +            || format == PostScriptGlyphName::Format3 
   1.268 +            || format == PostScriptGlyphName::Format25;
   1.269 +        return r;
   1.270 +    }
   1.271 +
   1.272 +    case Tag::hhea: // hhea
   1.273 +    {
   1.274 +        const Sfnt::HorizontalHeader * pHhea = 
   1.275 +            reinterpret_cast<const Sfnt::HorizontalHeader *>(pTable);
   1.276 +        bool r = be::swap(pHhea->version) == OneFix
   1.277 +            && be::swap(pHhea->metric_data_format) == 0
   1.278 +            && sizeof (Sfnt::HorizontalHeader) <= lTableSize;
   1.279 +        return r;
   1.280 +    }
   1.281 +
   1.282 +    case Tag::maxp: // maxp
   1.283 +    {
   1.284 +        const Sfnt::MaximumProfile * pMaxp = 
   1.285 +            reinterpret_cast<const Sfnt::MaximumProfile *>(pTable);
   1.286 +        bool r = be::swap(pMaxp->version) == OneFix
   1.287 +            && sizeof(Sfnt::MaximumProfile) <= lTableSize;
   1.288 +        return r;
   1.289 +    }
   1.290 +
   1.291 +    case Tag::OS_2: // OS/2
   1.292 +    {
   1.293 +        const Sfnt::Compatibility * pOs2 
   1.294 +            = reinterpret_cast<const Sfnt::Compatibility *>(pTable);
   1.295 +        if (be::swap(pOs2->version) == 0)
   1.296 +        { // OS/2 table version 1 size
   1.297 +//          if (sizeof(Sfnt::Compatibility) 
   1.298 +//                  - sizeof(uint32)*2 - sizeof(int16)*2 
   1.299 +//                  - sizeof(uint16)*3 <= lTableSize)
   1.300 +            if (sizeof(Sfnt::Compatibility0) <= lTableSize)
   1.301 +                return true;
   1.302 +        }
   1.303 +        else if (be::swap(pOs2->version) == 1)
   1.304 +        { // OS/2 table version 2 size
   1.305 +//          if (sizeof(Sfnt::Compatibility) 
   1.306 +//                  - sizeof(int16) *2 
   1.307 +//                  - sizeof(uint16)*3 <= lTableSize)
   1.308 +            if (sizeof(Sfnt::Compatibility1) <= lTableSize)
   1.309 +                return true;
   1.310 +        }
   1.311 +        else if (be::swap(pOs2->version) == 2)
   1.312 +        { // OS/2 table version 3 size
   1.313 +            if (sizeof(Sfnt::Compatibility2) <= lTableSize)
   1.314 +                return true;
   1.315 +        }
   1.316 +        else if (be::swap(pOs2->version) == 3 || be::swap(pOs2->version) == 4)
   1.317 +        { // OS/2 table version 4 size - version 4 changed the meaning of some fields which we don't use
   1.318 +            if (sizeof(Sfnt::Compatibility3) <= lTableSize)
   1.319 +                return true;
   1.320 +        }
   1.321 +        else
   1.322 +            return false;
   1.323 +        break;
   1.324 +    }
   1.325 +
   1.326 +    case Tag::name:
   1.327 +    {
   1.328 +        const Sfnt::FontNames * pName 
   1.329 +            = reinterpret_cast<const Sfnt::FontNames *>(pTable);
   1.330 +        return be::swap(pName->format) == 0;
   1.331 +    }
   1.332 +
   1.333 +    default:
   1.334 +        break;
   1.335 +    }
   1.336 +
   1.337 +    return true;
   1.338 +}
   1.339 +
   1.340 +/*----------------------------------------------------------------------------------------------
   1.341 +    Return the number of glyphs in the font. Should never be less than zero.
   1.342 +
   1.343 +    Note: this method is not currently used by the Graphite engine.
   1.344 +----------------------------------------------------------------------------------------------*/
   1.345 +size_t GlyphCount(const void * pMaxp)
   1.346 +{
   1.347 +    const Sfnt::MaximumProfile * pTable = 
   1.348 +            reinterpret_cast<const Sfnt::MaximumProfile *>(pMaxp);
   1.349 +    return be::swap(pTable->num_glyphs);
   1.350 +}
   1.351 +
   1.352 +#ifdef ALL_TTFUTILS
   1.353 +/*----------------------------------------------------------------------------------------------
   1.354 +    Return the maximum number of components for any composite glyph in the font.
   1.355 +
   1.356 +    Note: this method is not currently used by the Graphite engine.
   1.357 +----------------------------------------------------------------------------------------------*/
   1.358 +size_t  MaxCompositeComponentCount(const void * pMaxp)
   1.359 +{
   1.360 +    const Sfnt::MaximumProfile * pTable = 
   1.361 +            reinterpret_cast<const Sfnt::MaximumProfile *>(pMaxp);
   1.362 +    return be::swap(pTable->max_component_elements);
   1.363 +}
   1.364 +
   1.365 +/*----------------------------------------------------------------------------------------------
   1.366 +    Composite glyphs can be composed of glyphs that are themselves composites.
   1.367 +    This method returns the maximum number of levels like this for any glyph in the font.
   1.368 +    A non-composite glyph has a level of 1.
   1.369 +
   1.370 +    Note: this method is not currently used by the Graphite engine.
   1.371 +----------------------------------------------------------------------------------------------*/
   1.372 +size_t  MaxCompositeLevelCount(const void * pMaxp)
   1.373 +{
   1.374 +    const Sfnt::MaximumProfile * pTable = 
   1.375 +            reinterpret_cast<const Sfnt::MaximumProfile *>(pMaxp);
   1.376 +    return be::swap(pTable->max_component_depth);
   1.377 +}
   1.378 +
   1.379 +/*----------------------------------------------------------------------------------------------
   1.380 +    Return the number of glyphs in the font according to a differt source.
   1.381 +    Should never be less than zero. Return -1 on failure.
   1.382 +
   1.383 +    Note: this method is not currently used by the Graphite engine.
   1.384 +----------------------------------------------------------------------------------------------*/
   1.385 +size_t LocaGlyphCount(size_t lLocaSize, const void * pHead) //throw(std::domain_error)
   1.386 +{
   1.387 +
   1.388 +    const Sfnt::FontHeader * pTable 
   1.389 +        = reinterpret_cast<const Sfnt::FontHeader *>(pHead);
   1.390 +
   1.391 +    if (be::swap(pTable->index_to_loc_format)
   1.392 +        == Sfnt::FontHeader::ShortIndexLocFormat)
   1.393 +    // loca entries are two bytes and have been divided by two
   1.394 +        return (lLocaSize >> 1) - 1;
   1.395 +    
   1.396 +    if (be::swap(pTable->index_to_loc_format)
   1.397 +        == Sfnt::FontHeader::LongIndexLocFormat)
   1.398 +     // loca entries are four bytes
   1.399 +        return (lLocaSize >> 2) - 1;
   1.400 +
   1.401 +    return -1;
   1.402 +    //throw std::domain_error("head table in inconsistent state. The font may be corrupted");
   1.403 +}
   1.404 +#endif
   1.405 +
   1.406 +/*----------------------------------------------------------------------------------------------
   1.407 +    Return the design units the font is designed with
   1.408 +----------------------------------------------------------------------------------------------*/
   1.409 +int DesignUnits(const void * pHead)
   1.410 +{
   1.411 +    const Sfnt::FontHeader * pTable = 
   1.412 +            reinterpret_cast<const Sfnt::FontHeader *>(pHead);
   1.413 +    
   1.414 +    return be::swap(pTable->units_per_em);
   1.415 +}
   1.416 +
   1.417 +#ifdef ALL_TTFUTILS
   1.418 +/*----------------------------------------------------------------------------------------------
   1.419 +    Return the checksum from the head table, which serves as a unique identifer for the font.
   1.420 +----------------------------------------------------------------------------------------------*/
   1.421 +int HeadTableCheckSum(const void * pHead)
   1.422 +{
   1.423 +    const Sfnt::FontHeader * pTable = 
   1.424 +            reinterpret_cast<const Sfnt::FontHeader *>(pHead);
   1.425 +    
   1.426 +    return be::swap(pTable->check_sum_adjustment);
   1.427 +}
   1.428 +
   1.429 +/*----------------------------------------------------------------------------------------------
   1.430 +    Return the create time from the head table. This consists of a 64-bit integer, which
   1.431 +    we return here as two 32-bit integers.
   1.432 +
   1.433 +    Note: this method is not currently used by the Graphite engine.
   1.434 +----------------------------------------------------------------------------------------------*/
   1.435 +void HeadTableCreateTime(const void * pHead,
   1.436 +    unsigned int * pnDateBC, unsigned int * pnDateAD)
   1.437 +{
   1.438 +    const Sfnt::FontHeader * pTable = 
   1.439 +            reinterpret_cast<const Sfnt::FontHeader *>(pHead);
   1.440 +    
   1.441 +    *pnDateBC = be::swap(pTable->created[0]);
   1.442 +    *pnDateAD = be::swap(pTable->created[1]);
   1.443 +}
   1.444 +
   1.445 +/*----------------------------------------------------------------------------------------------
   1.446 +    Return the modify time from the head table.This consists of a 64-bit integer, which
   1.447 +    we return here as two 32-bit integers.
   1.448 +
   1.449 +    Note: this method is not currently used by the Graphite engine.
   1.450 +----------------------------------------------------------------------------------------------*/
   1.451 +void HeadTableModifyTime(const void * pHead,
   1.452 +    unsigned int * pnDateBC, unsigned int *pnDateAD)
   1.453 +{
   1.454 +    const Sfnt::FontHeader * pTable = 
   1.455 +            reinterpret_cast<const Sfnt::FontHeader *>(pHead);
   1.456 +    
   1.457 +    *pnDateBC = be::swap(pTable->modified[0]);
   1.458 +    *pnDateAD = be::swap(pTable->modified[1]);
   1.459 +}
   1.460 +
   1.461 +/*----------------------------------------------------------------------------------------------
   1.462 +    Return true if the font is italic.
   1.463 +----------------------------------------------------------------------------------------------*/
   1.464 +bool IsItalic(const void * pHead)
   1.465 +{
   1.466 +    const Sfnt::FontHeader * pTable = 
   1.467 +            reinterpret_cast<const Sfnt::FontHeader *>(pHead);
   1.468 +
   1.469 +    return ((be::swap(pTable->mac_style) & 0x00000002) != 0);
   1.470 +}
   1.471 +
   1.472 +/*----------------------------------------------------------------------------------------------
   1.473 +    Return the ascent for the font
   1.474 +----------------------------------------------------------------------------------------------*/
   1.475 +int FontAscent(const void * pOs2)
   1.476 +{
   1.477 +    const Sfnt::Compatibility * pTable = reinterpret_cast<const Sfnt::Compatibility *>(pOs2);
   1.478 +
   1.479 +    return be::swap(pTable->win_ascent);
   1.480 +}
   1.481 +
   1.482 +/*----------------------------------------------------------------------------------------------
   1.483 +    Return the descent for the font
   1.484 +----------------------------------------------------------------------------------------------*/
   1.485 +int FontDescent(const void * pOs2)
   1.486 +{
   1.487 +    const Sfnt::Compatibility * pTable = reinterpret_cast<const Sfnt::Compatibility *>(pOs2);
   1.488 +
   1.489 +    return be::swap(pTable->win_descent);
   1.490 +}
   1.491 +
   1.492 +/*----------------------------------------------------------------------------------------------
   1.493 +    Get the bold and italic style bits.
   1.494 +    Return true if successful. false otherwise.
   1.495 +    In addition to checking the OS/2 table, one could also check
   1.496 +        the head table's macStyle field (overridden by the OS/2 table on Win)
   1.497 +        the sub-family name in the name table (though this can contain oblique, dark, etc too)
   1.498 +----------------------------------------------------------------------------------------------*/
   1.499 +bool FontOs2Style(const void *pOs2, bool & fBold, bool & fItalic)
   1.500 +{
   1.501 +    const Sfnt::Compatibility * pTable = reinterpret_cast<const Sfnt::Compatibility *>(pOs2);
   1.502 +
   1.503 +    fBold = (be::swap(pTable->fs_selection) & Sfnt::Compatibility::Bold) != 0;
   1.504 +    fItalic = (be::swap(pTable->fs_selection) & Sfnt::Compatibility::Italic) != 0;
   1.505 +    
   1.506 +    return true;
   1.507 +}
   1.508 +#endif
   1.509 +
   1.510 +/*----------------------------------------------------------------------------------------------
   1.511 +    Method for searching name table.
   1.512 +----------------------------------------------------------------------------------------------*/
   1.513 +bool GetNameInfo(const void * pName, int nPlatformId, int nEncodingId,
   1.514 +        int nLangId, int nNameId, size_t & lOffset, size_t & lSize)
   1.515 +{
   1.516 +    lOffset = 0;
   1.517 +    lSize = 0;
   1.518 +
   1.519 +    const Sfnt::FontNames * pTable = reinterpret_cast<const Sfnt::FontNames *>(pName);
   1.520 +    uint16 cRecord = be::swap(pTable->count);
   1.521 +    uint16 nRecordOffset = be::swap(pTable->string_offset);
   1.522 +    const Sfnt::NameRecord * pRecord = reinterpret_cast<const Sfnt::NameRecord *>(pTable + 1);
   1.523 +
   1.524 +    for (int i = 0; i < cRecord; ++i)
   1.525 +    {
   1.526 +        if (be::swap(pRecord->platform_id) == nPlatformId &&
   1.527 +            be::swap(pRecord->platform_specific_id) == nEncodingId &&
   1.528 +            be::swap(pRecord->language_id) == nLangId &&
   1.529 +            be::swap(pRecord->name_id) == nNameId)
   1.530 +        {
   1.531 +            lOffset = be::swap(pRecord->offset) + nRecordOffset;
   1.532 +            lSize = be::swap(pRecord->length);
   1.533 +            return true;
   1.534 +        }
   1.535 +        pRecord++;
   1.536 +    }
   1.537 +
   1.538 +    return false;
   1.539 +}
   1.540 +
   1.541 +#ifdef ALL_TTFUTILS
   1.542 +/*----------------------------------------------------------------------------------------------
   1.543 +    Return all the lang-IDs that have data for the given name-IDs. Assume that there is room
   1.544 +    in the return array (langIdList) for 128 items. The purpose of this method is to return
   1.545 +    a list of all possible lang-IDs.
   1.546 +----------------------------------------------------------------------------------------------*/
   1.547 +int GetLangsForNames(const void * pName, int nPlatformId, int nEncodingId,
   1.548 +        int * nameIdList, int cNameIds, short * langIdList)
   1.549 +{
   1.550 +    const Sfnt::FontNames * pTable = reinterpret_cast<const Sfnt::FontNames *>(pName);
   1.551 +        int cLangIds = 0;
   1.552 +    uint16 cRecord = be::swap(pTable->count);
   1.553 +        if (cRecord > 127) return cLangIds;
   1.554 +    //uint16 nRecordOffset = swapw(pTable->stringOffset);
   1.555 +    const Sfnt::NameRecord * pRecord = reinterpret_cast<const Sfnt::NameRecord *>(pTable + 1);
   1.556 +
   1.557 +    for (int i = 0; i < cRecord; ++i)
   1.558 +    {
   1.559 +        if (be::swap(pRecord->platform_id) == nPlatformId &&
   1.560 +            be::swap(pRecord->platform_specific_id) == nEncodingId)
   1.561 +        {
   1.562 +            bool fNameFound = false;
   1.563 +            int nLangId = be::swap(pRecord->language_id);
   1.564 +            int nNameId = be::swap(pRecord->name_id);
   1.565 +            for (int j = 0; j < cNameIds; j++)
   1.566 +            {
   1.567 +                if (nNameId == nameIdList[j])
   1.568 +                {
   1.569 +                    fNameFound = true;
   1.570 +                    break;
   1.571 +                }
   1.572 +            }
   1.573 +            if (fNameFound)
   1.574 +            {
   1.575 +                // Add it if it's not there.
   1.576 +                int ilang;
   1.577 +                for (ilang = 0; ilang < cLangIds; ilang++)
   1.578 +                    if (langIdList[ilang] == nLangId)
   1.579 +                        break;
   1.580 +                if (ilang >= cLangIds)
   1.581 +                {
   1.582 +                    langIdList[cLangIds] = short(nLangId);
   1.583 +                    cLangIds++;
   1.584 +                }
   1.585 +                if (cLangIds == 128)
   1.586 +                    return cLangIds;
   1.587 +            }
   1.588 +        }
   1.589 +        pRecord++;
   1.590 +    }
   1.591 +
   1.592 +    return cLangIds;
   1.593 +}
   1.594 +
   1.595 +/*----------------------------------------------------------------------------------------------
   1.596 +    Get the offset and size of the font family name in English for the MS Platform with Unicode
   1.597 +    writing system. The offset is within the pName data. The string is double byte with MSB
   1.598 +    first.
   1.599 +----------------------------------------------------------------------------------------------*/
   1.600 +bool Get31EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize)
   1.601 +{
   1.602 +    return GetNameInfo(pName, Sfnt::NameRecord::Microsoft, 1, 1033, 
   1.603 +        Sfnt::NameRecord::Family, lOffset, lSize);
   1.604 +}
   1.605 +
   1.606 +/*----------------------------------------------------------------------------------------------
   1.607 +    Get the offset and size of the full font name in English for the MS Platform with Unicode
   1.608 +    writing system. The offset is within the pName data. The string is double byte with MSB
   1.609 +    first.
   1.610 +
   1.611 +    Note: this method is not currently used by the Graphite engine.
   1.612 +----------------------------------------------------------------------------------------------*/
   1.613 +bool Get31EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize)
   1.614 +{
   1.615 +    return GetNameInfo(pName, Sfnt::NameRecord::Microsoft, 1, 1033, 
   1.616 +        Sfnt::NameRecord::Fullname, lOffset, lSize);
   1.617 +}
   1.618 +
   1.619 +/*----------------------------------------------------------------------------------------------
   1.620 +    Get the offset and size of the font family name in English for the MS Platform with Symbol
   1.621 +    writing system. The offset is within the pName data. The string is double byte with MSB
   1.622 +    first.
   1.623 +----------------------------------------------------------------------------------------------*/
   1.624 +bool Get30EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize)
   1.625 +{
   1.626 +    return GetNameInfo(pName, Sfnt::NameRecord::Microsoft, 0, 1033, 
   1.627 +        Sfnt::NameRecord::Family, lOffset, lSize);
   1.628 +}
   1.629 +
   1.630 +/*----------------------------------------------------------------------------------------------
   1.631 +    Get the offset and size of the full font name in English for the MS Platform with Symbol
   1.632 +    writing system. The offset is within the pName data. The string is double byte with MSB
   1.633 +    first.
   1.634 +
   1.635 +    Note: this method is not currently used by the Graphite engine.
   1.636 +----------------------------------------------------------------------------------------------*/
   1.637 +bool Get30EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize)
   1.638 +{
   1.639 +    return GetNameInfo(pName, Sfnt::NameRecord::Microsoft, 0, 1033, 
   1.640 +        Sfnt::NameRecord::Fullname, lOffset, lSize);
   1.641 +}
   1.642 +
   1.643 +/*----------------------------------------------------------------------------------------------
   1.644 +    Return the Glyph ID for a given Postscript name. This method finds the first glyph which
   1.645 +    matches the requested Postscript name. Ideally every glyph should have a unique Postscript 
   1.646 +    name (except for special names such as .notdef), but this is not always true.
   1.647 +    On failure return value less than zero.
   1.648 +       -1 - table search failed
   1.649 +       -2 - format 3 table (no Postscript glyph info)
   1.650 +       -3 - other failures
   1.651 +
   1.652 +    Note: this method is not currently used by the Graphite engine.
   1.653 +----------------------------------------------------------------------------------------------*/
   1.654 +int PostLookup(const void * pPost, size_t lPostSize, const void * pMaxp, 
   1.655 +                        const char * pPostName)
   1.656 +{
   1.657 +    using namespace Sfnt;
   1.658 +    
   1.659 +    const Sfnt::PostScriptGlyphName * pTable 
   1.660 +        = reinterpret_cast<const Sfnt::PostScriptGlyphName *>(pPost);
   1.661 +    fixed format = be::swap(pTable->format);
   1.662 +
   1.663 +    if (format == PostScriptGlyphName::Format3)
   1.664 +    { // format 3 - no Postscript glyph info in font
   1.665 +        return -2;
   1.666 +    }
   1.667 +
   1.668 +    // search for given Postscript name among the standard names
   1.669 +    int iPostName = -1; // index in standard names
   1.670 +    for (int i = 0; i < kcPostNames; i++)
   1.671 +    {
   1.672 +        if (!strcmp(pPostName, rgPostName[i]))
   1.673 +        {
   1.674 +            iPostName = i;
   1.675 +            break;
   1.676 +        }
   1.677 +    }
   1.678 +
   1.679 +    if (format == PostScriptGlyphName::Format1)
   1.680 +    { // format 1 - use standard Postscript names
   1.681 +        return iPostName;
   1.682 +    }
   1.683 +    
   1.684 +    if (format == PostScriptGlyphName::Format25)
   1.685 +    { 
   1.686 +        if (iPostName == -1)
   1.687 +            return -1;
   1.688 +        
   1.689 +        const PostScriptGlyphName25 * pTable25 
   1.690 +            = static_cast<const PostScriptGlyphName25 *>(pTable);
   1.691 +        int cnGlyphs = GlyphCount(pMaxp);
   1.692 +        for (gid16 nGlyphId = 0; nGlyphId < cnGlyphs && nGlyphId < kcPostNames; 
   1.693 +                nGlyphId++)
   1.694 +        { // glyph_name_index25 contains bytes so no byte swapping needed
   1.695 +          // search for first glyph id that uses the standard name 
   1.696 +            if (nGlyphId + pTable25->offset[nGlyphId] == iPostName)
   1.697 +                return nGlyphId;
   1.698 +        }
   1.699 +    }
   1.700 +
   1.701 +    if (format == PostScriptGlyphName::Format2)
   1.702 +    { // format 2
   1.703 +        const PostScriptGlyphName2 * pTable2 
   1.704 +            = static_cast<const PostScriptGlyphName2 *>(pTable);
   1.705 +        
   1.706 +        int cnGlyphs = be::swap(pTable2->number_of_glyphs);
   1.707 +
   1.708 +        if (iPostName != -1)
   1.709 +        { // did match a standard name, look for first glyph id mapped to that name
   1.710 +            for (gid16 nGlyphId = 0; nGlyphId < cnGlyphs; nGlyphId++)
   1.711 +            {
   1.712 +                if (be::swap(pTable2->glyph_name_index[nGlyphId]) == iPostName)
   1.713 +                    return nGlyphId;
   1.714 +            }
   1.715 +        }
   1.716 +
   1.717 +        { // did not match a standard name, search font specific names
   1.718 +            size_t nStrSizeGoal = strlen(pPostName);
   1.719 +            const char * pFirstGlyphName = reinterpret_cast<const char *>(
   1.720 +                &pTable2->glyph_name_index[0] + cnGlyphs);
   1.721 +            const char * pGlyphName = pFirstGlyphName;
   1.722 +            int iInNames = 0; // index in font specific names
   1.723 +            bool fFound = false;
   1.724 +            const char * const endOfTable 
   1.725 +                = reinterpret_cast<const char *>(pTable2) + lPostSize;
   1.726 +            while (pGlyphName < endOfTable && !fFound) 
   1.727 +            { // search Pascal strings for first matching name
   1.728 +                size_t nStringSize = size_t(*pGlyphName);
   1.729 +                if (nStrSizeGoal != nStringSize ||
   1.730 +                    strncmp(pGlyphName + 1, pPostName, nStringSize))
   1.731 +                { // did not match
   1.732 +                    ++iInNames;
   1.733 +                    pGlyphName += nStringSize + 1;
   1.734 +                }
   1.735 +                else
   1.736 +                { // did match
   1.737 +                    fFound = true;
   1.738 +                }
   1.739 +            }
   1.740 +            if (!fFound)
   1.741 +                return -1; // no font specific name matches request
   1.742 +
   1.743 +            iInNames += kcPostNames;
   1.744 +            for (gid16 nGlyphId = 0; nGlyphId < cnGlyphs; nGlyphId++)
   1.745 +            { // search for first glyph id that maps to the found string index
   1.746 +                if (be::swap(pTable2->glyph_name_index[nGlyphId]) == iInNames)
   1.747 +                    return nGlyphId;
   1.748 +            }
   1.749 +            return -1; // no glyph mapped to this index (very strange)
   1.750 +        }
   1.751 +    }
   1.752 +
   1.753 +    return -3;
   1.754 +}
   1.755 +
   1.756 +/*----------------------------------------------------------------------------------------------
   1.757 +    Convert a Unicode character string from big endian (MSB first, Motorola) format to little 
   1.758 +    endian (LSB first, Intel) format. 
   1.759 +    nSize is the number of Unicode characters in the string. It should not include any 
   1.760 +    terminating null. If nSize is 0, it is assumed the string is null terminated. nSize 
   1.761 +    defaults to 0.
   1.762 +    Return true if successful, false otherwise. 
   1.763 +----------------------------------------------------------------------------------------------*/
   1.764 +void SwapWString(void * pWStr, size_t nSize /* = 0 */) //throw (std::invalid_argument)
   1.765 +{
   1.766 +    if (pWStr == 0)
   1.767 +    {
   1.768 +//      throw std::invalid_argument("null pointer given");
   1.769 +        return;
   1.770 +    }
   1.771 +
   1.772 +    uint16 * pStr = reinterpret_cast<uint16 *>(pWStr);
   1.773 +    uint16 * const pStrEnd = pStr + (nSize == 0 ? wcslen((const wchar_t*)pStr) : nSize);
   1.774 +
   1.775 +        for (; pStr != pStrEnd; ++pStr)
   1.776 +          *pStr = be::swap(*pStr);
   1.777 +//  std::transform(pStr, pStrEnd, pStr, read<uint16>);
   1.778 +
   1.779 +//      for (int i = 0; i < nSize; i++)
   1.780 +//      { // swap the wide characters in the string
   1.781 +//          pStr[i] = utf16(be::swap(uint16(pStr[i])));
   1.782 +//      }
   1.783 +}
   1.784 +#endif
   1.785 +
   1.786 +/*----------------------------------------------------------------------------------------------
   1.787 +    Get the left-side bearing and and advance width based on the given tables and Glyph ID
   1.788 +    Return true if successful, false otherwise. On false, one or both value could be INT_MIN
   1.789 +----------------------------------------------------------------------------------------------*/
   1.790 +bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize, const void * pHhea, 
   1.791 +                         int & nLsb, unsigned int & nAdvWid)
   1.792 +{
   1.793 +    const Sfnt::HorizontalMetric * phmtx = 
   1.794 +        reinterpret_cast<const Sfnt::HorizontalMetric *>(pHmtx);
   1.795 +
   1.796 +    const Sfnt::HorizontalHeader * phhea = 
   1.797 +        reinterpret_cast<const Sfnt::HorizontalHeader *>(pHhea);
   1.798 +
   1.799 +    size_t cLongHorMetrics = be::swap(phhea->num_long_hor_metrics);
   1.800 +    if (nGlyphId < cLongHorMetrics) 
   1.801 +    {   // glyph id is acceptable
   1.802 +        if (nGlyphId * sizeof(Sfnt::HorizontalMetric) >= lHmtxSize) return false;
   1.803 +        nAdvWid = be::swap(phmtx[nGlyphId].advance_width);
   1.804 +        nLsb = be::swap(phmtx[nGlyphId].left_side_bearing);
   1.805 +    }
   1.806 +    else
   1.807 +    {
   1.808 +        // guard against bad glyph id
   1.809 +        size_t lLsbOffset = sizeof(Sfnt::HorizontalMetric) * cLongHorMetrics +
   1.810 +            sizeof(int16) * (nGlyphId - cLongHorMetrics); // offset in bytes
   1.811 +        // We test like this as LsbOffset is an offset not a length.
   1.812 +        if (lLsbOffset > lHmtxSize - sizeof(int16))
   1.813 +        {
   1.814 +            nLsb = 0;
   1.815 +            return false;
   1.816 +        }
   1.817 +        nAdvWid = be::swap(phmtx[cLongHorMetrics - 1].advance_width);
   1.818 +        nLsb = be::peek<int16>(reinterpret_cast<const byte *>(phmtx) + lLsbOffset);
   1.819 +    }
   1.820 +
   1.821 +    return true;
   1.822 +}
   1.823 +
   1.824 +/*----------------------------------------------------------------------------------------------
   1.825 +    Return a pointer to the requested cmap subtable. By default find the Microsoft Unicode
   1.826 +    subtable. Pass nEncoding as -1 to find first table that matches only nPlatformId.
   1.827 +    Return NULL if the subtable cannot be found.
   1.828 +----------------------------------------------------------------------------------------------*/
   1.829 +const void * FindCmapSubtable(const void * pCmap, int nPlatformId, /* =3 */ int nEncodingId, /* = 1 */ size_t length)
   1.830 +{
   1.831 +    const Sfnt::CharacterCodeMap * pTable = reinterpret_cast<const Sfnt::CharacterCodeMap *>(pCmap);
   1.832 +    uint16 csuPlatforms = be::swap(pTable->num_subtables);
   1.833 +    if (length && (sizeof(Sfnt::CharacterCodeMap) + 8 * (csuPlatforms - 1) > length))
   1.834 +        return NULL;
   1.835 +    for (int i = 0; i < csuPlatforms; i++)
   1.836 +    {
   1.837 +        if (be::swap(pTable->encoding[i].platform_id) == nPlatformId &&
   1.838 +                (nEncodingId == -1 || be::swap(pTable->encoding[i].platform_specific_id) == nEncodingId))
   1.839 +        {
   1.840 +            uint32 offset = be::swap(pTable->encoding[i].offset);
   1.841 +            const uint8 * pRtn = reinterpret_cast<const uint8 *>(pCmap) + offset;
   1.842 +            if (length)
   1.843 +            {
   1.844 +                if (offset > length) return NULL;
   1.845 +                uint16 format = be::read<uint16>(pRtn);
   1.846 +                if (format == 4)
   1.847 +                {
   1.848 +                    uint16 subTableLength = be::peek<uint16>(pRtn);
   1.849 +                    if (i + 1 == csuPlatforms)
   1.850 +                    {
   1.851 +                        if (subTableLength > length - offset)
   1.852 +                            return NULL;
   1.853 +                    }
   1.854 +                    else if (subTableLength > be::swap(pTable->encoding[i+1].offset))
   1.855 +                        return NULL;
   1.856 +                }
   1.857 +                if (format == 12)
   1.858 +                {
   1.859 +                    uint32 subTableLength = be::peek<uint32>(pRtn);
   1.860 +                    if (i + 1 == csuPlatforms)
   1.861 +                    {
   1.862 +                        if (subTableLength > length - offset)
   1.863 +                            return NULL;
   1.864 +                    }
   1.865 +                    else if (subTableLength > be::swap(pTable->encoding[i+1].offset))
   1.866 +                        return NULL;
   1.867 +                }
   1.868 +            }
   1.869 +            return reinterpret_cast<const uint8 *>(pCmap) + offset;
   1.870 +        }
   1.871 +    }
   1.872 +
   1.873 +    return 0;
   1.874 +}
   1.875 +
   1.876 +/*----------------------------------------------------------------------------------------------
   1.877 +    Check the Microsoft Unicode subtable for expected values
   1.878 +----------------------------------------------------------------------------------------------*/
   1.879 +bool CheckCmapSubtable4(const void * pCmapSubtable4)
   1.880 +{
   1.881 +    if (!pCmapSubtable4) return false;
   1.882 +    const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable4);
   1.883 +    // Bob H says ome freeware TT fonts have version 1 (eg, CALIGULA.TTF) 
   1.884 +    // so don't check subtable version. 21 Mar 2002 spec changes version to language.
   1.885 +    if (be::swap(pTable->format) != 4) return false;
   1.886 +    const Sfnt::CmapSubTableFormat4 * pTable4 = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtable4);
   1.887 +    uint16 length = be::swap(pTable4->length);
   1.888 +    if (length < sizeof(Sfnt::CmapSubTableFormat4))
   1.889 +        return false;
   1.890 +    uint16 nRanges = be::swap(pTable4->seg_count_x2) >> 1;
   1.891 +    if (length < sizeof(Sfnt::CmapSubTableFormat4) + 4 * nRanges * sizeof(uint16))
   1.892 +        return false;
   1.893 +    // check last range is properly terminated
   1.894 +    uint16 chEnd = be::peek<uint16>(pTable4->end_code + nRanges - 1);
   1.895 +    return (chEnd == 0xFFFF);
   1.896 +}
   1.897 +
   1.898 +/*----------------------------------------------------------------------------------------------
   1.899 +    Return the Glyph ID for the given Unicode ID in the Microsoft Unicode subtable.
   1.900 +    (Actually this code only depends on subtable being format 4.)
   1.901 +    Return 0 if the Unicode ID is not in the subtable.
   1.902 +----------------------------------------------------------------------------------------------*/
   1.903 +gid16 CmapSubtable4Lookup(const void * pCmapSubtabel4, unsigned int nUnicodeId, int rangeKey)
   1.904 +{
   1.905 +    const Sfnt::CmapSubTableFormat4 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtabel4);
   1.906 +
   1.907 +    uint16 nSeg = be::swap(pTable->seg_count_x2) >> 1;
   1.908 +  
   1.909 +    uint16 n;
   1.910 +        const uint16 * pLeft, * pMid;
   1.911 +    uint16 cMid, chStart, chEnd;
   1.912 +
   1.913 +    if (rangeKey)
   1.914 +    {
   1.915 +        pMid = &(pTable->end_code[rangeKey]);
   1.916 +        chEnd = be::peek<uint16>(pMid);
   1.917 +    }
   1.918 +    else
   1.919 +    {
   1.920 +        // Binary search of the endCode[] array
   1.921 +        pLeft = &(pTable->end_code[0]);
   1.922 +        n = nSeg;
   1.923 +        while (n > 0)
   1.924 +        {
   1.925 +            cMid = n >> 1;           // Pick an element in the middle
   1.926 +            pMid = pLeft + cMid;
   1.927 +            chEnd = be::peek<uint16>(pMid);
   1.928 +            if (nUnicodeId <= chEnd)
   1.929 +            {
   1.930 +                if (cMid == 0 || nUnicodeId > be::peek<uint16>(pMid -1))
   1.931 +                        break;          // Must be this seg or none!
   1.932 +                n = cMid;            // Continue on left side, omitting mid point
   1.933 +            }
   1.934 +            else
   1.935 +            {
   1.936 +                pLeft = pMid + 1;    // Continue on right side, omitting mid point
   1.937 +                n -= (cMid + 1);
   1.938 +            }
   1.939 +        }
   1.940 +
   1.941 +        if (!n)
   1.942 +        return 0;
   1.943 +    }
   1.944 +
   1.945 +    // Ok, we're down to one segment and pMid points to the endCode element
   1.946 +    // Either this is it or none is.
   1.947 +
   1.948 +    chStart = be::peek<uint16>(pMid += nSeg + 1);
   1.949 +    if (chEnd >= nUnicodeId && nUnicodeId >= chStart)
   1.950 +    {
   1.951 +        // Found correct segment. Find Glyph Id
   1.952 +        int16 idDelta = be::peek<uint16>(pMid += nSeg);
   1.953 +        uint16 idRangeOffset = be::peek<uint16>(pMid += nSeg);
   1.954 +
   1.955 +        if (idRangeOffset == 0)
   1.956 +            return (uint16)(idDelta + nUnicodeId); // must use modulus 2^16
   1.957 +
   1.958 +        // Look up value in glyphIdArray
   1.959 +        const ptrdiff_t offset = (nUnicodeId - chStart) + (idRangeOffset >> 1) +
   1.960 +                (pMid - reinterpret_cast<const uint16 *>(pTable));
   1.961 +        if (offset * 2 >= be::swap<uint16>(pTable->length))
   1.962 +            return 0;
   1.963 +        gid16 nGlyphId = be::peek<uint16>(reinterpret_cast<const uint16 *>(pTable)+offset);
   1.964 +        // If this value is 0, return 0. Else add the idDelta
   1.965 +        return nGlyphId ? nGlyphId + idDelta : 0;
   1.966 +    }
   1.967 +
   1.968 +    return 0;
   1.969 +}
   1.970 +
   1.971 +/*----------------------------------------------------------------------------------------------
   1.972 +    Return the next Unicode value in the cmap. Pass 0 to obtain the first item.
   1.973 +    Returns 0xFFFF as the last item.
   1.974 +    pRangeKey is an optional key that is used to optimize the search; its value is the range
   1.975 +    in which the character is found.
   1.976 +----------------------------------------------------------------------------------------------*/
   1.977 +unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnicodeId, int * pRangeKey)
   1.978 +{
   1.979 +    const Sfnt::CmapSubTableFormat4 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmap31);
   1.980 +
   1.981 +    uint16 nRange = be::swap(pTable->seg_count_x2) >> 1;
   1.982 +
   1.983 +    uint32 nUnicodePrev = (uint32)nUnicodeId;
   1.984 +
   1.985 +    const uint16 * pStartCode = &(pTable->end_code[0])
   1.986 +        + nRange // length of end code array
   1.987 +        + 1;   // reserved word
   1.988 +
   1.989 +    if (nUnicodePrev == 0)
   1.990 +    {
   1.991 +        // return the first codepoint.
   1.992 +        if (pRangeKey)
   1.993 +            *pRangeKey = 0;
   1.994 +        return be::peek<uint16>(pStartCode);
   1.995 +    }
   1.996 +    else if (nUnicodePrev >= 0xFFFF)
   1.997 +    {
   1.998 +        if (pRangeKey)
   1.999 +            *pRangeKey = nRange - 1;
  1.1000 +        return 0xFFFF;
  1.1001 +    }
  1.1002 +
  1.1003 +    int iRange = (pRangeKey) ? *pRangeKey : 0;
  1.1004 +    // Just in case we have a bad key:
  1.1005 +    while (iRange > 0 && be::peek<uint16>(pStartCode + iRange) > nUnicodePrev)
  1.1006 +        iRange--;
  1.1007 +    while (be::peek<uint16>(pTable->end_code + iRange) < nUnicodePrev)
  1.1008 +        iRange++;
  1.1009 +
  1.1010 +    // Now iRange is the range containing nUnicodePrev.
  1.1011 +    unsigned int nStartCode = be::peek<uint16>(pStartCode + iRange);
  1.1012 +    unsigned int nEndCode = be::peek<uint16>(pTable->end_code + iRange);
  1.1013 +
  1.1014 +    if (nStartCode > nUnicodePrev)
  1.1015 +        // Oops, nUnicodePrev is not in the cmap! Adjust so we get a reasonable
  1.1016 +        // answer this time around.
  1.1017 +        nUnicodePrev = nStartCode - 1;
  1.1018 +
  1.1019 +    if (nEndCode > nUnicodePrev)
  1.1020 +    {
  1.1021 +        // Next is in the same range; it is the next successive codepoint.
  1.1022 +        if (pRangeKey)
  1.1023 +            *pRangeKey = iRange;
  1.1024 +        return nUnicodePrev + 1;
  1.1025 +    }
  1.1026 +
  1.1027 +    // Otherwise the next codepoint is the first one in the next range.
  1.1028 +    // There is guaranteed to be a next range because there must be one that
  1.1029 +    // ends with 0xFFFF.
  1.1030 +    if (pRangeKey)
  1.1031 +        *pRangeKey = iRange + 1;
  1.1032 +    return be::peek<uint16>(pStartCode + iRange + 1);
  1.1033 +}
  1.1034 +
  1.1035 +/*----------------------------------------------------------------------------------------------
  1.1036 +    Check the Microsoft UCS-4 subtable for expected values.
  1.1037 +----------------------------------------------------------------------------------------------*/
  1.1038 +bool CheckCmapSubtable12(const void *pCmapSubtable12)
  1.1039 +{
  1.1040 +    if (!pCmapSubtable12)  return false;
  1.1041 +    const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable12);
  1.1042 +    if (be::swap(pTable->format) != 12)
  1.1043 +        return false;
  1.1044 +    const Sfnt::CmapSubTableFormat12 * pTable12 = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmapSubtable12);
  1.1045 +    uint32 length = be::swap(pTable12->length);
  1.1046 +    if (length < sizeof(Sfnt::CmapSubTableFormat12))
  1.1047 +        return false;
  1.1048 +    
  1.1049 +    return (length == (sizeof(Sfnt::CmapSubTableFormat12) + (be::swap(pTable12->num_groups) - 1)
  1.1050 +        * sizeof(uint32) * 3));
  1.1051 +}
  1.1052 +
  1.1053 +/*----------------------------------------------------------------------------------------------
  1.1054 +    Return the Glyph ID for the given Unicode ID in the Microsoft UCS-4 subtable.
  1.1055 +    (Actually this code only depends on subtable being format 12.)
  1.1056 +    Return 0 if the Unicode ID is not in the subtable.
  1.1057 +----------------------------------------------------------------------------------------------*/
  1.1058 +gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey)
  1.1059 +{
  1.1060 +    const Sfnt::CmapSubTableFormat12 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmap310);
  1.1061 +
  1.1062 +    //uint32 uLength = be::swap(pTable->length); //could use to test for premature end of table
  1.1063 +    uint32 ucGroups = be::swap(pTable->num_groups);
  1.1064 +
  1.1065 +    for (unsigned int i = rangeKey; i < ucGroups; i++)
  1.1066 +    {
  1.1067 +        uint32 uStartCode = be::swap(pTable->group[i].start_char_code);
  1.1068 +        uint32 uEndCode = be::swap(pTable->group[i].end_char_code);
  1.1069 +        if (uUnicodeId >= uStartCode && uUnicodeId <= uEndCode)
  1.1070 +        {
  1.1071 +            uint32 uDiff = uUnicodeId - uStartCode;
  1.1072 +            uint32 uStartGid = be::swap(pTable->group[i].start_glyph_id);
  1.1073 +            return static_cast<gid16>(uStartGid + uDiff);
  1.1074 +        }
  1.1075 +    }
  1.1076 +
  1.1077 +    return 0;
  1.1078 +}
  1.1079 +
  1.1080 +/*----------------------------------------------------------------------------------------------
  1.1081 +    Return the next Unicode value in the cmap. Pass 0 to obtain the first item.
  1.1082 +    Returns 0x10FFFF as the last item.
  1.1083 +    pRangeKey is an optional key that is used to optimize the search; its value is the range
  1.1084 +    in which the character is found.
  1.1085 +----------------------------------------------------------------------------------------------*/
  1.1086 +unsigned int CmapSubtable12NextCodepoint(const void *pCmap310, unsigned int nUnicodeId, int * pRangeKey)
  1.1087 +{
  1.1088 +    const Sfnt::CmapSubTableFormat12 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmap310);
  1.1089 +
  1.1090 +    int nRange = be::swap(pTable->num_groups);
  1.1091 +
  1.1092 +    uint32 nUnicodePrev = (uint32)nUnicodeId;
  1.1093 +
  1.1094 +    if (nUnicodePrev == 0)
  1.1095 +    {
  1.1096 +        // return the first codepoint.
  1.1097 +        if (pRangeKey)
  1.1098 +            *pRangeKey = 0;
  1.1099 +        return be::swap(pTable->group[0].start_char_code);
  1.1100 +    }
  1.1101 +    else if (nUnicodePrev >= 0x10FFFF)
  1.1102 +    {
  1.1103 +        if (pRangeKey)
  1.1104 +            *pRangeKey = nRange;
  1.1105 +        return 0x10FFFF;
  1.1106 +    }
  1.1107 +
  1.1108 +    int iRange = (pRangeKey) ? *pRangeKey : 0;
  1.1109 +    // Just in case we have a bad key:
  1.1110 +    while (iRange > 0 && be::swap(pTable->group[iRange].start_char_code) > nUnicodePrev)
  1.1111 +        iRange--;
  1.1112 +    while (be::swap(pTable->group[iRange].end_char_code) < nUnicodePrev)
  1.1113 +        iRange++;
  1.1114 +
  1.1115 +    // Now iRange is the range containing nUnicodePrev.
  1.1116 +
  1.1117 +    unsigned int nStartCode = be::swap(pTable->group[iRange].start_char_code);
  1.1118 +    unsigned int nEndCode = be::swap(pTable->group[iRange].end_char_code);
  1.1119 +
  1.1120 +    if (nStartCode > nUnicodePrev)
  1.1121 +        // Oops, nUnicodePrev is not in the cmap! Adjust so we get a reasonable
  1.1122 +        // answer this time around.
  1.1123 +        nUnicodePrev = nStartCode - 1;
  1.1124 +
  1.1125 +    if (nEndCode > nUnicodePrev)
  1.1126 +    {
  1.1127 +        // Next is in the same range; it is the next successive codepoint.
  1.1128 +        if (pRangeKey)
  1.1129 +            *pRangeKey = iRange;
  1.1130 +        return nUnicodePrev + 1;
  1.1131 +    }
  1.1132 +
  1.1133 +    // Otherwise the next codepoint is the first one in the next range, or 10FFFF if we're done.
  1.1134 +    if (pRangeKey)
  1.1135 +        *pRangeKey = iRange + 1;
  1.1136 +    return (iRange + 1 >= nRange) ? 0x10FFFF : be::swap(pTable->group[iRange + 1].start_char_code);
  1.1137 +}
  1.1138 +
  1.1139 +/*----------------------------------------------------------------------------------------------
  1.1140 +    Return the offset stored in the loca table for the given Glyph ID.
  1.1141 +    (This offset is into the glyf table.)
  1.1142 +    Return -1 if the lookup failed.
  1.1143 +    Technically this method should return an unsigned long but it is unlikely the offset will
  1.1144 +        exceed 2^31.
  1.1145 +----------------------------------------------------------------------------------------------*/
  1.1146 +size_t LocaLookup(gid16 nGlyphId, 
  1.1147 +        const void * pLoca, size_t lLocaSize, 
  1.1148 +        const void * pHead) // throw (std::out_of_range)
  1.1149 +{
  1.1150 +    const Sfnt::FontHeader * pTable = reinterpret_cast<const Sfnt::FontHeader *>(pHead);
  1.1151 +
  1.1152 +    // CheckTable verifies the index_to_loc_format is valid
  1.1153 +    if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::ShortIndexLocFormat)
  1.1154 +    { // loca entries are two bytes and have been divided by two
  1.1155 +        if (nGlyphId < (lLocaSize >> 1) - 1) // allow sentinel value to be accessed
  1.1156 +        {
  1.1157 +            const uint16 * pShortTable = reinterpret_cast<const uint16 *>(pLoca);
  1.1158 +            return (be::peek<uint16>(pShortTable + nGlyphId) << 1);
  1.1159 +        }
  1.1160 +    }
  1.1161 +    
  1.1162 +    if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat)
  1.1163 +    { // loca entries are four bytes
  1.1164 +        if (nGlyphId < (lLocaSize >> 2) - 1)
  1.1165 +        {
  1.1166 +            const uint32 * pLongTable = reinterpret_cast<const uint32 *>(pLoca);
  1.1167 +            return be::peek<uint32>(pLongTable + nGlyphId);
  1.1168 +        }
  1.1169 +    }
  1.1170 +
  1.1171 +    // only get here if glyph id was bad
  1.1172 +    return -1;
  1.1173 +    //throw std::out_of_range("glyph id out of range for font");
  1.1174 +}
  1.1175 +
  1.1176 +/*----------------------------------------------------------------------------------------------
  1.1177 +    Return a pointer into the glyf table based on the given offset (from LocaLookup).
  1.1178 +    Return NULL on error.
  1.1179 +----------------------------------------------------------------------------------------------*/
  1.1180 +void * GlyfLookup(const void * pGlyf, size_t nGlyfOffset, size_t nTableLen)
  1.1181 +{
  1.1182 +    const uint8 * pByte = reinterpret_cast<const uint8 *>(pGlyf);
  1.1183 +        if (nGlyfOffset == size_t(-1) || nGlyfOffset >= nTableLen)
  1.1184 +            return NULL;
  1.1185 +    return const_cast<uint8 *>(pByte + nGlyfOffset);
  1.1186 +}
  1.1187 +
  1.1188 +/*----------------------------------------------------------------------------------------------
  1.1189 +    Get the bounding box coordinates for a simple glyf entry (non-composite).
  1.1190 +    Return true if successful, false otherwise.
  1.1191 +----------------------------------------------------------------------------------------------*/
  1.1192 +bool GlyfBox(const void * pSimpleGlyf, int & xMin, int & yMin, 
  1.1193 +                      int & xMax, int & yMax)
  1.1194 +{
  1.1195 +    const Sfnt::Glyph * pGlyph = reinterpret_cast<const Sfnt::Glyph *>(pSimpleGlyf);
  1.1196 +
  1.1197 +    xMin = be::swap(pGlyph->x_min);
  1.1198 +    yMin = be::swap(pGlyph->y_min);
  1.1199 +    xMax = be::swap(pGlyph->x_max);
  1.1200 +    yMax = be::swap(pGlyph->y_max);
  1.1201 +
  1.1202 +    return true;
  1.1203 +}
  1.1204 +
  1.1205 +#ifdef ALL_TTFUTILS
  1.1206 +/*----------------------------------------------------------------------------------------------
  1.1207 +    Return the number of contours for a simple glyf entry (non-composite)
  1.1208 +    Returning -1 means this is a composite glyph
  1.1209 +----------------------------------------------------------------------------------------------*/
  1.1210 +int GlyfContourCount(const void * pSimpleGlyf)
  1.1211 +{
  1.1212 +    const Sfnt::Glyph * pGlyph = reinterpret_cast<const Sfnt::Glyph *>(pSimpleGlyf);
  1.1213 +    return be::swap(pGlyph->number_of_contours); // -1 means composite glyph
  1.1214 +}
  1.1215 +
  1.1216 +/*----------------------------------------------------------------------------------------------
  1.1217 +    Get the point numbers for the end points of the glyph contours for a simple
  1.1218 +    glyf entry (non-composite). 
  1.1219 +    cnPointsTotal - count of contours from GlyfContourCount(); (same as number of end points)
  1.1220 +    prgnContourEndPoints - should point to a buffer large enough to hold cnPoints integers
  1.1221 +    cnPoints - count of points placed in above range
  1.1222 +    Return true if successful, false otherwise.
  1.1223 +        False could indicate a multi-level composite glyphs.
  1.1224 +----------------------------------------------------------------------------------------------*/
  1.1225 +bool GlyfContourEndPoints(const void * pSimpleGlyf, int * prgnContourEndPoint, 
  1.1226 +                                   int cnPointsTotal, int & cnPoints)
  1.1227 +{
  1.1228 +    const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf);
  1.1229 +
  1.1230 +    int cContours = be::swap(pGlyph->number_of_contours);
  1.1231 +    if (cContours < 0)
  1.1232 +        return false; // this method isn't supposed handle composite glyphs
  1.1233 +
  1.1234 +    for (int i = 0; i < cContours && i < cnPointsTotal; i++)
  1.1235 +    {
  1.1236 +        prgnContourEndPoint[i] = be::swap(pGlyph->end_pts_of_contours[i]);
  1.1237 +    }
  1.1238 +
  1.1239 +    cnPoints = cContours;
  1.1240 +    return true;
  1.1241 +}
  1.1242 +
  1.1243 +/*----------------------------------------------------------------------------------------------
  1.1244 +    Get the points for a simple glyf entry (non-composite)
  1.1245 +    cnPointsTotal - count of points from largest end point obtained from GlyfContourEndPoints
  1.1246 +    prgnX & prgnY - should point to buffers large enough to hold cnPointsTotal integers
  1.1247 +        The ranges are parallel so that coordinates for point(n) are found at offset n in both 
  1.1248 +        ranges. This is raw point data with relative coordinates.
  1.1249 +    prgbFlag - should point to a buffer a large enough to hold cnPointsTotal bytes
  1.1250 +        This range is parallel to the prgnX & prgnY
  1.1251 +    cnPoints - count of points placed in above ranges
  1.1252 +    Return true if successful, false otherwise. 
  1.1253 +        False could indicate a composite glyph
  1.1254 +----------------------------------------------------------------------------------------------*/
  1.1255 +bool GlyfPoints(const void * pSimpleGlyf, int * prgnX, int * prgnY, 
  1.1256 +        char * prgbFlag, int cnPointsTotal, int & cnPoints)
  1.1257 +{
  1.1258 +    using namespace Sfnt;
  1.1259 +    
  1.1260 +    const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf);
  1.1261 +    int cContours = be::swap(pGlyph->number_of_contours);
  1.1262 +    // return false for composite glyph
  1.1263 +    if (cContours <= 0)
  1.1264 +        return false;
  1.1265 +    int cPts = be::swap(pGlyph->end_pts_of_contours[cContours - 1]) + 1;
  1.1266 +    if (cPts > cnPointsTotal)
  1.1267 +        return false;
  1.1268 +
  1.1269 +    // skip over bounding box data & point to byte count of instructions (hints)
  1.1270 +    const uint8 * pbGlyph = reinterpret_cast<const uint8 *>
  1.1271 +        (&pGlyph->end_pts_of_contours[cContours]);
  1.1272 +    
  1.1273 +    // skip over hints & point to first flag
  1.1274 +    int cbHints = be::swap(*(uint16 *)pbGlyph);
  1.1275 +    pbGlyph += sizeof(uint16);
  1.1276 +    pbGlyph += cbHints;
  1.1277 +
  1.1278 +    // load flags & point to first x coordinate
  1.1279 +    int iFlag = 0;
  1.1280 +    while (iFlag < cPts)
  1.1281 +    {
  1.1282 +        if (!(*pbGlyph & SimpleGlyph::Repeat))
  1.1283 +        { // flag isn't repeated
  1.1284 +            prgbFlag[iFlag] = (char)*pbGlyph;
  1.1285 +            pbGlyph++;
  1.1286 +            iFlag++;
  1.1287 +        }
  1.1288 +        else
  1.1289 +        { // flag is repeated; count specified by next byte
  1.1290 +            char chFlag = (char)*pbGlyph;
  1.1291 +            pbGlyph++;
  1.1292 +            int cFlags = (int)*pbGlyph;
  1.1293 +            pbGlyph++;
  1.1294 +            prgbFlag[iFlag] = chFlag;
  1.1295 +            iFlag++;
  1.1296 +            for (int i = 0; i < cFlags; i++)
  1.1297 +            {
  1.1298 +                prgbFlag[iFlag + i] = chFlag;
  1.1299 +            }
  1.1300 +            iFlag += cFlags;
  1.1301 +        }
  1.1302 +    }
  1.1303 +    if (iFlag != cPts)
  1.1304 +        return false;
  1.1305 +
  1.1306 +    // load x coordinates
  1.1307 +    iFlag = 0;
  1.1308 +    while (iFlag < cPts)
  1.1309 +    {
  1.1310 +        if (prgbFlag[iFlag] & SimpleGlyph::XShort)
  1.1311 +        {
  1.1312 +            prgnX[iFlag] = *pbGlyph;
  1.1313 +            if (!(prgbFlag[iFlag] & SimpleGlyph::XIsPos))
  1.1314 +            {
  1.1315 +                prgnX[iFlag] = -prgnX[iFlag];
  1.1316 +            }
  1.1317 +            pbGlyph++;
  1.1318 +        }
  1.1319 +        else
  1.1320 +        {
  1.1321 +            if (prgbFlag[iFlag] & SimpleGlyph::XIsSame)
  1.1322 +            {
  1.1323 +                prgnX[iFlag] = 0;
  1.1324 +                // do NOT increment pbGlyph
  1.1325 +            }
  1.1326 +            else
  1.1327 +            {
  1.1328 +                prgnX[iFlag] = be::swap(*(int16 *)pbGlyph);
  1.1329 +                pbGlyph += sizeof(int16);
  1.1330 +            }
  1.1331 +        }
  1.1332 +        iFlag++;
  1.1333 +    }
  1.1334 +        
  1.1335 +    // load y coordinates
  1.1336 +    iFlag = 0;
  1.1337 +    while (iFlag < cPts)
  1.1338 +    {
  1.1339 +        if (prgbFlag[iFlag] & SimpleGlyph::YShort)
  1.1340 +        {
  1.1341 +            prgnY[iFlag] = *pbGlyph;
  1.1342 +            if (!(prgbFlag[iFlag] & SimpleGlyph::YIsPos))
  1.1343 +            {
  1.1344 +                prgnY[iFlag] = -prgnY[iFlag];
  1.1345 +            }
  1.1346 +            pbGlyph++;
  1.1347 +        }
  1.1348 +        else
  1.1349 +        {
  1.1350 +            if (prgbFlag[iFlag] & SimpleGlyph::YIsSame)
  1.1351 +            {
  1.1352 +                prgnY[iFlag] = 0;
  1.1353 +                // do NOT increment pbGlyph
  1.1354 +            }
  1.1355 +            else
  1.1356 +            {
  1.1357 +                prgnY[iFlag] = be::swap(*(int16 *)pbGlyph);
  1.1358 +                pbGlyph += sizeof(int16);
  1.1359 +            }
  1.1360 +        }
  1.1361 +        iFlag++;
  1.1362 +    }
  1.1363 +        
  1.1364 +    cnPoints = cPts;
  1.1365 +    return true;
  1.1366 +}
  1.1367 +
  1.1368 +/*----------------------------------------------------------------------------------------------
  1.1369 +    Fill prgnCompId with the component Glyph IDs from pSimpleGlyf.
  1.1370 +    Client must allocate space before calling.
  1.1371 +    pSimpleGlyf - assumed to point to a composite glyph
  1.1372 +    cCompIdTotal - the number of elements in prgnCompId 
  1.1373 +    cCompId  - the total number of Glyph IDs stored in prgnCompId
  1.1374 +    Return true if successful, false otherwise
  1.1375 +        False could indicate a non-composite glyph or the input array was not big enough
  1.1376 +----------------------------------------------------------------------------------------------*/
  1.1377 +bool GetComponentGlyphIds(const void * pSimpleGlyf, int * prgnCompId, 
  1.1378 +        size_t cnCompIdTotal, size_t & cnCompId)
  1.1379 +{
  1.1380 +    using namespace Sfnt;
  1.1381 +    
  1.1382 +    if (GlyfContourCount(pSimpleGlyf) >= 0)
  1.1383 +        return false;
  1.1384 +
  1.1385 +    const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf);
  1.1386 +    // for a composite glyph, the special data begins here
  1.1387 +    const uint8 * pbGlyph = reinterpret_cast<const uint8 *>(&pGlyph->end_pts_of_contours[0]);
  1.1388 +
  1.1389 +    uint16 GlyphFlags;
  1.1390 +    size_t iCurrentComp = 0;
  1.1391 +    do 
  1.1392 +    {
  1.1393 +        GlyphFlags = be::swap(*((uint16 *)pbGlyph));
  1.1394 +        pbGlyph += sizeof(uint16);
  1.1395 +        prgnCompId[iCurrentComp++] = be::swap(*((uint16 *)pbGlyph));
  1.1396 +        pbGlyph += sizeof(uint16);
  1.1397 +        if (iCurrentComp >= cnCompIdTotal) 
  1.1398 +            return false;
  1.1399 +        int nOffset = 0;
  1.1400 +        nOffset += GlyphFlags & CompoundGlyph::Arg1Arg2Words ? 4 : 2;
  1.1401 +        nOffset += GlyphFlags & CompoundGlyph::HaveScale ? 2 : 0;
  1.1402 +        nOffset += GlyphFlags & CompoundGlyph::HaveXAndYScale  ? 4 : 0;
  1.1403 +        nOffset += GlyphFlags & CompoundGlyph::HaveTwoByTwo  ? 8 :  0;
  1.1404 +        pbGlyph += nOffset;
  1.1405 +    } while (GlyphFlags & CompoundGlyph::MoreComponents);
  1.1406 +
  1.1407 +    cnCompId = iCurrentComp;
  1.1408 +
  1.1409 +    return true;
  1.1410 +}
  1.1411 +
  1.1412 +/*----------------------------------------------------------------------------------------------
  1.1413 +    Return info on how a component glyph is to be placed
  1.1414 +    pSimpleGlyph - assumed to point to a composite glyph
  1.1415 +    nCompId - glyph id for component of interest
  1.1416 +    bOffset - if true, a & b are the x & y offsets for this component
  1.1417 +              if false, b is the point on this component that is attaching to point a on the
  1.1418 +                preceding glyph
  1.1419 +    Return true if successful, false otherwise
  1.1420 +        False could indicate a non-composite glyph or that component wasn't found
  1.1421 +----------------------------------------------------------------------------------------------*/
  1.1422 +bool GetComponentPlacement(const void * pSimpleGlyf, int nCompId,
  1.1423 +                                    bool fOffset, int & a, int & b)
  1.1424 +{
  1.1425 +    using namespace Sfnt;
  1.1426 +    
  1.1427 +    if (GlyfContourCount(pSimpleGlyf) >= 0)
  1.1428 +        return false;
  1.1429 +
  1.1430 +    const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf);
  1.1431 +    // for a composite glyph, the special data begins here
  1.1432 +    const uint8 * pbGlyph = reinterpret_cast<const uint8 *>(&pGlyph->end_pts_of_contours[0]);
  1.1433 +
  1.1434 +    uint16 GlyphFlags;
  1.1435 +    do 
  1.1436 +    {
  1.1437 +        GlyphFlags = be::swap(*((uint16 *)pbGlyph));
  1.1438 +        pbGlyph += sizeof(uint16);
  1.1439 +        if (be::swap(*((uint16 *)pbGlyph)) == nCompId)
  1.1440 +        {
  1.1441 +            pbGlyph += sizeof(uint16); // skip over glyph id of component
  1.1442 +            fOffset = (GlyphFlags & CompoundGlyph::ArgsAreXYValues) == CompoundGlyph::ArgsAreXYValues;
  1.1443 +
  1.1444 +            if (GlyphFlags & CompoundGlyph::Arg1Arg2Words )
  1.1445 +            {
  1.1446 +                a = be::swap(*(int16 *)pbGlyph);
  1.1447 +                pbGlyph += sizeof(int16);
  1.1448 +                b = be::swap(*(int16 *)pbGlyph);
  1.1449 +                pbGlyph += sizeof(int16);
  1.1450 +            }
  1.1451 +            else
  1.1452 +            { // args are signed bytes
  1.1453 +                a = *pbGlyph++;
  1.1454 +                b = *pbGlyph++;
  1.1455 +            }
  1.1456 +            return true;
  1.1457 +        }
  1.1458 +        pbGlyph += sizeof(uint16); // skip over glyph id of component
  1.1459 +        int nOffset = 0;
  1.1460 +        nOffset += GlyphFlags & CompoundGlyph::Arg1Arg2Words  ? 4 : 2;
  1.1461 +        nOffset += GlyphFlags & CompoundGlyph::HaveScale ? 2 : 0;
  1.1462 +        nOffset += GlyphFlags & CompoundGlyph::HaveXAndYScale  ? 4 : 0;
  1.1463 +        nOffset += GlyphFlags & CompoundGlyph::HaveTwoByTwo  ? 8 :  0;
  1.1464 +        pbGlyph += nOffset;
  1.1465 +    } while (GlyphFlags & CompoundGlyph::MoreComponents);
  1.1466 +
  1.1467 +    // didn't find requested component
  1.1468 +    fOffset = true;
  1.1469 +    a = 0;
  1.1470 +    b = 0;
  1.1471 +    return false;
  1.1472 +}
  1.1473 +
  1.1474 +/*----------------------------------------------------------------------------------------------
  1.1475 +    Return info on how a component glyph is to be transformed
  1.1476 +    pSimpleGlyph - assumed to point to a composite glyph
  1.1477 +    nCompId - glyph id for component of interest
  1.1478 +    flt11, flt11, flt11, flt11 - a 2x2 matrix giving the transform
  1.1479 +    bTransOffset - whether to transform the offset from above method 
  1.1480 +        The spec is unclear about the meaning of this flag
  1.1481 +        Currently - initialize to true for MS rasterizer and false for Mac rasterizer, then
  1.1482 +            on return it will indicate whether transform should apply to offset (MSDN CD 10/99)
  1.1483 +    Return true if successful, false otherwise
  1.1484 +        False could indicate a non-composite glyph or that component wasn't found
  1.1485 +----------------------------------------------------------------------------------------------*/
  1.1486 +bool GetComponentTransform(const void * pSimpleGlyf, int nCompId, 
  1.1487 +                                    float & flt11, float & flt12, float & flt21, float & flt22, 
  1.1488 +                                    bool & fTransOffset)
  1.1489 +{
  1.1490 +    using namespace Sfnt;
  1.1491 +    
  1.1492 +    if (GlyfContourCount(pSimpleGlyf) >= 0)
  1.1493 +        return false;
  1.1494 +
  1.1495 +    const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf);
  1.1496 +    // for a composite glyph, the special data begins here
  1.1497 +    const uint8 * pbGlyph = reinterpret_cast<const uint8 *>(&pGlyph->end_pts_of_contours[0]);
  1.1498 +
  1.1499 +    uint16 GlyphFlags;
  1.1500 +    do 
  1.1501 +    {
  1.1502 +        GlyphFlags = be::swap(*((uint16 *)pbGlyph));
  1.1503 +        pbGlyph += sizeof(uint16);
  1.1504 +        if (be::swap(*((uint16 *)pbGlyph)) == nCompId)
  1.1505 +        {
  1.1506 +            pbGlyph += sizeof(uint16); // skip over glyph id of component
  1.1507 +            pbGlyph += GlyphFlags & CompoundGlyph::Arg1Arg2Words  ? 4 : 2; // skip over placement data
  1.1508 +
  1.1509 +            if (fTransOffset) // MS rasterizer
  1.1510 +                fTransOffset = !(GlyphFlags & CompoundGlyph::UnscaledOffset); 
  1.1511 +            else // Apple rasterizer
  1.1512 +                fTransOffset = (GlyphFlags & CompoundGlyph::ScaledOffset) != 0;
  1.1513 +
  1.1514 +            if (GlyphFlags & CompoundGlyph::HaveScale)
  1.1515 +            {
  1.1516 +                flt11 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph));
  1.1517 +                pbGlyph += sizeof(uint16);
  1.1518 +                flt12 = 0;
  1.1519 +                flt21 = 0;
  1.1520 +                flt22 = flt11;
  1.1521 +            }
  1.1522 +            else if (GlyphFlags & CompoundGlyph::HaveXAndYScale)
  1.1523 +            {
  1.1524 +                flt11 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph));
  1.1525 +                pbGlyph += sizeof(uint16);
  1.1526 +                flt12 = 0;
  1.1527 +                flt21 = 0;
  1.1528 +                flt22 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph));
  1.1529 +                pbGlyph += sizeof(uint16);
  1.1530 +            }
  1.1531 +            else if (GlyphFlags & CompoundGlyph::HaveTwoByTwo)
  1.1532 +            {
  1.1533 +                flt11 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph));
  1.1534 +                pbGlyph += sizeof(uint16);
  1.1535 +                flt12 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph));
  1.1536 +                pbGlyph += sizeof(uint16);
  1.1537 +                flt21 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph));
  1.1538 +                pbGlyph += sizeof(uint16);
  1.1539 +                flt22 = fixed_to_float<14>(be::swap(*(uint16 *)pbGlyph));
  1.1540 +                pbGlyph += sizeof(uint16);
  1.1541 +            }
  1.1542 +            else
  1.1543 +            { // identity transform
  1.1544 +                flt11 = 1.0;
  1.1545 +                flt12 = 0.0;
  1.1546 +                flt21 = 0.0;
  1.1547 +                flt22 = 1.0;
  1.1548 +            }
  1.1549 +            return true;
  1.1550 +        }
  1.1551 +        pbGlyph += sizeof(uint16); // skip over glyph id of component
  1.1552 +        int nOffset = 0;
  1.1553 +        nOffset += GlyphFlags & CompoundGlyph::Arg1Arg2Words  ? 4 : 2;
  1.1554 +        nOffset += GlyphFlags & CompoundGlyph::HaveScale ? 2 : 0;
  1.1555 +        nOffset += GlyphFlags & CompoundGlyph::HaveXAndYScale  ? 4 : 0;
  1.1556 +        nOffset += GlyphFlags & CompoundGlyph::HaveTwoByTwo  ? 8 :  0;
  1.1557 +        pbGlyph += nOffset;
  1.1558 +    } while (GlyphFlags & CompoundGlyph::MoreComponents);
  1.1559 +
  1.1560 +    // didn't find requested component
  1.1561 +    fTransOffset = false;
  1.1562 +    flt11 = 1;
  1.1563 +    flt12 = 0;
  1.1564 +    flt21 = 0;
  1.1565 +    flt22 = 1;
  1.1566 +    return false;
  1.1567 +}
  1.1568 +#endif
  1.1569 +
  1.1570 +/*----------------------------------------------------------------------------------------------
  1.1571 +    Return a pointer into the glyf table based on the given tables and Glyph ID
  1.1572 +    Since this method doesn't check for spaces, it is good to call IsSpace before using it.
  1.1573 +    Return NULL on error.
  1.1574 +----------------------------------------------------------------------------------------------*/
  1.1575 +void * GlyfLookup(gid16 nGlyphId, const void * pGlyf, const void * pLoca, 
  1.1576 +                           size_t lGlyfSize, size_t lLocaSize, const void * pHead)
  1.1577 +{
  1.1578 +    // test for valid glyph id
  1.1579 +    // CheckTable verifies the index_to_loc_format is valid
  1.1580 +    
  1.1581 +    const Sfnt::FontHeader * pTable 
  1.1582 +        = reinterpret_cast<const Sfnt::FontHeader *>(pHead);
  1.1583 +
  1.1584 +    if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::ShortIndexLocFormat)
  1.1585 +    { // loca entries are two bytes (and have been divided by two)
  1.1586 +        if (nGlyphId >= (lLocaSize >> 1) - 1) // don't allow nGlyphId to access sentinel
  1.1587 +        {
  1.1588 +//          throw std::out_of_range("glyph id out of range for font");
  1.1589 +            return NULL;
  1.1590 +        }
  1.1591 +    }
  1.1592 +    if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat)
  1.1593 +    { // loca entries are four bytes
  1.1594 +        if (nGlyphId >= (lLocaSize >> 2) - 1)
  1.1595 +        {
  1.1596 +//          throw std::out_of_range("glyph id out of range for font");
  1.1597 +            return NULL;
  1.1598 +        }
  1.1599 +    }
  1.1600 +
  1.1601 +    long lGlyfOffset = LocaLookup(nGlyphId, pLoca, lLocaSize, pHead);
  1.1602 +    void * pSimpleGlyf = GlyfLookup(pGlyf, lGlyfOffset, lGlyfSize); // invalid loca offset returns null
  1.1603 +    return pSimpleGlyf;
  1.1604 +}
  1.1605 +
  1.1606 +#ifdef ALL_TTFUTILS
  1.1607 +/*----------------------------------------------------------------------------------------------
  1.1608 +    Determine if a particular Glyph ID has any data in the glyf table. If it is white space,
  1.1609 +    there will be no glyf data, though there will be metric data in hmtx, etc.
  1.1610 +----------------------------------------------------------------------------------------------*/
  1.1611 +bool IsSpace(gid16 nGlyphId, const void * pLoca, size_t lLocaSize, const void * pHead)
  1.1612 +{
  1.1613 +    size_t lGlyfOffset = LocaLookup(nGlyphId, pLoca, lLocaSize, pHead);
  1.1614 +    
  1.1615 +    // the +1 should always work because there is a sentinel value at the end of the loca table
  1.1616 +    size_t lNextGlyfOffset = LocaLookup(nGlyphId + 1, pLoca, lLocaSize, pHead);
  1.1617 +
  1.1618 +    return (lNextGlyfOffset - lGlyfOffset) == 0;
  1.1619 +}
  1.1620 +
  1.1621 +/*----------------------------------------------------------------------------------------------
  1.1622 +    Determine if a particular Glyph ID is a multi-level composite.
  1.1623 +----------------------------------------------------------------------------------------------*/
  1.1624 +bool IsDeepComposite(gid16 nGlyphId, const void * pGlyf, const void * pLoca, 
  1.1625 +                    size_t lGlyfSize, long lLocaSize, const void * pHead)
  1.1626 +{
  1.1627 +    if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) {return false;}
  1.1628 +
  1.1629 +    void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lGlyfSize, lLocaSize, pHead);
  1.1630 +    if (pSimpleGlyf == NULL)
  1.1631 +        return false; // no way to really indicate an error occured here
  1.1632 +
  1.1633 +    if (GlyfContourCount(pSimpleGlyf) >= 0)
  1.1634 +        return false;
  1.1635 +
  1.1636 +    int rgnCompId[kMaxGlyphComponents]; // assumes only a limited number of glyph components
  1.1637 +    size_t cCompIdTotal = kMaxGlyphComponents;
  1.1638 +    size_t cCompId = 0;
  1.1639 +
  1.1640 +    if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId))
  1.1641 +        return false;
  1.1642 +
  1.1643 +    for (size_t i = 0; i < cCompId; i++)
  1.1644 +    {
  1.1645 +        pSimpleGlyf = GlyfLookup(static_cast<gid16>(rgnCompId[i]), 
  1.1646 +                            pGlyf, pLoca, lGlyfSize, lLocaSize, pHead);
  1.1647 +        if (pSimpleGlyf == NULL) {return false;}
  1.1648 +
  1.1649 +        if (GlyfContourCount(pSimpleGlyf) < 0)
  1.1650 +            return true;
  1.1651 +    }
  1.1652 +
  1.1653 +    return false;
  1.1654 +}
  1.1655 +
  1.1656 +/*----------------------------------------------------------------------------------------------
  1.1657 +    Get the bounding box coordinates based on the given tables and Glyph ID
  1.1658 +    Handles both simple and composite glyphs.
  1.1659 +    Return true if successful, false otherwise. On false, all point values will be INT_MIN
  1.1660 +        False may indicate a white space glyph
  1.1661 +----------------------------------------------------------------------------------------------*/
  1.1662 +bool GlyfBox(gid16  nGlyphId, const void * pGlyf, const void * pLoca, 
  1.1663 +        size_t lGlyfSize, size_t lLocaSize, const void * pHead, int & xMin, int & yMin, int & xMax, int & yMax)
  1.1664 +{
  1.1665 +    xMin = yMin = xMax = yMax = INT_MIN;
  1.1666 +
  1.1667 +    if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) {return false;}
  1.1668 +
  1.1669 +    void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lGlyfSize, lLocaSize, pHead);
  1.1670 +    if (pSimpleGlyf == NULL) {return false;}
  1.1671 +
  1.1672 +    return GlyfBox(pSimpleGlyf, xMin, yMin, xMax, yMax);
  1.1673 +}
  1.1674 +
  1.1675 +/*----------------------------------------------------------------------------------------------
  1.1676 +    Get the number of contours based on the given tables and Glyph ID
  1.1677 +    Handles both simple and composite glyphs.
  1.1678 +    Return true if successful, false otherwise. On false, cnContours will be INT_MIN
  1.1679 +        False may indicate a white space glyph or a multi-level composite glyph.
  1.1680 +----------------------------------------------------------------------------------------------*/
  1.1681 +bool GlyfContourCount(gid16 nGlyphId, const void * pGlyf, const void * pLoca, 
  1.1682 +    size_t lGlyfSize, size_t lLocaSize, const void * pHead, size_t & cnContours)
  1.1683 +{
  1.1684 +    cnContours = static_cast<size_t>(INT_MIN);
  1.1685 +
  1.1686 +    if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) {return false;}
  1.1687 +
  1.1688 +    void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lGlyfSize, lLocaSize, pHead);
  1.1689 +    if (pSimpleGlyf == NULL) {return false;}
  1.1690 +
  1.1691 +    int cRtnContours = GlyfContourCount(pSimpleGlyf);
  1.1692 +    if (cRtnContours >= 0)
  1.1693 +    {
  1.1694 +        cnContours = size_t(cRtnContours);
  1.1695 +        return true;
  1.1696 +    }
  1.1697 +        
  1.1698 +    //handle composite glyphs
  1.1699 +
  1.1700 +    int rgnCompId[kMaxGlyphComponents]; // assumes no glyph will be made of more than 8 components
  1.1701 +    size_t cCompIdTotal = kMaxGlyphComponents;
  1.1702 +    size_t cCompId = 0;
  1.1703 +
  1.1704 +    if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId))
  1.1705 +        return false;
  1.1706 +
  1.1707 +    cRtnContours = 0;
  1.1708 +    int cTmp = 0;
  1.1709 +    for (size_t i = 0; i < cCompId; i++)
  1.1710 +    {
  1.1711 +        if (IsSpace(static_cast<gid16>(rgnCompId[i]), pLoca, lLocaSize, pHead)) {return false;}
  1.1712 +        pSimpleGlyf = GlyfLookup(static_cast<gid16>(rgnCompId[i]), 
  1.1713 +                                 pGlyf, pLoca, lGlyfSize, lLocaSize, pHead);
  1.1714 +        if (pSimpleGlyf == 0) {return false;}
  1.1715 +        // return false on multi-level composite
  1.1716 +        if ((cTmp = GlyfContourCount(pSimpleGlyf)) < 0) 
  1.1717 +            return false;
  1.1718 +        cRtnContours += cTmp;
  1.1719 +    }
  1.1720 +
  1.1721 +    cnContours = size_t(cRtnContours);
  1.1722 +    return true;
  1.1723 +}
  1.1724 +
  1.1725 +/*----------------------------------------------------------------------------------------------
  1.1726 +    Get the point numbers for the end points of the glyph contours based on the given tables 
  1.1727 +    and Glyph ID
  1.1728 +    Handles both simple and composite glyphs.
  1.1729 +    cnPoints - count of contours from GlyfContourCount (same as number of end points)
  1.1730 +    prgnContourEndPoints - should point to a buffer large enough to hold cnPoints integers
  1.1731 +    Return true if successful, false otherwise. On false, all end points are INT_MIN
  1.1732 +        False may indicate a white space glyph or a multi-level composite glyph.
  1.1733 +----------------------------------------------------------------------------------------------*/
  1.1734 +bool GlyfContourEndPoints(gid16 nGlyphId, const void * pGlyf, const void * pLoca, 
  1.1735 +    size_t lGlyfSize, size_t lLocaSize, const void * pHead,
  1.1736 +    int * prgnContourEndPoint, size_t cnPoints)
  1.1737 +{
  1.1738 +        memset(prgnContourEndPoint, 0xFF, cnPoints * sizeof(int));
  1.1739 +    // std::fill_n(prgnContourEndPoint, cnPoints, INT_MIN);
  1.1740 +
  1.1741 +    if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) {return false;}
  1.1742 +
  1.1743 +    void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lGlyfSize, lLocaSize, pHead);
  1.1744 +    if (pSimpleGlyf == NULL) {return false;}
  1.1745 +
  1.1746 +    int cContours = GlyfContourCount(pSimpleGlyf);
  1.1747 +    int cActualPts = 0;
  1.1748 +    if (cContours > 0)
  1.1749 +        return GlyfContourEndPoints(pSimpleGlyf, prgnContourEndPoint, cnPoints, cActualPts);
  1.1750 +    
  1.1751 +    // handle composite glyphs
  1.1752 +    
  1.1753 +    int rgnCompId[kMaxGlyphComponents]; // assumes no glyph will be made of more than 8 components
  1.1754 +    size_t cCompIdTotal = kMaxGlyphComponents;
  1.1755 +    size_t cCompId = 0;
  1.1756 +
  1.1757 +    if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId))
  1.1758 +        return false;
  1.1759 +
  1.1760 +    int * prgnCurrentEndPoint = prgnContourEndPoint;
  1.1761 +    int cCurrentPoints = cnPoints;
  1.1762 +    int nPrevPt = 0;
  1.1763 +    for (size_t i = 0; i < cCompId; i++)
  1.1764 +    {
  1.1765 +        if (IsSpace(static_cast<gid16>(rgnCompId[i]), pLoca, lLocaSize, pHead)) {return false;}
  1.1766 +        pSimpleGlyf = GlyfLookup(static_cast<gid16>(rgnCompId[i]), pGlyf, pLoca, lGlyfSize, lLocaSize, pHead);
  1.1767 +        if (pSimpleGlyf == NULL) {return false;}
  1.1768 +        // returns false on multi-level composite
  1.1769 +        if (!GlyfContourEndPoints(pSimpleGlyf, prgnCurrentEndPoint, cCurrentPoints, cActualPts))
  1.1770 +            return false;
  1.1771 +        // points in composite are numbered sequentially as components are added
  1.1772 +        //  must adjust end point numbers for new point numbers
  1.1773 +        for (int j = 0; j < cActualPts; j++)
  1.1774 +            prgnCurrentEndPoint[j] += nPrevPt;
  1.1775 +        nPrevPt = prgnCurrentEndPoint[cActualPts - 1] + 1;
  1.1776 +
  1.1777 +        prgnCurrentEndPoint += cActualPts;
  1.1778 +        cCurrentPoints -= cActualPts;
  1.1779 +    }
  1.1780 +
  1.1781 +    return true;
  1.1782 +}
  1.1783 +
  1.1784 +/*----------------------------------------------------------------------------------------------
  1.1785 +    Get the points for a glyph based on the given tables and Glyph ID
  1.1786 +    Handles both simple and composite glyphs.
  1.1787 +    cnPoints - count of points from largest end point obtained from GlyfContourEndPoints
  1.1788 +    prgnX & prgnY - should point to buffers large enough to hold cnPoints integers
  1.1789 +        The ranges are parallel so that coordinates for point(n) are found at offset n in 
  1.1790 +        both ranges. These points are in absolute coordinates.
  1.1791 +    prgfOnCurve - should point to a buffer a large enough to hold cnPoints bytes (bool)
  1.1792 +        This range is parallel to the prgnX & prgnY
  1.1793 +    Return true if successful, false otherwise. On false, all points may be INT_MIN
  1.1794 +        False may indicate a white space glyph, a multi-level composite, or a corrupt font
  1.1795 +    // TODO: doesn't support composite glyphs whose components are themselves components
  1.1796 +        It's not clear from the TTF spec when the transforms should be applied. Should the 
  1.1797 +        transform be done before or after attachment point calcs? (current code - before) 
  1.1798 +        Should the transform be applied to other offsets? (currently - no; however commented 
  1.1799 +        out code is in place so that if CompoundGlyph::UnscaledOffset on the MS rasterizer is 
  1.1800 +        clear (typical) then yes, and if CompoundGlyph::ScaledOffset on the Apple rasterizer is 
  1.1801 +        clear (typical?) then no). See GetComponentTransform.
  1.1802 +        It's also unclear where point numbering with attachment poinst starts 
  1.1803 +        (currently - first point number is relative to whole glyph, second point number is 
  1.1804 +        relative to current glyph). 
  1.1805 +----------------------------------------------------------------------------------------------*/
  1.1806 +bool GlyfPoints(gid16 nGlyphId, const void * pGlyf,
  1.1807 +        const void * pLoca, size_t lGlyfSize, size_t lLocaSize, const void * pHead,
  1.1808 +        const int * /*prgnContourEndPoint*/, size_t /*cnEndPoints*/,
  1.1809 +        int * prgnX, int * prgnY, bool * prgfOnCurve, size_t cnPoints)
  1.1810 +{
  1.1811 +        memset(prgnX, 0x7F, cnPoints * sizeof(int));
  1.1812 +        memset(prgnY, 0x7F, cnPoints * sizeof(int));
  1.1813 +
  1.1814 +    if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) 
  1.1815 +        return false;
  1.1816 +
  1.1817 +    void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lGlyfSize, lLocaSize, pHead);
  1.1818 +    if (pSimpleGlyf == NULL)
  1.1819 +        return false;
  1.1820 +
  1.1821 +    int cContours = GlyfContourCount(pSimpleGlyf);
  1.1822 +    int cActualPts;
  1.1823 +    if (cContours > 0)
  1.1824 +    {
  1.1825 +        if (!GlyfPoints(pSimpleGlyf, prgnX, prgnY, (char *)prgfOnCurve, cnPoints, cActualPts))
  1.1826 +            return false;
  1.1827 +        CalcAbsolutePoints(prgnX, prgnY, cnPoints);
  1.1828 +        SimplifyFlags((char *)prgfOnCurve, cnPoints);
  1.1829 +        return true;
  1.1830 +    }
  1.1831 +
  1.1832 +    // handle composite glyphs  
  1.1833 +    int rgnCompId[kMaxGlyphComponents]; // assumes no glyph will be made of more than 8 components
  1.1834 +    size_t cCompIdTotal = kMaxGlyphComponents;
  1.1835 +    size_t cCompId = 0;
  1.1836 +
  1.1837 +    // this will fail if there are more components than there is room for
  1.1838 +    if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId))
  1.1839 +        return false;
  1.1840 +
  1.1841 +    int * prgnCurrentX = prgnX;
  1.1842 +    int * prgnCurrentY = prgnY;
  1.1843 +    char * prgbCurrentFlag = (char *)prgfOnCurve; // converting bool to char should be safe
  1.1844 +    int cCurrentPoints = cnPoints;
  1.1845 +    bool fOffset = true, fTransOff = true;
  1.1846 +    int a, b;
  1.1847 +    float flt11, flt12, flt21, flt22;
  1.1848 +    // int * prgnPrevX = prgnX; // in case first att pt number relative to preceding glyph
  1.1849 +    // int * prgnPrevY = prgnY;
  1.1850 +    for (size_t i = 0; i < cCompId; i++)
  1.1851 +    {
  1.1852 +        if (IsSpace(static_cast<gid16>(rgnCompId[i]), pLoca, lLocaSize, pHead)) {return false;}
  1.1853 +        void * pCompGlyf = GlyfLookup(static_cast<gid16>(rgnCompId[i]), pGlyf, pLoca, lGlyfSize, lLocaSize, pHead);
  1.1854 +        if (pCompGlyf == NULL) {return false;}
  1.1855 +        // returns false on multi-level composite
  1.1856 +        if (!GlyfPoints(pCompGlyf, prgnCurrentX, prgnCurrentY, prgbCurrentFlag, 
  1.1857 +            cCurrentPoints, cActualPts))
  1.1858 +            return false; 
  1.1859 +        if (!GetComponentPlacement(pSimpleGlyf, rgnCompId[i], fOffset, a, b))
  1.1860 +            return false;
  1.1861 +        if (!GetComponentTransform(pSimpleGlyf, rgnCompId[i], 
  1.1862 +            flt11, flt12, flt21, flt22, fTransOff))
  1.1863 +            return false;
  1.1864 +        bool fIdTrans = flt11 == 1.0 && flt12 == 0.0 && flt21 == 0.0 && flt22 == 1.0;
  1.1865 +
  1.1866 +        // convert points to absolute coordinates
  1.1867 +        // do before transform and attachment point placement are applied
  1.1868 +        CalcAbsolutePoints(prgnCurrentX, prgnCurrentY, cActualPts);
  1.1869 +
  1.1870 +        // apply transform - see main method note above
  1.1871 +        // do before attachment point calcs
  1.1872 +        if (!fIdTrans)
  1.1873 +            for (int j = 0; j < cActualPts; j++)
  1.1874 +            {
  1.1875 +                int x = prgnCurrentX[j]; // store before transform applied
  1.1876 +                int y = prgnCurrentY[j];
  1.1877 +                prgnCurrentX[j] = (int)(x * flt11 + y * flt12);
  1.1878 +                prgnCurrentY[j] = (int)(x * flt21 + y * flt22);
  1.1879 +            }
  1.1880 +            
  1.1881 +        // apply placement - see main method note above
  1.1882 +        int nXOff, nYOff;
  1.1883 +        if (fOffset) // explicit x & y offsets
  1.1884 +        { 
  1.1885 +            /* ignore fTransOff for now
  1.1886 +            if (fTransOff && !fIdTrans) 
  1.1887 +            {   // transform x & y offsets
  1.1888 +                nXOff = (int)(a * flt11 + b * flt12);
  1.1889 +                nYOff = (int)(a * flt21 + b * flt22);
  1.1890 +            }
  1.1891 +            else */ 
  1.1892 +            { // don't transform offset
  1.1893 +                nXOff = a;
  1.1894 +                nYOff = b;
  1.1895 +            }
  1.1896 +        }
  1.1897 +        else  // attachment points
  1.1898 +        {   // in case first point is relative to preceding glyph and second relative to current
  1.1899 +            // nXOff = prgnPrevX[a] - prgnCurrentX[b];
  1.1900 +            // nYOff = prgnPrevY[a] - prgnCurrentY[b];
  1.1901 +            // first point number relative to whole composite, second relative to current glyph
  1.1902 +            nXOff = prgnX[a] - prgnCurrentX[b];
  1.1903 +            nYOff = prgnY[a] - prgnCurrentY[b];
  1.1904 +        }
  1.1905 +        for (int j = 0; j < cActualPts; j++)
  1.1906 +        {
  1.1907 +            prgnCurrentX[j] += nXOff;
  1.1908 +            prgnCurrentY[j] += nYOff;
  1.1909 +        }
  1.1910 +
  1.1911 +        // prgnPrevX = prgnCurrentX;
  1.1912 +        // prgnPrevY = prgnCurrentY;
  1.1913 +        prgnCurrentX += cActualPts;
  1.1914 +        prgnCurrentY += cActualPts;
  1.1915 +        prgbCurrentFlag += cActualPts;
  1.1916 +        cCurrentPoints -= cActualPts;
  1.1917 +    }
  1.1918 +
  1.1919 +    SimplifyFlags((char *)prgfOnCurve, cnPoints);
  1.1920 +
  1.1921 +    return true;
  1.1922 +}
  1.1923 +
  1.1924 +/*----------------------------------------------------------------------------------------------
  1.1925 +    Simplify the meaning of flags to just indicate whether point is on-curve or off-curve.
  1.1926 +---------------------------------------------------------------------------------------------*/
  1.1927 +bool SimplifyFlags(char * prgbFlags, int cnPoints)
  1.1928 +{
  1.1929 +    for (int i = 0; i < cnPoints; i++)
  1.1930 +        prgbFlags[i] = static_cast<char>(prgbFlags[i] & Sfnt::SimpleGlyph::OnCurve);
  1.1931 +    return true;
  1.1932 +}
  1.1933 +
  1.1934 +/*----------------------------------------------------------------------------------------------
  1.1935 +    Convert relative point coordinates to absolute coordinates
  1.1936 +    Points are stored in the font such that they are offsets from one another except for the 
  1.1937 +        first point of a glyph.
  1.1938 +---------------------------------------------------------------------------------------------*/
  1.1939 +bool CalcAbsolutePoints(int * prgnX, int * prgnY, int cnPoints)
  1.1940 +{
  1.1941 +    int nX = prgnX[0];
  1.1942 +    int nY = prgnY[0];
  1.1943 +    for (int i = 1; i < cnPoints; i++)
  1.1944 +    {
  1.1945 +        prgnX[i] += nX;
  1.1946 +        nX = prgnX[i];
  1.1947 +        prgnY[i] += nY;
  1.1948 +        nY = prgnY[i];
  1.1949 +    }
  1.1950 +
  1.1951 +    return true;
  1.1952 +}
  1.1953 +#endif
  1.1954 +
  1.1955 +/*----------------------------------------------------------------------------------------------
  1.1956 +    Return the length of the 'name' table in bytes.
  1.1957 +    Currently used.
  1.1958 +---------------------------------------------------------------------------------------------*/
  1.1959 +#if 0
  1.1960 +size_t NameTableLength(const byte * pTable)
  1.1961 +{
  1.1962 +    byte * pb = (const_cast<byte *>(pTable)) + 2; // skip format
  1.1963 +    size_t cRecords = *pb++ << 8; cRecords += *pb++;
  1.1964 +    int dbStringOffset0 = (*pb++) << 8; dbStringOffset0 += *pb++;
  1.1965 +    int dbMaxStringOffset = 0;
  1.1966 +    for (size_t irec = 0; irec < cRecords; irec++)
  1.1967 +    {
  1.1968 +        int nPlatform = (*pb++) << 8; nPlatform += *pb++;
  1.1969 +        int nEncoding = (*pb++) << 8; nEncoding += *pb++;
  1.1970 +        int nLanguage = (*pb++) << 8; nLanguage += *pb++;
  1.1971 +        int nName = (*pb++) << 8; nName += *pb++;
  1.1972 +        int cbStringLen = (*pb++) << 8; cbStringLen += *pb++;
  1.1973 +        int dbStringOffset = (*pb++) << 8; dbStringOffset += *pb++;
  1.1974 +        if (dbMaxStringOffset < dbStringOffset + cbStringLen)
  1.1975 +            dbMaxStringOffset = dbStringOffset + cbStringLen;
  1.1976 +    }
  1.1977 +    return dbStringOffset0 + dbMaxStringOffset;
  1.1978 +}
  1.1979 +#endif
  1.1980 +
  1.1981 +} // end of namespace TtfUtil
  1.1982 +} // end of namespace graphite

mercurial