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 <utility>

#include "inc/Main.h"
#include "inc/List.h"
#include "inc/json.h"
#include "inc/Position.h"

// An IntervalSet represents the possible movement of a given glyph in a given direction
// (horizontally, vertically, or diagonally).
// A vector is needed to represent disjoint ranges, eg, -300..-150, 20..200, 500..750.
// Each pair represents the min/max of a sub-range.

namespace graphite2 {

class Segment;

enum zones_t {SD, XY};

class Zones
{
    struct Exclusion
    {
        template<zones_t O>
        static Exclusion weighted(float xmin, float xmax, float f, float a0,
                float m, float xi, float ai, float c, bool nega);

        float   x,  // x position
                xm, // xmax position
                c,  // constant + sum(MiXi^2)
                sm, // sum(Mi)
                smx; // sum(MiXi)
        bool    open;

        Exclusion(float x, float w, float smi, float smxi, float c);
        Exclusion & operator += (Exclusion const & rhs);
        uint8 outcode(float p) const;

        Exclusion   split_at(float p);
        void        left_trim(float p);

        bool        track_cost(float & cost, float & x, float origin) const;

    private:
        float test_position(float origin) const;
        float cost(float x) const;
     };

    typedef Vector<Exclusion>                   exclusions;

    typedef exclusions::iterator                iterator;
    typedef Exclusion *                         pointer;
    typedef Exclusion &                         reference;
    typedef std::reverse_iterator<iterator>     reverse_iterator;

public:
    typedef exclusions::const_iterator              const_iterator;
    typedef Exclusion const *                       const_pointer;
    typedef Exclusion const &                       const_reference;
    typedef std::reverse_iterator<const_iterator>   const_reverse_iterator;

#if !defined GRAPHITE2_NTRACING
    struct Debug
    {
        Exclusion       _excl;
        bool            _isdel;
        Vector<void *>  _env;

        Debug(Exclusion *e, bool isdel, json *dbg) : _excl(*e), _isdel(isdel), _env(dbg->getenvs()) { };
    };

    typedef Vector<Debug>                       debugs;
    typedef debugs::const_iterator                    idebugs;
    void addDebug(Exclusion *e);
    void removeDebug(float pos, float posm);
    void setdebug(json *dbgout) { _dbg = dbgout; }
    idebugs dbgs_begin() const { return _dbgs.begin(); }
    idebugs dbgs_end() const { return _dbgs.end(); }
    void jsonDbgOut(Segment *seg) const;
    Position position() const { return Position(_pos, _posm); }
#endif

    Zones();
    template<zones_t O>
    void initialise(float xmin, float xmax, float margin_len, float margin_weight, float ao);

    void exclude(float xmin, float xmax);
    void exclude_with_margins(float xmin, float xmax, int axis);

    template<zones_t O>
    void weighted(float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega);
    void weightedAxis(int axis, float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega);

    float closest( float origin, float &cost) const;

    const_iterator begin() const { return _exclusions.begin(); }
    const_iterator end() const { return _exclusions.end(); }

private:
    exclusions  _exclusions;
#if !defined GRAPHITE2_NTRACING
    json      * _dbg;
    debugs      _dbgs;
#endif
    float       _margin_len,
                _margin_weight,
                _pos,
                _posm;

    void            insert(Exclusion e);
    void            remove(float x, float xm);
    const_iterator  find_exclusion_under(float x) const;
};

inline
Zones::Zones()
: _margin_len(0), _margin_weight(0), _pos(0), _posm(0)
{
#if !defined GRAPHITE2_NTRACING
    _dbg = 0;
#endif
    _exclusions.reserve(8);
}

inline
Zones::Exclusion::Exclusion(float x_, float xm_, float smi, float smxi, float c_)
: x(x_), xm(xm_), c(c_), sm(smi), smx(smxi), open(false)
{ }

template<zones_t O>
inline
void Zones::initialise(float xmin, float xmax, float margin_len,
        float margin_weight, float a0)
{
    _margin_len = margin_len;
    _margin_weight = margin_weight;
    _pos = xmin;
    _posm = xmax;
    _exclusions.clear();
    _exclusions.push_back(Exclusion::weighted<O>(xmin, xmax, 1, a0, 0, 0, 0, 0, false));
    _exclusions.front().open = true;
#if !defined GRAPHITE2_NTRACING
    _dbgs.clear();
#endif
}

inline
void Zones::exclude(float xmin, float xmax) {
    remove(xmin, xmax);
}

template<zones_t O>
inline
void Zones::weighted(float xmin, float xmax, float f, float a0,
        float m, float xi, float ai, float c, bool nega) {
    insert(Exclusion::weighted<O>(xmin, xmax, f, a0, m, xi, ai, c, nega));
}

inline
void Zones::weightedAxis(int axis, float xmin, float xmax, float f, float a0,
        float m, float xi, float ai, float c, bool nega) {
    if (axis < 2)
        weighted<XY>(xmin, xmax, f, a0, m, xi, ai, c, nega);
    else
        weighted<SD>(xmin, xmax, f, a0, m, xi, ai, c, nega);
}

#if !defined GRAPHITE2_NTRACING
inline
void Zones::addDebug(Exclusion *e) {
    if (_dbg)
        _dbgs.push_back(Debug(e, false, _dbg));
}

inline
void Zones::removeDebug(float pos, float posm) {
    if (_dbg)
    {
        Exclusion e(pos, posm, 0, 0, 0);
        _dbgs.push_back(Debug(&e, true, _dbg));
    }
}
#endif

template<>
inline
Zones::Exclusion Zones::Exclusion::weighted<XY>(float xmin, float xmax, float f, float a0,
        float m, float xi, GR_MAYBE_UNUSED float ai, float c, GR_MAYBE_UNUSED bool nega) {
    return Exclusion(xmin, xmax,
            m + f,
            m * xi,
            m * xi * xi + f * a0 * a0 + c);
}

template<>
inline
Zones::Exclusion Zones::Exclusion::weighted<SD>(float xmin, float xmax, float f, float a0,
        float m, float xi, float ai,float c, bool nega) {
    float xia = nega ? xi - ai : xi + ai;
    return Exclusion(xmin, xmax,
            0.25f * (m + 2.f * f),
            0.25f * m * xia,
            0.25f * (m * xia * xia + 2.f * f * a0 * a0) + c);
}

} // 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.
*/
#pragma once

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

namespace graphite2 {

class Segment;
class Face;
class Silf;
struct Rule;
struct RuleEntry;
struct State;
class FiniteStateMachine;
class Error;
class ShiftCollider;
class KernCollider;
class json;

enum passtype;

class Pass
{
public:
    Pass();
    ~Pass();

    bool readPass(const byte * pPass, size_t pass_length, size_t subtable_base, Face & face,
        enum passtype pt, uint32 version, Error &e);
    bool runGraphite(vm::Machine & m, FiniteStateMachine & fsm, bool reverse) const;
    void init(Silf *silf) { m_silf = silf; }
    byte collisionLoops() const { return m_numCollRuns; }
    bool reverseDir() const { return m_isReverseDir; }

    CLASS_NEW_DELETE
private:
    void    findNDoRule(Slot* & iSlot, vm::Machine &, FiniteStateMachine& fsm) const;
    int     doAction(const vm::Machine::Code* codeptr, Slot * & slot_out, vm::Machine &) const;
    bool    testPassConstraint(vm::Machine & m) const;
    bool    testConstraint(const Rule & r, vm::Machine &) const;
    bool    readRules(const byte * rule_map, const size_t num_entries,
                     const byte *precontext, const uint16 * sort_key,
                     const uint16 * o_constraint, const byte *constraint_data,
                     const uint16 * o_action, const byte * action_data,
                     Face &, enum passtype pt, Error &e);
    bool    readStates(const byte * starts, const byte * states, const byte * o_rule_map, Face &, Error &e);
    bool    readRanges(const byte * ranges, size_t num_ranges, Error &e);
    uint16  glyphToCol(const uint16 gid) const;
    bool    runFSM(FiniteStateMachine & fsm, Slot * slot) const;
    void    dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const;
    void    dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * os) const;
    void    adjustSlot(int delta, Slot * & slot_out, SlotMap &) const;
    bool    collisionShift(Segment *seg, int dir, json * const dbgout) const;
    bool    collisionKern(Segment *seg, int dir, json * const dbgout) const;
    bool    collisionFinish(Segment *seg, GR_MAYBE_UNUSED json * const dbgout) const;
    bool    resolveCollisions(Segment *seg, Slot *slot, Slot *start, ShiftCollider &coll, bool isRev,
                     int dir, bool &moved, bool &hasCol, json * const dbgout) const;
    float   resolveKern(Segment *seg, Slot *slot, Slot *start, int dir,
                     float &ymin, float &ymax, json *const dbgout) const;

    const Silf        * m_silf;
    uint16            * m_cols;
    Rule              * m_rules; // rules
    RuleEntry         * m_ruleMap;
    uint16            * m_startStates; // prectxt length
    uint16            * m_transitions;
    State             * m_states;
    vm::Machine::Code * m_codes;
    byte              * m_progs;

    byte   m_numCollRuns;
    byte   m_kernColls;
    byte   m_iMaxLoop;
    uint16 m_numGlyphs;
    uint16 m_numRules;
    uint16 m_numStates;
    uint16 m_numTransition;
    uint16 m_numSuccess;
    uint16 m_successStart;
    uint16 m_numColumns;
    byte m_minPreCtxt;
    byte m_maxPreCtxt;
    byte m_colThreshold;
    bool m_isReverseDir;
    vm::Machine::Code m_cPConstraint;

private:        //defensive
    Pass(const Pass&);
    Pass& operator=(const Pass&);
};

} // namespace graphite2

repo_language: C

mime_type: text/x-c


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/Position.h"
#include "inc/Sparse.h"

namespace graphite2 {

enum metrics {
    kgmetLsb = 0, kgmetRsb,
    kgmetBbTop, kgmetBbBottom, kgmetBbLeft, kgmetBbRight,
    kgmetBbHeight, kgmetBbWidth,
    kgmetAdvWidth, kgmetAdvHeight,
    kgmetAscent, kgmetDescent
};

class GlyphFace
{
public:
    GlyphFace();
    template<typename I>
    GlyphFace(const Rect & bbox, const Position & adv, I first, const I last);

    const Position    & theAdvance() const;
    const Rect        & theBBox() const { return m_bbox; }
    const sparse      & attrs() const { return m_attrs; }
    int32               getMetric(uint8 metric) const;

    CLASS_NEW_DELETE;
private:
    Rect     m_bbox;        // bounding box metrics in design units
    Position m_advance;     // Advance width and height in design units
    sparse   m_attrs;
};

// Inlines: class GlyphFace
//
inline
GlyphFace::GlyphFace()
{}

template<typename I>
GlyphFace::GlyphFace(const Rect & bbox, const Position & adv, I first, const I last)
: m_bbox(bbox),
  m_advance(adv),
  m_attrs(first, last)
{
}

inline
const Position & GlyphFace::theAdvance() const {
    return m_advance;
}

} // 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"

#include <cassert>

#include "inc/CharInfo.h"
#include "inc/Face.h"
#include "inc/FeatureVal.h"
#include "inc/GlyphCache.h"
#include "inc/GlyphFace.h"
#include "inc/Slot.h"
#include "inc/Position.h"
#include "inc/List.h"
#include "inc/Collider.h"

#define MAX_SEG_GROWTH_FACTOR  64

namespace graphite2 {

typedef Vector<Features>        FeatureList;
typedef Vector<Slot *>          SlotRope;
typedef Vector<int16 *>         AttributeRope;
typedef Vector<SlotJustify *>   JustifyRope;

class Font;
class Segment;
class Silf;

enum SpliceParam {
/** sub-Segments longer than this are not cached
 * (in Unicode code points) */
    eMaxSpliceSize = 96
};

enum justFlags {
    gr_justStartInline = 1,
    gr_justEndInline = 2
};

class SegmentScopeState
{
private:
    friend class Segment;
    Slot * realFirstSlot;
    Slot * slotBeforeScope;
    Slot * slotAfterScope;
    Slot * realLastSlot;
    size_t numGlyphsOutsideScope;
};

class Segment
{
    // Prevent copying of any kind.
    Segment(const Segment&);
    Segment& operator=(const Segment&);

public:

    enum {
        SEG_INITCOLLISIONS = 1,
        SEG_HASCOLLISIONS = 2
    };

    size_t slotCount() const { return m_numGlyphs; }      //one slot per glyph
    void extendLength(ptrdiff_t num) { m_numGlyphs += num; }
    Position advance() const { return m_advance; }
    bool runGraphite() { if (m_silf) return m_face->runGraphite(this, m_silf); else return true;};
    void chooseSilf(uint32 script) { m_silf = m_face->chooseSilf(script); }
    const Silf *silf() const { return m_silf; }
    size_t charInfoCount() const { return m_numCharinfo; }
    const CharInfo *charinfo(unsigned int index) const { return index < m_numCharinfo ? m_charinfo + index : NULL; }
    CharInfo *charinfo(unsigned int index) { return index < m_numCharinfo ? m_charinfo + index : NULL; }

    Segment(size_t numchars, const Face* face, uint32 script, int dir);
    ~Segment();
    uint8 flags() const { return m_flags; }
    void flags(uint8 f) { m_flags = f; }
    Slot *first() { return m_first; }
    void first(Slot *p) { m_first = p; }
    Slot *last() { return m_last; }
    void last(Slot *p) { m_last = p; }
    void appendSlot(int i, int cid, int gid, int fid, size_t coffset);
    Slot *newSlot();
    void freeSlot(Slot *);
    SlotJustify *newJustify();
    void freeJustify(SlotJustify *aJustify);
    Position positionSlots(const Font *font=0, Slot *first=0, Slot *last=0, bool isRtl = false, bool isFinal = true);
    void associateChars(int offset, size_t num);
    void linkClusters(Slot *first, Slot *last);
    uint16 getClassGlyph(uint16 cid, uint16 offset) const { return m_silf->getClassGlyph(cid, offset); }
    uint16 findClassIndex(uint16 cid, uint16 gid) const { return m_silf->findClassIndex(cid, gid); }
    int addFeatures(const Features& feats) { m_feats.push_back(feats); return int(m_feats.size()) - 1; }
    uint32 getFeature(int index, uint8 findex) const { const FeatureRef* pFR=m_face->theSill().theFeatureMap().featureRef(findex); if (!pFR) return 0; else return pFR->getFeatureVal(m_feats[index]); }
    void setFeature(int index, uint8 findex, uint32 val) {
        const FeatureRef* pFR=m_face->theSill().theFeatureMap().featureRef(findex);
        if (pFR)
        {
            if (val > pFR->maxVal()) val = pFR->maxVal();
            pFR->applyValToFeature(val, m_feats[index]);
        } }
    int8 dir() const { return m_dir; }
    void dir(int8 val) { m_dir = val; }
    bool currdir() const { return ((m_dir >> 6) ^ m_dir) & 1; }
    uint8 passBits() const { return m_passBits; }
    void mergePassBits(const uint8 val) { m_passBits &= val; }
    int16 glyphAttr(uint16 gid, uint16 gattr) const { const GlyphFace * p = m_face->glyphs().glyphSafe(gid); return p ? p->attrs()[gattr] : 0; }
    int32 getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel, bool rtl) const;
    float glyphAdvance(uint16 gid) const { return m_face->glyphs().glyph(gid)->theAdvance().x; }
    const Rect &theGlyphBBoxTemporary(uint16 gid) const { return m_face->glyphs().glyph(gid)->theBBox(); }   //warning value may become invalid when another glyph is accessed
    Slot *findRoot(Slot *is) const { return is->attachedTo() ? findRoot(is->attachedTo()) : is; }
    int numAttrs() const { return m_silf->numUser(); }
    int defaultOriginal() const { return m_defaultOriginal; }
    const Face * getFace() const { return m_face; }
    const Features & getFeatures(unsigned int /*charIndex*/) { assert(m_feats.size() == 1); return m_feats[0]; }
    void bidiPass(int paradir, uint8 aMirror);
    int8 getSlotBidiClass(Slot *s) const;
    void doMirror(uint16 aMirror);
    Slot *addLineEnd(Slot *nSlot);
    void delLineEnd(Slot *s);
    bool hasJustification() const { return m_justifies.size() != 0; }
    void reverseSlots();

    bool isWhitespace(const int cid) const;
    bool hasCollisionInfo() const { return (m_flags & SEG_HASCOLLISIONS) && m_collisions; }
    SlotCollision *collisionInfo(const Slot *s) const { return m_collisions ? m_collisions + s->index() : 0; }
    CLASS_NEW_DELETE

public:       //only used by: GrSegment* makeAndInitialize(const GrFont *font, const GrFace *face, uint32 script, const FeaturesHandle& pFeats/*must not be IsNull*/, encform enc, const void* pStart, size_t nChars, int dir);
    bool read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void*pStart, size_t nChars);
    void finalise(const Font *font, bool reverse=false);
    float justify(Slot *pSlot, const Font *font, float width, enum justFlags flags, Slot *pFirst, Slot *pLast);
    bool initCollisions();

private:
    Position        m_advance;          // whole segment advance
    SlotRope        m_slots;            // Vector of slot buffers
    AttributeRope   m_userAttrs;        // Vector of userAttrs buffers
    JustifyRope     m_justifies;        // Slot justification info buffers
    FeatureList     m_feats;            // feature settings referenced by charinfos in this segment
    Slot          * m_freeSlots;        // linked list of free slots
    SlotJustify   * m_freeJustifies;    // Slot justification blocks free list
    CharInfo      * m_charinfo;         // character info, one per input character
    SlotCollision * m_collisions;
    const Face    * m_face;             // GrFace
    const Silf    * m_silf;
    Slot          * m_first;            // first slot in segment
    Slot          * m_last;             // last slot in segment
    size_t          m_bufSize,          // how big a buffer to create when need more slots
                    m_numGlyphs,
                    m_numCharinfo;      // size of the array and number of input characters
    int             m_defaultOriginal;  // number of whitespace chars in the string
    int8            m_dir;
    uint8           m_flags,            // General purpose flags
                    m_passBits;         // if bit set then skip pass
};

inline
int8 Segment::getSlotBidiClass(Slot *s) const
{
    int8 res = s->getBidiClass();
    if (res != -1) return res;
    res = int8(glyphAttr(s->gid(), m_silf->aBidi()));
    s->setBidiClass(res);
    return res;
}

inline
void Segment::finalise(const Font *font, bool reverse)
{
    if (!m_first || !m_last) return;

    m_advance = positionSlots(font, m_first, m_last, m_silf->dir(), true);
    //associateChars(0, m_numCharinfo);
    if (reverse && currdir() != (m_dir & 1))
        reverseSlots();
    linkClusters(m_first, m_last);
}

inline
int32 Segment::getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel, bool rtl) const {
    if (attrLevel > 0)
    {
        Slot *is = findRoot(iSlot);
        return is->clusterMetric(this, metric, attrLevel, rtl);
    }
    else
        return m_face->getGlyphMetric(iSlot->gid(), metric);
}

inline
bool Segment::isWhitespace(const int cid) const
{
    return ((cid >= 0x0009) * (cid <= 0x000D)
         + (cid == 0x0020)
         + (cid == 0x0085)
         + (cid == 0x00A0)
         + (cid == 0x1680)
         + (cid == 0x180E)
         + (cid >= 0x2000) * (cid <= 0x200A)
         + (cid == 0x2028)
         + (cid == 0x2029)
         + (cid == 0x202F)
         + (cid == 0x205F)
         + (cid == 0x3000)) != 0;
}

} // namespace graphite2

struct gr_segment : public graphite2::Segment {};


text:
/*  GRAPHITE2 LICENSING

    Copyright 2015, 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 <cassert>
#include <cstddef>
#include <cstring>

namespace
{

#if defined(_MSC_VER)
typedef unsigned __int8 u8;
typedef unsigned __int16 u16;
typedef unsigned __int32 u32;
typedef unsigned __int64 u64;
#else
#include <stdint.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#endif

ptrdiff_t const     MINMATCH = 4,
                    LASTLITERALS = 5,
                    MINCODA  = LASTLITERALS+1,
                    MINSRCSIZE = 13;

template<int S>
inline
void unaligned_copy(void * d, void const * s) {
  ::memcpy(d, s, S);
}

inline
size_t align(size_t p) {
    return (p + sizeof(unsigned long)-1) & ~(sizeof(unsigned long)-1);
}

inline
u8 * safe_copy(u8 * d, u8 const * s, size_t n) {
    while (n--) *d++ = *s++;
    return d;
}

inline
u8 * overrun_copy(u8 * d, u8 const * s, size_t n) {
    size_t const WS = sizeof(unsigned long);
    u8 const * e = s + n;
    do
    {
        unaligned_copy<WS>(d, s);
        d += WS;
        s += WS;
    }
    while (s < e);
    d-=(s-e);

    return d;
}

inline
u8 * fast_copy(u8 * d, u8 const * s, size_t n) {
    size_t const WS = sizeof(unsigned long);
    size_t wn = n/WS;
    while (wn--)
    {
        unaligned_copy<WS>(d, s);
        d += WS;
        s += WS;
    }
    n &= WS-1;
    return safe_copy(d, s, n);
}

} // end of anonymous namespace


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/Font.h"
#include "inc/Main.h"
#include "inc/Pass.h"

namespace graphite2 {

class Face;
class Segment;
class FeatureVal;
class VMScratch;
class Error;

class Pseudo
{
public:
    uint32 uid;
    uint32 gid;
    CLASS_NEW_DELETE;
};

class Justinfo
{
public:
    Justinfo(uint8 stretch, uint8 shrink, uint8 step, uint8 weight) :
        m_astretch(stretch), m_ashrink(shrink), m_astep(step),
        m_aweight(weight) {};
    uint8 attrStretch() const { return m_astretch; }
    uint8 attrShrink() const { return m_ashrink; }
    uint8 attrStep() const { return m_astep; }
    uint8 attrWeight() const { return m_aweight; }

private:
    uint8   m_astretch;
    uint8   m_ashrink;
    uint8   m_astep;
    uint8   m_aweight;
};

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

public:
    Silf() throw();
    ~Silf() throw();

    bool readGraphite(const byte * const pSilf, size_t lSilf, Face &face, uint32 version);
    bool runGraphite(Segment *seg, uint8 firstPass=0, uint8 lastPass=0, int dobidi = 0) const;
    uint16 findClassIndex(uint16 cid, uint16 gid) const;
    uint16 getClassGlyph(uint16 cid, unsigned int index) const;
    uint16 findPseudo(uint32 uid) const;
    uint8 numUser() const { return m_aUser; }
    uint8 aPseudo() const { return m_aPseudo; }
    uint8 aBreak() const { return m_aBreak; }
    uint8 aMirror() const {return m_aMirror; }
    uint8 aPassBits() const { return m_aPassBits; }
    uint8 aBidi() const { return m_aBidi; }
    uint8 aCollision() const { return m_aCollision; }
    uint8 substitutionPass() const { return m_sPass; }
    uint8 positionPass() const { return m_pPass; }
    uint8 justificationPass() const { return m_jPass; }
    uint8 bidiPass() const { return m_bPass; }
    uint8 numPasses() const { return m_numPasses; }
    uint8 maxCompPerLig() const { return m_iMaxComp; }
    uint16 numClasses() const { return m_nClass; }
    byte  flags() const { return m_flags; }
    byte  dir() const { return m_dir; }
    uint8 numJustLevels() const { return m_numJusts; }
    Justinfo *justAttrs() const { return m_justs; }
    uint16 endLineGlyphid() const { return m_gEndLine; }
    const gr_faceinfo *silfInfo() const { return &m_silfinfo; }

    CLASS_NEW_DELETE;

private:
    size_t readClassMap(const byte *p, size_t data_len, uint32 version, Error &e);
    template<typename T> inline uint32 readClassOffsets(const byte *&p, size_t data_len, Error &e);

    Pass          * m_passes;
    Pseudo        * m_pseudos;
    uint32        * m_classOffsets;
    uint16        * m_classData;
    Justinfo      * m_justs;
    uint8           m_numPasses;
    uint8           m_numJusts;
    uint8           m_sPass, m_pPass, m_jPass, m_bPass,
                    m_flags, m_dir;

    uint8       m_aPseudo, m_aBreak, m_aUser, m_aBidi, m_aMirror, m_aPassBits,
                m_iMaxComp, m_aCollision;
    uint16      m_aLig, m_numPseudo, m_nClass, m_nLinear,
                m_gEndLine;
    gr_faceinfo m_silfinfo;

    void releaseBuffers() throw();
};

} // 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
// This file will be pulled into and integrated into a machine implmentation
// DO NOT build directly and under no circumstances ever #include headers in
// here or you will break the direct_machine.
//
// Implementers' notes
// ==================
// You have access to a few primitives and the full C++ code:
//    declare_params(n) Tells the interpreter how many bytes of parameter
//                      space to claim for this instruction uses and
//                      initialises the param pointer.  You *must* before the
//                      first use of param.
//    use_params(n)     Claim n extra bytes of param space beyond what was
//                      claimed using delcare_param.
//    param             A const byte pointer for the parameter space claimed by
//                      this instruction.
//    binop(op)         Implement a binary operation on the stack using the
//                      specified C++ operator.
//    NOT_IMPLEMENTED   Any instruction body containing this will exit the
//                      program with an assertion error.  Instructions that are
//                      not implemented should also be marked NILOP in the
//                      opcodes tables this will cause the code class to spot
//                      them in a live code stream and throw a runtime_error
//                      instead.
//    push(n)           Push the value n onto the stack.
//    pop()             Pop the top most value and return it.
//
//    You have access to the following named fast 'registers':
//        sp        = The pointer to the current top of stack, the last value
//                    pushed.
//        seg       = A reference to the Segment this code is running over.
//        is        = The current slot index
//        isb       = The original base slot index at the start of this rule
//        isf       = The first positioned slot
//        isl       = The last positioned slot
//        ip        = The current instruction pointer
//        endPos    = Position of advance of last cluster
//        dir       = writing system directionality of the font

// #define NOT_IMPLEMENTED     assert(false)
// #define NOT_IMPLEMENTED

#define binop(op)           const uint32 a = pop(); *sp = uint32(*sp) op a
#define sbinop(op)          const int32 a = pop(); *sp = int32(*sp) op a
#define use_params(n)       dp += n

#define declare_params(n)   const byte * param = dp; \
                            use_params(n);

#define push(n)             { *++sp = n; }
#define pop()               (*sp--)
#define slotat(x)           (map[(x)])
#define DIE                 { is=seg.last(); status = Machine::died_early; EXIT(1); }
#define POSITIONED          1

STARTOP(nop)
    do {} while (0);
ENDOP

STARTOP(push_byte)
    declare_params(1);
    push(int8(*param));
ENDOP

STARTOP(push_byte_u)
    declare_params(1);
    push(uint8(*param));
ENDOP

STARTOP(push_short)
    declare_params(2);
    const int16 r   = int16(param[0]) << 8
                    | uint8(param[1]);
    push(r);
ENDOP

STARTOP(push_short_u)
    declare_params(2);
    const uint16 r  = uint16(param[0]) << 8
                    | uint8(param[1]);
    push(r);
ENDOP

STARTOP(push_long)
    declare_params(4);
    const  int32 r  = int32(param[0]) << 24
                    | uint32(param[1]) << 16
                    | uint32(param[2]) << 8
                    | uint8(param[3]);
    push(r);
ENDOP

STARTOP(add)
    binop(+);
ENDOP

STARTOP(sub)
    binop(-);
ENDOP

STARTOP(mul)
    binop(*);
ENDOP

STARTOP(div_)
    const int32 b = pop();
    const int32 a = int32(*sp);
    if (b == 0 || (a == std::numeric_limits<int32>::min() && b == -1)) DIE;
    *sp = int32(*sp) / b;
ENDOP

STARTOP(min_)
    const int32 a = pop(), b = *sp;
    if (a < b) *sp = a;
ENDOP

STARTOP(max_)
    const int32 a = pop(), b = *sp;
    if (a > b) *sp = a;
ENDOP

STARTOP(neg)
    *sp = uint32(-int32(*sp));
ENDOP

STARTOP(trunc8)
    *sp = uint8(*sp);
ENDOP

STARTOP(trunc16)
    *sp = uint16(*sp);
ENDOP

STARTOP(cond)
    const uint32 f = pop(), t = pop(), c = pop();
    push(c ? t : f);
ENDOP

STARTOP(and_)
    binop(&&);
ENDOP

STARTOP(or_)
    binop(||);
ENDOP

STARTOP(not_)
    *sp = !*sp;
ENDOP

STARTOP(equal)
    binop(==);
ENDOP

STARTOP(not_eq_)
    binop(!=);
ENDOP

STARTOP(less)
    sbinop(<);
ENDOP

STARTOP(gtr)
    sbinop(>);
ENDOP

STARTOP(less_eq)
    sbinop(<=);
ENDOP

STARTOP(gtr_eq)
    sbinop(>=);
ENDOP

STARTOP(next)
    if (map - &smap[0] >= int(smap.size())) DIE
    if (is)
    {
        if (is == smap.highwater())
            smap.highpassed(true);
        is = is->next();
    }
    ++map;
ENDOP

//STARTOP(next_n)
//    use_params(1);
//    NOT_IMPLEMENTED;
    //declare_params(1);
    //const size_t num = uint8(*param);
//ENDOP

//STARTOP(copy_next)
//     if (is) is = is->next();
//     ++map;
// ENDOP

STARTOP(put_glyph_8bit_obs)
    declare_params(1);
    const unsigned int output_class = uint8(*param);
    is->setGlyph(&seg, seg.getClassGlyph(output_class, 0));
ENDOP

STARTOP(put_subs_8bit_obs)
    declare_params(3);
    const int           slot_ref     = int8(param[0]);
    const unsigned int  input_class  = uint8(param[1]),
                        output_class = uint8(param[2]);
    uint16 index;
    slotref slot = slotat(slot_ref);
    if (slot)
    {
        index = seg.findClassIndex(input_class, slot->gid());
        is->setGlyph(&seg, seg.getClassGlyph(output_class, index));
    }
ENDOP

STARTOP(put_copy)
    declare_params(1);
    const int  slot_ref = int8(*param);
    if (is && !is->isDeleted())
    {
        slotref ref = slotat(slot_ref);
        if (ref && ref != is)
        {
            int16 *tempUserAttrs = is->userAttrs();
            if (is->attachedTo() || is->firstChild()) DIE
            Slot *prev = is->prev();
            Slot *next = is->next();
            memcpy(tempUserAttrs, ref->userAttrs(), seg.numAttrs() * sizeof(uint16));
            memcpy(is, ref, sizeof(Slot));
            is->firstChild(NULL);
            is->nextSibling(NULL);
            is->userAttrs(tempUserAttrs);
            is->next(next);
            is->prev(prev);
            if (is->attachedTo())
                is->attachedTo()->child(is);
        }
        is->markCopied(false);
        is->markDeleted(false);
    }
ENDOP

STARTOP(insert)
    if (smap.decMax() <= 0) DIE;
    Slot *newSlot = seg.newSlot();
    if (!newSlot) DIE;
    Slot *iss = is;
    while (iss && iss->isDeleted()) iss = iss->next();
    if (!iss)
    {
        if (seg.last())
        {
            seg.last()->next(newSlot);
            newSlot->prev(seg.last());
            newSlot->before(seg.last()->before());
            seg.last(newSlot);
        }
        else
        {
            seg.first(newSlot);
            seg.last(newSlot);
        }
    }
    else if (iss->prev())
    {
        iss->prev()->next(newSlot);
        newSlot->prev(iss->prev());
        newSlot->before(iss->prev()->after());
    }
    else
    {
        newSlot->prev(NULL);
        newSlot->before(iss->before());
        seg.first(newSlot);
    }
    newSlot->next(iss);
    if (iss)
    {
        iss->prev(newSlot);
        newSlot->originate(iss->original());
        newSlot->after(iss->before());
    }
    else if (newSlot->prev())
    {
        newSlot->originate(newSlot->prev()->original());
        newSlot->after(newSlot->prev()->after());
    }
    else
    {
        newSlot->originate(seg.defaultOriginal());
    }
    if (is == smap.highwater())
        smap.highpassed(false);
    is = newSlot;
    seg.extendLength(1);
    if (map != &smap[-1])
        --map;
ENDOP

STARTOP(delete_)
    if (!is || is->isDeleted()) DIE
    is->markDeleted(true);
    if (is->prev())
        is->prev()->next(is->next());
    else
        seg.first(is->next());

    if (is->next())
        is->next()->prev(is->prev());
    else
        seg.last(is->prev());

    if (is == smap.highwater())
            smap.highwater(is->next());
    if (is->prev())
        is = is->prev();
    seg.extendLength(-1);
ENDOP

STARTOP(assoc)
    declare_params(1);
    unsigned int  num = uint8(*param);
    const int8 *  assocs = reinterpret_cast<const int8 *>(param+1);
    use_params(num);
    int max = -1;
    int min = -1;

    while (num-- > 0)
    {
        int sr = *assocs++;
        slotref ts = slotat(sr);
        if (ts && (min == -1 || ts->before() < min)) min = ts->before();
        if (ts && ts->after() > max) max = ts->after();
    }
    if (min > -1)   // implies max > -1
    {
        is->before(min);
        is->after(max);
    }
ENDOP

STARTOP(cntxt_item)
    // It turns out this is a cunningly disguised condition forward jump.
    declare_params(3);
    const int       is_arg = int8(param[0]);
    const size_t    iskip  = uint8(param[1]),
                    dskip  = uint8(param[2]);

    if (mapb + is_arg != map)
    {
        ip += iskip;
        dp += dskip;
        push(true);
    }
ENDOP

STARTOP(attr_set)
    declare_params(1);
    const attrCode      slat = attrCode(uint8(*param));
    const          int  val  = pop();
    is->setAttr(&seg, slat, 0, val, smap);
ENDOP

STARTOP(attr_add)
    declare_params(1);
    const attrCode      slat = attrCode(uint8(*param));
    const     uint32_t  val  = pop();
    if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
    {
        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
        flags |= POSITIONED;
    }
    uint32_t res = uint32_t(is->getAttr(&seg, slat, 0));
    is->setAttr(&seg, slat, 0, int32_t(val + res), smap);
ENDOP

STARTOP(attr_sub)
    declare_params(1);
    const attrCode      slat = attrCode(uint8(*param));
    const     uint32_t  val  = pop();
    if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
    {
        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
        flags |= POSITIONED;
    }
    uint32_t res = uint32_t(is->getAttr(&seg, slat, 0));
    is->setAttr(&seg, slat, 0, int32_t(res - val), smap);
ENDOP

STARTOP(attr_set_slot)
    declare_params(1);
    const attrCode  slat   = attrCode(uint8(*param));
    const int       offset = int(map - smap.begin())*int(slat == gr_slatAttTo);
    const int       val    = pop()  + offset;
    is->setAttr(&seg, slat, offset, val, smap);
ENDOP

STARTOP(iattr_set_slot)
    declare_params(2);
    const attrCode  slat = attrCode(uint8(param[0]));
    const uint8     idx  = uint8(param[1]);
    const int       val  = int(pop()  + (map - smap.begin())*int(slat == gr_slatAttTo));
    is->setAttr(&seg, slat, idx, val, smap);
ENDOP

STARTOP(push_slot_attr)
    declare_params(2);
    const attrCode      slat     = attrCode(uint8(param[0]));
    const int           slot_ref = int8(param[1]);
    if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
    {
        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
        flags |= POSITIONED;
    }
    slotref slot = slotat(slot_ref);
    if (slot)
    {
        int res = slot->getAttr(&seg, slat, 0);
        push(res);
    }
ENDOP

STARTOP(push_glyph_attr_obs)
    declare_params(2);
    const unsigned int  glyph_attr = uint8(param[0]);
    const int           slot_ref   = int8(param[1]);
    slotref slot = slotat(slot_ref);
    if (slot)
        push(int32(seg.glyphAttr(slot->gid(), glyph_attr)));
ENDOP

STARTOP(push_glyph_metric)
    declare_params(3);
    const unsigned int  glyph_attr  = uint8(param[0]);
    const int           slot_ref    = int8(param[1]);
    const signed int    attr_level  = uint8(param[2]);
    slotref slot = slotat(slot_ref);
    if (slot)
        push(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir));
ENDOP

STARTOP(push_feat)
    declare_params(2);
    const unsigned int  feat        = uint8(param[0]);
    const int           slot_ref    = int8(param[1]);
    slotref slot = slotat(slot_ref);
    if (slot)
    {
        uint8 fid = seg.charinfo(slot->original())->fid();
        push(seg.getFeature(fid, feat));
    }
ENDOP

STARTOP(push_att_to_gattr_obs)
    declare_params(2);
    const unsigned int  glyph_attr  = uint8(param[0]);
    const int           slot_ref    = int8(param[1]);
    slotref slot = slotat(slot_ref);
    if (slot)
    {
        slotref att = slot->attachedTo();
        if (att) slot = att;
        push(int32(seg.glyphAttr(slot->gid(), glyph_attr)));
    }
ENDOP

STARTOP(push_att_to_glyph_metric)
    declare_params(3);
    const unsigned int  glyph_attr  = uint8(param[0]);
    const int           slot_ref    = int8(param[1]);
    const signed int    attr_level  = uint8(param[2]);
    slotref slot = slotat(slot_ref);
    if (slot)
    {
        slotref att = slot->attachedTo();
        if (att) slot = att;
        push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir)));
    }
ENDOP

STARTOP(push_islot_attr)
    declare_params(3);
    const attrCode  slat     = attrCode(uint8(param[0]));
    const int           slot_ref = int8(param[1]),
                        idx      = uint8(param[2]);
    if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
    {
        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
        flags |= POSITIONED;
    }
    slotref slot = slotat(slot_ref);
    if (slot)
    {
        int res = slot->getAttr(&seg, slat, idx);
        push(res);
    }
ENDOP

#if 0
STARTOP(push_iglyph_attr) // not implemented
    NOT_IMPLEMENTED;
ENDOP
#endif

STARTOP(pop_ret)
    const uint32 ret = pop();
    EXIT(ret);
ENDOP

STARTOP(ret_zero)
    EXIT(0);
ENDOP

STARTOP(ret_true)
    EXIT(1);
ENDOP

STARTOP(iattr_set)
    declare_params(2);
    const attrCode      slat = attrCode(uint8(param[0]));
    const uint8         idx  = uint8(param[1]);
    const          int  val  = pop();
    is->setAttr(&seg, slat, idx, val, smap);
ENDOP

STARTOP(iattr_add)
    declare_params(2);
    const attrCode      slat = attrCode(uint8(param[0]));
    const uint8         idx  = uint8(param[1]);
    const     uint32_t  val  = pop();
    if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
    {
        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
        flags |= POSITIONED;
    }
    uint32_t res = uint32_t(is->getAttr(&seg, slat, idx));
    is->setAttr(&seg, slat, idx, int32_t(val + res), smap);
ENDOP

STARTOP(iattr_sub)
    declare_params(2);
    const attrCode      slat = attrCode(uint8(param[0]));
    const uint8         idx  = uint8(param[1]);
    const     uint32_t  val  = pop();
    if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
    {
        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
        flags |= POSITIONED;
    }
    uint32_t res = uint32_t(is->getAttr(&seg, slat, idx));
    is->setAttr(&seg, slat, idx, int32_t(res - val), smap);
ENDOP

STARTOP(push_proc_state)
    use_params(1);
    push(1);
ENDOP

STARTOP(push_version)
    push(0x00030000);
ENDOP

STARTOP(put_subs)
    declare_params(5);
    const int        slot_ref     = int8(param[0]);
    const unsigned int  input_class  = uint8(param[1]) << 8
                                     | uint8(param[2]);
    const unsigned int  output_class = uint8(param[3]) << 8
                                     | uint8(param[4]);
    slotref slot = slotat(slot_ref);
    if (slot)
    {
        int index = seg.findClassIndex(input_class, slot->gid());
        is->setGlyph(&seg, seg.getClassGlyph(output_class, index));
    }
ENDOP

#if 0
STARTOP(put_subs2) // not implemented
    NOT_IMPLEMENTED;
ENDOP

STARTOP(put_subs3) // not implemented
    NOT_IMPLEMENTED;
ENDOP
#endif

STARTOP(put_glyph)
    declare_params(2);
    const unsigned int output_class  = uint8(param[0]) << 8
                                     | uint8(param[1]);
    is->setGlyph(&seg, seg.getClassGlyph(output_class, 0));
ENDOP

STARTOP(push_glyph_attr)
    declare_params(3);
    const unsigned int  glyph_attr  = uint8(param[0]) << 8
                                    | uint8(param[1]);
    const int           slot_ref    = int8(param[2]);
    slotref slot = slotat(slot_ref);
    if (slot)
        push(int32(seg.glyphAttr(slot->gid(), glyph_attr)));
ENDOP

STARTOP(push_att_to_glyph_attr)
    declare_params(3);
    const unsigned int  glyph_attr  = uint8(param[0]) << 8
                                    | uint8(param[1]);
    const int           slot_ref    = int8(param[2]);
    slotref slot = slotat(slot_ref);
    if (slot)
    {
        slotref att = slot->attachedTo();
        if (att) slot = att;
        push(int32(seg.glyphAttr(slot->gid(), glyph_attr)));
    }
ENDOP

STARTOP(temp_copy)
    slotref newSlot = seg.newSlot();
    if (!newSlot || !is) DIE;
    int16 *tempUserAttrs = newSlot->userAttrs();
    memcpy(newSlot, is, sizeof(Slot));
    memcpy(tempUserAttrs, is->userAttrs(), seg.numAttrs() * sizeof(uint16));
    newSlot->userAttrs(tempUserAttrs);
    newSlot->markCopied(true);
    *map = newSlot;
ENDOP

STARTOP(band)
    binop(&);
ENDOP

STARTOP(bor)
    binop(|);
ENDOP

STARTOP(bnot)
    *sp = ~*sp;
ENDOP

STARTOP(setbits)
    declare_params(4);
    const uint16 m  = uint16(param[0]) << 8
                    | uint8(param[1]);
    const uint16 v  = uint16(param[2]) << 8
                    | uint8(param[3]);
    *sp = ((*sp) & ~m) | v;
ENDOP

STARTOP(set_feat)
    declare_params(2);
    const unsigned int  feat        = uint8(param[0]);
    const int           slot_ref    = int8(param[1]);
    slotref slot = slotat(slot_ref);
    if (slot)
    {
        uint8 fid = seg.charinfo(slot->original())->fid();
        seg.setFeature(fid, feat, pop());
    }
ENDOP


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/List.h"
#include "inc/Position.h"
#include "inc/Intervals.h"
#include "inc/debug.h"

namespace graphite2 {

class json;
class Slot;
class Segment;

#define SLOTCOLSETUINTPROP(x, y) uint16 x() const { return _ ##x; } void y (uint16 v) { _ ##x = v; }
#define SLOTCOLSETINTPROP(x, y) int16 x() const { return _ ##x; } void y (int16 v) { _ ##x = v; }
#define SLOTCOLSETPOSITIONPROP(x, y) const Position &x() const { return _ ##x; } void y (const Position &v) { _ ##x = v; }

// Slot attributes related to collision-fixing
class SlotCollision
{
public:
    enum {
    //  COLL_TESTONLY = 0,  // default - test other glyphs for collision with this one, but don't move this one
        COLL_FIX = 1,       // fix collisions involving this glyph
        COLL_IGNORE = 2,    // ignore this glyph altogether
        COLL_START = 4,     // start of range of possible collisions
        COLL_END = 8,       // end of range of possible collisions
        COLL_KERN = 16,     // collisions with this glyph are fixed by adding kerning space after it
        COLL_ISCOL = 32,    // this glyph has a collision
        COLL_KNOWN = 64,    // we've figured out what's happening with this glyph
        COLL_ISSPACE = 128,		// treat this glyph as a space with regard to kerning
        COLL_TEMPLOCK = 256,    // Lock glyphs that have been given priority positioning
        ////COLL_JUMPABLE = 128,    // moving glyphs may jump this stationary glyph in any direction - DELETE
        ////COLL_OVERLAP = 256,    // use maxoverlap to restrict - DELETE
    };

    // Behavior for the collision.order attribute. To GDL this is an enum, to us it's a bitfield, with only 1 bit set
    // Allows for easier inversion.
    enum {
        SEQ_ORDER_LEFTDOWN = 1,
        SEQ_ORDER_RIGHTUP = 2,
        SEQ_ORDER_NOABOVE = 4,
        SEQ_ORDER_NOBELOW = 8,
        SEQ_ORDER_NOLEFT = 16,
        SEQ_ORDER_NORIGHT = 32
    };

    SlotCollision(Segment *seg, Slot *slot);
    void initFromSlot(Segment *seg, Slot *slot);

    const Rect &limit() const { return _limit; }
    void setLimit(const Rect &r) { _limit = r; }
    SLOTCOLSETPOSITIONPROP(shift, setShift)
    SLOTCOLSETPOSITIONPROP(offset, setOffset)
    SLOTCOLSETPOSITIONPROP(exclOffset, setExclOffset)
    SLOTCOLSETUINTPROP(margin, setMargin)
    SLOTCOLSETUINTPROP(marginWt, setMarginWt)
    SLOTCOLSETUINTPROP(flags, setFlags)
    SLOTCOLSETUINTPROP(exclGlyph, setExclGlyph)
    SLOTCOLSETUINTPROP(seqClass, setSeqClass)
    SLOTCOLSETUINTPROP(seqProxClass, setSeqProxClass)
    SLOTCOLSETUINTPROP(seqOrder, setSeqOrder)
    SLOTCOLSETINTPROP(seqAboveXoff, setSeqAboveXoff)
    SLOTCOLSETUINTPROP(seqAboveWt, setSeqAboveWt)
    SLOTCOLSETINTPROP(seqBelowXlim, setSeqBelowXlim)
    SLOTCOLSETUINTPROP(seqBelowWt, setSeqBelowWt)
    SLOTCOLSETUINTPROP(seqValignHt, setSeqValignHt)
    SLOTCOLSETUINTPROP(seqValignWt, setSeqValignWt)

    float getKern(int dir) const;
    bool ignore() const;

private:
    Rect        _limit;
    Position    _shift;     // adjustment within the given pass
    Position    _offset;    // total adjustment for collisions
    Position    _exclOffset;
    uint16		_margin;
    uint16		_marginWt;
    uint16		_flags;
    uint16		_exclGlyph;
    uint16		_seqClass;
	uint16		_seqProxClass;
    uint16		_seqOrder;
    int16		_seqAboveXoff;
    uint16		_seqAboveWt;
    int16		_seqBelowXlim;
    uint16		_seqBelowWt;
    uint16		_seqValignHt;
    uint16		_seqValignWt;

};  // end of class SlotColllision

struct BBox;
struct SlantBox;

class ShiftCollider
{
public:
    typedef std::pair<float, float> fpair;
    typedef Vector<fpair> vfpairs;
    typedef vfpairs::iterator ivfpairs;

    ShiftCollider(json *dbgout);
    ~ShiftCollider() throw() { };

    bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint,
                float margin, float marginMin, const Position &currShift,
                const Position &currOffset, int dir, GR_MAYBE_UNUSED json * const dbgout);
    bool mergeSlot(Segment *seg, Slot *slot, const SlotCollision *cinfo, const Position &currShift, bool isAfter,
                bool sameCluster, bool &hasCol, bool isExclusion, GR_MAYBE_UNUSED json * const dbgout);
    Position resolve(Segment *seg, bool &isCol, GR_MAYBE_UNUSED json * const dbgout);
    void addBox_slope(bool isx, const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, float weight, float m, bool minright, int mode);
    void removeBox(const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, int mode);
    const Position &origin() const { return _origin; }

#if !defined GRAPHITE2_NTRACING
	void outputJsonDbg(json * const dbgout, Segment *seg, int axis);
	void outputJsonDbgStartSlot(json * const dbgout, Segment *seg);
	void outputJsonDbgEndSlot(json * const dbgout, Position resultPos, int bestAxis, bool isCol);
	void outputJsonDbgOneVector(json * const dbgout, Segment *seg, int axis, float tleft, float bestCost, float bestVal);
	void outputJsonDbgRawRanges(json * const dbgout, int axis);
	void outputJsonDbgRemovals(json * const dbgout, int axis, Segment *seg);
#endif

    CLASS_NEW_DELETE;

protected:
    Zones _ranges[4];   // possible movements in 4 directions (horizontally, vertically, diagonally);
    Slot *  _target;    // the glyph to fix
    Rect    _limit;
    Position _currShift;
    Position _currOffset;
    Position _origin;   // Base for all relative calculations
    float   _margin;
	float	_marginWt;
    float   _len[4];
    uint16  _seqClass;
	uint16	_seqProxClass;
    uint16  _seqOrder;

	//bool _scraping[4];

};	// end of class ShiftCollider

inline
ShiftCollider::ShiftCollider(GR_MAYBE_UNUSED json *dbgout)
: _target(0),
  _margin(0.0),
  _marginWt(0.0),
  _seqClass(0),
  _seqProxClass(0),
  _seqOrder(0)
{
#if !defined GRAPHITE2_NTRACING
    for (int i = 0; i < 4; ++i)
        _ranges[i].setdebug(dbgout);
#endif
}

class KernCollider
{
public:
    KernCollider(json *dbg);
    ~KernCollider() throw() { };
    bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint, float margin,
            const Position &currShift, const Position &offsetPrev, int dir,
            float ymin, float ymax, json * const dbgout);
    bool mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, json * const dbgout);
    Position resolve(Segment *seg, Slot *slot, int dir, json * const dbgout);
    void shift(const Position &mv, int dir);

    CLASS_NEW_DELETE;

private:
    Slot *  _target;        // the glyph to fix
    Rect    _limit;
    float   _margin;
    Position _offsetPrev;   // kern from a previous pass
    Position _currShift;    // NOT USED??
    float _miny;	        // y-coordinates offset by global slot position
    float _maxy;
    Vector<float> _edges;   // edges of horizontal slices
    float _sliceWidth;      // width of each slice
    float _mingap;
    float _xbound;        // max or min edge
    bool  _hit;

#if !defined GRAPHITE2_NTRACING
    // Debugging
    Segment * _seg;
    Vector<float> _nearEdges; // closest potential collision in each slice
    Vector<Slot*> _slotNear;
#endif
};	// end of class KernCollider

inline
float sqr(float x) {
    return x * x;
}

inline
KernCollider::KernCollider(GR_MAYBE_UNUSED json *dbg)
: _target(0),
  _margin(0.0f),
  _miny(-1e38f),
  _maxy(1e38f),
  _sliceWidth(0.0f),
  _mingap(0.0f),
  _xbound(0.0),
  _hit(false)
{
#if !defined GRAPHITE2_NTRACING
    _seg = 0;
#endif
};

};  // 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.
*/
#pragma once
#include <cassert>
#include "graphite2/Font.h"
#include "inc/Main.h"
#include "inc/Face.h"

namespace graphite2 {

#define INVALID_ADVANCE -1e38f      // can't be a static const because non-integral

class Font
{
public:
    Font(float ppm, const Face & face, const void * appFontHandle=0, const gr_font_ops * ops=0);
    virtual ~Font();

    float advance(unsigned short glyphid) const;
    float scale() const;
    bool isHinted() const;
    const Face & face() const;
    operator bool () const throw()  { return m_advances; }

    CLASS_NEW_DELETE;
private:
    gr_font_ops         m_ops;
    const void  * const m_appFontHandle;
    float             * m_advances;  // One advance per glyph in pixels. Nan if not defined
    const Face        & m_face;
    float               m_scale;      // scales from design units to ppm
    bool                m_hinted;

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

inline
float Font::advance(unsigned short glyphid) const
{
    if (m_advances[glyphid] == INVALID_ADVANCE)
        m_advances[glyphid] = (*m_ops.glyph_advance_x)(m_appFontHandle, glyphid);
    return m_advances[glyphid];
}

inline
float Font::scale() const
{
    return m_scale;
}

inline
bool Font::isHinted() const
{
    return m_hinted;
}

inline
const Face & Font::face() const
{
    return m_face;
}

} // namespace graphite2

struct gr_font : public graphite2::Font {};


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 <cstdio>

#include "graphite2/Font.h"

#include "inc/Main.h"
#include "inc/FeatureMap.h"
#include "inc/TtfUtil.h"
#include "inc/Silf.h"
#include "inc/Error.h"

namespace graphite2 {

class Cmap;
class FileFace;
class GlyphCache;
class NameTable;
class json;
class Font;

using TtfUtil::Tag;

// These are the actual tags, as distinct from the consecutive IDs in TtfUtil.h

class Face
{
    // Prevent any kind of copying
    Face(const Face&);
    Face& operator=(const Face&);

public:
    class Table;
    static float default_glyph_advance(const void* face_ptr, gr_uint16 glyphid);

    Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops);
    virtual ~Face();

    virtual bool        runGraphite(Segment *seg, const Silf *silf) const;

public:
    bool                readGlyphs(uint32 faceOptions);
    bool                readGraphite(const Table & silf);
    bool                readFeatures();
    void                takeFileFace(FileFace* pFileFace/*takes ownership*/);

    const SillMap     & theSill() const;
    const GlyphCache  & glyphs() const;
    Cmap              & cmap() const;
    NameTable         * nameTable() const;
    void                setLogger(FILE *log_file);
    json              * logger() const throw();

    const Silf        * chooseSilf(uint32 script) const;
    uint16              languageForLocale(const char * locale) const;

    // Features
    uint16              numFeatures() const;
    const FeatureRef  * featureById(uint32 id) const;
    const FeatureRef  * feature(uint16 index) const;

    // Glyph related
    int32  getGlyphMetric(uint16 gid, uint8 metric) const;
    uint16 findPseudo(uint32 uid) const;

    // Errors
    unsigned int        error() const { return m_error; }
    bool                error(Error e) { m_error = e.error(); return false; }
    unsigned int        error_context() const { return m_error; }
    void                error_context(unsigned int errcntxt) { m_errcntxt = errcntxt; }

    CLASS_NEW_DELETE;
private:
    SillMap                 m_Sill;
    gr_face_ops             m_ops;
    const void            * m_appFaceHandle;    // non-NULL
    FileFace              * m_pFileFace;        //owned
    mutable GlyphCache    * m_pGlyphFaceCache;  // owned - never NULL
    mutable Cmap          * m_cmap;             // cmap cache if available
    mutable NameTable     * m_pNames;
    mutable json          * m_logger;
    unsigned int            m_error;
    unsigned int            m_errcntxt;
protected:
    Silf                  * m_silfs;    // silf subtables.
    uint16                  m_numSilf;  // num silf subtables in the silf table
private:
    uint16 m_ascent,
           m_descent;
#ifdef GRAPHITE2_TELEMETRY
public:
    mutable telemetry   tele;
#endif
};

inline
const SillMap & Face::theSill() const
{
    return m_Sill;
}

inline
uint16 Face::numFeatures() const
{
    return m_Sill.theFeatureMap().numFeats();
}

inline
const FeatureRef * Face::featureById(uint32 id) const
{
    return m_Sill.theFeatureMap().findFeatureRef(id);
}

inline
const FeatureRef *Face::feature(uint16 index) const
{
    return m_Sill.theFeatureMap().feature(index);
}

inline
const GlyphCache & Face::glyphs() const
{
    return *m_pGlyphFaceCache;
}

inline
Cmap & Face::cmap() const
{
    return *m_cmap;
};

inline
json * Face::logger() const throw()
{
    return m_logger;
}

class Face::Table
{
    const Face *            _f;
    mutable const byte *    _p;
    size_t                  _sz;
    bool                    _compressed;

    Error decompress();

    void release();

public:
    Table() throw();
    Table(const Face & face, const Tag n, uint32 version=0xffffffff) throw();
    ~Table() throw();
    Table(const Table && rhs) throw();

    operator const byte * () const throw();

    size_t  size() const throw();
    Table & operator = (const Table && rhs) throw();
};

inline
Face::Table::Table() throw()
: _f(0), _p(0), _sz(0), _compressed(false)
{
}

inline
Face::Table::Table(const Table && rhs) throw()
: _f(rhs._f), _p(rhs._p), _sz(rhs._sz), _compressed(rhs._compressed)
{
    rhs._p = 0;
}

inline
Face::Table::~Table() throw()
{
    release();
}

inline
Face::Table::operator const byte * () const throw()
{
    return _p;
}

inline
size_t  Face::Table::size() const throw()
{
    return _sz;
}

} // namespace graphite2

struct gr_face : public graphite2::Face {};


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 file will be pulled into and integrated into a machine implmentation
// DO NOT build directly
#pragma once

#define do2(n)  do_(n) ,do_(n)
#define NILOP   0U

// types or parameters are: (.. is inclusive)
//      number - any byte
//      output_class - 0 .. silf.m_nClass
//      input_class - 0 .. silf.m_nClass
//      sattrnum - 0 .. 29 (gr_slatJWidth) , 55 (gr_slatUserDefn)
//      attrid - 0 .. silf.numUser() where sattrnum == 55; 0..silf.m_iMaxComp where sattrnum == 15 otherwise 0
//      gattrnum - 0 .. face->getGlyphFaceCache->numAttrs()
//      gmetric - 0 .. 11 (kgmetDescent)
//      featidx - 0 .. face.numFeatures()
//      level - any byte
static const opcode_t opcode_table[] =
{
    {{do2(nop)},                                    0, "NOP"},

    {{do2(push_byte)},                              1, "PUSH_BYTE"},                // number
    {{do2(push_byte_u)},                            1, "PUSH_BYTE_U"},              // number
    {{do2(push_short)},                             2, "PUSH_SHORT"},               // number number
    {{do2(push_short_u)},                           2, "PUSH_SHORT_U"},             // number number
    {{do2(push_long)},                              4, "PUSH_LONG"},                // number number number number

    {{do2(add)},                                    0, "ADD"},
    {{do2(sub)},                                    0, "SUB"},
    {{do2(mul)},                                    0, "MUL"},
    {{do2(div_)},                                   0, "DIV"},
    {{do2(min_)},                                   0, "MIN"},
    {{do2(max_)},                                   0, "MAX"},
    {{do2(neg)},                                    0, "NEG"},
    {{do2(trunc8)},                                 0, "TRUNC8"},
    {{do2(trunc16)},                                0, "TRUNC16"},

    {{do2(cond)},                                   0, "COND"},
    {{do2(and_)},                                   0, "AND"},      // 0x10
    {{do2(or_)},                                    0, "OR"},
    {{do2(not_)},                                   0, "NOT"},
    {{do2(equal)},                                  0, "EQUAL"},
    {{do2(not_eq_)},                                0, "NOT_EQ"},
    {{do2(less)},                                   0, "LESS"},
    {{do2(gtr)},                                    0, "GTR"},
    {{do2(less_eq)},                                0, "LESS_EQ"},
    {{do2(gtr_eq)},                                 0, "GTR_EQ"},   // 0x18

    {{do_(next), NILOP},                            0, "NEXT"},
    {{NILOP, NILOP},                                1, "NEXT_N"},                   // number <= smap.end - map
    {{do_(next), NILOP},                            0, "COPY_NEXT"},
    {{do_(put_glyph_8bit_obs), NILOP},              1, "PUT_GLYPH_8BIT_OBS"},       // output_class
    {{do_(put_subs_8bit_obs), NILOP},               3, "PUT_SUBS_8BIT_OBS"},        // slot input_class output_class
    {{do_(put_copy), NILOP},                        1, "PUT_COPY"},                 // slot
    {{do_(insert), NILOP},                          0, "INSERT"},
    {{do_(delete_), NILOP},                         0, "DELETE"},   // 0x20
    {{do_(assoc), NILOP},                     VARARGS, "ASSOC"},
    {{NILOP ,do_(cntxt_item)},                      2, "CNTXT_ITEM"},               // slot offset

    {{do_(attr_set), NILOP},                        1, "ATTR_SET"},                 // sattrnum
    {{do_(attr_add), NILOP},                        1, "ATTR_ADD"},                 // sattrnum
    {{do_(attr_sub), NILOP},                        1, "ATTR_SUB"},                 // sattrnum
    {{do_(attr_set_slot), NILOP},                   1, "ATTR_SET_SLOT"},            // sattrnum
    {{do_(iattr_set_slot), NILOP},                  2, "IATTR_SET_SLOT"},           // sattrnum attrid
    {{do2(push_slot_attr)},                         2, "PUSH_SLOT_ATTR"},           // sattrnum slot
    {{do2(push_glyph_attr_obs)},                    2, "PUSH_GLYPH_ATTR_OBS"},      // gattrnum slot
    {{do2(push_glyph_metric)},                      3, "PUSH_GLYPH_METRIC"},        // gmetric slot level
    {{do2(push_feat)},                              2, "PUSH_FEAT"},                // featidx slot

    {{do2(push_att_to_gattr_obs)},                  2, "PUSH_ATT_TO_GATTR_OBS"},    // gattrnum slot
    {{do2(push_att_to_glyph_metric)},               3, "PUSH_ATT_TO_GLYPH_METRIC"}, // gmetric slot level
    {{do2(push_islot_attr)},                        3, "PUSH_ISLOT_ATTR"},          // sattrnum slot attrid

    {{NILOP,NILOP},                                 3, "PUSH_IGLYPH_ATTR"},

    {{do2(pop_ret)},                                0, "POP_RET"},  // 0x30
    {{do2(ret_zero)},                               0, "RET_ZERO"},
    {{do2(ret_true)},                               0, "RET_TRUE"},

    {{do_(iattr_set), NILOP},                       2, "IATTR_SET"},                // sattrnum attrid
    {{do_(iattr_add), NILOP},                       2, "IATTR_ADD"},                // sattrnum attrid
    {{do_(iattr_sub), NILOP},                       2, "IATTR_SUB"},                // sattrnum attrid
    {{do2(push_proc_state)},                        1, "PUSH_PROC_STATE"},          // dummy
    {{do2(push_version)},                           0, "PUSH_VERSION"},
    {{do_(put_subs), NILOP},                        5, "PUT_SUBS"},                 // slot input_class input_class output_class output_class
    {{NILOP,NILOP},                                 0, "PUT_SUBS2"},
    {{NILOP,NILOP},                                 0, "PUT_SUBS3"},
    {{do_(put_glyph), NILOP},                       2, "PUT_GLYPH"},                // output_class output_class
    {{do2(push_glyph_attr)},                        3, "PUSH_GLYPH_ATTR"},          // gattrnum gattrnum slot
    {{do2(push_att_to_glyph_attr)},                 3, "PUSH_ATT_TO_GLYPH_ATTR"},   // gattrnum gattrnum slot
    {{do2(bor)},                                    0, "BITOR"},
    {{do2(band)},                                   0, "BITAND"},
    {{do2(bnot)},                                   0, "BITNOT"},   // 0x40
    {{do2(setbits)},                                4, "BITSET"},
    {{do_(set_feat), NILOP},                        2, "SET_FEAT"},                 // featidx slot
    // private opcodes for internal use only, comes after all other on disk opcodes.
    {{do_(temp_copy), NILOP},                       0, "TEMP_COPY"}
};


text:
/*  GRAPHITE2 LICENSING

    Copyright 2015, 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 <cstddef>

namespace lz4
{

// decompress an LZ4 block
// Parameters:
//      @in         -   Input buffer containing an LZ4 block.
//      @in_size    -   Size of the input LZ4 block in bytes.
//      @out        -   Output buffer to hold decompressed results.
//      @out_size   -   The size of the buffer pointed to by @out.
// Invariants:
//      @in         -   This buffer must be at least 1 machine word in length,
//                      regardless of the actual LZ4 block size.
//      @in_size    -   This must be at least 4 and must also be <= to the
//                      allocated buffer @in.
//      @out        -   This must be bigger than the input buffer and at least
//                      13 bytes.
//      @out_size   -   Must always be big enough to hold the expected size.
// Return:
//      -1          -  Decompression failed.
//      size        -  Actual number of bytes decompressed.
int decompress(void const *in, size_t in_size, void *out, size_t out_size);

} // end of namespace shrinker


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

namespace graphite2
{

#if defined GRAPHITE2_BUILTINS && (defined __GNUC__ || defined __clang__)

template<typename T>
inline unsigned int bit_set_count(T v)
{
    return __builtin_popcount(v);
}

template<>
inline unsigned int bit_set_count(int16 v)
{
    return __builtin_popcount(static_cast<uint16>(v));
}

template<>
inline unsigned int bit_set_count(int8 v)
{
    return __builtin_popcount(static_cast<uint8>(v));
}

template<>
inline unsigned int bit_set_count(unsigned long v)
{
    return __builtin_popcountl(v);
}

template<>
inline unsigned int bit_set_count(signed long v)
{
    return __builtin_popcountl(v);
}

template<>
inline unsigned int bit_set_count(unsigned long long v)
{
    return __builtin_popcountll(v);
}

template<>
inline unsigned int bit_set_count(signed long long v)
{
    return __builtin_popcountll(v);
}

#else

template<typename T>
inline unsigned int bit_set_count(T v)
{
	static size_t const ONES = ~0;

	v = v - ((v >> 1) & T(ONES/3));                      // temp
    v = (v & T(ONES/15*3)) + ((v >> 2) & T(ONES/15*3));  // temp
    v = (v + (v >> 4)) & T(ONES/255*15);                 // temp
    return (T)(v * T(ONES/255)) >> (sizeof(T)-1)*8;      // count
}

#endif

//TODO: Changed these to uintmax_t when we go to C++11
template<int S>
inline size_t _mask_over_val(size_t v)
{
    v = _mask_over_val<S/2>(v);
    v |= v >> S*4;
    return v;
}

//TODO: Changed these to uintmax_t when we go to C++11
template<>
inline size_t _mask_over_val<1>(size_t v)
{
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    return v;
}

template<typename T>
inline T mask_over_val(T v)
{
    return T(_mask_over_val<sizeof(T)>(v));
}

template<typename T>
inline unsigned long next_highest_power2(T v)
{
    return _mask_over_val<sizeof(T)>(v-1)+1;
}

template<typename T>
inline unsigned int log_binary(T v)
{
    return bit_set_count(mask_over_val(v))-1;
}

template<typename T>
inline T has_zero(const T x)
{
    return (x - T(~T(0)/255)) & ~x & T(~T(0)/255*128);
}

template<typename T>
inline T zero_bytes(const T x, unsigned char n)
{
    const T t = T(~T(0)/255*n);
    return T((has_zero(x^t) >> 7)*n);
}

#if 0
inline float float_round(float x, uint32 m)
{
    *reinterpret_cast<unsigned int *>(&x) &= m;
    return *reinterpret_cast<float *>(&x);
}
#endif

}