text:
/*  GRAPHITE2 LICENSING

    Copyright 2010, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once

#include "graphite2/Types.h"
#include "graphite2/Segment.h"
#include "inc/Main.h"
#include "inc/Font.h"
#include "inc/Position.h"

namespace graphite2 {

typedef gr_attrCode attrCode;

class GlyphFace;
class Segment;

struct SlotJustify
{
    static const int NUMJUSTPARAMS = 5;

    SlotJustify(const SlotJustify &);
    SlotJustify & operator = (const SlotJustify &);

public:
    static size_t size_of(size_t levels) { return sizeof(SlotJustify) + ((levels > 1 ? levels : 1)*NUMJUSTPARAMS - 1)*sizeof(int16); }

    void LoadSlot(const Slot *s, const Segment *seg);

    SlotJustify *next;
    int16 values[1];
};

class Slot
{
    enum Flag
    {
        DELETED     = 1,
        INSERTED    = 2,
        COPIED      = 4,
        POSITIONED  = 8,
        ATTACHED    = 16
    };

public:
    struct iterator;

    unsigned short gid() const { return m_glyphid; }
    Position origin() const { return m_position; }
    float advance() const { return m_advance.x; }
    void advance(Position &val) { m_advance = val; }
    Position advancePos() const { return m_advance; }
    int before() const { return m_before; }
    int after() const { return m_after; }
    uint32 index() const { return m_index; }
    void index(uint32 val) { m_index = val; }

    Slot(int16 *m_userAttr = NULL);
    void set(const Slot & slot, int charOffset, size_t numUserAttr, size_t justLevels, size_t numChars);
    Slot *next() const { return m_next; }
    void next(Slot *s) { m_next = s; }
    Slot *prev() const { return m_prev; }
    void prev(Slot *s) { m_prev = s; }
    uint16 glyph() const { return m_realglyphid ? m_realglyphid : m_glyphid; }
    void setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph = NULL);
    void setRealGid(uint16 realGid) { m_realglyphid = realGid; }
    void adjKern(const Position &pos) { m_shift = m_shift + pos; m_advance = m_advance + pos; }
    void origin(const Position &pos) { m_position = pos + m_shift; }
    void originate(int ind) { m_original = ind; }
    int original() const { return m_original; }
    void before(int ind) { m_before = ind; }
    void after(int ind) { m_after = ind; }
    bool isBase() const { return (!m_parent); }
    void update(int numSlots, int numCharInfo, Position &relpos);
    Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal, int depth = 0);
    bool isDeleted() const { return (m_flags & DELETED) ? true : false; }
    void markDeleted(bool state) { if (state) m_flags |= DELETED; else m_flags &= ~DELETED; }
    bool isCopied() const { return (m_flags & COPIED) ? true : false; }
    void markCopied(bool state) { if (state) m_flags |= COPIED; else m_flags &= ~COPIED; }
    bool isPositioned() const { return (m_flags & POSITIONED) ? true : false; }
    void markPositioned(bool state) { if (state) m_flags |= POSITIONED; else m_flags &= ~POSITIONED; }
    bool isInsertBefore() const { return !(m_flags & INSERTED); }
    uint8 getBidiLevel() const { return m_bidiLevel; }
    void setBidiLevel(uint8 level) { m_bidiLevel = level; }
    int8 getBidiClass(const Segment *seg);
    int8 getBidiClass() const { return m_bidiCls; }
    void setBidiClass(int8 cls) { m_bidiCls = cls; }
    int16 *userAttrs() const { return m_userAttr; }
    void userAttrs(int16 *p) { m_userAttr = p; }
    void markInsertBefore(bool state) { if (!state) m_flags |= INSERTED; else m_flags &= ~INSERTED; }
    void setAttr(Segment* seg, attrCode ind, uint8 subindex, int16 val, const SlotMap & map);
    int getAttr(const Segment *seg, attrCode ind, uint8 subindex) const;
    int getJustify(const Segment *seg, uint8 level, uint8 subindex) const;
    void setJustify(Segment *seg, uint8 level, uint8 subindex, int16 value);
    bool isLocalJustify() const { return m_justs != NULL; };
    void attachTo(Slot *ap) { m_parent = ap; }
    Slot *attachedTo() const { return m_parent; }
    Position attachOffset() const { return m_attach - m_with; }
    Slot* firstChild() const { return m_child; }
    void firstChild(Slot *ap) { m_child = ap; }
    bool child(Slot *ap);
    Slot* nextSibling() const { return m_sibling; }
    void nextSibling(Slot *ap) { m_sibling = ap; }
    bool sibling(Slot *ap);
    bool removeChild(Slot *ap);
    int32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel, bool rtl);
    void positionShift(Position a) { m_position += a; }
    void floodShift(Position adj, int depth = 0);
    float just() const { return m_just; }
    void just(float j) { m_just = j; }
    Slot *nextInCluster(const Slot *s) const;
    bool isChildOf(const Slot *base) const;

    CLASS_NEW_DELETE

private:
    Slot *m_next;           // linked list of slots
    Slot *m_prev;
    unsigned short m_glyphid;        // glyph id
    uint16 m_realglyphid;
    uint32 m_original;      // charinfo that originated this slot (e.g. for feature values)
    uint32 m_before;        // charinfo index of before association
    uint32 m_after;         // charinfo index of after association
    uint32 m_index;         // slot index given to this slot during finalising
    Slot *m_parent;         // index to parent we are attached to
    Slot *m_child;          // index to first child slot that attaches to us
    Slot *m_sibling;        // index to next child that attaches to our parent
    Position m_position;    // absolute position of glyph
    Position m_shift;       // .shift slot attribute
    Position m_advance;     // .advance slot attribute
    Position m_attach;      // attachment point on us
    Position m_with;        // attachment point position on parent
    float    m_just;        // Justification inserted space
    uint8    m_flags;       // holds bit flags
    byte     m_attLevel;    // attachment level
    int8     m_bidiCls;     // bidirectional class
    byte     m_bidiLevel;   // bidirectional level
    int16   *m_userAttr;    // pointer to user attributes
    SlotJustify *m_justs;   // pointer to justification parameters

    friend class Segment;
};

} // namespace graphite2

struct gr_slot : public graphite2::Slot {};


text:
/*  GRAPHITE2 LICENSING

    Copyright 2010, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once

#include "inc/Main.h"
#include "inc/Face.h"

namespace graphite2 {

class Face;

class Cmap
{
public:

    virtual ~Cmap() throw() {}

    virtual uint16 operator [] (const uint32) const throw() { return 0; }

    virtual operator bool () const throw() { return false; }

    CLASS_NEW_DELETE;
};

class DirectCmap : public Cmap
{
    DirectCmap(const DirectCmap &);
    DirectCmap & operator = (const DirectCmap &);

public:
    DirectCmap(const Face &);
    virtual uint16 operator [] (const uint32 usv) const throw();
    virtual operator bool () const throw();

    CLASS_NEW_DELETE;
private:
    const Face::Table   _cmap;
    const void        * _smp,
                      * _bmp;
};

class CachedCmap : public Cmap
{
    CachedCmap(const CachedCmap &);
    CachedCmap & operator = (const CachedCmap &);

public:
    CachedCmap(const Face &);
    virtual ~CachedCmap() throw();
    virtual uint16 operator [] (const uint32 usv) const throw();
    virtual operator bool () const throw();
    CLASS_NEW_DELETE;
private:
    bool m_isBmpOnly;
    uint16 ** m_blocks;
};

} // namespace graphite2

repo_language: C

mime_type: text/x-c


text:
/*  GRAPHITE2 LICENSING

    Copyright 2011, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/

#pragma once

#include "inc/Code.h"
#include "inc/Slot.h"

namespace graphite2 {

struct Rule {
  const vm::Machine::Code * constraint,
                 * action;
  unsigned short   sort;
  byte             preContext;
#ifndef NDEBUG
  uint16           rule_idx;
#endif

  Rule();
  ~Rule() {}

  CLASS_NEW_DELETE;

private:
  Rule(const Rule &);
  Rule & operator = (const Rule &);
};

inline
Rule::Rule()
: constraint(0),
  action(0),
  sort(0),
  preContext(0)
{
#ifndef NDEBUG
  rule_idx = 0;
#endif
}

struct RuleEntry
{
  const Rule   * rule;

  inline
  bool operator < (const RuleEntry &r) const
  {
    const unsigned short lsort = rule->sort, rsort = r.rule->sort;
    return lsort > rsort || (lsort == rsort && rule < r.rule);
  }

  inline
  bool operator == (const RuleEntry &r) const
  {
    return rule == r.rule;
  }
};

struct State
{
  const RuleEntry     * rules,
                      * rules_end;

  bool   empty() const;
};

inline
bool State::empty() const
{
    return rules_end == rules;
}

class SlotMap
{
public:
  enum {MAX_SLOTS=64};
  SlotMap(Segment & seg, uint8 direction, size_t maxSize);

  Slot       * * begin();
  Slot       * * end();
  size_t         size() const;
  unsigned short context() const;
  void           reset(Slot &, unsigned short);

  Slot * const & operator[](int n) const;
  Slot       * & operator [] (int);
  void           pushSlot(Slot * const slot);
  void           collectGarbage(Slot *& aSlot);

  Slot         * highwater() { return m_highwater; }
  void           highwater(Slot *s) { m_highwater = s; m_highpassed = false; }
  bool           highpassed() const { return m_highpassed; }
  void           highpassed(bool v) { m_highpassed = v; }

  uint8          dir() const { return m_dir; }
  int            decMax() { return --m_maxSize; }

  Segment &    segment;
private:
  Slot         * m_slot_map[MAX_SLOTS+1];
  unsigned short m_size;
  unsigned short m_precontext;
  Slot         * m_highwater;
  int            m_maxSize;
  uint8          m_dir;
  bool           m_highpassed;
};

class FiniteStateMachine
{
public:
  enum {MAX_RULES=128};

private:
  class Rules
  {
  public:
      Rules();
      void              clear();
      const RuleEntry * begin() const;
      const RuleEntry * end() const;
      size_t            size() const;

      void accumulate_rules(const State &state);

  private:
      RuleEntry * m_begin,
                * m_end,
                  m_rules[MAX_RULES*2];
  };

public:
  FiniteStateMachine(SlotMap & map, json * logger);
  void      reset(Slot * & slot, const short unsigned int max_pre_ctxt);

  Rules     rules;
  SlotMap   & slots;
  json    * const dbgout;
};

inline
FiniteStateMachine::FiniteStateMachine(SlotMap& map, json * logger)
: slots(map),
  dbgout(logger)
{
}

inline
void FiniteStateMachine::reset(Slot * & slot, const short unsigned int max_pre_ctxt)
{
  rules.clear();
  int ctxt = 0;
  for (; ctxt != max_pre_ctxt && slot->prev(); ++ctxt, slot = slot->prev());
  slots.reset(*slot, ctxt);
}

inline
FiniteStateMachine::Rules::Rules()
  : m_begin(m_rules), m_end(m_rules)
{
}

inline
void FiniteStateMachine::Rules::clear()
{
  m_end = m_begin;
}

inline
const RuleEntry * FiniteStateMachine::Rules::begin() const
{
  return m_begin;
}

inline
const RuleEntry * FiniteStateMachine::Rules::end() const
{
  return m_end;
}

inline
size_t FiniteStateMachine::Rules::size() const
{
  return m_end - m_begin;
}

inline
void FiniteStateMachine::Rules::accumulate_rules(const State &state)
{
  // Only bother if there are rules in the State object.
  if (state.empty()) return;

  // Merge the new sorted rules list into the current sorted result set.
  const RuleEntry * lre = begin(), * rre = state.rules;
  RuleEntry * out = m_rules + (m_begin == m_rules)*MAX_RULES;
  const RuleEntry * const lrend = out + MAX_RULES,
                  * const rrend = state.rules_end;
  m_begin = out;
  while (lre != end() && out != lrend)
  {
    if (*lre < *rre)      *out++ = *lre++;
    else if (*rre < *lre) { *out++ = *rre++; }
    else                { *out++ = *lre++; ++rre; }

    if (rre == rrend)
    {
      while (lre != end() && out != lrend) { *out++ = *lre++; }
      m_end = out;
      return;
    }
  }
  while (rre != rrend && out != lrend) { *out++ = *rre++; }
  m_end = out;
}

inline
SlotMap::SlotMap(Segment & seg, uint8 direction, size_t maxSize)
: segment(seg), m_size(0), m_precontext(0), m_highwater(0),
    m_maxSize(int(maxSize)), m_dir(direction), m_highpassed(false)
{
    m_slot_map[0] = 0;
}

inline
Slot * * SlotMap::begin()
{
  return &m_slot_map[1]; // allow map to go 1 before slot_map when inserting
                         // at start of segment.
}

inline
Slot * * SlotMap::end()
{
  return m_slot_map + m_size + 1;
}

inline
size_t SlotMap::size() const
{
  return m_size;
}

inline
short unsigned int SlotMap::context() const
{
  return m_precontext;
}

inline
void SlotMap::reset(Slot & slot, short unsigned int ctxt)
{
  m_size = 0;
  m_precontext = ctxt;
  *m_slot_map = slot.prev();
}

inline
void SlotMap::pushSlot(Slot*const slot)
{
  m_slot_map[++m_size] = slot;
}

inline
Slot * const & SlotMap::operator[](int n) const
{
  return m_slot_map[n + 1];
}

inline
Slot * & SlotMap::operator[](int n)
{
  return m_slot_map[n + 1];
}

} // namespace graphite2


text:
/*  GRAPHITE2 LICENSING

    Copyright 2011, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
//  debug.h
//
//  Created on: 22 Dec 2011
//      Author: tim

#pragma once

#if !defined GRAPHITE2_NTRACING

#include <utility>
#include "inc/json.h"
#include "inc/Position.h"

namespace graphite2
{

class CharInfo;
class Segment;
class Slot;

typedef std::pair<const Segment * const, const Slot * const>    dslot;
struct objectid
{
    char name[16];
    objectid(const dslot &) throw();
    objectid(const Segment * const p) throw();
};

json & operator << (json & j, const Position &) throw();
json & operator << (json & j, const Rect &) throw();
json & operator << (json & j, const CharInfo &) throw();
json & operator << (json & j, const dslot &) throw();
json & operator << (json & j, const objectid &) throw();
json & operator << (json & j, const telemetry &) throw();

inline
json & operator << (json & j, const Position & p) throw()
{
    return j << json::flat << json::array << p.x << p.y << json::close;
}

inline
json & operator << (json & j, const Rect & p) throw()
{
    return j << json::flat << json::array << p.bl.x << p.bl.y << p.tr.x << p.tr.y << json::close;
}

inline
json & operator << (json & j, const objectid & sid) throw()
{
    return j << sid.name;
}

} // namespace graphite2

#endif //!defined GRAPHITE2_NTRACING


text:
/*  GRAPHITE2 LICENSING

    Copyright 2011, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
// JSON pretty printer for graphite font debug output logging.
// Created on: 15 Dec 2011
//     Author: Tim Eves

#pragma once

#include "inc/Main.h"
#include <cassert>
#include <cstdio>
#include <cstdint>
#include "inc/List.h"

namespace graphite2 {

class json
{
    // Prevent copying
    json(const json &);
    json & operator = (const json &);

    typedef void (*_context_t)(json &);

    FILE * const    _stream;
    char            _contexts[128], // context stack
                  * _context,       // current context (top of stack)
                  * _flatten;       // if !0 points to context above which
                                    //  pretty printed output should occur.
    Vector<void *>  _env;

    void context(const char current) throw();
    void indent(const int d=0) throw();
    void push_context(const char, const char) throw();
    void pop_context() throw();

public:
    class closer;

    using string = const char *;
    using number = double;
    enum class integer : std::intmax_t {};
    enum class integer_u : std::uintmax_t {};
    using boolean = bool;
    static const std::nullptr_t  null;

    void setenv(unsigned int index, void *val) { _env.reserve(index + 1); if (index >= _env.size()) _env.insert(_env.end(), _env.size() - index + 1, 0); _env[index] = val; }
    void *getenv(unsigned int index) const { return _env[index]; }
    const Vector<void *> &getenvs() const { return _env; }

    static void flat(json &) throw();
    static void close(json &) throw();
    static void object(json &) throw();
    static void array(json &) throw();
    static void item(json &) throw();

    json(FILE * stream) throw();
    ~json() throw ();

    FILE * stream() const throw();

    json & operator << (string) throw();
    json & operator << (number) throw();
    json & operator << (integer) throw();
    json & operator << (integer_u) throw();
    json & operator << (boolean) throw();
    json & operator << (std::nullptr_t) throw();
    json & operator << (_context_t) throw();

    operator bool() const throw();
    bool good() const throw();
    bool eof() const throw();

    CLASS_NEW_DELETE;
};

class json::closer
{
    // Prevent copying.
    closer(const closer &);
    closer & operator = (const closer &);

    json * const    _j;
public:
    closer(json * const j) : _j(j) {}
    ~closer() throw() { if (_j)  *_j << close; }
};

inline
json::json(FILE * s) throw()
: _stream(s), _context(_contexts), _flatten(0)
{
    if (good())
        fflush(s);
}

inline
json::~json() throw ()
{
    while (_context > _contexts)    pop_context();
}

inline
FILE * json::stream() const throw()     { return _stream; }

inline
json & json::operator << (json::_context_t ctxt) throw()
{
    ctxt(*this);
    return *this;
}

inline
json & operator << (json & j, signed char d) throw()   { return j << json::integer(d); }

inline
json & operator << (json & j, unsigned char d) throw() { return j << json::integer_u(d); }

inline
json & operator << (json & j, short int d) throw()   { return j << json::integer(d); }

inline
json & operator << (json & j, unsigned short int d) throw() { return j << json::integer_u(d); }

inline
json & operator << (json & j, int d) throw()         { return j << json::integer(d); }

inline
json & operator << (json & j, unsigned int d) throw()       { return j << json::integer_u(d); }

inline
json & operator << (json & j, long int d) throw()         { return j << json::integer(d); }

inline
json & operator << (json & j, unsigned long int d) throw()       { return j << json::integer_u(d); }

inline
json & operator << (json & j, long long int d) throw()         { return j << json::integer(d); }

inline
json & operator << (json & j, unsigned long long int d) throw()       { return j << json::integer_u(d); }

inline
json::operator bool() const throw()     { return good(); }

inline
bool json::good() const throw()         { return _stream && ferror(_stream) == 0; }

inline
bool json::eof() const throw()          { return feof(_stream) != 0; }

} // namespace graphite2


text:
/*  GRAPHITE2 LICENSING

    Copyright 2010, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include "inc/Main.h"

namespace graphite2 {

class CharInfo
{

public:
    CharInfo() : m_char(0), m_before(-1), m_after(-1), m_base(0), m_featureid(0), m_break(0), m_flags(0) {}
    void init(int cid) { m_char = cid; }
    unsigned int unicodeChar() const { return m_char; }
    void feats(int offset) { m_featureid = offset; }
    int fid() const { return m_featureid; }
    int breakWeight() const { return m_break; }
    void breakWeight(int val) { m_break = val; }
    int after() const { return m_after; }
    void after(int val) { m_after = val; }
    int before() const { return m_before; }
    void before(int val) { m_before = val; }
    size_t base() const { return m_base; }
    void base(size_t offset) { m_base = offset; }
    void addflags(uint8 val) { m_flags |= val; }
    uint8 flags() const { return m_flags; }

    CLASS_NEW_DELETE
private:
    int m_char;     // Unicode character from character stream
    int m_before;   // slot index before us, comes before
    int m_after;    // slot index after us, comes after
    size_t  m_base; // offset into input string corresponding to this charinfo
    uint8 m_featureid;  // index into features list in the segment
    int8 m_break;   // breakweight coming from lb table
    uint8 m_flags;  // 0,1 segment split.
};

} // namespace graphite2

struct gr_char_info : public graphite2::CharInfo {};


text:
/*  GRAPHITE2 LICENSING

    Copyright 2010, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once

#include <cstdlib>
#include "graphite2/Types.h"

#ifdef GRAPHITE2_CUSTOM_HEADER
#include GRAPHITE2_CUSTOM_HEADER
#endif

namespace graphite2 {

typedef gr_uint8        uint8;
typedef gr_uint8        byte;
typedef gr_uint16       uint16;
typedef gr_uint32       uint32;
typedef gr_int8         int8;
typedef gr_int16        int16;
typedef gr_int32        int32;
typedef size_t          uintptr;

#ifdef GRAPHITE2_TELEMETRY
struct telemetry
{
    class category;

    static size_t   * _category;
    static void set_category(size_t & t) throw()    { _category = &t; }
    static void stop() throw()                      { _category = 0; }
    static void count_bytes(size_t n) throw()       { if (_category) *_category += n; }

    size_t  misc,
            silf,
            glyph,
            code,
            states,
            starts,
            transitions;

    telemetry() : misc(0), silf(0), glyph(0), code(0), states(0), starts(0), transitions(0) {}
};

class telemetry::category
{
    size_t * _prev;
public:
    category(size_t & t) : _prev(_category) { _category = &t; }
    ~category() { _category = _prev; }
};

#else
struct telemetry  {};
#endif

// Checked multiplaction to catch overflow or underflow when allocating memory
#if defined(__has_builtin)
  #if __has_builtin(__builtin_mul_overflow)
    #define HAVE_BUILTIN_OVERFLOW
  #endif
#elif defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__INTEL_COMPILER)
  #define HAVE_BUILTIN_OVERFLOW
#endif
#if defined(__has_include)
  #if __has_include(<intsafe.h>) && !defined(__CYGWIN__)
    #define HAVE_INTSAFE_H
  #endif
#elif defined(_WIN32)
  #define HAVE_INTSAFE_H
#endif

// Need to import intsafe into the top level namespace
#if defined(HAVE_INTSAFE_H)
} // namespace graphite2

#include <intsafe.h>

namespace graphite2 {
#endif

#if defined(HAVE_BUILTIN_OVERFLOW)
inline
bool checked_mul(const size_t a, const size_t b, size_t & t) {
    return __builtin_mul_overflow(a, b, &t);
}
#elif defined(HAVE_INTSAFE_H)
inline
bool checked_mul(const size_t a, const size_t b, size_t & t) {
    return SizeTMult(a, b, &t) == INTSAFE_E_ARITHMETIC_OVERFLOW;
}
#else
inline
bool checked_mul(const size_t a, const size_t b, size_t & t) {
  t = a*b;
  return (((a | b) & (~size_t(0) << (sizeof(size_t) << 2))) && (t / a != b));
}
#endif

// typesafe wrapper around malloc for simple types
// use free(pointer) to deallocate

template <typename T> T * gralloc(size_t n)
{
    size_t total;
    if (checked_mul(n, sizeof(T), total))
      return 0;
#ifdef GRAPHITE2_TELEMETRY
    telemetry::count_bytes(total);
#endif
    return static_cast<T*>(malloc(total));
}

template <typename T> T * grzeroalloc(size_t n)
{
#ifdef GRAPHITE2_TELEMETRY
    telemetry::count_bytes(sizeof(T) * n);
#endif
    return static_cast<T*>(calloc(n, sizeof(T)));
}

template <typename T>
inline T min(const T a, const T b)
{
    return a < b ? a : b;
}

template <typename T>
inline T max(const T a, const T b)
{
    return a > b ? a : b;
}

} // namespace graphite2

#define CLASS_NEW_DELETE \
    void * operator new   (size_t size){ return gralloc<byte>(size);} \
    void * operator new   (size_t, void * p) throw() { return p; } \
    void * operator new[] (size_t size) {return gralloc<byte>(size);} \
    void * operator new[] (size_t, void * p) throw() { return p; } \
    void operator delete   (void * p) throw() { free(p);} \
    void operator delete   (void *, void *) throw() {} \
    void operator delete[] (void * p)throw() { free(p); } \
    void operator delete[] (void *, void *) throw() {}

#if defined(__GNUC__)  || defined(__clang__)
#define GR_MAYBE_UNUSED __attribute__((unused))
#else
#define GR_MAYBE_UNUSED
#endif

#ifndef __has_cpp_attribute
#  define __has_cpp_attribute(x) 0
#endif

#if __has_cpp_attribute(clang::fallthrough)
#  define GR_FALLTHROUGH [[clang::fallthrough]]
#elif __has_cpp_attribute(gnu::fallthrough)
#  define GR_FALLTHROUGH [[gnu::fallthrough]]
#elif defined(_MSC_VER)
   /*
    * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
    * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
    */
    #include <sal.h>
    #define GR_FALLTHROUGH __fallthrough
#elif __GNUC__ >= 7
    #define GR_FALLTHROUGH __attribute__ ((fallthrough))
#else
    #define GR_FALLTHROUGH /* fallthrough */
#endif

#ifdef _MSC_VER
#pragma warning(disable: 4800)
#pragma warning(disable: 4355)
#endif


text:
/*  GRAPHITE2 LICENSING

    Copyright 2012, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once

//#include "inc/FeatureMap.h"
//#include "inc/GlyphsCache.h"
//#include "inc/Silf.h"

#ifndef GRAPHITE2_NFILEFACE

#include <cstdio>
#include <cassert>

#include "graphite2/Font.h"

#include "inc/Main.h"
#include "inc/TtfTypes.h"
#include "inc/TtfUtil.h"

namespace graphite2 {

class FileFace
{
    static const void * get_table_fn(const void* appFaceHandle, unsigned int name, size_t *len);
    static void         rel_table_fn(const void* appFaceHandle, const void *table_buffer);

public:
    static const gr_face_ops ops;

    FileFace(const char *filename);
    ~FileFace();

    operator bool () const throw();
    CLASS_NEW_DELETE;

private:        //defensive
    FILE          * _file;
    size_t          _file_len;

    TtfUtil::Sfnt::OffsetSubTable         * _header_tbl;
    TtfUtil::Sfnt::OffsetSubTable::Entry  * _table_dir;

    FileFace(const FileFace&);
    FileFace& operator=(const FileFace&);
};

inline
FileFace::operator bool() const throw()
{
    return _file && _header_tbl && _table_dir;
}

} // namespace graphite2

#endif      //!GRAPHITE2_NFILEFACE


text:
/*  GRAPHITE2 LICENSING

    Copyright 2010, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once

#include <graphite2/Segment.h>
#include "inc/TtfTypes.h"
#include "inc/locale2lcid.h"

namespace graphite2 {

class NameTable
{
    NameTable(const NameTable &);
    NameTable & operator = (const NameTable &);

public:
    NameTable(const void * data, size_t length, uint16 platfromId=3, uint16 encodingID = 1);
    ~NameTable() { free(const_cast<TtfUtil::Sfnt::FontNames *>(m_table)); }
    enum eNameFallback {
        eNoFallback = 0,
        eEnUSFallbackOnly = 1,
        eEnOrAnyFallback = 2
    };
    uint16 setPlatformEncoding(uint16 platfromId=3, uint16 encodingID = 1);
    void * getName(uint16 & languageId, uint16 nameId, gr_encform enc, uint32 & length);
    uint16 getLanguageId(const char * bcp47Locale);

    CLASS_NEW_DELETE
private:
    uint16 m_platformId;
    uint16 m_encodingId;
    uint16 m_languageCount;
    uint16 m_platformOffset; // offset of first NameRecord with for platform 3, encoding 1
    uint16 m_platformLastRecord;
    uint16 m_nameDataLength;
    const TtfUtil::Sfnt::FontNames * m_table;
    const uint8 * m_nameData;
    Locale2Lang m_locale2Lang;
};

} // namespace graphite2


text:
/*  GRAPHITE2 LICENSING

    Copyright 2010, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once

namespace graphite2 {

class Position
{
public:
    Position() : x(0), y(0) { }
    Position(const float inx, const float iny) : x(inx), y(iny) {}
    Position operator + (const Position& a) const { return Position(x + a.x, y + a.y); }
    Position operator - (const Position& a) const { return Position(x - a.x, y - a.y); }
    Position operator * (const float m) const { return Position(x * m, y * m); }
    Position &operator += (const Position &a) { x += a.x; y += a.y; return *this; }
    Position &operator *= (const float m) { x *= m; y *= m; return *this; }

    float x;
    float y;
};

class Rect
{
public :
    Rect() {}
    Rect(const Position& botLeft, const Position& topRight): bl(botLeft), tr(topRight) {}
    Rect widen(const Rect& other) { return Rect(Position(bl.x > other.bl.x ? other.bl.x : bl.x, bl.y > other.bl.y ? other.bl.y : bl.y), Position(tr.x > other.tr.x ? tr.x : other.tr.x, tr.y > other.tr.y ? tr.y : other.tr.y)); }
    Rect operator + (const Position &a) const { return Rect(Position(bl.x + a.x, bl.y + a.y), Position(tr.x + a.x, tr.y + a.y)); }
    Rect operator - (const Position &a) const { return Rect(Position(bl.x - a.x, bl.y - a.y), Position(tr.x - a.x, tr.y - a.y)); }
    Rect operator * (float m) const { return Rect(Position(bl.x, bl.y) * m, Position(tr.x, tr.y) * m); }
    float width() const { return tr.x - bl.x; }
    float height() const { return tr.y - bl.y; }

    bool hitTest(Rect &other);

    // returns Position(overlapx, overlapy) where overlap<0 if overlapping else positive)
    Position overlap(Position &offset, Rect &other, Position &otherOffset);
    //Position constrainedAvoid(Position &offset, Rect &box, Rect &sdbox, Position &other, Rect &obox, Rect &osdbox);

    Position bl;
    Position tr;
};

} // namespace graphite2


text:
/*  GRAPHITE2 LICENSING

    Copyright 2010, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
/*--------------------------------------------------------------------*//*:Ignore this sentence.

File: TtfUtil.h
Responsibility: Alan Ward
Last reviewed: Not yet.

Description:
    Utility class for handling TrueType font files.
----------------------------------------------------------------------------------------------*/

#include <cstddef>

namespace graphite2
{
namespace TtfUtil
{

#define OVERFLOW_OFFSET_CHECK(p, o) (o + reinterpret_cast<size_t>(p) < reinterpret_cast<size_t>(p))

typedef long fontTableId32;
typedef unsigned short gid16;

#define TTF_TAG(a,b,c,d) ((a << 24UL) + (b << 16UL) + (c << 8UL) + (d))

// Enumeration used to specify a table in a TTF file
class Tag
{
    unsigned int _v;
public:
    Tag(const char n[5]) throw()            : _v(TTF_TAG(n[0],n[1],n[2],n[3])) {}
    Tag(const unsigned int tag) throw()    : _v(tag) {}

    operator unsigned int () const throw () { return _v; }

    enum
    {
        Feat = TTF_TAG('F','e','a','t'),
        Glat = TTF_TAG('G','l','a','t'),
        Gloc = TTF_TAG('G','l','o','c'),
        Sile = TTF_TAG('S','i','l','e'),
        Silf = TTF_TAG('S','i','l','f'),
        Sill = TTF_TAG('S','i','l','l'),
        cmap = TTF_TAG('c','m','a','p'),
        cvt  = TTF_TAG('c','v','t',' '),
        cryp = TTF_TAG('c','r','y','p'),
        head = TTF_TAG('h','e','a','d'),
        fpgm = TTF_TAG('f','p','g','m'),
        gdir = TTF_TAG('g','d','i','r'),
        glyf = TTF_TAG('g','l','y','f'),
        hdmx = TTF_TAG('h','d','m','x'),
        hhea = TTF_TAG('h','h','e','a'),
        hmtx = TTF_TAG('h','m','t','x'),
        loca = TTF_TAG('l','o','c','a'),
        kern = TTF_TAG('k','e','r','n'),
        LTSH = TTF_TAG('L','T','S','H'),
        maxp = TTF_TAG('m','a','x','p'),
        name = TTF_TAG('n','a','m','e'),
        OS_2 = TTF_TAG('O','S','/','2'),
        post = TTF_TAG('p','o','s','t'),
        prep = TTF_TAG('p','r','e','p')
    };
};

/*----------------------------------------------------------------------------------------------
    Class providing utility methods to parse a TrueType font file (TTF).
    Callling application handles all file input and memory allocation.
    Assumes minimal knowledge of TTF file format.
----------------------------------------------------------------------------------------------*/
    ////////////////////////////////// tools to find & check TTF tables
    bool GetHeaderInfo(size_t & lOffset, size_t & lSize);
    bool CheckHeader(const void * pHdr);
    bool GetTableDirInfo(const void * pHdr, size_t & lOffset, size_t & lSize);
    bool GetTableInfo(const Tag TableTag, const void * pHdr, const void * pTableDir,
        size_t & lOffset, size_t & lSize);
    bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize);

    ////////////////////////////////// simple font wide info
    size_t  GlyphCount(const void * pMaxp);
#ifdef ALL_TTFUTILS
    size_t  MaxCompositeComponentCount(const void * pMaxp);
    size_t  MaxCompositeLevelCount(const void * pMaxp);
    size_t  LocaGlyphCount(size_t lLocaSize, const void * pHead); // throw (std::domain_error);
#endif
    int DesignUnits(const void * pHead);
#ifdef ALL_TTFUTILS
    int HeadTableCheckSum(const void * pHead);
    void HeadTableCreateTime(const void * pHead, unsigned int * pnDateBC, unsigned int * pnDateAD);
    void HeadTableModifyTime(const void * pHead, unsigned int * pnDateBC, unsigned int * pnDateAD);
    bool IsItalic(const void * pHead);
    int FontAscent(const void * pOs2);
    int FontDescent(const void * pOs2);
    bool FontOs2Style(const void *pOs2, bool & fBold, bool & fItalic);
    bool Get31EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize);
    bool Get31EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize);
    bool Get30EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize);
    bool Get30EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize);
    int PostLookup(const void * pPost, size_t lPostSize, const void * pMaxp,
        const char * pPostName);
#endif

    ////////////////////////////////// utility methods helpful for name table
    bool GetNameInfo(const void * pName, int nPlatformId, int nEncodingId,
        int nLangId, int nNameId, size_t & lOffset, size_t & lSize);
    //size_t NameTableLength(const byte * pTable);
#ifdef ALL_TTFUTILS
    int GetLangsForNames(const void * pName, int nPlatformId, int nEncodingId,
        int *nameIdList, int cNameIds, short *langIdList);
    void SwapWString(void * pWStr, size_t nSize = 0); // throw (std::invalid_argument);
#endif

    ////////////////////////////////// cmap lookup tools
    const void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3,
        int nEncodingId = 1, size_t length = 0);
    bool CheckCmapSubtable4(const void * pCmap31, const void * pCmapEnd /*, unsigned int maxgid*/);
    gid16 CmapSubtable4Lookup(const void * pCmapSubtabel4, unsigned int nUnicodeId, int rangeKey = 0);
    unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnicodeId,
        int * pRangeKey = 0);
    bool CheckCmapSubtable12(const void *pCmap310, const void * pCmapEnd /*, unsigned int maxgid*/);
    gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey = 0);
    unsigned int CmapSubtable12NextCodepoint(const void *pCmap310, unsigned int nUnicodeId,
        int * pRangeKey = 0);

    ///////////////////////////////// horizontal metric data for a glyph
    bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize,
        const void * pHhea, int & nLsb, unsigned int & nAdvWid);

    ////////////////////////////////// primitives for loca and glyf lookup
    size_t LocaLookup(gid16 nGlyphId, const void * pLoca, size_t lLocaSize,
        const void * pHead); // throw (std::out_of_range);
    void * GlyfLookup(const void * pGlyf, size_t lGlyfOffset, size_t lTableLen);

    ////////////////////////////////// primitves for simple glyph data
    bool GlyfBox(const void * pSimpleGlyf, int & xMin, int & yMin,
        int & xMax, int & yMax);

#ifdef ALL_TTFUTILS
    int GlyfContourCount(const void * pSimpleGlyf);
    bool GlyfContourEndPoints(const void * pSimpleGlyf, int * prgnContourEndPoint,
        int cnPointsTotal, size_t & cnPoints);
    bool GlyfPoints(const void * pSimpleGlyf, int * prgnX, int * prgnY,
        char * prgbFlag, int cnPointsTotal, int & cnPoints);

    // primitive to find the glyph ids in a composite glyph
    bool GetComponentGlyphIds(const void * pSimpleGlyf, int * prgnCompId,
        size_t cnCompIdTotal, size_t & cnCompId);
    // primitive to find the placement data for a component in a composite glyph
    bool GetComponentPlacement(const void * pSimpleGlyf, int nCompId,
        bool fOffset, int & a, int & b);
    // primitive to find the transform data for a component in a composite glyph
    bool GetComponentTransform(const void * pSimpleGlyf, int nCompId,
        float & flt11, float & flt12, float & flt21, float & flt22, bool & fTransOffset);
#endif

    ////////////////////////////////// operate on composite or simple glyph (auto glyf lookup)
    void * GlyfLookup(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
        size_t lGlyfSize, size_t lLocaSize, const void * pHead); // primitive used by below methods

#ifdef ALL_TTFUTILS
    // below are primary user methods for handling glyf data
    bool IsSpace(gid16 nGlyphId, const void * pLoca, size_t lLocaSize, const void * pHead);
    bool IsDeepComposite(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
        size_t lGlyfSize, size_t lLocaSize, const void * pHead);

    bool GlyfBox(gid16 nGlyphId, const void * pGlyf, const void * pLoca, size_t lGlyfSize, size_t lLocaSize,
        const void * pHead, int & xMin, int & yMin, int & xMax, int & yMax);
    bool GlyfContourCount(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
        size_t lGlyfSize, size_t lLocaSize, const void *pHead, size_t & cnContours);
    bool GlyfContourEndPoints(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
        size_t lGlyfSize, size_t lLocaSize, const void * pHead, int * prgnContourEndPoint, size_t cnPoints);
    bool GlyfPoints(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
        size_t lGlyfSize, size_t lLocaSize, const void * pHead, const int * prgnContourEndPoint, size_t cnEndPoints,
        int * prgnX, int * prgnY, bool * prgfOnCurve, size_t cnPoints);

    // utitily method used by high-level GlyfPoints
    bool SimplifyFlags(char * prgbFlags, int cnPoints);
    bool CalcAbsolutePoints(int * prgnX, int * prgnY, int cnPoints);
#endif

} // end of namespace TtfUtil
} // end of namespace graphite2


text:
/*  GRAPHITE2 LICENSING

    Copyright 2010, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
// This class represents loaded graphite stack machine code.  It performs
// basic sanity checks, on the incoming code to prevent more obvious problems
// from crashing graphite.
// Author: Tim Eves

#pragma once

#include <cassert>
#include <graphite2/Types.h>
#include "inc/Main.h"
#include "inc/Machine.h"

namespace graphite2 {

class Silf;
class Face;

enum passtype {
    PASS_TYPE_UNKNOWN = 0,
    PASS_TYPE_LINEBREAK,
    PASS_TYPE_SUBSTITUTE,
    PASS_TYPE_POSITIONING,
    PASS_TYPE_JUSTIFICATION
};

namespace vm {

class Machine::Code
{
public:
    enum status_t
    {
        loaded,
        alloc_failed,
        invalid_opcode,
        unimplemented_opcode_used,
        out_of_range_data,
        jump_past_end,
        arguments_exhausted,
        missing_return,
        nested_context_item,
        underfull_stack
    };

private:
    class decoder;

    instr *     _code;
    byte  *     _data;
    size_t      _data_size,
                _instr_count;
    byte        _max_ref;
    mutable status_t _status;
    bool        _constraint,
                _modify,
                _delete;
    mutable bool _own;

    void release_buffers() throw ();
    void failure(const status_t) throw();

public:
    static size_t estimateCodeDataOut(size_t num_bytecodes, int nRules, int nSlots);

    Code() throw();
    Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
         uint8 pre_context, uint16 rule_length, const Silf &, const Face &,
         enum passtype pt, byte * * const _out = 0);
    Code(const Machine::Code &) throw();
    ~Code() throw();

    Code & operator=(const Code &rhs) throw();
    operator bool () const throw()                  { return _code && status() == loaded; }
    status_t      status() const throw()            { return _status; }
    bool          constraint() const throw()        { return _constraint; }
    size_t        dataSize() const throw()          { return _data_size; }
    size_t        instructionCount() const throw()  { return _instr_count; }
    bool          immutable() const throw()         { return !(_delete || _modify); }
    bool          deletes() const throw()           { return _delete; }
    size_t        maxRef() const throw()            { return _max_ref; }
    void          externalProgramMoved(ptrdiff_t) throw();

    int32 run(Machine &m, slotref * & map) const;

    CLASS_NEW_DELETE;
};

inline
size_t  Machine::Code::estimateCodeDataOut(size_t n_bc, int nRules, int nSlots)
{
    // max is: all codes are instructions + 1 for each rule + max tempcopies
    // allocate space for separate maximal code and data then merge them later
    return (n_bc + nRules + nSlots) * sizeof(instr) + n_bc * sizeof(byte);
}

inline Machine::Code::Code() throw()
: _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0),
  _status(loaded), _constraint(false), _modify(false), _delete(false),
  _own(false)
{
}

inline Machine::Code::Code(const Machine::Code &obj) throw ()
 :  _code(obj._code),
    _data(obj._data),
    _data_size(obj._data_size),
    _instr_count(obj._instr_count),
    _max_ref(obj._max_ref),
    _status(obj._status),
    _constraint(obj._constraint),
    _modify(obj._modify),
    _delete(obj._delete),
    _own(obj._own)
{
    obj._own = false;
}

inline Machine::Code & Machine::Code::operator=(const Machine::Code &rhs) throw() {
    if (_instr_count > 0)
        release_buffers();
    _code        = rhs._code;
    _data        = rhs._data;
    _data_size   = rhs._data_size;
    _instr_count = rhs._instr_count;
    _status      = rhs._status;
    _constraint  = rhs._constraint;
    _modify      = rhs._modify;
    _delete      = rhs._delete;
    _own         = rhs._own;
    rhs._own = false;
    return *this;
}

inline void Machine::Code::externalProgramMoved(ptrdiff_t dist) throw()
{
    if (_code && !_own)
    {
        _code += dist / signed(sizeof(instr));
        _data += dist;
    }
}

} // namespace vm
} // namespace graphite2


text:
/*  GRAPHITE2 LICENSING

    Copyright 2011, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <iterator>
#include <utility>

#include "inc/Main.h"

namespace graphite2 {

// A read-only packed fast sparse array of uint16 with uint16 keys.
// Like most container classes this has capacity and size properties and these
// refer to the number of stored entries and the number of addressable entries
// as normal. However due the sparse nature the capacity is always <= than the
// size.
class sparse
{
public:
    typedef uint16  key_type;
    typedef uint16  mapped_type;
    typedef std::pair<const key_type, mapped_type> value_type;

private:
    typedef unsigned long   mask_t;

    static const unsigned char  SIZEOF_CHUNK = (sizeof(mask_t) - sizeof(key_type))*8;

    struct chunk
    {
        mask_t          mask:SIZEOF_CHUNK;
        key_type        offset;
    };

    static const chunk  empty_chunk;
    sparse(const sparse &);
    sparse & operator = (const sparse &);

public:
    template<typename I>
    sparse(I first, const I last);
    sparse() throw();
    ~sparse() throw();

    operator bool () const throw();
    mapped_type     operator [] (const key_type k) const throw();

    size_t capacity() const throw();
    size_t size()     const throw();

    size_t _sizeof() const throw();

    CLASS_NEW_DELETE;

private:
    union {
        chunk         * map;
        mapped_type   * values;
    }           m_array;
    key_type    m_nchunks;
};

inline
sparse::sparse() throw() : m_nchunks(0)
{
    m_array.map = const_cast<graphite2::sparse::chunk *>(&empty_chunk);
}

template <typename I>
sparse::sparse(I attr, const I last)
: m_nchunks(0)
{
    m_array.map = 0;

    // Find the maximum extent of the key space.
    size_t n_values=0;
    long lastkey = -1;
    for (I i = attr; i != last; ++i, ++n_values)
    {
        const typename std::iterator_traits<I>::value_type v = *i;
        if (v.second == 0)      { --n_values; continue; }
        if (v.first <= lastkey) { m_nchunks = 0; return; }

        lastkey = v.first;
        const key_type k = v.first / SIZEOF_CHUNK;
        if (k >= m_nchunks) m_nchunks = k+1;
    }
    if (m_nchunks == 0)
    {
        m_array.map=const_cast<graphite2::sparse::chunk *>(&empty_chunk);
        return;
    }

    m_array.values = grzeroalloc<mapped_type>((m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)
                                                 / sizeof(mapped_type)
                                                 + n_values);

    if (m_array.values == 0)
        return;

    // coverity[forward_null : FALSE] Since m_array is union and m_array.values is not NULL
    chunk * ci = m_array.map;
    ci->offset = (m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)/sizeof(mapped_type);
    mapped_type * vi = m_array.values + ci->offset;
    for (; attr != last; ++attr, ++vi)
    {
        const typename std::iterator_traits<I>::value_type v = *attr;
        if (v.second == 0)  { --vi; continue; }

        chunk * const ci_ = m_array.map + v.first/SIZEOF_CHUNK;

        if (ci != ci_)
        {
            ci = ci_;
            ci->offset = key_type(vi - m_array.values);
        }

        ci->mask |= 1UL << (SIZEOF_CHUNK - 1 - (v.first % SIZEOF_CHUNK));
        *vi = v.second;
    }
}

inline
sparse::operator bool () const throw()
{
    return m_array.map != 0;
}

inline
size_t sparse::size() const throw()
{
    return m_nchunks*SIZEOF_CHUNK;
}

inline
size_t sparse::_sizeof() const throw()
{
    return sizeof(sparse) + capacity()*sizeof(mapped_type) + m_nchunks*sizeof(chunk);
}

} // namespace graphite2


text:
/*  GRAPHITE2 LICENSING

    Copyright 2011, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once

#include <cstdlib>
#include "inc/Main.h"

namespace graphite2 {

typedef uint32  uchar_t;

template <int N>
struct _utf_codec
{
    typedef uchar_t codeunit_t;

    static void     put(codeunit_t * cp, const uchar_t , int8 & len) throw();
    static uchar_t  get(const codeunit_t * cp, int8 & len) throw();
    static bool     validate(const codeunit_t * s, const codeunit_t * const e) throw();
};

template <>
struct _utf_codec<32>
{
private:
    static const uchar_t    limit = 0x110000;
public:
    typedef uint32  codeunit_t;

    inline
    static void put(codeunit_t * cp, const uchar_t usv, int8 & l) throw()
    {
        *cp = usv; l = 1;
    }

    inline
    static uchar_t get(const codeunit_t * cp, int8 & l) throw()
    {
        if (cp[0] < limit)  { l = 1;  return cp[0]; }
        else                { l = -1; return 0xFFFD; }
    }

    inline
    static bool validate(const codeunit_t * s, const codeunit_t * const e) throw()
    {
        return s <= e;
    }
};

template <>
struct _utf_codec<16>
{
private:
    static const int32  lead_offset      = 0xD800 - (0x10000 >> 10);
    static const int32  surrogate_offset = 0x10000 - (0xD800 << 10) - 0xDC00;
public:
    typedef uint16  codeunit_t;

    inline
    static void put(codeunit_t * cp, const uchar_t usv, int8 & l) throw()
    {
        if (usv < 0x10000)  { l = 1; cp[0] = codeunit_t(usv); }
        else
        {
            cp[0] = codeunit_t(lead_offset + (usv >> 10));
            cp[1] = codeunit_t(0xDC00 + (usv & 0x3FF));
            l = 2;
        }
    }

    inline
    static uchar_t get(const codeunit_t * cp, int8 & l) throw()
    {
        const uint32    uh = cp[0];
        l = 1;

        if (uh < 0xD800|| uh > 0xDFFF) { return uh; }
        if (uh > 0xDBFF) { l = -1; return 0xFFFD; }
        const uint32 ul = cp[1];
        if (ul < 0xDC00 || ul > 0xDFFF) { l = -1; return 0xFFFD; }
        ++l;
        return (uh<<10) + ul + surrogate_offset;
    }

    inline
    static bool validate(const codeunit_t * s, const codeunit_t * const e) throw()
    {
        const ptrdiff_t n = e-s;
        if (n <= 0) return n == 0;
        const uint32 u = *(e-1); // Get the last codepoint
        return (u < 0xD800 || u > 0xDBFF);
    }
};

template <>
struct _utf_codec<8>
{
private:
    static const int8 sz_lut[16];
    static const byte mask_lut[5];
    static const uchar_t    limit = 0x110000;

public:
    typedef uint8   codeunit_t;

    inline
    static void put(codeunit_t * cp, const uchar_t usv, int8 & l) throw()
    {
        if (usv < 0x80)     {l = 1; cp[0] = usv; return; }
        if (usv < 0x0800)   {l = 2; cp[0] = 0xC0 + (usv >> 6);  cp[1] = 0x80 + (usv & 0x3F); return; }
        if (usv < 0x10000)  {l = 3; cp[0] = 0xE0 + (usv >> 12); cp[1] = 0x80 + ((usv >> 6) & 0x3F);  cp[2] = 0x80 + (usv & 0x3F); return; }
        else                {l = 4; cp[0] = 0xF0 + (usv >> 18); cp[1] = 0x80 + ((usv >> 12) & 0x3F); cp[2] = 0x80 + ((usv >> 6) & 0x3F); cp[3] = 0x80 + (usv & 0x3F); return; }
    }

    inline
    static uchar_t get(const codeunit_t * cp, int8 & l) throw()
    {
        const int8 seq_sz = sz_lut[*cp >> 4];
        uchar_t u = *cp & mask_lut[seq_sz];
        l = 1;
        bool toolong = false;

        switch(seq_sz) {
            case 4:     u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong  = (u < 0x10); GR_FALLTHROUGH;
                // no break
            case 3:     u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x20); GR_FALLTHROUGH;
                // no break
            case 2:     u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x80); GR_FALLTHROUGH;
                // no break
            case 1:     break;
            case 0:     l = -1; return 0xFFFD;
        }

        if (l != seq_sz || toolong  || u >= limit)
        {
            l = -l;
            return 0xFFFD;
        }
        return u;
    }

    inline
    static bool validate(const codeunit_t * s, const codeunit_t * const e) throw()
    {
        const ptrdiff_t n = e-s;
        if (n <= 0) return n == 0;
        s += (n-1);
        if (*s < 0x80) return true;
        if (*s >= 0xC0) return false;
        if (n == 1) return true;
        if (*--s < 0x80) return true;
        if (*s >= 0xE0) return false;
        if (n == 2 || *s >= 0xC0) return true;
        if (*--s < 0x80) return true;
        if (*s >= 0xF0) return false;
        return true;
    }

};

template <typename C>
class _utf_iterator
{
    typedef _utf_codec<sizeof(C)*8> codec;

    C             * cp;
    mutable int8    sl;

public:
    typedef C           codeunit_type;
    typedef uchar_t     value_type;
    typedef uchar_t   * pointer;

    class reference
    {
        const _utf_iterator & _i;

        reference(const _utf_iterator & i): _i(i) {}
    public:
        operator value_type () const throw ()                   { return codec::get(_i.cp, _i.sl); }
        reference & operator = (const value_type usv) throw()   { codec::put(_i.cp, usv, _i.sl); return *this; }

        friend class _utf_iterator;
    };

    _utf_iterator(const void * us=0)    : cp(reinterpret_cast<C *>(const_cast<void *>(us))), sl(1) { }

    _utf_iterator   & operator ++ ()    { cp += abs(sl); return *this; }
    _utf_iterator   operator ++ (int)   { _utf_iterator tmp(*this); operator++(); return tmp; }

    bool operator == (const _utf_iterator & rhs) const throw() { return cp >= rhs.cp; }
    bool operator != (const _utf_iterator & rhs) const throw() { return !operator==(rhs); }

    reference   operator * () const throw() { return *this; }
    pointer     operator ->() const throw() { return &operator *(); }

    operator codeunit_type * () const throw() { return cp; }

    bool error() const throw()  { return sl < 1; }
    bool validate(const _utf_iterator & e)  { return codec::validate(cp, e.cp); }
};

template <typename C>
struct utf
{
    typedef typename _utf_codec<sizeof(C)*8>::codeunit_t codeunit_t;

    typedef _utf_iterator<C>        iterator;
    typedef _utf_iterator<const C>  const_iterator;

    inline
    static bool validate(codeunit_t * s, codeunit_t * e) throw() {
        return _utf_codec<sizeof(C)*8>::validate(s,e);
    }
};

typedef utf<uint32> utf32;
typedef utf<uint16> utf16;
typedef utf<uint8>  utf8;

} // namespace graphite2


text:
/*  GRAPHITE2 LICENSING

    Copyright 2010, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <cstring>
#include <cassert>

#include "inc/Main.h"

namespace graphite2 {

struct IsoLangEntry
{
    unsigned short mnLang;
    char maLangStr[4];
    char maCountry[3];
};

// Windows Language ID, Locale ISO-639 language, country code as used in
// naming table of OpenType fonts
const IsoLangEntry LANG_ENTRIES[] = {
    { 0x0401, "ar","SA" }, // Arabic Saudi Arabia
    { 0x0402, "bg","BG" }, // Bulgarian Bulgaria
    { 0x0403, "ca","ES" }, // Catalan Catalan
    { 0x0404, "zh","TW" }, // Chinese Taiwan
    { 0x0405, "cs","CZ" }, // Czech Czech Republic
    { 0x0406, "da","DK" }, // Danish Denmark
    { 0x0407, "de","DE" }, // German Germany
    { 0x0408, "el","GR" }, // Greek Greece
    { 0x0409, "en","US" }, // English United States
    { 0x040A, "es","ES" }, // Spanish (Traditional Sort) Spain
    { 0x040B, "fi","FI" }, // Finnish Finland
    { 0x040C, "fr","FR" }, // French France
    { 0x040D, "he","IL" }, // Hebrew Israel
    { 0x040E, "hu","HU" }, // Hungarian Hungary
    { 0x040F, "is","IS" }, // Icelandic Iceland
    { 0x0410, "it","IT" }, // Italian Italy
    { 0x0411, "jp","JP" }, // Japanese Japan
    { 0x0412, "ko","KR" }, // Korean Korea
    { 0x0413, "nl","NL" }, // Dutch Netherlands
    { 0x0414, "no","NO" }, // Norwegian (Bokmal) Norway
    { 0x0415, "pl","PL" }, // Polish Poland
    { 0x0416, "pt","BR" }, // Portuguese Brazil
    { 0x0417, "rm","CH" }, // Romansh Switzerland
    { 0x0418, "ro","RO" }, // Romanian Romania
    { 0x0419, "ru","RU" }, // Russian Russia
    { 0x041A, "hr","HR" }, // Croatian Croatia
    { 0x041B, "sk","SK" }, // Slovak Slovakia
    { 0x041C, "sq","AL" }, // Albanian Albania
    { 0x041D, "sv","SE" }, // Swedish Sweden
    { 0x041E, "th","TH" }, // Thai Thailand
    { 0x041F, "tr","TR" }, // Turkish Turkey
    { 0x0420, "ur","PK" }, // Urdu Islamic Republic of Pakistan
    { 0x0421, "id","ID" }, // Indonesian Indonesia
    { 0x0422, "uk","UA" }, // Ukrainian Ukraine
    { 0x0423, "be","BY" }, // Belarusian Belarus
    { 0x0424, "sl","SI" }, // Slovenian Slovenia
    { 0x0425, "et","EE" }, // Estonian Estonia
    { 0x0426, "lv","LV" }, // Latvian Latvia
    { 0x0427, "lt","LT" }, // Lithuanian Lithuania
    { 0x0428, "tg","TJ" }, // Tajik (Cyrillic) Tajikistan
    { 0x042A, "vi","VN" }, // Vietnamese Vietnam
    { 0x042B, "hy","AM" }, // Armenian Armenia
    { 0x042C, "az","AZ" }, // Azeri (Latin) Azerbaijan
    { 0x042D, "eu","" }, // Basque Basque
    { 0x042E, "hsb","DE" }, // Upper Sorbian Germany
    { 0x042F, "mk","MK" }, // Macedonian (FYROM) Former Yugoslav Republic of Macedonia
    { 0x0432, "tn","ZA" }, // Setswana South Africa
    { 0x0434, "xh","ZA" }, // isiXhosa South Africa
    { 0x0435, "zu","ZA" }, // isiZulu South Africa
    { 0x0436, "af","ZA" }, // Afrikaans South Africa
    { 0x0437, "ka","GE" }, // Georgian Georgia
    { 0x0438, "fo","FO" }, // Faroese Faroe Islands
    { 0x0439, "hi","IN" }, // Hindi India
    { 0x043A, "mt","MT" }, // Maltese Malta
    { 0x043B, "se","NO" }, // Sami (Northern) Norway
    { 0x043E, "ms","MY" }, // Malay Malaysia
    { 0x043F, "kk","KZ" }, // Kazakh Kazakhstan
    { 0x0440, "ky","KG" }, // Kyrgyz Kyrgyzstan
    { 0x0441, "sw","KE" }, // Kiswahili Kenya
    { 0x0442, "tk","TM" }, // Turkmen Turkmenistan
    { 0x0443, "uz","UZ" }, // Uzbek (Latin) Uzbekistan
    { 0x0444, "tt","RU" }, // Tatar Russia
    { 0x0445, "bn","IN" }, // Bengali India
    { 0x0446, "pa","IN" }, // Punjabi India
    { 0x0447, "gu","IN" }, // Gujarati India
    { 0x0448, "or","IN" }, // Oriya India
    { 0x0448, "wo","SN" }, // Wolof Senegal
    { 0x0449, "ta","IN" }, // Tamil India
    { 0x044A, "te","IN" }, // Telugu India
    { 0x044B, "kn","IN" }, // Kannada India
    { 0x044C, "ml","IN" }, // Malayalam India
    { 0x044D, "as","IN" }, // Assamese India
    { 0x044E, "mr","IN" }, // Marathi India
    { 0x044F, "sa","IN" }, // Sanskrit India
    { 0x0450, "mn","MN" }, // Mongolian (Cyrillic) Mongolia
    { 0x0451, "bo","CN" }, // Tibetan PRC
    { 0x0452, "cy","GB" }, // Welsh United Kingdom
    { 0x0453, "km","KH" }, // Khmer Cambodia
    { 0x0454, "lo","LA" }, // Lao Lao P.D.R.
    { 0x0455, "my","MM" }, // Burmese Myanmar - not listed in Microsoft docs anymore
    { 0x0456, "gl","ES" }, // Galician Galician
    { 0x0457, "kok","IN" }, // Konkani India
    { 0x045A, "syr","TR" }, // Syriac Syria
    { 0x045B, "si","LK" }, // Sinhala Sri Lanka
    { 0x045D, "iu","CA" }, // Inuktitut Canada
    { 0x045E, "am","ET" }, // Amharic Ethiopia
    { 0x0461, "ne","NP" }, // Nepali Nepal
    { 0x0462, "fy","NL" }, // Frisian Netherlands
    { 0x0463, "ps","AF" }, // Pashto Afghanistan
    { 0x0464, "fil","PH" }, // Filipino Philippines
    { 0x0465, "dv","MV" }, // Divehi Maldives
    { 0x0468, "ha","NG" }, // Hausa (Latin) Nigeria
    { 0x046A, "yo","NG" }, // Yoruba Nigeria
    { 0x046B, "qu","BO" }, // Quechua Bolivia
    { 0x046C, "st","ZA" }, // Sesotho sa Leboa South Africa
    { 0x046D, "ba","RU" }, // Bashkir Russia
    { 0x046E, "lb","LU" }, // Luxembourgish Luxembourg
    { 0x046F, "kl","GL" }, // Greenlandic Greenland
    { 0x0470, "ig","NG" }, // Igbo Nigeria
    { 0x0478, "ii","CN" }, // Yi PRC
    { 0x047A, "arn","CL" }, // Mapudungun Chile
    { 0x047C, "moh","CA" }, // Mohawk Mohawk
    { 0x047E, "br","FR" }, // Breton France
    { 0x0480, "ug","CN" }, // Uighur PRC
    { 0x0481, "mi","NZ" }, // Maori New Zealand
    { 0x0482, "oc","FR" }, // Occitan France
    { 0x0483, "co","FR" }, // Corsican France
    { 0x0484, "gsw","FR" }, // Alsatian France
    { 0x0485, "sah","RU" }, // Yakut Russia
    { 0x0486, "qut","GT" }, // K'iche Guatemala
    { 0x0487, "rw","RW" }, // Kinyarwanda Rwanda
    { 0x048C, "gbz","AF" }, // Dari Afghanistan
    { 0x0801, "ar","IQ" }, // Arabic Iraq
    { 0x0804, "zn","CH" }, // Chinese People's Republic of China
    { 0x0807, "de","CH" }, // German Switzerland
    { 0x0809, "en","GB" }, // English United Kingdom
    { 0x080A, "es","MX" }, // Spanish Mexico
    { 0x080C, "fr","BE" }, // French Belgium
    { 0x0810, "it","CH" }, // Italian Switzerland
    { 0x0813, "nl","BE" }, // Dutch Belgium
    { 0x0814, "nn","NO" }, // Norwegian (Nynorsk) Norway
    { 0x0816, "pt","PT" }, // Portuguese Portugal
    { 0x081A, "sh","RS" }, // Serbian (Latin) Serbia
    { 0x081D, "sv","FI" }, // Sweden Finland
    { 0x082C, "az","AZ" }, // Azeri (Cyrillic) Azerbaijan
    { 0x082E, "dsb","DE" }, // Lower Sorbian Germany
    { 0x083B, "se","SE" }, // Sami (Northern) Sweden
    { 0x083C, "ga","IE" }, // Irish Ireland
    { 0x083E, "ms","BN" }, // Malay Brunei Darussalam
    { 0x0843, "uz","UZ" }, // Uzbek (Cyrillic) Uzbekistan
    { 0x0845, "bn","BD" }, // Bengali Bangladesh
    { 0x0850, "mn","MN" }, // Mongolian (Traditional) People's Republic of China
    { 0x085D, "iu","CA" }, // Inuktitut (Latin) Canada
    { 0x085F, "ber","DZ" }, // Tamazight (Latin) Algeria
    { 0x086B, "es","EC" }, // Quechua Ecuador
    { 0x0C01, "ar","EG" }, // Arabic Egypt
    { 0x0C04, "zh","HK" }, // Chinese Hong Kong S.A.R.
    { 0x0C07, "de","AT" }, // German Austria
    { 0x0C09, "en","AU" }, // English Australia
    { 0x0C0A, "es","ES" }, // Spanish (Modern Sort) Spain
    { 0x0C0C, "fr","CA" }, // French Canada
    { 0x0C1A, "sr","CS" }, // Serbian (Cyrillic) Serbia
    { 0x0C3B, "se","FI" }, // Sami (Northern) Finland
    { 0x0C6B, "qu","PE" }, // Quechua Peru
    { 0x1001, "ar","LY" }, // Arabic Libya
    { 0x1004, "zh","SG" }, // Chinese Singapore
    { 0x1007, "de","LU" }, // German Luxembourg
    { 0x1009, "en","CA" }, // English Canada
    { 0x100A, "es","GT" }, // Spanish Guatemala
    { 0x100C, "fr","CH" }, // French Switzerland
    { 0x101A, "hr","BA" }, // Croatian (Latin) Bosnia and Herzegovina
    { 0x103B, "smj","NO" }, // Sami (Lule) Norway
    { 0x1401, "ar","DZ" }, // Arabic Algeria
    { 0x1404, "zh","MO" }, // Chinese Macao S.A.R.
    { 0x1407, "de","LI" }, // German Liechtenstein
    { 0x1409, "en","NZ" }, // English New Zealand
    { 0x140A, "es","CR" }, // Spanish Costa Rica
    { 0x140C, "fr","LU" }, // French Luxembourg
    { 0x141A, "bs","BA" }, // Bosnian (Latin) Bosnia and Herzegovina
    { 0x143B, "smj","SE" }, // Sami (Lule) Sweden
    { 0x1801, "ar","MA" }, // Arabic Morocco
    { 0x1809, "en","IE" }, // English Ireland
    { 0x180A, "es","PA" }, // Spanish Panama
    { 0x180C, "fr","MC" }, // French Principality of Monoco
    { 0x181A, "sh","BA" }, // Serbian (Latin) Bosnia and Herzegovina
    { 0x183B, "sma","NO" }, // Sami (Southern) Norway
    { 0x1C01, "ar","TN" }, // Arabic Tunisia
    { 0x1C09, "en","ZA" }, // English South Africa
    { 0x1C0A, "es","DO" }, // Spanish Dominican Republic
    { 0x1C1A, "sr","BA" }, // Serbian (Cyrillic) Bosnia and Herzegovina
    { 0x1C3B, "sma","SE" }, // Sami (Southern) Sweden
    { 0x2001, "ar","OM" }, // Arabic Oman
    { 0x2009, "en","JM" }, // English Jamaica
    { 0x200A, "es","VE" }, // Spanish Venezuela
    { 0x201A, "bs","BA" }, // Bosnian (Cyrillic) Bosnia and Herzegovina
    { 0x203B, "sms","FI" }, // Sami (Skolt) Finland
    { 0x2401, "ar","YE" }, // Arabic Yemen
    { 0x2409, "en","BS" }, // English Caribbean
    { 0x240A, "es","CO" }, // Spanish Colombia
    { 0x243B, "smn","FI" }, // Sami (Inari) Finland
    { 0x2801, "ar","SY" }, // Arabic Syria
    { 0x2809, "en","BZ" }, // English Belize
    { 0x280A, "es","PE" }, // Spanish Peru
    { 0x2C01, "ar","JO" }, // Arabic Jordan
    { 0x2C09, "en","TT" }, // English Trinidad and Tobago
    { 0x2C0A, "es","AR" }, // Spanish Argentina
    { 0x3001, "ar","LB" }, // Arabic Lebanon
    { 0x3009, "en","ZW" }, // English Zimbabwe
    { 0x300A, "es","EC" }, // Spanish Ecuador
    { 0x3401, "ar","KW" }, // Arabic Kuwait
    { 0x3409, "en","PH" }, // English Republic of the Philippines
    { 0x340A, "es","CL" }, // Spanish Chile
    { 0x3801, "ar","AE" }, // Arabic U.A.E.
    { 0x380A, "es","UY" }, // Spanish Uruguay
    { 0x3C01, "ar","BH" }, // Arabic Bahrain
    { 0x3C0A, "es","PY" }, // Spanish Paraguay
    { 0x4001, "ar","QA" }, // Arabic Qatar
    { 0x4009, "en","IN" }, // English India
    { 0x400A, "es","BO" }, // Spanish Bolivia
    { 0x4409, "en","MY" }, // English Malaysia
    { 0x440A, "es","SV" }, // Spanish El Salvador
    { 0x4809, "en","SG" }, // English Singapore
    { 0x480A, "es","HN" }, // Spanish Honduras
    { 0x4C0A, "es","NI" }, // Spanish Nicaragua
    { 0x500A, "es","PR" }, // Spanish Puerto Rico
    { 0x540A, "es","US" } // Spanish United States
};

class Locale2Lang
{
    Locale2Lang(const Locale2Lang &);
    Locale2Lang & operator = (const Locale2Lang &);

public:
    Locale2Lang() : mSeedPosition(128)
    {
        memset((void*)mLangLookup, 0, sizeof(mLangLookup));
        // create a tri lookup on first 2 letters of language code
        static const int maxIndex = sizeof(LANG_ENTRIES)/sizeof(IsoLangEntry);
        for (int i = 0; i < maxIndex; i++)
        {
            size_t a = LANG_ENTRIES[i].maLangStr[0] - 'a';
            size_t b = LANG_ENTRIES[i].maLangStr[1] - 'a';
            if (mLangLookup[a][b])
            {
                const IsoLangEntry ** old = mLangLookup[a][b];
                int len = 1;
                while (old[len]) len++;
                len += 2;
                mLangLookup[a][b] = gralloc<const IsoLangEntry *>(len);
                if (!mLangLookup[a][b])
                {
                    mLangLookup[a][b] = old;
                    continue;
                }
                mLangLookup[a][b][--len] = NULL;
                mLangLookup[a][b][--len] = &LANG_ENTRIES[i];
                while (--len >= 0)
                {
                    assert(len >= 0);
                    mLangLookup[a][b][len] = old[len];
                }
                free(old);
            }
            else
            {
                mLangLookup[a][b] = gralloc<const IsoLangEntry *>(2);
                if (!mLangLookup[a][b]) continue;
                mLangLookup[a][b][1] = NULL;
                mLangLookup[a][b][0] = &LANG_ENTRIES[i];
            }
        }
        while (2 * mSeedPosition < maxIndex)
            mSeedPosition *= 2;
    };
    ~Locale2Lang()
    {
        for (int i = 0; i != 26; ++i)
            for (int j = 0; j != 26; ++j)
                free(mLangLookup[i][j]);
    }
    unsigned short getMsId(const char * locale) const
    {
        size_t length = strlen(locale);
        size_t langLength = length;
        const char * language = locale;
        const char * script = NULL;
        const char * region = NULL;
        size_t regionLength = 0;
        const char * dash = strchr(locale, '-');
        if (dash && (dash != locale))
        {
            langLength = (dash - locale);
            size_t nextPartLength = length - langLength - 1;
            if (nextPartLength >= 2)
            {
                script = ++dash;
                dash = strchr(dash, '-');
                if (dash)
                {
                    nextPartLength = (dash - script);
                    region = ++dash;
                }
                if (nextPartLength == 2 &&
                    (locale[langLength+1] > 0x40) && (locale[langLength+1] < 0x5B) &&
                    (locale[langLength+2] > 0x40) && (locale[langLength+2] < 0x5B))
                {
                    region = script;
                    regionLength = nextPartLength;
                    script = NULL;
                }
                else if (nextPartLength == 4)
                {
                    if (dash)
                    {
                        dash = strchr(dash, '-');
                        if (dash)
                        {
                            nextPartLength = (dash - region);
                        }
                        else
                        {
                            nextPartLength = langLength - (region - locale);
                        }
                        regionLength = nextPartLength;
                    }
                }
            }
        }
        size_t a = 'e' - 'a';
        size_t b = 'n' - 'a';
        unsigned short langId = 0;
        int i = 0;
        switch (langLength)
        {
            case 2:
            {
                a = language[0] - 'a';
                b = language[1] - 'a';
                if ((a < 26) && (b < 26) && mLangLookup[a][b])
                {
                    while (mLangLookup[a][b][i])
                    {
                        if (mLangLookup[a][b][i]->maLangStr[2] != '\0')
                        {
                            ++i;
                            continue;
                        }
                        if (region && (strncmp(mLangLookup[a][b][i]->maCountry, region, regionLength) == 0))
                        {
                            langId = mLangLookup[a][b][i]->mnLang;
                            break;
                        }
                        else if (langId == 0)
                        {
                            // possible fallback code
                            langId = mLangLookup[a][b][i]->mnLang;
                        }
                        ++i;
                    }
                }
            }
            break;
            case 3:
            {
                a = language[0] - 'a';
                b = language[1] - 'a';
                if (mLangLookup[a][b])
                {
                    while (mLangLookup[a][b][i])
                    {
                        if (mLangLookup[a][b][i]->maLangStr[2] != language[2])
                        {
                            ++i;
                            continue;
                        }
                        if (region && (strncmp(mLangLookup[a][b][i]->maCountry, region, regionLength) == 0))
                        {
                            langId = mLangLookup[a][b][i]->mnLang;
                            break;
                        }
                        else if (langId == 0)
                        {
                            // possible fallback code
                            langId = mLangLookup[a][b][i]->mnLang;
                        }
                        ++i;
                    }
                }
            }
            break;
            default:
                break;
        }
        if (langId == 0) langId = 0x409;
        return langId;
    }
    const IsoLangEntry * findEntryById(unsigned short langId) const
    {
        static const int maxIndex = sizeof(LANG_ENTRIES)/sizeof(IsoLangEntry);
        int window = mSeedPosition;
        int guess = mSeedPosition - 1;
        while (LANG_ENTRIES[guess].mnLang != langId)
        {
            window /= 2;
            if (window == 0) return NULL;
            guess += (LANG_ENTRIES[guess].mnLang > langId)? -window : window;
            while (guess >= maxIndex)
            {
                window /= 2;
                guess -= window;
                assert(window);
            }
        }
        return &LANG_ENTRIES[guess];
    }

    CLASS_NEW_DELETE;

private:
    const IsoLangEntry ** mLangLookup[26][26];
    int mSeedPosition;
};

} // namespace graphite2


text:
/*  GRAPHITE2 LICENSING

    Copyright 2010, SIL International
    All rights reserved.

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 of License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should also have received a copy of the GNU Lesser General Public
    License along with this library in the file named "LICENSE".
    If not, write to the Free Software Foundation, 51 Franklin Street,
    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    internet at http://www.fsf.org/licenses/lgpl.html.

Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
/*--------------------------------------------------------------------*//*:Ignore this sentence.

File: TtfTypes.h
Responsibility: Tim Eves
Last reviewed: Not yet.

Description:
Provides types required to represent the TTF basic types.
-------------------------------------------------------------------------------*//*:End Ignore*/

//**********************************************************************************************
//  Include files
//**********************************************************************************************
namespace graphite2
{
namespace TtfUtil
{
//**********************************************************************************************
//  Forward declarations
//**********************************************************************************************

//**********************************************************************************************
//  Type declarations
//**********************************************************************************************
typedef unsigned char   uint8;
typedef uint8           byte;
typedef signed char     int8;
typedef unsigned short  uint16;
typedef short           int16;
typedef unsigned int    uint32;
typedef int             int32;

typedef int16   short_frac;
typedef int32   fixed;
typedef int16   fword;
typedef uint16  ufword;
typedef int16   f2dot14;
typedef uint32  long_date_time[2];

//**********************************************************************************************
//  Constants and enum types
//**********************************************************************************************/
enum
{
    OneFix = 1<<16
};

//**********************************************************************************************
//  Table declarations
//**********************************************************************************************
namespace Sfnt
{
#pragma pack(push,1) // We need this or the structure members aren't aligned
                        // correctly.  Fortunately this form of pragma is supposed
                        // to be recognised by VS C++ too (at least according to
                        // MSDN).

    struct OffsetSubTable
    {
        uint32  scaler_type;
        uint16  num_tables,
            search_range,
            entry_selector,
            range_shift;
        struct Entry
        {
            uint32  tag,
                checksum,
                offset,
                length;
        } table_directory[1];

        enum ScalerType
        {
            TrueTypeMac = 0x74727565U,
            TrueTypeWin = 0x00010000U,
            Type1   = 0x74797031U
        };
    };

    struct CharacterCodeMap
    {
        uint16  version,
            num_subtables;
        struct
        {
            uint16  platform_id,
                platform_specific_id;
            uint32  offset;
        } encoding[1];
    };

    struct CmapSubTable
    {
        uint16  format,
            length,
            language;
    };

    struct CmapSubTableFormat4 : CmapSubTable
    {
        uint16  seg_count_x2,
            search_range,
            entry_selector,
            range_shift,
            end_code[1];
        // There are arrarys after this which need their
        // start positions calculated since end_code is
        // seg_count uint16s long.
    };

    struct CmapSubTableFormat12
    {
        fixed   format;
        uint32  length,
            language,
            num_groups;
        struct
        {
            uint32  start_char_code,
                end_char_code,
                start_glyph_id;
        } group[1];
    };

    struct FontHeader
    {
        fixed   version,
            font_revision;
        uint32  check_sum_adjustment,
            magic_number;
        uint16  flags,
            units_per_em;
        long_date_time  created,
                modified;
        fword   x_min,
            y_min,
            x_max,
            y_max;
        uint16  mac_style,
            lowest_rec_ppem;
        int16   font_direction_hint,
            index_to_loc_format,
            glyph_data_format;
        enum
        {
            MagicNumber = 0x5F0F3CF5,
            GlypDataFormat = 0
        };
        enum {ShortIndexLocFormat, LongIndexLocFormat};
    };

    struct PostScriptGlyphName
    {
        fixed   format,
            italic_angle;
        fword   underline_position,
            underline_thickness;
        uint32  is_fixed_pitch,
            min_mem_type42,
            max_mem_type42,
            min_mem_type1,
            max_mem_type1;
        enum
        {
            Format1  = 0x10000,
            Format2  = 0x20000,
            Format25 = 0x28000,
            Format3  = 0x30000,
            Format4  = 0x40000
        };
    };

    struct PostScriptGlyphName2 : PostScriptGlyphName
    {
        uint16  number_of_glyphs,
            glyph_name_index[1];
    };

    struct PostScriptGlyphName25 : PostScriptGlyphName
    {
        uint16  number_of_glyphs;
        int8    offset[1];
    };

    struct PostScriptGlyphName3 : PostScriptGlyphName {};

    struct PostScriptGlyphName4 : PostScriptGlyphName
    {
        uint16 glyph_to_char_map[1];
    };

    struct HorizontalHeader
    {
        fixed   version;
        fword   ascent,
            descent,
            line_gap;
        ufword  advance_width_max;
        fword   min_left_side_bearing,
            max_left_side_bearing,
            x_max_element;
        int16   caret_slope_rise,
            caret_slope_run;
        fword   caret_offset;
        int16   reserved[4],
            metric_data_format;
        uint16  num_long_hor_metrics;
    };

    struct MaximumProfile
    {
        fixed   version;
        uint16  num_glyphs,
            max_points,
            max_contours,
            max_component_points,
            max_component_contours,
            max_zones,
            max_twilight_points,
            max_storage,
            max_function_defs,
            max_instruction_defs,
            max_stack_elements,
            max_size_of_instructions,
            max_component_elements,
            max_component_depth;
    };

    typedef byte    Panose[10];

    struct Compatibility0
    {
        uint16  version;
        int16   x_avg_char_width;
        uint16  weight_class,
            width_class;
        int16   fs_type,
            y_subscript_x_size,
            y_subscript_y_size,
            y_subscript_x_offset,
            y_subscript_y_offset,
            y_superscript_x_size,
            y_superscript_y_size,
            y_superscript_x_offset,
            y_superscript_y_offset,
            y_strikeout_size,
            y_strikeout_position,
            family_class;
        Panose  panose;
        uint32  unicode_range[4];
        int8    ach_vend_id[4];
        uint16  fs_selection,
            fs_first_char_index,
            fs_last_char_index, // Acording to Apple's spec this is where v0 should end
            typo_ascender,
            typo_descender,
            type_linegap,
            win_ascent,
            win_descent;

        enum
        {
            Italic    =0x01,
            Underscore=0x02,
            Negative  =0x04,
            Outlined  =0x08,
            StrikeOut =0x10,
            Bold      =0x20
        };
    };

    struct Compatibility1 : Compatibility0
    {
        uint32  codepage_range[2];
    };

    struct Compatibility2 : Compatibility1
    {
            int16   x_height,
                cap_height;
            uint16  default_char,
                break_char,
                max_context;
    };

    struct Compatibility3 : Compatibility2 {};

    typedef Compatibility3  Compatibility;

    struct NameRecord
    {
        uint16  platform_id,
            platform_specific_id,
            language_id,
            name_id,
            length,
            offset;
        enum    {Unicode, Mactintosh, Reserved, Microsoft};
        enum
        {
            Copyright, Family, Subfamily, UniqueSubfamily,
            Fullname, Version, PostScript
        };
    };

    struct LangTagRecord
    {
        uint16 length,
            offset;
    };

    struct FontNames
    {
        uint16  format,
            count,
            string_offset;
        NameRecord name_record[1];
    };

    struct HorizontalMetric
    {
        uint16  advance_width;
        int16   left_side_bearing;
    };

    struct Glyph
    {
        int16   number_of_contours;
        fword   x_min,
            y_min,
            x_max,
            y_max;
    };

    struct SimpleGlyph : Glyph
    {
        uint16  end_pts_of_contours[1];
        enum
        {
            OnCurve = 0x01,
            XShort  = 0x02,
            YShort  = 0x04,
            Repeat  = 0x08,
            XIsSame = 0x10,
            XIsPos  = 0x10,
            YIsSame = 0x20,
            YIsPos  = 0x20
        };
    };

    struct CompoundGlyph : Glyph
    {
        uint16  flags,
            glyph_index;
        enum
        {
            Arg1Arg2Words   = 0x01,
            ArgsAreXYValues = 0x02,
            RoundXYToGrid   = 0x04,
            HaveScale       = 0x08,
            MoreComponents  = 0x20,
            HaveXAndYScale  = 0x40,
            HaveTwoByTwo    = 0x80,
            HaveInstructions = 0x100,
            UseMyMetrics    = 0x200,
            OverlapCompund  = 0x400,
            ScaledOffset    = 0x800,
            UnscaledOffset  = 0x1000
        };
    };

#pragma pack(pop)
} // end of namespace Sfnt

} // end of namespace TtfUtil
} // end of namespace graphite2