mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1191167 - Update graphite2 library to release 1.3.0. r=jdaggett
This commit is contained in:
parent
f6b5af82b5
commit
73bbff7ee6
@ -1,6 +1,6 @@
|
||||
This directory contains the Graphite2 library from http://hg.palaso.org/graphitedev
|
||||
|
||||
Current version derived from upstream changeset 1efd96aeade9
|
||||
Current version derived from upstream changeset e6539b6769cf
|
||||
|
||||
See gfx/graphite2/moz-gr-update.sh for update procedure.
|
||||
|
||||
|
@ -29,8 +29,8 @@
|
||||
#include "graphite2/Types.h"
|
||||
|
||||
#define GR2_VERSION_MAJOR 1
|
||||
#define GR2_VERSION_MINOR 2
|
||||
#define GR2_VERSION_BUGFIX 4
|
||||
#define GR2_VERSION_MINOR 3
|
||||
#define GR2_VERSION_BUGFIX 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
|
@ -120,13 +120,45 @@ enum gr_attrCode {
|
||||
/// Justification weight for this glyph (not implemented)
|
||||
gr_slatJWeight,
|
||||
/// Amount this slot mush shrink or stretch in design units
|
||||
gr_slatJWidth,
|
||||
gr_slatJWidth = 29,
|
||||
/// SubSegment split point
|
||||
gr_slatSegSplit = gr_slatJStretch + 29,
|
||||
/// User defined attribute, see subattr for user attr number
|
||||
gr_slatUserDefn,
|
||||
/// Bidi level
|
||||
gr_slatBidiLevel,
|
||||
gr_slatBidiLevel = 56,
|
||||
/// Collision flags
|
||||
gr_slatColFlags,
|
||||
/// Collision constraint rectangle left (bl.x)
|
||||
gr_slatColLimitblx,
|
||||
/// Collision constraint rectangle lower (bl.y)
|
||||
gr_slatColLimitbly,
|
||||
/// Collision constraint rectangle right (tr.x)
|
||||
gr_slatColLimittrx,
|
||||
/// Collision constraint rectangle upper (tr.y)
|
||||
gr_slatColLimittry,
|
||||
/// Collision shift x
|
||||
gr_slatColShiftx,
|
||||
/// Collision shift y
|
||||
gr_slatColShifty,
|
||||
/// Collision margin
|
||||
gr_slatColMargin,
|
||||
/// Margin cost weight
|
||||
gr_slatColMarginWt,
|
||||
// Additional glyph that excludes movement near this one:
|
||||
gr_slatColExclGlyph,
|
||||
gr_slatColExclOffx,
|
||||
gr_slatColExclOffy,
|
||||
// Collision sequence enforcing attributes:
|
||||
gr_slatSeqClass,
|
||||
gr_slatSeqProxClass,
|
||||
gr_slatSeqOrder,
|
||||
gr_slatSeqAboveXoff,
|
||||
gr_slatSeqAboveWt,
|
||||
gr_slatSeqBelowXlim,
|
||||
gr_slatSeqBelowWt,
|
||||
gr_slatSeqValignHt,
|
||||
gr_slatSeqValignWt,
|
||||
|
||||
/// not implemented
|
||||
gr_slatMax,
|
||||
|
@ -58,12 +58,15 @@ enum gr_encform {
|
||||
#endif
|
||||
#endif
|
||||
#define GR2_LOCAL
|
||||
#else
|
||||
#if __GNUC__ >= 4
|
||||
#define GR2_API __attribute__ ((visibility("default")))
|
||||
#define GR2_LOCAL __attribute__ ((visibility("hidden")))
|
||||
#elif __GNUC__ >= 4
|
||||
#if defined GRAPHITE2_STATIC
|
||||
#define GR2_API __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define GR2_API
|
||||
#define GR2_LOCAL
|
||||
#define GR2_API __attribute__ ((visibility("default")))
|
||||
#endif
|
||||
#define GR2_LOCAL __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define GR2_API
|
||||
#define GR2_LOCAL
|
||||
#endif
|
||||
|
||||
|
@ -62,8 +62,8 @@ enum DirCode { // Hungarian: dirc
|
||||
};
|
||||
|
||||
enum DirMask {
|
||||
WSflag = (1 << 7), // keep track of WS for eos handling
|
||||
WSMask = ~(1 << 7)
|
||||
WSflag = int8(1 << 7), // keep track of WS for eos handling
|
||||
WSMask = int8(~(1 << 7))
|
||||
};
|
||||
|
||||
inline uint8 BaseClass(Slot *s) { return s->getBidiClass() & WSMask; }
|
||||
@ -540,7 +540,7 @@ void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairS
|
||||
BracketPair *p;
|
||||
for ( ; s; s = s->prev()) // walk the sequence
|
||||
{
|
||||
uint16 ogid = seg->glyphAttr(s->gid(), aMirror);
|
||||
uint16 ogid = seg->glyphAttr(s->gid(), aMirror) || s->gid();
|
||||
int cls = BaseClass(s);
|
||||
|
||||
switch(cls)
|
||||
@ -571,35 +571,38 @@ void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairS
|
||||
mask |= 2;
|
||||
}
|
||||
}
|
||||
for (p = stack.start(); p; p =p->next()) // walk the stack
|
||||
if (stack.size())
|
||||
{
|
||||
if (p->close() && p->mask())
|
||||
for (p = stack.start(); p; p =p->next()) // walk the stack
|
||||
{
|
||||
int dir = (level & 1) + 1;
|
||||
if (p->mask() & dir)
|
||||
{ }
|
||||
else if (p->mask() & (1 << (~level & 1))) // if inside has strong other embedding
|
||||
if (p->close() && p->mask())
|
||||
{
|
||||
int ldir = p->before();
|
||||
if ((p->before() == OPP || p->before() == CPP) && p->prev())
|
||||
int dir = (level & 1) + 1;
|
||||
if (p->mask() & dir)
|
||||
{ }
|
||||
else if (p->mask() & (1 << (~level & 1))) // if inside has strong other embedding
|
||||
{
|
||||
for (BracketPair *q = p->prev(); q; q = q->prev())
|
||||
int ldir = p->before();
|
||||
if ((p->before() == OPP || p->before() == CPP) && p->prev())
|
||||
{
|
||||
ldir = q->open()->getBidiClass();
|
||||
if (ldir < 3) break;
|
||||
ldir = q->before();
|
||||
if (ldir < 3) break;
|
||||
for (BracketPair *q = p->prev(); q; q = q->prev())
|
||||
{
|
||||
ldir = q->open()->getBidiClass();
|
||||
if (ldir < 3) break;
|
||||
ldir = q->before();
|
||||
if (ldir < 3) break;
|
||||
}
|
||||
if (ldir > 2) ldir = 0;
|
||||
}
|
||||
if (ldir > 2) ldir = 0;
|
||||
if (ldir > 0 && (ldir - 1) != (level & 1)) // is dir given opp. to level dir (ldir == R or L)
|
||||
dir = (~level & 1) + 1;
|
||||
}
|
||||
if (ldir > 0 && (ldir - 1) != (level & 1)) // is dir given opp. to level dir (ldir == R or L)
|
||||
dir = (~level & 1) + 1;
|
||||
p->open()->setBidiClass(dir);
|
||||
p->close()->setBidiClass(dir);
|
||||
}
|
||||
p->open()->setBidiClass(dir);
|
||||
p->close()->setBidiClass(dir);
|
||||
}
|
||||
stack.clear();
|
||||
}
|
||||
stack.clear();
|
||||
}
|
||||
|
||||
int GetDeferredNeutrals(int action, int level)
|
||||
|
@ -78,15 +78,18 @@ add_library(graphite2 SHARED
|
||||
CachedFace.cpp
|
||||
CmapCache.cpp
|
||||
Code.cpp
|
||||
Collider.cpp
|
||||
Decompressor.cpp
|
||||
Face.cpp
|
||||
FeatureMap.cpp
|
||||
Font.cpp
|
||||
GlyphFace.cpp
|
||||
GlyphCache.cpp
|
||||
Intervals.cpp
|
||||
Justifier.cpp
|
||||
NameTable.cpp
|
||||
Pass.cpp
|
||||
Rule.cpp
|
||||
Position.cpp
|
||||
Segment.cpp
|
||||
Silf.cpp
|
||||
Slot.cpp
|
||||
@ -112,7 +115,7 @@ endif (${CMAKE_BUILD_TYPE} STREQUAL "ClangASN")
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set_target_properties(graphite2 PROPERTIES
|
||||
COMPILE_FLAGS "-Wall -Wextra -Wno-unknown-pragmas -Wendif-labels -Wshadow -Wctor-dtor-privacy -Wnon-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector"
|
||||
COMPILE_FLAGS "-Wall -Wextra -Wno-unknown-pragmas -Wendif-labels -Wshadow -Wctor-dtor-privacy -Wnon-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector -Wdouble-promotion"
|
||||
LINK_FLAGS "-nodefaultlibs ${GRAPHITE_LINK_FLAGS}"
|
||||
LINKER_LANGUAGE C)
|
||||
if (${CMAKE_CXX_COMPILER} MATCHES ".*mingw.*")
|
||||
|
@ -77,6 +77,7 @@ struct context
|
||||
|
||||
} // end namespace
|
||||
|
||||
byte * Machine::Code::local_memory = 0;
|
||||
|
||||
class Machine::Code::decoder
|
||||
{
|
||||
@ -94,7 +95,7 @@ public:
|
||||
|
||||
};
|
||||
|
||||
decoder(const limits & lims, Code &code) throw();
|
||||
decoder(limits & lims, Code &code, enum passtype pt) throw();
|
||||
|
||||
bool load(const byte * bc_begin, const byte * bc_end);
|
||||
void apply_analysis(instr * const code, instr * code_end);
|
||||
@ -107,6 +108,7 @@ private:
|
||||
bool emit_opcode(opcode opc, const byte * & bc);
|
||||
bool validate_opcode(const opcode opc, const byte * const bc);
|
||||
bool valid_upto(const uint16 limit, const uint16 x) const throw();
|
||||
bool test_context() const throw();
|
||||
void failure(const status_t s) const throw() { _code.failure(s); }
|
||||
|
||||
Code & _code;
|
||||
@ -114,14 +116,16 @@ private:
|
||||
uint16 _rule_length;
|
||||
instr * _instr;
|
||||
byte * _data;
|
||||
const limits & _max;
|
||||
limits & _max;
|
||||
analysis _analysis;
|
||||
enum passtype _passtype;
|
||||
int _stack_depth;
|
||||
};
|
||||
|
||||
|
||||
struct Machine::Code::decoder::limits
|
||||
{
|
||||
const byte * const bytecode;
|
||||
const byte * bytecode;
|
||||
const uint8 pre_context;
|
||||
const uint16 rule_length,
|
||||
classes,
|
||||
@ -130,19 +134,21 @@ struct Machine::Code::decoder::limits
|
||||
const byte attrid[gr_slatMax];
|
||||
};
|
||||
|
||||
inline Machine::Code::decoder::decoder(const limits & lims, Code &code) throw()
|
||||
inline Machine::Code::decoder::decoder(limits & lims, Code &code, enum passtype pt) throw()
|
||||
: _code(code),
|
||||
_pre_context(code._constraint ? 0 : lims.pre_context),
|
||||
_rule_length(code._constraint ? 1 : lims.rule_length),
|
||||
_instr(code._code), _data(code._data), _max(lims)
|
||||
_instr(code._code), _data(code._data), _max(lims), _passtype(pt),
|
||||
_stack_depth(0)
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
|
||||
uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face)
|
||||
uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face,
|
||||
enum passtype pt, byte * & _out)
|
||||
: _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded),
|
||||
_constraint(is_constraint), _modify(false), _delete(false), _own(true)
|
||||
_constraint(is_constraint), _modify(false), _delete(false), _own(_out==0)
|
||||
{
|
||||
#ifdef GRAPHITE2_TELEMETRY
|
||||
telemetry::category _code_cat(face.tele.code);
|
||||
@ -150,7 +156,7 @@ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte
|
||||
assert(bytecode_begin != 0);
|
||||
if (bytecode_begin == bytecode_end)
|
||||
{
|
||||
::new (this) Code();
|
||||
// ::new (this) Code();
|
||||
return;
|
||||
}
|
||||
assert(bytecode_end > bytecode_begin);
|
||||
@ -158,17 +164,17 @@ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte
|
||||
|
||||
// Allocate code and dat target buffers, these sizes are a worst case
|
||||
// estimate. Once we know their real sizes the we'll shrink them.
|
||||
_code = static_cast<instr *>(malloc((bytecode_end - bytecode_begin)
|
||||
* sizeof(instr)));
|
||||
_data = static_cast<byte *>(malloc((bytecode_end - bytecode_begin)
|
||||
* sizeof(byte)));
|
||||
if (_out) _code = reinterpret_cast<instr *>(_out);
|
||||
else _code = static_cast<instr *>(malloc((bytecode_end - bytecode_begin)
|
||||
* (sizeof(instr)+sizeof(byte))));
|
||||
_data = reinterpret_cast<byte *>(_code + (bytecode_end - bytecode_begin));
|
||||
|
||||
if (!_code || !_data) {
|
||||
failure(alloc_failed);
|
||||
return;
|
||||
}
|
||||
|
||||
const decoder::limits lims = {
|
||||
decoder::limits lims = {
|
||||
bytecode_end,
|
||||
pre_context,
|
||||
rule_length,
|
||||
@ -184,7 +190,7 @@ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte
|
||||
0,0,0,0,0,0,0, silf.numUser()}
|
||||
};
|
||||
|
||||
decoder dec(lims, *this);
|
||||
decoder dec(lims, *this, pt);
|
||||
if(!dec.load(bytecode_begin, bytecode_end))
|
||||
return;
|
||||
|
||||
@ -211,8 +217,13 @@ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte
|
||||
// memory.
|
||||
assert((bytecode_end - bytecode_begin) >= std::ptrdiff_t(_instr_count));
|
||||
assert((bytecode_end - bytecode_begin) >= std::ptrdiff_t(_data_size));
|
||||
_code = static_cast<instr *>(realloc(_code, (_instr_count+1)*sizeof(instr)));
|
||||
_data = static_cast<byte *>(realloc(_data, _data_size*sizeof(byte)));
|
||||
memmove(_code + (_instr_count+1), _data, _data_size*sizeof(byte));
|
||||
size_t const total_sz = ((_instr_count+1) + (_data_size + sizeof(instr)-1)/sizeof(instr))*sizeof(instr);
|
||||
if (_out)
|
||||
_out += total_sz;
|
||||
else
|
||||
_code = static_cast<instr *>(realloc(_code, total_sz));
|
||||
_data = reinterpret_cast<byte *>(_code + (_instr_count+1));
|
||||
|
||||
if (!_code)
|
||||
{
|
||||
@ -237,6 +248,7 @@ Machine::Code::~Code() throw ()
|
||||
|
||||
bool Machine::Code::decoder::load(const byte * bc, const byte * bc_end)
|
||||
{
|
||||
_max.bytecode = bc_end;
|
||||
while (bc < bc_end)
|
||||
{
|
||||
const opcode opc = fetch_opcode(bc++);
|
||||
@ -266,55 +278,82 @@ opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
|
||||
switch (opc)
|
||||
{
|
||||
case NOP :
|
||||
break;
|
||||
case PUSH_BYTE :
|
||||
case PUSH_BYTEU :
|
||||
case PUSH_SHORT :
|
||||
case PUSH_SHORTU :
|
||||
case PUSH_LONG :
|
||||
++_stack_depth;
|
||||
break;
|
||||
case ADD :
|
||||
case SUB :
|
||||
case MUL :
|
||||
case DIV :
|
||||
case MIN_ :
|
||||
case MAX_ :
|
||||
case NEG :
|
||||
case TRUNC8 :
|
||||
case TRUNC16 :
|
||||
case COND :
|
||||
case AND :
|
||||
case OR :
|
||||
case NOT :
|
||||
case EQUAL :
|
||||
case NOT_EQ :
|
||||
case LESS :
|
||||
case GTR :
|
||||
case LESS_EQ :
|
||||
case GTR_EQ :
|
||||
case BITOR :
|
||||
case BITAND :
|
||||
if (--_stack_depth <= 0)
|
||||
failure(underfull_stack);
|
||||
break;
|
||||
case NEG :
|
||||
case TRUNC8 :
|
||||
case TRUNC16 :
|
||||
case NOT :
|
||||
case BITNOT :
|
||||
case BITSET :
|
||||
if (_stack_depth <= 0)
|
||||
failure(underfull_stack);
|
||||
break;
|
||||
case COND :
|
||||
_stack_depth -= 2;
|
||||
if (_stack_depth <= 0)
|
||||
failure(underfull_stack);
|
||||
break;
|
||||
case NEXT :
|
||||
case NEXT_N : // runtime checked
|
||||
case COPY_NEXT :
|
||||
test_context();
|
||||
++_pre_context;
|
||||
break;
|
||||
case PUT_GLYPH_8BIT_OBS :
|
||||
valid_upto(_max.classes, bc[0]);
|
||||
test_context();
|
||||
break;
|
||||
case PUT_SUBS_8BIT_OBS :
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[0]));
|
||||
valid_upto(_max.classes, bc[1]);
|
||||
valid_upto(_max.classes, bc[2]);
|
||||
test_context();
|
||||
break;
|
||||
case PUT_COPY :
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[0]));
|
||||
test_context();
|
||||
break;
|
||||
case INSERT :
|
||||
--_pre_context;
|
||||
if (_passtype >= PASS_TYPE_POSITIONING)
|
||||
failure(invalid_opcode);
|
||||
else
|
||||
--_pre_context;
|
||||
break;
|
||||
case DELETE :
|
||||
if (_passtype >= PASS_TYPE_POSITIONING)
|
||||
failure(invalid_opcode);
|
||||
test_context();
|
||||
break;
|
||||
case ASSOC :
|
||||
for (uint8 num = bc[0]; num; --num)
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[num]));
|
||||
test_context();
|
||||
break;
|
||||
case CNTXT_ITEM :
|
||||
valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
|
||||
@ -325,39 +364,52 @@ opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
|
||||
case ATTR_ADD :
|
||||
case ATTR_SUB :
|
||||
case ATTR_SET_SLOT :
|
||||
if (--_stack_depth < 0)
|
||||
failure(underfull_stack);
|
||||
valid_upto(gr_slatMax, bc[0]);
|
||||
test_context();
|
||||
break;
|
||||
case IATTR_SET_SLOT :
|
||||
if (--_stack_depth < 0)
|
||||
failure(underfull_stack);
|
||||
if (valid_upto(gr_slatMax, bc[0]))
|
||||
valid_upto(_max.attrid[bc[0]], bc[1]);
|
||||
test_context();
|
||||
break;
|
||||
case PUSH_SLOT_ATTR :
|
||||
++_stack_depth;
|
||||
valid_upto(gr_slatMax, bc[0]);
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[1]));
|
||||
break;
|
||||
case PUSH_GLYPH_ATTR_OBS :
|
||||
++_stack_depth;
|
||||
valid_upto(_max.glyf_attrs, bc[0]);
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[1]));
|
||||
break;
|
||||
case PUSH_GLYPH_METRIC :
|
||||
++_stack_depth;
|
||||
valid_upto(kgmetDescent, bc[0]);
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[1]));
|
||||
// level: dp[2] no check necessary
|
||||
break;
|
||||
case PUSH_FEAT :
|
||||
++_stack_depth;
|
||||
valid_upto(_max.features, bc[0]);
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[1]));
|
||||
break;
|
||||
case PUSH_ATT_TO_GATTR_OBS :
|
||||
++_stack_depth;
|
||||
valid_upto(_max.glyf_attrs, bc[0]);
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[1]));
|
||||
break;
|
||||
case PUSH_ATT_TO_GLYPH_METRIC :
|
||||
++_stack_depth;
|
||||
valid_upto(kgmetDescent, bc[0]);
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[1]));
|
||||
// level: dp[2] no check necessary
|
||||
break;
|
||||
case PUSH_ISLOT_ATTR :
|
||||
++_stack_depth;
|
||||
if (valid_upto(gr_slatMax, bc[0]))
|
||||
{
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[1]));
|
||||
@ -365,32 +417,42 @@ opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
|
||||
}
|
||||
break;
|
||||
case PUSH_IGLYPH_ATTR :// not implemented
|
||||
++_stack_depth;
|
||||
case POP_RET :
|
||||
if (--_stack_depth < 0)
|
||||
failure(underfull_stack);
|
||||
case RET_ZERO :
|
||||
case RET_TRUE :
|
||||
break;
|
||||
case IATTR_SET :
|
||||
case IATTR_ADD :
|
||||
case IATTR_SUB :
|
||||
if (--_stack_depth < 0)
|
||||
failure(underfull_stack);
|
||||
if (valid_upto(gr_slatMax, bc[0]))
|
||||
valid_upto(_max.attrid[bc[0]], bc[1]);
|
||||
test_context();
|
||||
break;
|
||||
case PUSH_PROC_STATE : // dummy: dp[0] no check necessary
|
||||
case PUSH_VERSION :
|
||||
++_stack_depth;
|
||||
break;
|
||||
case PUT_SUBS :
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[0]));
|
||||
valid_upto(_max.classes, uint16(bc[1]<< 8) | bc[2]);
|
||||
valid_upto(_max.classes, uint16(bc[3]<< 8) | bc[4]);
|
||||
test_context();
|
||||
break;
|
||||
case PUT_SUBS2 : // not implemented
|
||||
case PUT_SUBS3 : // not implemented
|
||||
break;
|
||||
case PUT_GLYPH :
|
||||
valid_upto(_max.classes, uint16(bc[0]<< 8) | bc[1]);
|
||||
test_context();
|
||||
break;
|
||||
case PUSH_GLYPH_ATTR :
|
||||
case PUSH_ATT_TO_GLYPH_ATTR :
|
||||
++_stack_depth;
|
||||
valid_upto(_max.glyf_attrs, uint16(bc[0]<< 8) | bc[1]);
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[2]));
|
||||
break;
|
||||
@ -506,16 +568,20 @@ bool Machine::Code::decoder::emit_opcode(opcode opc, const byte * & bc)
|
||||
byte & instr_skip = _data[-1];
|
||||
byte & data_skip = *_data++;
|
||||
++_code._data_size;
|
||||
const byte *curr_end = _max.bytecode;
|
||||
|
||||
if (load(bc, bc + instr_skip))
|
||||
{
|
||||
bc += instr_skip;
|
||||
data_skip = instr_skip - (_code._instr_count - ctxt_start);
|
||||
instr_skip = _code._instr_count - ctxt_start;
|
||||
_max.bytecode = curr_end;
|
||||
|
||||
_rule_length = 1;
|
||||
_pre_context = 0;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
return bool(_code);
|
||||
@ -554,7 +620,7 @@ bool Machine::Code::decoder::validate_opcode(const opcode opc, const byte * cons
|
||||
}
|
||||
const opcode_t & op = Machine::getOpcodeTable()[opc];
|
||||
const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
|
||||
if (bc + param_sz > _max.bytecode)
|
||||
if (bc - 1 + param_sz > _max.bytecode)
|
||||
{
|
||||
failure(arguments_exhausted);
|
||||
return false;
|
||||
@ -570,6 +636,15 @@ bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) cons
|
||||
return t;
|
||||
}
|
||||
|
||||
bool Machine::Code::decoder::test_context() const throw()
|
||||
{
|
||||
if (_pre_context >= _rule_length)
|
||||
{
|
||||
failure(out_of_range_data);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
void Machine::Code::failure(const status_t s) throw() {
|
||||
@ -594,8 +669,8 @@ void Machine::Code::decoder::analysis::set_changed(const int index) throw() {
|
||||
|
||||
void Machine::Code::release_buffers() throw()
|
||||
{
|
||||
free(_code);
|
||||
free(_data);
|
||||
if (_own)
|
||||
free(_code);
|
||||
_code = 0;
|
||||
_data = 0;
|
||||
_own = false;
|
||||
@ -604,13 +679,12 @@ void Machine::Code::release_buffers() throw()
|
||||
|
||||
int32 Machine::Code::run(Machine & m, slotref * & map) const
|
||||
{
|
||||
assert(_own);
|
||||
// assert(_own);
|
||||
assert(*this); // Check we are actually runnable
|
||||
|
||||
if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context()))
|
||||
{
|
||||
m._status = Machine::slot_offset_out_bounds;
|
||||
// return (m.slotMap().end() - map);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
1080
gfx/graphite2/src/Collider.cpp
Normal file
1080
gfx/graphite2/src/Collider.cpp
Normal file
File diff suppressed because it is too large
Load Diff
102
gfx/graphite2/src/Decompressor.cpp
Normal file
102
gfx/graphite2/src/Decompressor.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/* Copyright (c) 2012, Siyuan Fu <fusiyuan2010@gmail.com>
|
||||
Copyright (c) 2015, SIL International
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <cassert>
|
||||
|
||||
#include "inc/Decompressor.h"
|
||||
#include "inc/Shrinker.h"
|
||||
|
||||
using namespace shrinker;
|
||||
|
||||
namespace {
|
||||
|
||||
u8 const LONG_DIST = 0x10;
|
||||
u8 const MATCH_LEN = 0x0f;
|
||||
|
||||
template <int M>
|
||||
inline
|
||||
u32 read_literal(u8 const * &s, u8 const * const e, u32 l) {
|
||||
if (unlikely(l == M))
|
||||
{
|
||||
u8 b = 0;
|
||||
do { l += b = *s++; } while(b==0xff && s != e);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
bool read_directive(u8 const * &src, u8 const * const end, u32 & literal_len, u32 & match_len, u32 & match_dist)
|
||||
{
|
||||
u8 const flag = *src++;
|
||||
|
||||
literal_len = read_literal<7>(src, end, flag >> 5);
|
||||
match_len = read_literal<15>(src, end, flag & MATCH_LEN);
|
||||
|
||||
match_dist = *src++;
|
||||
if (flag & LONG_DIST)
|
||||
match_dist |= ((*src++) << 8);
|
||||
|
||||
return match_dist != 0xffff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int shrinker::decompress(void const *in, size_t in_size, void *out, size_t out_size)
|
||||
{
|
||||
u8 const * src = static_cast<u8 const *>(in),
|
||||
* const src_end = src + in_size;
|
||||
|
||||
u8 * dst = static_cast<u8*>(out),
|
||||
* const dst_end = dst + out_size;
|
||||
|
||||
u32 literal_len = 0,
|
||||
match_len = 0,
|
||||
match_dist = 0;
|
||||
|
||||
while (read_directive(src, src_end, literal_len, match_len, match_dist))
|
||||
{
|
||||
// Copy in literal
|
||||
if (unlikely(dst + literal_len + sizeof(unsigned long) > dst_end)) return -1;
|
||||
dst = memcpy_nooverlap(dst, src, literal_len);
|
||||
src += literal_len;
|
||||
|
||||
// Copy, possibly repeating, match from earlier in the
|
||||
// decoded output.
|
||||
u8 const * const pcpy = dst - match_dist - 1;
|
||||
if (unlikely(pcpy < static_cast<u8*>(out)
|
||||
|| dst + match_len + MINMATCH + sizeof(unsigned long) > dst_end)) return -1;
|
||||
dst = memcpy_(dst, pcpy, match_len + MINMATCH);
|
||||
}
|
||||
|
||||
if (unlikely(dst + literal_len > dst_end)) return -1;
|
||||
dst = memcpy_nooverlap_surpass(dst, src, literal_len);
|
||||
|
||||
return dst - (u8*)out;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ of the License or (at your option) any later version.
|
||||
#include "graphite2/Segment.h"
|
||||
#include "inc/CmapCache.h"
|
||||
#include "inc/debug.h"
|
||||
#include "inc/Decompressor.h"
|
||||
#include "inc/Endian.h"
|
||||
#include "inc/Face.h"
|
||||
#include "inc/FileFace.h"
|
||||
@ -40,6 +41,16 @@ of the License or (at your option) any later version.
|
||||
|
||||
using namespace graphite2;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum compression
|
||||
{
|
||||
NONE,
|
||||
SHRINKER
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Face::Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops)
|
||||
: m_appFaceHandle(appFaceHandle),
|
||||
m_pFileFace(NULL),
|
||||
@ -84,19 +95,21 @@ bool Face::readGlyphs(uint32 faceOptions)
|
||||
telemetry::category _glyph_cat(tele.glyph);
|
||||
#endif
|
||||
error_context(EC_READGLYPHS);
|
||||
m_pGlyphFaceCache = new GlyphCache(*this, faceOptions);
|
||||
|
||||
if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM)
|
||||
|| e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS)
|
||||
|| e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM))
|
||||
{
|
||||
return error(e);
|
||||
}
|
||||
|
||||
if (faceOptions & gr_face_cacheCmap)
|
||||
m_cmap = new CachedCmap(*this);
|
||||
else
|
||||
m_cmap = new DirectCmap(*this);
|
||||
|
||||
m_pGlyphFaceCache = new GlyphCache(*this, faceOptions);
|
||||
if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM)
|
||||
|| e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS)
|
||||
|| e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM)
|
||||
|| e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
|
||||
{
|
||||
if (e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
|
||||
return error(e);
|
||||
}
|
||||
|
||||
if (faceOptions & gr_face_preloadGlyphs)
|
||||
nameTable(); // preload the name table along with the glyphs.
|
||||
@ -119,10 +132,12 @@ bool Face::readGraphite(const Table & silf)
|
||||
if (version >= 0x00030000)
|
||||
be::skip<uint32>(p); // compilerVersion
|
||||
m_numSilf = be::read<uint16>(p);
|
||||
|
||||
be::skip<uint16>(p); // reserved
|
||||
|
||||
bool havePasses = false;
|
||||
m_silfs = new Silf[m_numSilf];
|
||||
if (e.test(!m_silfs, E_OUTOFMEM)) return error(e);
|
||||
for (int i = 0; i < m_numSilf; i++)
|
||||
{
|
||||
error_context(EC_ASILF + (i << 8));
|
||||
@ -158,9 +173,14 @@ bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
|
||||
}
|
||||
#endif
|
||||
|
||||
bool res = aSilf->runGraphite(seg, 0, aSilf->justificationPass(), true);
|
||||
bool res = aSilf->runGraphite(seg, 0, aSilf->positionPass(), true);
|
||||
if (res)
|
||||
res = aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
|
||||
{
|
||||
seg->associateChars(0, seg->charInfoCount());
|
||||
if (aSilf->flags() & 0x20)
|
||||
res &= seg->initCollisions();
|
||||
res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
|
||||
}
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout)
|
||||
@ -245,17 +265,24 @@ uint16 Face::languageForLocale(const char * locale) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
Face::Table::Table(const Face & face, const Tag n) throw()
|
||||
: _f(&face)
|
||||
|
||||
|
||||
Face::Table::Table(const Face & face, const Tag n, uint32 version) throw()
|
||||
: _f(&face), _compressed(false)
|
||||
{
|
||||
size_t sz = 0;
|
||||
_p = reinterpret_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &sz));
|
||||
_p = static_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &sz));
|
||||
_sz = uint32(sz);
|
||||
|
||||
if (!TtfUtil::CheckTable(n, _p, _sz))
|
||||
{
|
||||
this->~Table(); // Make sure we release the table buffer even if the table filed it's checks
|
||||
_p = 0; _sz = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (be::peek<uint32>(_p) >= version)
|
||||
decompress();
|
||||
}
|
||||
|
||||
Face::Table & Face::Table::operator = (const Table & rhs) throw()
|
||||
@ -267,3 +294,50 @@ Face::Table & Face::Table::operator = (const Table & rhs) throw()
|
||||
return *this;
|
||||
}
|
||||
|
||||
Error Face::Table::decompress()
|
||||
{
|
||||
Error e;
|
||||
byte * uncompressed_table = 0;
|
||||
size_t uncompressed_size = 0;
|
||||
|
||||
const byte * p = _p;
|
||||
const uint32 version = be::read<uint32>(p); // Table version number.
|
||||
|
||||
// The scheme is in the top 5 bits of the 1st uint32.
|
||||
const uint32 hdr = be::read<uint32>(p);
|
||||
switch(compression(hdr >> 27))
|
||||
{
|
||||
case NONE: return e;
|
||||
case SHRINKER:
|
||||
{
|
||||
uncompressed_size = hdr & 0x07ffffff;
|
||||
uncompressed_table = gralloc<byte>(uncompressed_size);
|
||||
if (!e.test(!uncompressed_table, E_OUTOFMEM))
|
||||
e.test(shrinker::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
e.error(E_BADSCHEME);
|
||||
};
|
||||
|
||||
// Check the uncompressed version number against the original.
|
||||
if (!e)
|
||||
e.test(be::peek<uint32>(uncompressed_table) != version, E_SHRINKERFAILED);
|
||||
|
||||
// Tell the provider to release the compressed form since were replacing
|
||||
// it anyway.
|
||||
this->~Table();
|
||||
|
||||
if (e)
|
||||
{
|
||||
free(uncompressed_table);
|
||||
uncompressed_table = 0;
|
||||
uncompressed_size = 0;
|
||||
}
|
||||
|
||||
_p = uncompressed_table;
|
||||
_sz = uncompressed_size + sizeof(uint32);
|
||||
_compressed = true;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
@ -165,16 +165,16 @@ bool FeatureMap::readFeats(const Face & face)
|
||||
label, uiName, flags,
|
||||
uiSet, num_settings);
|
||||
}
|
||||
m_defaultFeatures = new Features(bits/(sizeof(uint32)*8) + 1, *this);
|
||||
new (&m_defaultFeatures) Features(bits/(sizeof(uint32)*8) + 1, *this);
|
||||
m_pNamedFeats = new NameAndFeatureRef[m_numFeats];
|
||||
if (!m_defaultFeatures || !m_pNamedFeats)
|
||||
if (!m_pNamedFeats)
|
||||
{
|
||||
free(defVals);
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < m_numFeats; ++i)
|
||||
{
|
||||
m_feats[i].applyValToFeature(defVals[i], *m_defaultFeatures);
|
||||
m_feats[i].applyValToFeature(defVals[i], m_defaultFeatures);
|
||||
m_pNamedFeats[i] = m_feats+i;
|
||||
}
|
||||
|
||||
@ -214,7 +214,7 @@ bool SillMap::readSill(const Face & face)
|
||||
uint16 numSettings = be::read<uint16>(p);
|
||||
uint16 offset = be::read<uint16>(p);
|
||||
if (offset + 8U * numSettings > sill.size() && numSettings > 0) return false;
|
||||
Features* feats = new Features(*m_FeatureMap.m_defaultFeatures);
|
||||
Features* feats = new Features(m_FeatureMap.m_defaultFeatures);
|
||||
if (!feats) return false;
|
||||
const byte *pLSet = sill + offset;
|
||||
|
||||
@ -250,7 +250,7 @@ Features* SillMap::cloneFeatures(uint32 langname/*0 means default*/) const
|
||||
return new Features(*m_langFeats[i].m_pFeatures);
|
||||
}
|
||||
}
|
||||
return new Features (*m_FeatureMap.m_defaultFeatures);
|
||||
return new Features (m_FeatureMap.m_defaultFeatures);
|
||||
}
|
||||
|
||||
|
||||
|
@ -31,6 +31,7 @@ of the License or (at your option) any later version.
|
||||
#include "inc/GlyphCache.h"
|
||||
#include "inc/GlyphFace.h"
|
||||
#include "inc/Endian.h"
|
||||
#include "inc/bits.h"
|
||||
|
||||
using namespace graphite2;
|
||||
|
||||
@ -70,13 +71,14 @@ namespace
|
||||
|
||||
protected:
|
||||
const byte * _e, * _v;
|
||||
ptrdiff_t _n;
|
||||
size_t _n;
|
||||
};
|
||||
|
||||
typedef _glat_iterator<uint8> glat_iterator;
|
||||
typedef _glat_iterator<uint16> glat2_iterator;
|
||||
}
|
||||
|
||||
const Rect GlyphCache::nullRect = Rect();
|
||||
|
||||
class GlyphCache::Loader
|
||||
{
|
||||
@ -87,8 +89,10 @@ public:
|
||||
unsigned short int units_per_em() const throw();
|
||||
unsigned short int num_glyphs() const throw();
|
||||
unsigned short int num_attrs() const throw();
|
||||
bool has_boxes() const throw();
|
||||
|
||||
const GlyphFace * read_glyph(unsigned short gid, GlyphFace &) const throw();
|
||||
const GlyphFace * read_glyph(unsigned short gid, GlyphFace &, int *numsubs) const throw();
|
||||
GlyphBox * read_box(uint16 gid, GlyphBox *curr, const GlyphFace & face) const throw();
|
||||
|
||||
CLASS_NEW_DELETE;
|
||||
private:
|
||||
@ -101,6 +105,7 @@ private:
|
||||
m_pGloc;
|
||||
|
||||
bool _long_fmt;
|
||||
bool _has_boxes;
|
||||
unsigned short _num_glyphs_graphics, //i.e. boundary box and advance
|
||||
_num_glyphs_attributes,
|
||||
_num_attrs; // number of glyph attributes per glyph
|
||||
@ -111,31 +116,49 @@ private:
|
||||
GlyphCache::GlyphCache(const Face & face, const uint32 face_options)
|
||||
: _glyph_loader(new Loader(face, bool(face_options & gr_face_dumbRendering))),
|
||||
_glyphs(_glyph_loader && *_glyph_loader ? grzeroalloc<const GlyphFace *>(_glyph_loader->num_glyphs()) : 0),
|
||||
_boxes(_glyph_loader && _glyph_loader->has_boxes() ? grzeroalloc<GlyphBox *>(_glyph_loader->num_glyphs()) : 0),
|
||||
_num_glyphs(_glyphs ? _glyph_loader->num_glyphs() : 0),
|
||||
_num_attrs(_glyphs ? _glyph_loader->num_attrs() : 0),
|
||||
_upem(_glyphs ? _glyph_loader->units_per_em() : 0)
|
||||
{
|
||||
if ((face_options & gr_face_preloadGlyphs) && _glyph_loader && _glyphs)
|
||||
{
|
||||
int numsubs = 0;
|
||||
GlyphFace * const glyphs = new GlyphFace [_num_glyphs];
|
||||
if (!glyphs)
|
||||
return;
|
||||
|
||||
// The 0 glyph is definately required.
|
||||
_glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0]);
|
||||
_glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0], &numsubs);
|
||||
|
||||
// glyphs[0] has the same address as the glyphs array just allocated,
|
||||
// thus assigning the &glyphs[0] to _glyphs[0] means _glyphs[0] points
|
||||
// to the entire array.
|
||||
const GlyphFace * loaded = _glyphs[0];
|
||||
for (uint16 gid = 1; loaded && gid != _num_glyphs; ++gid)
|
||||
_glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid]);
|
||||
_glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid], &numsubs);
|
||||
|
||||
if (!loaded)
|
||||
{
|
||||
_glyphs[0] = 0;
|
||||
delete [] glyphs;
|
||||
}
|
||||
else if (numsubs > 0)
|
||||
{
|
||||
GlyphBox * boxes = (GlyphBox *)gralloc<char>(_num_glyphs * sizeof(GlyphBox) + (numsubs-1) * 8 * sizeof(float));
|
||||
GlyphBox * currbox = boxes;
|
||||
|
||||
for (uint16 gid = 0; currbox && gid != _num_glyphs; ++gid)
|
||||
{
|
||||
_boxes[gid] = currbox;
|
||||
currbox = _glyph_loader->read_box(gid, currbox, *_glyphs[gid]);
|
||||
}
|
||||
if (!currbox)
|
||||
{
|
||||
free(boxes);
|
||||
_boxes[0] = 0;
|
||||
}
|
||||
}
|
||||
delete _glyph_loader;
|
||||
_glyph_loader = 0;
|
||||
}
|
||||
@ -144,6 +167,11 @@ GlyphCache::GlyphCache(const Face & face, const uint32 face_options)
|
||||
{
|
||||
free(_glyphs);
|
||||
_glyphs = 0;
|
||||
if (_boxes)
|
||||
{
|
||||
free(_boxes);
|
||||
_boxes = 0;
|
||||
}
|
||||
_num_glyphs = _num_attrs = _upem = 0;
|
||||
}
|
||||
}
|
||||
@ -163,6 +191,18 @@ GlyphCache::~GlyphCache()
|
||||
delete [] _glyphs[0];
|
||||
free(_glyphs);
|
||||
}
|
||||
if (_boxes)
|
||||
{
|
||||
if (_glyph_loader)
|
||||
{
|
||||
GlyphBox * * g = _boxes;
|
||||
for (uint16 n = _num_glyphs; n; --n, ++g)
|
||||
free(*g);
|
||||
}
|
||||
else
|
||||
free(_boxes[0]);
|
||||
free(_boxes);
|
||||
}
|
||||
delete _glyph_loader;
|
||||
}
|
||||
|
||||
@ -171,13 +211,23 @@ const GlyphFace *GlyphCache::glyph(unsigned short glyphid) const //result m
|
||||
const GlyphFace * & p = _glyphs[glyphid];
|
||||
if (p == 0 && _glyph_loader)
|
||||
{
|
||||
int numsubs = 0;
|
||||
GlyphFace * g = new GlyphFace();
|
||||
if (g) p = _glyph_loader->read_glyph(glyphid, *g);
|
||||
if (g) p = _glyph_loader->read_glyph(glyphid, *g, &numsubs);
|
||||
if (!p)
|
||||
{
|
||||
delete g;
|
||||
return *_glyphs;
|
||||
}
|
||||
if (_boxes)
|
||||
{
|
||||
_boxes[glyphid] = (GlyphBox *)gralloc<char>(sizeof(GlyphBox) + 8 * numsubs * sizeof(float));
|
||||
if (!_glyph_loader->read_box(glyphid, _boxes[glyphid], *_glyphs[glyphid]))
|
||||
{
|
||||
free(_boxes[glyphid]);
|
||||
_boxes[glyphid] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
@ -191,6 +241,7 @@ GlyphCache::Loader::Loader(const Face & face, const bool dumb_font)
|
||||
_glyf(face, Tag::glyf),
|
||||
_loca(face, Tag::loca),
|
||||
_long_fmt(false),
|
||||
_has_boxes(false),
|
||||
_num_glyphs_graphics(0),
|
||||
_num_glyphs_attributes(0),
|
||||
_num_attrs(0)
|
||||
@ -203,7 +254,7 @@ GlyphCache::Loader::Loader(const Face & face, const bool dumb_font)
|
||||
|
||||
_num_glyphs_graphics = TtfUtil::GlyphCount(maxp);
|
||||
// This will fail if the number of glyphs is wildly out of range.
|
||||
if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-1))
|
||||
if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-2))
|
||||
{
|
||||
_head = Face::Table();
|
||||
return;
|
||||
@ -211,7 +262,7 @@ GlyphCache::Loader::Loader(const Face & face, const bool dumb_font)
|
||||
|
||||
if (!dumb_font)
|
||||
{
|
||||
if ((m_pGlat = Face::Table(face, Tag::Glat)) == NULL
|
||||
if ((m_pGlat = Face::Table(face, Tag::Glat, 0x00030000)) == NULL
|
||||
|| (m_pGloc = Face::Table(face, Tag::Gloc)) == NULL
|
||||
|| m_pGloc.size() < 6)
|
||||
{
|
||||
@ -219,7 +270,7 @@ GlyphCache::Loader::Loader(const Face & face, const bool dumb_font)
|
||||
return;
|
||||
}
|
||||
const byte * p = m_pGloc;
|
||||
const int version = be::read<uint32>(p);
|
||||
int version = be::read<uint32>(p);
|
||||
const uint16 flags = be::read<uint16>(p);
|
||||
_num_attrs = be::read<uint16>(p);
|
||||
// We can accurately calculate the number of attributed glyphs by
|
||||
@ -231,13 +282,22 @@ GlyphCache::Loader::Loader(const Face & face, const bool dumb_font)
|
||||
- sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0))
|
||||
/ (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1;
|
||||
|
||||
if (version != 0x00010000
|
||||
if (version >= 0x00020000
|
||||
|| _num_attrs == 0 || _num_attrs > 0x3000 // is this hard limit appropriate?
|
||||
|| _num_glyphs_graphics > _num_glyphs_attributes)
|
||||
{
|
||||
_head = Face::Table();
|
||||
return;
|
||||
}
|
||||
|
||||
p = m_pGlat;
|
||||
version = be::read<uint32>(p);
|
||||
if (version >= 0x00040000) // reject Glat tables that are too new
|
||||
{
|
||||
_head = Face::Table();
|
||||
return;
|
||||
}
|
||||
_has_boxes = (version == 0x00030000);
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,7 +325,13 @@ unsigned short int GlyphCache::Loader::num_attrs() const throw()
|
||||
return _num_attrs;
|
||||
}
|
||||
|
||||
const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph) const throw()
|
||||
inline
|
||||
bool GlyphCache::Loader::has_boxes () const throw()
|
||||
{
|
||||
return _has_boxes;
|
||||
}
|
||||
|
||||
const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph, int *numsubs) const throw()
|
||||
{
|
||||
Rect bbox;
|
||||
Position advance;
|
||||
@ -312,30 +378,89 @@ const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFa
|
||||
return 0;
|
||||
|
||||
const uint32 glat_version = be::peek<uint32>(m_pGlat);
|
||||
if (glat_version == 0x00030000)
|
||||
{
|
||||
const byte * p = m_pGlat + glocs;
|
||||
uint16 bmap = be::read<uint16>(p);
|
||||
int num = bit_set_count((uint32)bmap);
|
||||
if (numsubs) *numsubs += num;
|
||||
glocs += 6 + 8 * num;
|
||||
if (glocs > gloce)
|
||||
return 0;
|
||||
}
|
||||
if (glat_version < 0x00020000)
|
||||
{
|
||||
if (gloce - glocs < 2*sizeof(byte)+sizeof(uint16)
|
||||
|| gloce - glocs > _num_attrs*(2*sizeof(byte)+sizeof(uint16)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
new (&glyph) GlyphFace(bbox, advance, glat_iterator(m_pGlat + glocs), glat_iterator(m_pGlat + gloce));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gloce - glocs < 3*sizeof(uint16)
|
||||
if (gloce - glocs < 3*sizeof(uint16) // can a glyph have no attributes? why not?
|
||||
|| gloce - glocs > _num_attrs*3*sizeof(uint16))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce));
|
||||
}
|
||||
|
||||
if (!glyph.attrs() || glyph.attrs().capacity() > _num_attrs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return &glyph;
|
||||
}
|
||||
|
||||
inline float scale_to(uint8 t, float zmin, float zmax)
|
||||
{
|
||||
return (zmin + t * (zmax - zmin) / 255);
|
||||
}
|
||||
|
||||
Rect readbox(Rect &b, uint8 zxmin, uint8 zymin, uint8 zxmax, uint8 zymax)
|
||||
{
|
||||
return Rect(Position(scale_to(zxmin, b.bl.x, b.tr.x), scale_to(zymin, b.bl.y, b.tr.y)),
|
||||
Position(scale_to(zxmax, b.bl.x, b.tr.x), scale_to(zymax, b.bl.y, b.tr.y)));
|
||||
}
|
||||
|
||||
GlyphBox * GlyphCache::Loader::read_box(uint16 gid, GlyphBox *curr, const GlyphFace & glyph) const throw()
|
||||
{
|
||||
if (gid >= _num_glyphs_attributes) return 0;
|
||||
|
||||
const byte * gloc = m_pGloc;
|
||||
size_t glocs = 0, gloce = 0;
|
||||
|
||||
be::skip<uint32>(gloc);
|
||||
be::skip<uint16>(gloc,2);
|
||||
if (_long_fmt)
|
||||
{
|
||||
be::skip<uint32>(gloc, gid);
|
||||
glocs = be::read<uint32>(gloc);
|
||||
gloce = be::peek<uint32>(gloc);
|
||||
}
|
||||
else
|
||||
{
|
||||
be::skip<uint16>(gloc, gid);
|
||||
glocs = be::read<uint16>(gloc);
|
||||
gloce = be::peek<uint16>(gloc);
|
||||
}
|
||||
|
||||
if (glocs >= m_pGlat.size() || gloce > m_pGlat.size())
|
||||
return 0;
|
||||
|
||||
const byte * p = m_pGlat + glocs;
|
||||
uint16 bmap = be::read<uint16>(p);
|
||||
int num = bit_set_count((uint32)bmap);
|
||||
|
||||
Rect bbox = glyph.theBBox();
|
||||
Rect diamax(Position(bbox.bl.x + bbox.bl.y, bbox.bl.x - bbox.tr.y),
|
||||
Position(bbox.tr.x + bbox.tr.y, bbox.tr.x - bbox.bl.y));
|
||||
Rect diabound = readbox(diamax, p[0], p[2], p[1], p[3]);
|
||||
::new (curr) GlyphBox(num, bmap, &diabound);
|
||||
be::skip<uint8>(p, 4);
|
||||
|
||||
for (int i = 0; i < num * 2; ++i)
|
||||
{
|
||||
Rect box = readbox((i & 1) ? diamax : bbox, p[0], p[2], p[1], p[3]);
|
||||
curr->addSubBox(i >> 1, i & 1, &box);
|
||||
be::skip<uint8>(p, 4);
|
||||
}
|
||||
return (GlyphBox *)((char *)(curr) + sizeof(GlyphBox) + 2 * num * sizeof(Rect));
|
||||
}
|
||||
|
||||
|
292
gfx/graphite2/src/Intervals.cpp
Normal file
292
gfx/graphite2/src/Intervals.cpp
Normal file
@ -0,0 +1,292 @@
|
||||
/* 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.
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include "inc/Intervals.h"
|
||||
#include "inc/Segment.h"
|
||||
#include "inc/Slot.h"
|
||||
#include "inc/debug.h"
|
||||
#include "inc/bits.h"
|
||||
|
||||
using namespace graphite2;
|
||||
|
||||
#include <cmath>
|
||||
|
||||
inline
|
||||
Zones::Exclusion Zones::Exclusion::split_at(float p) {
|
||||
Exclusion r(*this);
|
||||
r.xm = x = p;
|
||||
return r;
|
||||
}
|
||||
|
||||
inline
|
||||
void Zones::Exclusion::left_trim(float p) {
|
||||
x = p;
|
||||
}
|
||||
|
||||
inline
|
||||
Zones::Exclusion & Zones::Exclusion::operator += (Exclusion const & rhs) {
|
||||
c += rhs.c; sm += rhs.sm; smx += rhs.smx; open = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline
|
||||
uint8 Zones::Exclusion::outcode(float val) const {
|
||||
float p = val;
|
||||
return ((p >= xm) << 1) | (p < x);
|
||||
}
|
||||
|
||||
void Zones::exclude_with_margins(float xmin, float xmax, int axis) {
|
||||
remove(xmin, xmax);
|
||||
weightedAxis(axis, xmin-_margin_len, xmin, 0, 0, _margin_weight, xmin-_margin_len, 0, 0, false);
|
||||
weightedAxis(axis, xmax, xmax+_margin_len, 0, 0, _margin_weight, xmax+_margin_len, 0, 0, false);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
inline
|
||||
bool separated(float a, float b) {
|
||||
return a != b;
|
||||
//return std::fabs(a-b) > std::numeric_limits<float>::epsilon(); // std::epsilon may not work. but 0.5 fails exising 64 bit tests
|
||||
//return std::fabs(a-b) > 0.5f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Zones::insert(Exclusion e)
|
||||
{
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
addDebug(&e);
|
||||
#endif
|
||||
e.x = std::max(e.x, _pos);
|
||||
e.xm = std::min(e.xm, _posm);
|
||||
if (e.x >= e.xm) return;
|
||||
|
||||
for (iterator i = _exclusions.begin(), ie = _exclusions.end(); i != ie && e.x < e.xm; ++i)
|
||||
{
|
||||
const uint8 oca = e.outcode(i->x),
|
||||
ocb = e.outcode(i->xm);
|
||||
if ((oca & ocb) != 0) continue;
|
||||
|
||||
switch (oca ^ ocb) // What kind of overlap?
|
||||
{
|
||||
case 0: // e completely covers i
|
||||
// split e at i.x into e1,e2
|
||||
// split e2 at i.mx into e2,e3
|
||||
// drop e1 ,i+e2, e=e3
|
||||
*i += e;
|
||||
e.left_trim(i->xm);
|
||||
break;
|
||||
case 1: // e overlaps on the rhs of i
|
||||
// split i at e->x into i1,i2
|
||||
// split e at i.mx into e1,e2
|
||||
// trim i1, insert i2+e1, e=e2
|
||||
if (!separated(i->xm, e.x)) break;
|
||||
if (separated(i->x,e.x)) { i = _exclusions.insert(i,i->split_at(e.x)); ++i; }
|
||||
*i += e;
|
||||
e.left_trim(i->xm);
|
||||
break;
|
||||
case 2: // e overlaps on the lhs of i
|
||||
// split e at i->x into e1,e2
|
||||
// split i at e.mx into i1,i2
|
||||
// drop e1, insert e2+i1, trim i2
|
||||
if (!separated(e.xm, i->x)) return;
|
||||
if (separated(e.xm, i->xm)) i = _exclusions.insert(i,i->split_at(e.xm));
|
||||
*i += e;
|
||||
return;
|
||||
case 3: // i completely covers e
|
||||
// split i at e.x into i1,i2
|
||||
// split i2 at e.mx into i2,i3
|
||||
// insert i1, insert e+i2
|
||||
if (separated(e.xm, i->xm)) i = _exclusions.insert(i,i->split_at(e.xm));
|
||||
i = _exclusions.insert(i, i->split_at(e.x));
|
||||
*++i += e;
|
||||
return;
|
||||
}
|
||||
|
||||
ie = _exclusions.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Zones::remove(float x, float xm)
|
||||
{
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
removeDebug(x, xm);
|
||||
#endif
|
||||
x = std::max(x, _pos);
|
||||
xm = std::min(xm, _posm);
|
||||
if (x >= xm) return;
|
||||
|
||||
for (iterator i = _exclusions.begin(), ie = _exclusions.end(); i != ie; ++i)
|
||||
{
|
||||
const uint8 oca = i->outcode(x),
|
||||
ocb = i->outcode(xm);
|
||||
if ((oca & ocb) != 0) continue;
|
||||
|
||||
switch (oca ^ ocb) // What kind of overlap?
|
||||
{
|
||||
case 0: // i completely covers e
|
||||
if (separated(i->x, x)) { i = _exclusions.insert(i,i->split_at(x)); ++i; }
|
||||
// no break
|
||||
case 1: // i overlaps on the rhs of e
|
||||
i->left_trim(xm);
|
||||
return;
|
||||
case 2: // i overlaps on the lhs of e
|
||||
i->xm = x;
|
||||
if (separated(i->x, i->xm)) break;
|
||||
// no break
|
||||
case 3: // e completely covers i
|
||||
i = _exclusions.erase(i);
|
||||
--i;
|
||||
break;
|
||||
}
|
||||
|
||||
ie = _exclusions.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Zones::const_iterator Zones::find_exclusion_under(float x) const
|
||||
{
|
||||
int l = 0, h = _exclusions.size();
|
||||
|
||||
while (l < h)
|
||||
{
|
||||
int const p = (l+h) >> 1;
|
||||
switch (_exclusions[p].outcode(x))
|
||||
{
|
||||
case 0 : return _exclusions.begin()+p;
|
||||
case 1 : h = p; break;
|
||||
case 2 :
|
||||
case 3 : l = p+1; break;
|
||||
}
|
||||
}
|
||||
|
||||
return _exclusions.begin()+l;
|
||||
}
|
||||
|
||||
|
||||
float Zones::closest(float origin, float & cost) const
|
||||
{
|
||||
float best_c = std::numeric_limits<float>::max(),
|
||||
best_x = 0;
|
||||
|
||||
const const_iterator start = find_exclusion_under(origin);
|
||||
|
||||
// Forward scan looking for lowest cost
|
||||
for (const_iterator i = start, ie = _exclusions.end(); i != ie; ++i)
|
||||
if (i->track_cost(best_c, best_x, origin)) break;
|
||||
|
||||
// Backward scan looking for lowest cost
|
||||
// We start from the exclusion to the immediate left of start since we've
|
||||
// already tested start with the right most scan above.
|
||||
for (const_iterator i = start-1, ie = _exclusions.begin()-1; i != ie; --i)
|
||||
if (i->track_cost(best_c, best_x, origin)) break;
|
||||
|
||||
cost = (best_c == std::numeric_limits<float>::max() ? -1 : best_c);
|
||||
return best_x;
|
||||
}
|
||||
|
||||
|
||||
// Cost and test position functions
|
||||
|
||||
bool Zones::Exclusion::track_cost(float & best_cost, float & best_pos, float origin) const {
|
||||
const float p = test_position(origin),
|
||||
localc = cost(p - origin);
|
||||
if (open && localc > best_cost) return true;
|
||||
|
||||
if (localc < best_cost)
|
||||
{
|
||||
best_cost = localc;
|
||||
best_pos = p;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline
|
||||
float Zones::Exclusion::cost(float p) const {
|
||||
return (sm * p - 2 * smx) * p + c;
|
||||
}
|
||||
|
||||
|
||||
float Zones::Exclusion::test_position(float origin) const {
|
||||
if (sm < 0)
|
||||
{
|
||||
// sigh, test both ends and perhaps the middle too!
|
||||
float res = x;
|
||||
float cl = cost(x);
|
||||
if (x < origin && xm > origin)
|
||||
{
|
||||
float co = cost(origin);
|
||||
if (co < cl)
|
||||
{
|
||||
cl = co;
|
||||
res = origin;
|
||||
}
|
||||
}
|
||||
float cr = cost(xm);
|
||||
return cl > cr ? xm : res;
|
||||
}
|
||||
else
|
||||
{
|
||||
float zerox = smx / sm + origin;
|
||||
if (zerox < x) return x;
|
||||
else if (zerox > xm) return xm;
|
||||
else return zerox;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
|
||||
void Zones::jsonDbgOut(Segment *seg) const {
|
||||
|
||||
if (_dbg)
|
||||
{
|
||||
for (Zones::idebugs s = dbgs_begin(), e = dbgs_end(); s != e; ++s)
|
||||
{
|
||||
*_dbg << json::flat << json::array
|
||||
<< objectid(dslot(seg, (Slot *)(s->_env[0])))
|
||||
<< reinterpret_cast<ptrdiff_t>(s->_env[1]);
|
||||
if (s->_isdel)
|
||||
*_dbg << "remove" << Position(s->_excl.x, s->_excl.xm);
|
||||
else
|
||||
*_dbg << "exclude" << json::flat << json::array
|
||||
<< s->_excl.x << s->_excl.xm
|
||||
<< s->_excl.sm << s->_excl.smx << s->_excl.c
|
||||
<< json::close;
|
||||
*_dbg << json::close;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -60,7 +60,7 @@ void JustifyTotal::accumulate(Slot *s, Segment *seg, int level)
|
||||
m_tWeight += s->getJustify(seg, level, 3);
|
||||
}
|
||||
|
||||
float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUSED justFlags flags, Slot *pFirst, Slot *pLast)
|
||||
float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUSED justFlags jflags, Slot *pFirst, Slot *pLast)
|
||||
{
|
||||
Slot *s, *end;
|
||||
float currWidth = 0.0;
|
||||
@ -76,11 +76,11 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
|
||||
while (!pLast->isBase()) pLast = pLast->attachedTo();
|
||||
const float base = pFirst->origin().x / scale;
|
||||
width = width / scale;
|
||||
if ((flags & gr_justEndInline) == 0)
|
||||
if ((jflags & gr_justEndInline) == 0)
|
||||
{
|
||||
do {
|
||||
Rect bbox = theGlyphBBoxTemporary(pLast->glyph());
|
||||
if (bbox.bl.x != 0. || bbox.bl.y != 0. || bbox.tr.x != 0. || bbox.tr.y == 0.)
|
||||
if (bbox.bl.x != 0.f || bbox.bl.y != 0.f || bbox.tr.x != 0.f || bbox.tr.y == 0.f)
|
||||
break;
|
||||
pLast = pLast->prev();
|
||||
} while (pLast != pFirst);
|
||||
@ -116,8 +116,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
|
||||
++numLevels;
|
||||
}
|
||||
|
||||
JustifyTotal *stats = new JustifyTotal[numLevels];
|
||||
if (!stats) return -1.0;
|
||||
Vector<JustifyTotal> stats(numLevels);
|
||||
for (s = pFirst; s != end; s = s->nextSibling())
|
||||
{
|
||||
float w = s->origin().x / scale + s->advance() - base;
|
||||
@ -127,7 +126,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
|
||||
s->just(0);
|
||||
}
|
||||
|
||||
for (int i = (width < 0.0) ? -1 : numLevels - 1; i >= 0; --i)
|
||||
for (int i = (width < 0.0f) ? -1 : numLevels - 1; i >= 0; --i)
|
||||
{
|
||||
float diff;
|
||||
float error = 0.;
|
||||
@ -197,7 +196,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
|
||||
<< "passes" << json::array;
|
||||
#endif
|
||||
|
||||
if (m_silf->justificationPass() != m_silf->positionPass() && (width >= 0. || (silf()->flags() & 1)))
|
||||
if (m_silf->justificationPass() != m_silf->positionPass() && (width >= 0.f || (silf()->flags() & 1)))
|
||||
m_silf->runGraphite(this, m_silf->justificationPass(), m_silf->positionPass());
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
|
@ -31,10 +31,12 @@ of the License or (at your option) any later version.
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include "inc/Segment.h"
|
||||
#include "inc/Code.h"
|
||||
#include "inc/Rule.h"
|
||||
#include "inc/Error.h"
|
||||
#include "inc/Collider.h"
|
||||
|
||||
using namespace graphite2;
|
||||
using vm::Machine;
|
||||
@ -49,6 +51,8 @@ Pass::Pass()
|
||||
m_startStates(0),
|
||||
m_transitions(0),
|
||||
m_states(0),
|
||||
m_codes(0),
|
||||
m_progs(0),
|
||||
m_flags(0),
|
||||
m_iMaxLoop(0),
|
||||
m_numGlyphs(0),
|
||||
@ -70,21 +74,27 @@ Pass::~Pass()
|
||||
free(m_states);
|
||||
free(m_ruleMap);
|
||||
|
||||
delete [] m_rules;
|
||||
if (m_rules) delete [] m_rules;
|
||||
if (m_codes) delete [] m_codes;
|
||||
free(m_progs);
|
||||
}
|
||||
|
||||
bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t subtable_base, GR_MAYBE_UNUSED Face & face, Error &e)
|
||||
bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t subtable_base,
|
||||
GR_MAYBE_UNUSED Face & face, passtype pt, GR_MAYBE_UNUSED uint32 version, Error &e)
|
||||
{
|
||||
const byte * p = pass_start,
|
||||
* const pass_end = p + pass_length;
|
||||
const byte * p = pass_start,
|
||||
* const pass_end = p + pass_length;
|
||||
size_t numRanges;
|
||||
|
||||
if (e.test(pass_length < 40, E_BADPASSLENGTH)) return face.error(e);
|
||||
// Read in basic values
|
||||
m_flags = be::read<byte>(p);
|
||||
if (e.test((m_flags & 15) && pt < PASS_TYPE_POSITIONING, E_BADCOLLISIONPASS))
|
||||
return face.error(e);
|
||||
m_iMaxLoop = be::read<byte>(p);
|
||||
be::skip<byte>(p,2); // skip maxContext & maxBackup
|
||||
m_numRules = be::read<uint16>(p);
|
||||
if (e.test(!m_numRules && !(m_flags & 7), E_BADEMPTYPASS)) return face.error(e);
|
||||
be::skip<uint16>(p); // fsmOffset - not sure why we would want this
|
||||
const byte * const pcCode = pass_start + be::read<uint32>(p) - subtable_base,
|
||||
* const rcCode = pass_start + be::read<uint32>(p) - subtable_base,
|
||||
@ -101,7 +111,7 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
|
||||
if ( e.test(m_numTransition > m_numStates, E_BADNUMTRANS)
|
||||
|| e.test(m_numSuccess > m_numStates, E_BADNUMSUCCESS)
|
||||
|| e.test(m_numSuccess + m_numTransition < m_numStates, E_BADNUMSTATES)
|
||||
|| e.test(numRanges == 0, E_NORANGES))
|
||||
|| e.test(m_numRules && numRanges == 0, E_NORANGES))
|
||||
return face.error(e);
|
||||
|
||||
m_successStart = m_numStates - m_numSuccess;
|
||||
@ -131,23 +141,26 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
|
||||
be::skip<uint16>(p, m_numRules);
|
||||
const byte * const precontext = p;
|
||||
be::skip<byte>(p, m_numRules);
|
||||
be::skip<byte>(p); // skip reserved byte
|
||||
|
||||
if (e.test(p + sizeof(uint16) > pass_end, E_BADCTXTLENS)) return face.error(e);
|
||||
if (e.test(p + sizeof(uint16) + sizeof(uint8) > pass_end, E_BADCTXTLENS)) return face.error(e);
|
||||
m_colThreshold = be::read<uint8>(p);
|
||||
if (m_colThreshold == 0) m_colThreshold = 10; // A default
|
||||
const size_t pass_constraint_len = be::read<uint16>(p);
|
||||
|
||||
const uint16 * const o_constraint = reinterpret_cast<const uint16 *>(p);
|
||||
be::skip<uint16>(p, m_numRules + 1);
|
||||
const uint16 * const o_actions = reinterpret_cast<const uint16 *>(p);
|
||||
be::skip<uint16>(p, m_numRules + 1);
|
||||
const byte * const states = p;
|
||||
if (e.test(p + 2 * m_numTransition*m_numColumns >= pass_end, E_BADPASSLENGTH)) return face.error(e);
|
||||
be::skip<int16>(p, m_numTransition*m_numColumns);
|
||||
be::skip<byte>(p); // skip reserved byte
|
||||
if (e.test(p != pcCode, E_BADPASSCCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)) return face.error(e);
|
||||
be::skip<uint8>(p);
|
||||
if (e.test(p != pcCode, E_BADPASSCCODEPTR)) return face.error(e);
|
||||
be::skip<byte>(p, pass_constraint_len);
|
||||
if (e.test(p != rcCode, E_BADRULECCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)
|
||||
if (e.test(p != rcCode, E_BADRULECCODEPTR)
|
||||
|| e.test(size_t(rcCode - pcCode) != pass_constraint_len, E_BADCCODELEN)) return face.error(e);
|
||||
be::skip<byte>(p, be::peek<uint16>(o_constraint + m_numRules));
|
||||
if (e.test(p != aCode, E_BADACTIONCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)) return face.error(e);
|
||||
if (e.test(p != aCode, E_BADACTIONCODEPTR)) return face.error(e);
|
||||
be::skip<byte>(p, be::peek<uint16>(o_actions + m_numRules));
|
||||
|
||||
// We should be at the end or within the pass
|
||||
@ -158,19 +171,22 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
|
||||
{
|
||||
face.error_context(face.error_context() + 1);
|
||||
m_cPConstraint = vm::Machine::Code(true, pcCode, pcCode + pass_constraint_len,
|
||||
precontext[0], be::peek<uint16>(sort_keys), *m_silf, face);
|
||||
precontext[0], be::peek<uint16>(sort_keys), *m_silf, face, PASS_TYPE_UNKNOWN);
|
||||
if (e.test(!m_cPConstraint, E_OUTOFMEM)
|
||||
|| e.test(m_cPConstraint.status(), m_cPConstraint.status() + E_CODEFAILURE))
|
||||
|| e.test(!m_cPConstraint, m_cPConstraint.status() + E_CODEFAILURE))
|
||||
return face.error(e);
|
||||
face.error_context(face.error_context() - 1);
|
||||
}
|
||||
if (!readRanges(ranges, numRanges, e)) return face.error(e);
|
||||
if (!readRules(rule_map, numEntries, precontext, sort_keys,
|
||||
o_constraint, rcCode, o_actions, aCode, face, e)) return false;
|
||||
if (m_numRules)
|
||||
{
|
||||
if (!readRanges(ranges, numRanges, e)) return face.error(e);
|
||||
if (!readRules(rule_map, numEntries, precontext, sort_keys,
|
||||
o_constraint, rcCode, o_actions, aCode, face, pt, e)) return false;
|
||||
}
|
||||
#ifdef GRAPHITE2_TELEMETRY
|
||||
telemetry::category _states_cat(face.tele.states);
|
||||
#endif
|
||||
return readStates(start_states, states, o_rule_map, face, e);
|
||||
return m_numRules ? readStates(start_states, states, o_rule_map, face, e) : true;
|
||||
}
|
||||
|
||||
|
||||
@ -178,12 +194,11 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
|
||||
const byte *precontext, const uint16 * sort_key,
|
||||
const uint16 * o_constraint, const byte *rc_data,
|
||||
const uint16 * o_action, const byte * ac_data,
|
||||
Face & face, Error &e)
|
||||
Face & face, passtype pt, Error &e)
|
||||
{
|
||||
const byte * const ac_data_end = ac_data + be::peek<uint16>(o_action + m_numRules);
|
||||
const byte * const rc_data_end = rc_data + be::peek<uint16>(o_constraint + m_numRules);
|
||||
|
||||
if (e.test(!(m_rules = new Rule [m_numRules]), E_OUTOFMEM)) return face.error(e);
|
||||
precontext += m_numRules;
|
||||
sort_key += m_numRules;
|
||||
o_constraint += m_numRules;
|
||||
@ -193,6 +208,15 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
|
||||
const byte * ac_begin = 0, * rc_begin = 0,
|
||||
* ac_end = ac_data + be::peek<uint16>(o_action),
|
||||
* rc_end = rc_data + be::peek<uint16>(o_constraint);
|
||||
|
||||
// Allocate pools
|
||||
m_rules = new Rule [m_numRules];
|
||||
m_codes = new Code [m_numRules*2];
|
||||
m_progs = static_cast<byte *>(malloc((ac_end - ac_data + rc_end - rc_data)
|
||||
*(sizeof(vm::instr)+sizeof(byte))));
|
||||
byte * prog_pool_free = m_progs;
|
||||
if (e.test(!(m_rules && m_codes && m_progs), E_OUTOFMEM)) return face.error(e);
|
||||
|
||||
Rule * r = m_rules + m_numRules - 1;
|
||||
for (size_t n = m_numRules; n; --n, --r, ac_end = ac_begin, rc_end = rc_begin)
|
||||
{
|
||||
@ -211,8 +235,8 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
|
||||
if (ac_begin > ac_end || ac_begin > ac_data_end || ac_end > ac_data_end
|
||||
|| rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end)
|
||||
return false;
|
||||
r->action = new vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face);
|
||||
r->constraint = new vm::Machine::Code(true, rc_begin, rc_end, r->preContext, r->sort, *m_silf, face);
|
||||
r->action = new (m_codes+n*2-2) vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face, pt, prog_pool_free);
|
||||
r->constraint = new (m_codes+n*2-1) vm::Machine::Code(true, rc_begin, rc_end, r->preContext, r->sort, *m_silf, face, pt, prog_pool_free);
|
||||
|
||||
if (e.test(!r->action || !r->constraint, E_OUTOFMEM)
|
||||
|| e.test(r->action->status() != Code::loaded, r->action->status() + E_CODEFAILURE)
|
||||
@ -221,6 +245,17 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
|
||||
return face.error(e);
|
||||
}
|
||||
|
||||
// Shrink the program pool
|
||||
ptrdiff_t const delta = static_cast<byte *>(realloc(m_progs, prog_pool_free - m_progs)) - m_progs;
|
||||
if (delta)
|
||||
{
|
||||
m_progs += delta;
|
||||
for (Code * c = m_codes, * const ce = c + m_numRules*2; c != ce; ++c)
|
||||
{
|
||||
c->externalProgramMoved(delta);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the rule entries map
|
||||
face.error_context((face.error_context() & 0xFFFF00) + EC_APASS);
|
||||
RuleEntry * re = m_ruleMap = gralloc<RuleEntry>(num_entries);
|
||||
@ -325,33 +360,52 @@ bool Pass::readRanges(const byte * ranges, size_t num_ranges, Error &e)
|
||||
}
|
||||
|
||||
|
||||
void Pass::runGraphite(Machine & m, FiniteStateMachine & fsm) const
|
||||
bool Pass::runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const
|
||||
{
|
||||
Slot *s = m.slotMap().segment.first();
|
||||
if (!s || !testPassConstraint(m)) return;
|
||||
Slot *currHigh = s->next();
|
||||
if (!s || !testPassConstraint(m)) return true;
|
||||
if (m_numRules)
|
||||
{
|
||||
Slot *currHigh = s->next();
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (fsm.dbgout) *fsm.dbgout << "rules" << json::array;
|
||||
json::closer rules_array_closer(fsm.dbgout);
|
||||
if (fsm.dbgout) *fsm.dbgout << "rules" << json::array;
|
||||
json::closer rules_array_closer(fsm.dbgout);
|
||||
#endif
|
||||
|
||||
m.slotMap().highwater(currHigh);
|
||||
int lc = m_iMaxLoop;
|
||||
do
|
||||
{
|
||||
findNDoRule(s, m, fsm);
|
||||
if (s && (m.slotMap().highpassed() || s == m.slotMap().highwater() || --lc == 0)) {
|
||||
if (!lc)
|
||||
{
|
||||
// if (dbgout) *dbgout << json::item << json::flat << rule_event(-1, s, 1);
|
||||
s = m.slotMap().highwater();
|
||||
m.slotMap().highwater(currHigh);
|
||||
int lc = m_iMaxLoop;
|
||||
do
|
||||
{
|
||||
findNDoRule(s, m, fsm);
|
||||
if (s && (s == m.slotMap().highwater() || m.slotMap().highpassed() || --lc == 0)) {
|
||||
if (!lc)
|
||||
s = m.slotMap().highwater();
|
||||
lc = m_iMaxLoop;
|
||||
if (s)
|
||||
m.slotMap().highwater(s->next());
|
||||
}
|
||||
lc = m_iMaxLoop;
|
||||
if (s)
|
||||
m.slotMap().highwater(s->next());
|
||||
} while (s);
|
||||
}
|
||||
|
||||
if (!(m_flags & 15) || !m.slotMap().segment.hasCollisionInfo())
|
||||
return true;
|
||||
|
||||
if (m_flags & 7)
|
||||
{
|
||||
if (!(m.slotMap().segment.flags() & Segment::SEG_INITCOLLISIONS))
|
||||
{
|
||||
m.slotMap().segment.positionSlots(0, 0, 0, true);
|
||||
// m.slotMap().segment.flags(m.slotMap().segment.flags() | Segment::SEG_INITCOLLISIONS);
|
||||
}
|
||||
} while (s);
|
||||
if (!collisionShift(&m.slotMap().segment, m.slotMap().segment.dir(), fsm.dbgout))
|
||||
return false;
|
||||
}
|
||||
if ((m_flags & 24) && !collisionKern(&m.slotMap().segment, m.slotMap().segment.dir(), fsm.dbgout))
|
||||
return false;
|
||||
if ((m_flags & 15) && !collisionFinish(&m.slotMap().segment, fsm.dbgout))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pass::runFSM(FiniteStateMachine& fsm, Slot * slot) const
|
||||
@ -455,6 +509,7 @@ void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) cons
|
||||
}
|
||||
|
||||
slot = slot->next();
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
@ -464,9 +519,10 @@ void Pass::dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEnt
|
||||
*fsm.dbgout << "considered" << json::array;
|
||||
for (const RuleEntry *r = fsm.rules.begin(); r != &re; ++r)
|
||||
{
|
||||
if (r->rule->preContext > fsm.slots.context()) continue;
|
||||
*fsm.dbgout << json::flat << json::object
|
||||
<< "id" << r->rule - m_rules
|
||||
if (r->rule->preContext > fsm.slots.context())
|
||||
continue;
|
||||
*fsm.dbgout << json::flat << json::object
|
||||
<< "id" << r->rule - m_rules
|
||||
<< "failed" << true
|
||||
<< "input" << json::flat << json::object
|
||||
<< "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, -r->rule->preContext)))
|
||||
@ -586,15 +642,23 @@ int Pass::doAction(const Code *codeptr, Slot * & slot_out, vm::Machine & m) cons
|
||||
|
||||
void Pass::adjustSlot(int delta, Slot * & slot_out, SlotMap & smap) const
|
||||
{
|
||||
if (delta < 0)
|
||||
if (!slot_out)
|
||||
{
|
||||
if (!slot_out)
|
||||
if (smap.highpassed() || slot_out == smap.highwater())
|
||||
{
|
||||
slot_out = smap.segment.last();
|
||||
++delta;
|
||||
if (smap.highpassed() && !smap.highwater())
|
||||
if (!smap.highwater())
|
||||
smap.highpassed(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
slot_out = smap.segment.first();
|
||||
--delta;
|
||||
}
|
||||
}
|
||||
if (delta < 0)
|
||||
{
|
||||
while (++delta <= 0 && slot_out)
|
||||
{
|
||||
if (smap.highpassed() && smap.highwater() == slot_out)
|
||||
@ -604,11 +668,6 @@ void Pass::adjustSlot(int delta, Slot * & slot_out, SlotMap & smap) const
|
||||
}
|
||||
else if (delta > 0)
|
||||
{
|
||||
if (!slot_out)
|
||||
{
|
||||
slot_out = smap.segment.first();
|
||||
--delta;
|
||||
}
|
||||
while (--delta >= 0 && slot_out)
|
||||
{
|
||||
slot_out = slot_out->next();
|
||||
@ -618,3 +677,373 @@ void Pass::adjustSlot(int delta, Slot * & slot_out, SlotMap & smap) const
|
||||
}
|
||||
}
|
||||
|
||||
bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const
|
||||
{
|
||||
ShiftCollider shiftcoll(dbgout);
|
||||
// bool isfirst = true;
|
||||
const uint8 numLoops = m_flags & 7; // number of loops permitted to fix collisions; does not include kerning
|
||||
bool hasCollisions = false;
|
||||
Slot *start = seg->first(); // turn on collision fixing for the first slot
|
||||
Slot *end = NULL;
|
||||
bool moved = false;
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout)
|
||||
*dbgout << "collisions" << json::array
|
||||
<< json::flat << json::object << "num-loops" << numLoops << json::close;
|
||||
#endif
|
||||
|
||||
while (start)
|
||||
{
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout) *dbgout << json::object << "phase" << "1" << "moves" << json::array;
|
||||
#endif
|
||||
hasCollisions = false;
|
||||
end = NULL;
|
||||
// phase 1 : position shiftable glyphs, ignoring kernable glyphs
|
||||
for (Slot *s = start; s; s = s->next())
|
||||
{
|
||||
const SlotCollision * c = seg->collisionInfo(s);
|
||||
if (start && (c->flags() & (SlotCollision::COLL_FIX | SlotCollision::COLL_KERN)) == SlotCollision::COLL_FIX
|
||||
&& !resolveCollisions(seg, s, start, shiftcoll, false, dir, moved, hasCollisions, dbgout))
|
||||
return false;
|
||||
if (s != start && c->flags() & SlotCollision::COLL_END)
|
||||
{
|
||||
end = s->next();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout)
|
||||
*dbgout << json::close << json::close; // phase-1
|
||||
#endif
|
||||
|
||||
// phase 2 : loop until happy.
|
||||
for (int i = 0; i < numLoops - 1; ++i)
|
||||
{
|
||||
if (hasCollisions || moved)
|
||||
{
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout)
|
||||
*dbgout << json::object << "phase" << "2a" << "loop" << i << "moves" << json::array;
|
||||
#endif
|
||||
// phase 2a : if any shiftable glyphs are in collision, iterate backwards,
|
||||
// fixing them and ignoring other non-collided glyphs. Note that this handles ONLY
|
||||
// glyphs that are actually in collision from phases 1 or 2b, and working backwards
|
||||
// has the intended effect of breaking logjams.
|
||||
if (hasCollisions)
|
||||
{
|
||||
hasCollisions = false;
|
||||
#if 0
|
||||
moved = true;
|
||||
for (Slot *s = start; s != end; s = s->next())
|
||||
{
|
||||
SlotCollision * c = seg->collisionInfo(s);
|
||||
c->setShift(Position(0, 0));
|
||||
}
|
||||
#endif
|
||||
Slot *lend = end ? end->prev() : seg->last();
|
||||
Slot *lstart = start->prev();
|
||||
for (Slot *s = lend; s != lstart; s = s->prev())
|
||||
{
|
||||
SlotCollision * c = seg->collisionInfo(s);
|
||||
if (start && (c->flags() & (SlotCollision::COLL_FIX | SlotCollision::COLL_KERN | SlotCollision::COLL_ISCOL))
|
||||
== (SlotCollision::COLL_FIX | SlotCollision::COLL_ISCOL)) // ONLY if this glyph is still colliding
|
||||
{
|
||||
if (!resolveCollisions(seg, s, lend, shiftcoll, true, dir, moved, hasCollisions, dbgout))
|
||||
return false;
|
||||
c->setFlags(c->flags() | SlotCollision::COLL_TEMPLOCK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout)
|
||||
*dbgout << json::close << json::close // phase 2a
|
||||
<< json::object << "phase" << "2b" << "loop" << i << "moves" << json::array;
|
||||
#endif
|
||||
|
||||
// phase 2b : redo basic diacritic positioning pass for ALL glyphs. Each successive loop adjusts
|
||||
// glyphs from their current adjusted position, which has the effect of gradually minimizing the
|
||||
// resulting adjustment; ie, the final result will be gradually closer to the original location.
|
||||
// Also it allows more flexibility in the final adjustment, since it is moving along the
|
||||
// possible 8 vectors from successively different starting locations.
|
||||
if (moved)
|
||||
{
|
||||
moved = false;
|
||||
for (Slot *s = start; s != end; s = s->next())
|
||||
{
|
||||
SlotCollision * c = seg->collisionInfo(s);
|
||||
if (start && (c->flags() & (SlotCollision::COLL_FIX | SlotCollision::COLL_TEMPLOCK
|
||||
| SlotCollision::COLL_KERN)) == SlotCollision::COLL_FIX
|
||||
&& !resolveCollisions(seg, s, start, shiftcoll, false, dir, moved, hasCollisions, dbgout))
|
||||
return false;
|
||||
else if (c->flags() & SlotCollision::COLL_TEMPLOCK)
|
||||
c->setFlags(c->flags() & ~SlotCollision::COLL_TEMPLOCK);
|
||||
}
|
||||
}
|
||||
// if (!hasCollisions) // no, don't leave yet because phase 2b will continue to improve things
|
||||
// break;
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout)
|
||||
*dbgout << json::close << json::close; // phase 2
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (!end)
|
||||
break;
|
||||
start = NULL;
|
||||
for (Slot *s = end->prev(); s; s = s->next())
|
||||
{
|
||||
if (seg->collisionInfo(s)->flags() & SlotCollision::COLL_START)
|
||||
{
|
||||
start = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pass::collisionKern(Segment *seg, int dir, json * const dbgout) const
|
||||
{
|
||||
KernCollider kerncoll(dbgout);
|
||||
Slot *start = seg->first();
|
||||
float ymin = 1e38f;
|
||||
float ymax = -1e38f;
|
||||
const GlyphCache &gc = seg->getFace()->glyphs();
|
||||
|
||||
// phase 3 : handle kerning of clusters
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout)
|
||||
*dbgout << json::object << "phase" << "3" << "moves" << json::array;
|
||||
#endif
|
||||
|
||||
for (Slot *s = seg->first(); s; s = s->next())
|
||||
{
|
||||
if (!gc.check(s->gid()))
|
||||
return false;
|
||||
const SlotCollision * c = seg->collisionInfo(s);
|
||||
const Rect &bbox = seg->theGlyphBBoxTemporary(s->gid());
|
||||
float y = s->origin().y + c->shift().y;
|
||||
ymax = max(y + bbox.tr.y, ymax);
|
||||
ymin = min(y + bbox.bl.y, ymin);
|
||||
if (start && (c->flags() & (SlotCollision::COLL_KERN | SlotCollision::COLL_FIX))
|
||||
== (SlotCollision::COLL_KERN | SlotCollision::COLL_FIX))
|
||||
resolveKern(seg, s, start, kerncoll, dir, ymin, ymax, dbgout);
|
||||
if (c->flags() & SlotCollision::COLL_END)
|
||||
start = NULL;
|
||||
if (c->flags() & SlotCollision::COLL_START)
|
||||
start = s;
|
||||
}
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout)
|
||||
*dbgout << json::close << json::close; // phase 3
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pass::collisionFinish(Segment *seg, GR_MAYBE_UNUSED json * const dbgout) const
|
||||
{
|
||||
for (Slot *s = seg->first(); s; s = s->next())
|
||||
{
|
||||
SlotCollision *c = seg->collisionInfo(s);
|
||||
if (c->shift().x != 0 || c->shift().y != 0)
|
||||
{
|
||||
const Position newOffset = c->shift();
|
||||
const Position nullPosition(0, 0);
|
||||
c->setOffset(newOffset + c->offset());
|
||||
c->setShift(nullPosition);
|
||||
}
|
||||
}
|
||||
// seg->positionSlots();
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout)
|
||||
*dbgout << json::close;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// Can slot s be kerned, or is it attached to something that can be kerned?
|
||||
static bool inKernCluster(Segment *seg, Slot *s)
|
||||
{
|
||||
SlotCollision *c = seg->collisionInfo(s);
|
||||
if (c->flags() & SlotCollision::COLL_KERN /** && c->flags() & SlotCollision::COLL_FIX **/ )
|
||||
return true;
|
||||
while (s->attachedTo())
|
||||
{
|
||||
s = s->attachedTo();
|
||||
c = seg->collisionInfo(s);
|
||||
if (c->flags() & SlotCollision::COLL_KERN /** && c->flags() & SlotCollision::COLL_FIX **/ )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fix collisions for the given slot.
|
||||
// Return true if everything was fixed, false if there are still collisions remaining.
|
||||
// isRev means be we are processing backwards.
|
||||
bool Pass::resolveCollisions(Segment *seg, Slot *slotFix, Slot *start,
|
||||
ShiftCollider &coll, GR_MAYBE_UNUSED bool isRev, int dir, bool &moved, bool &hasCol,
|
||||
json * const dbgout) const
|
||||
{
|
||||
Slot * nbor; // neighboring slot
|
||||
SlotCollision *cFix = seg->collisionInfo(slotFix);
|
||||
if (!coll.initSlot(seg, slotFix, cFix->limit(), cFix->margin(), cFix->marginWt(),
|
||||
cFix->shift(), cFix->offset(), dir, dbgout))
|
||||
return false;
|
||||
bool collides = false;
|
||||
// When we're processing forward, ignore kernable glyphs that preceed the target glyph.
|
||||
// When processing backward, don't ignore these until we pass slotFix.
|
||||
bool ignoreForKern = !isRev;
|
||||
bool rtl = dir & 1;
|
||||
Slot *base = slotFix;
|
||||
while (base->attachedTo())
|
||||
base = base->attachedTo();
|
||||
Position zero(0., 0.);
|
||||
|
||||
// Look for collisions with the neighboring glyphs.
|
||||
for (nbor = start; nbor; nbor = isRev ? nbor->prev() : nbor->next())
|
||||
{
|
||||
SlotCollision *cNbor = seg->collisionInfo(nbor);
|
||||
bool sameCluster = nbor->isChildOf(base);
|
||||
if (nbor != slotFix // don't process if this is the slot of interest
|
||||
&& !(cNbor->flags() & SlotCollision::COLL_IGNORE) // don't process if ignoring
|
||||
&& (nbor == base || sameCluster // process if in the same cluster as slotFix
|
||||
|| !inKernCluster(seg, nbor) // or this cluster is not to be kerned
|
||||
|| (rtl ^ ignoreForKern)) // or it comes before(ltr) or after(rtl)
|
||||
&& (!isRev // if processing forwards then good to merge otherwise only:
|
||||
|| !(cNbor->flags() & SlotCollision::COLL_FIX) // merge in immovable stuff
|
||||
|| (cNbor->flags() & SlotCollision::COLL_KERN && !sameCluster) // ignore other kernable clusters
|
||||
|| (cNbor->flags() & SlotCollision::COLL_ISCOL)) // test against other collided glyphs
|
||||
&& !coll.mergeSlot(seg, nbor, cNbor->shift(), !ignoreForKern, sameCluster, collides, false, dbgout))
|
||||
return false;
|
||||
else if (nbor == slotFix)
|
||||
// Switching sides of this glyph - if we were ignoring kernable stuff before, don't anymore.
|
||||
ignoreForKern = !ignoreForKern;
|
||||
|
||||
if (nbor != start && (cNbor->flags() & (isRev ? SlotCollision::COLL_START : SlotCollision::COLL_END)))
|
||||
break;
|
||||
}
|
||||
bool isCol = false;
|
||||
if (collides || cFix->shift().x != 0.f || cFix->shift().y != 0.f)
|
||||
{
|
||||
Position shift = coll.resolve(seg, isCol, dbgout);
|
||||
// isCol has been set to true if a collision remains.
|
||||
if (std::fabs(shift.x) < 1e38f && std::fabs(shift.y) < 1e38f)
|
||||
{
|
||||
if (sqr(shift.x-cFix->shift().x) + sqr(shift.y-cFix->shift().y) >= m_colThreshold * m_colThreshold)
|
||||
moved = true;
|
||||
cFix->setShift(shift);
|
||||
if (slotFix->firstChild())
|
||||
{
|
||||
Rect bbox;
|
||||
Position here = slotFix->origin() + shift;
|
||||
float clusterMin = here.x;
|
||||
slotFix->firstChild()->finalise(seg, NULL, here, bbox, 0, clusterMin, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This glyph is not colliding with anything.
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout)
|
||||
{
|
||||
*dbgout << json::object
|
||||
<< "missed" << objectid(dslot(seg, slotFix));
|
||||
coll.outputJsonDbg(dbgout, seg, -1);
|
||||
*dbgout << json::close;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set the is-collision flag bit.
|
||||
if (isCol)
|
||||
{ cFix->setFlags(cFix->flags() | SlotCollision::COLL_ISCOL | SlotCollision::COLL_KNOWN); }
|
||||
else
|
||||
{ cFix->setFlags((cFix->flags() & ~SlotCollision::COLL_ISCOL) | SlotCollision::COLL_KNOWN); }
|
||||
hasCol |= isCol;
|
||||
return true;
|
||||
}
|
||||
|
||||
float Pass::resolveKern(Segment *seg, Slot *slotFix, GR_MAYBE_UNUSED Slot *start, KernCollider &coll, int dir,
|
||||
float &ymin, float &ymax, json *const dbgout) const
|
||||
{
|
||||
Slot *nbor; // neighboring slot
|
||||
float currSpace = 0.;
|
||||
bool collides = false;
|
||||
unsigned int space_count = 0;
|
||||
Slot *base = slotFix;
|
||||
while (base->attachedTo())
|
||||
base = base->attachedTo();
|
||||
SlotCollision *cFix = seg->collisionInfo(base);
|
||||
const GlyphCache &gc = seg->getFace()->glyphs();
|
||||
|
||||
if (base != slotFix)
|
||||
{
|
||||
cFix->setFlags(cFix->flags() | SlotCollision::COLL_KERN | SlotCollision::COLL_FIX);
|
||||
return 0;
|
||||
}
|
||||
bool seenEnd = (cFix->flags() & SlotCollision::COLL_END) != 0;
|
||||
bool isInit = false;
|
||||
|
||||
for (nbor = slotFix->next(); nbor; nbor = nbor->next())
|
||||
{
|
||||
if (nbor->isChildOf(base))
|
||||
continue;
|
||||
if (!gc.check(nbor->gid()))
|
||||
return 0.;
|
||||
const Rect &bb = seg->theGlyphBBoxTemporary(nbor->gid());
|
||||
SlotCollision *cNbor = seg->collisionInfo(nbor);
|
||||
if (bb.bl.y == 0.f && bb.tr.y == 0.f)
|
||||
{
|
||||
if ((m_flags & 24) == 16)
|
||||
break;
|
||||
// Add space for a space glyph.
|
||||
currSpace += nbor->advance();
|
||||
++space_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
space_count = 0;
|
||||
float y = nbor->origin().y + cNbor->shift().y;
|
||||
ymax = max(y + bb.tr.y, ymax);
|
||||
ymin = min(y + bb.bl.y, ymin);
|
||||
if (nbor != slotFix && !(cNbor->flags() & SlotCollision::COLL_IGNORE))
|
||||
{
|
||||
seenEnd = true;
|
||||
if (!isInit)
|
||||
{
|
||||
if (!coll.initSlot(seg, slotFix, cFix->limit(), cFix->margin(),
|
||||
cFix->shift(), cFix->offset(), dir, ymin, ymax, dbgout))
|
||||
return 0.;
|
||||
isInit = true;
|
||||
}
|
||||
collides |= coll.mergeSlot(seg, nbor, cNbor->shift(), currSpace, dir, dbgout);
|
||||
}
|
||||
}
|
||||
if (cNbor->flags() & SlotCollision::COLL_END)
|
||||
{
|
||||
if (seenEnd && space_count < 2)
|
||||
break;
|
||||
else
|
||||
seenEnd = true;
|
||||
}
|
||||
}
|
||||
if (collides)
|
||||
{
|
||||
Position mv = coll.resolve(seg, slotFix, dir, cFix->margin(), dbgout);
|
||||
coll.shift(mv, dir);
|
||||
Position delta = slotFix->advancePos() + mv - cFix->shift();
|
||||
slotFix->advance(delta);
|
||||
cFix->setShift(mv);
|
||||
return mv.x;
|
||||
}
|
||||
return 0.;
|
||||
}
|
||||
|
||||
|
98
gfx/graphite2/src/Position.cpp
Normal file
98
gfx/graphite2/src/Position.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
/* 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.
|
||||
*/
|
||||
#include "inc/Position.h"
|
||||
#include <cmath>
|
||||
|
||||
using namespace graphite2;
|
||||
|
||||
bool Rect::hitTest(Rect &other)
|
||||
{
|
||||
if (bl.x > other.tr.x) return false;
|
||||
if (tr.x < other.bl.x) return false;
|
||||
if (bl.y > other.tr.y) return false;
|
||||
if (tr.y < other.bl.y) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Position Rect::overlap(Position &offset, Rect &other, Position &othero)
|
||||
{
|
||||
float ax = (bl.x + offset.x) - (other.tr.x + othero.x);
|
||||
float ay = (bl.y + offset.y) - (other.tr.y + othero.y);
|
||||
float bx = (other.bl.x + othero.x) - (tr.x + offset.x);
|
||||
float by = (other.bl.y + othero.y) - (tr.y + offset.y);
|
||||
return Position((ax > bx ? ax : bx), (ay > by ? ay : by));
|
||||
}
|
||||
|
||||
float boundmin(float move, float lim1, float lim2, float &error)
|
||||
{
|
||||
// error is always positive for easy comparison
|
||||
if (move < lim1 && move < lim2)
|
||||
{ error = 0.; return move; }
|
||||
else if (lim1 < lim2)
|
||||
{ error = std::fabs(move - lim1); return lim1; }
|
||||
else
|
||||
{ error = std::fabs(move - lim2); return lim2; }
|
||||
}
|
||||
|
||||
#if 0
|
||||
Position Rect::constrainedAvoid(Position &offset, Rect &box, Rect &sdbox, Position &other, Rect &obox, Rect &osdbox)
|
||||
{
|
||||
// a = max, i = min, s = sum, d = diff
|
||||
float eax, eay, eix, eiy, eas, eis, ead, eid;
|
||||
float beste = INF;
|
||||
Position res;
|
||||
// calculate the movements in each direction and the error (amount of remaining overlap)
|
||||
// first param is movement, second and third are movement over the constraining box
|
||||
float ax = boundmin(obox.tr.x + other.x - box.bl.x - offset.x + 1, tr.x - offset.x, INF, &eax);
|
||||
float ay = boundmin(obox.tr.y + other.y - box.bl.y - offset.y + 1, tr.y - offset.y, INF, &eay);
|
||||
float ix = boundmin(obox.bl.x + other.x - box.tr.x - offset.x + 1, bl.x - offset.x, INF, &eix);
|
||||
float iy = boundmin(obox.bl.y + other.y - box.tr.y - offset.y + 1, bl.y - offset.y, INF, &eiy);
|
||||
float as = boundmin(ISQRT2 * (osdbox.tr.x + other.x + other.y - sdbox.bl.x - offset.x - offset.y) + 1, tr.x - offset.x, tr.y - offset.y, &eas);
|
||||
float is = boundmin(ISQRT2 * (osdbox.bl.x + other.x + other.y - sdbox.tr.x - offset.x - offset.y) + 1, bl.x - offset.x, bl.y - offset.y, &eis);
|
||||
float ad = boundmin(ISQRT2 * (osdbox.tr.y + other.x - other.y - sdbox.bl.y - offset.x + offset.y) + 1, tr.y - offset.y, tr.x - offset.x, &ead);
|
||||
float id = boundmin(ISQRT2 * (osdbox.bl.y + other.x - other.y - sdbox.tr.y - offset.x + offset.y) + 1, bl.y - offset.y, bl.x - offset.x, &eid);
|
||||
|
||||
if (eax < beste)
|
||||
{ res = Position(ax, 0); beste = eax; }
|
||||
if (eay < beste)
|
||||
{ res = Position(0, ay); beste = eay; }
|
||||
if (eix < beste)
|
||||
{ res = Position(ix, 0); beste = eix; }
|
||||
if (eiy < beste)
|
||||
{ res = Position(0, iy); beste = eiy; }
|
||||
if (SQRT2 * (eas) < beste)
|
||||
{ res = Position(as, ad); beste = SQRT2 * (eas); }
|
||||
if (SQRT2 * (eis) < beste)
|
||||
{ res = Position(is, is); beste = SQRT2 * (eis); }
|
||||
if (SQRT2 * (ead) < beste)
|
||||
{ res = Position(ad, ad); beste = SQRT2 * (ead); }
|
||||
if (SQRT2 * (eid) < beste)
|
||||
{ res = Position(id, id); beste = SQRT2 * (eid); }
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
@ -37,6 +37,7 @@ of the License or (at your option) any later version.
|
||||
#include "inc/Main.h"
|
||||
#include "inc/CmapCache.h"
|
||||
#include "inc/Bidi.h"
|
||||
#include "inc/Collider.h"
|
||||
#include "graphite2/Segment.h"
|
||||
|
||||
|
||||
@ -46,6 +47,7 @@ Segment::Segment(unsigned int numchars, const Face* face, uint32 script, int tex
|
||||
: m_freeSlots(NULL),
|
||||
m_freeJustifies(NULL),
|
||||
m_charinfo(new CharInfo[numchars]),
|
||||
m_collisions(NULL),
|
||||
m_face(face),
|
||||
m_silf(face->chooseSilf(script)),
|
||||
m_first(NULL),
|
||||
@ -55,7 +57,8 @@ Segment::Segment(unsigned int numchars, const Face* face, uint32 script, int tex
|
||||
m_numCharinfo(numchars),
|
||||
m_passBits(m_silf->aPassBits() ? -1 : 0),
|
||||
m_defaultOriginal(0),
|
||||
m_dir(textDir)
|
||||
m_dir(textDir),
|
||||
m_flags(0)
|
||||
{
|
||||
freeSlot(newSlot());
|
||||
m_bufSize = log_binary(numchars)+1;
|
||||
@ -335,7 +338,7 @@ void Segment::linkClusters(Slot *s, Slot * end)
|
||||
}
|
||||
}
|
||||
|
||||
Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd)
|
||||
Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isFinal)
|
||||
{
|
||||
Position currpos(0., 0.);
|
||||
float clusterMin = 0.;
|
||||
@ -349,7 +352,7 @@ Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd)
|
||||
for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev())
|
||||
{
|
||||
if (s->isBase())
|
||||
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x);
|
||||
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isFinal);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -357,7 +360,7 @@ Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd)
|
||||
for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next())
|
||||
{
|
||||
if (s->isBase())
|
||||
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x);
|
||||
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isFinal);
|
||||
}
|
||||
}
|
||||
return currpos;
|
||||
@ -434,11 +437,6 @@ bool Segment::read_text(const Face *face, const Features* pFeats/*must not be NU
|
||||
return true;
|
||||
}
|
||||
|
||||
void Segment::prepare_pos(const Font * /*font*/)
|
||||
{
|
||||
// copy key changeable metrics into slot (if any);
|
||||
}
|
||||
|
||||
Slot *process_bidi(Slot *start, int level, int prelevel, int &nextLevel, int dirover, int isol, int &cisol, int &isolerr, int &embederr, int init, Segment *seg, uint8 aMirror, BracketPairStack &stack);
|
||||
void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror);
|
||||
void resolveWhitespace(int baseLevel, Slot *s);
|
||||
@ -462,7 +460,7 @@ void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror)
|
||||
}
|
||||
bmask |= (1 << s->getBidiClass());
|
||||
s->setBidiLevel(baseLevel);
|
||||
if (glyphAttr(s->gid(), aMirror) && s->getBidiClass() == 21)
|
||||
if (s->getBidiClass() == 21)
|
||||
++ssize;
|
||||
}
|
||||
|
||||
@ -492,3 +490,16 @@ void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror)
|
||||
}
|
||||
}
|
||||
|
||||
bool Segment::initCollisions()
|
||||
{
|
||||
if (m_collisions) free(m_collisions);
|
||||
Slot *p = m_first;
|
||||
m_collisions = gralloc<SlotCollision>(slotCount());
|
||||
if (!m_collisions) return false;
|
||||
for (unsigned short i = 0; i < slotCount(); ++i)
|
||||
{
|
||||
::new (m_collisions + p->index()) SlotCollision(this, p);
|
||||
p = p->next();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -93,6 +93,10 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
|
||||
* const silf_end = p + lSilf;
|
||||
Error e;
|
||||
|
||||
if (e.test(version >= 0x00060000, E_BADSILFVERSION))
|
||||
{
|
||||
releaseBuffers(); return face.error(e);
|
||||
}
|
||||
if (version >= 0x00030000)
|
||||
{
|
||||
if (e.test(lSilf < 28, E_BADSIZE)) { releaseBuffers(); return face.error(e); }
|
||||
@ -140,7 +144,9 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
|
||||
m_aLig = be::read<uint16>(p);
|
||||
m_aUser = be::read<uint8>(p);
|
||||
m_iMaxComp = be::read<uint8>(p);
|
||||
be::skip<byte>(p,5); // direction and 4 reserved bytes
|
||||
be::skip<byte>(p); // direction
|
||||
m_aCollision = be::read<uint8>(p);
|
||||
be::skip<byte>(p,3);
|
||||
be::skip<uint16>(p, be::read<uint8>(p)); // don't need critical features yet
|
||||
be::skip<byte>(p); // reserved
|
||||
if (e.test(p >= silf_end, E_BADCRITFEATURES)) { releaseBuffers(); return face.error(e); }
|
||||
@ -155,6 +161,7 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
|
||||
|| e.test(m_aBreak >= num_attrs, E_BADABREAK)
|
||||
|| e.test(m_aBidi >= num_attrs, E_BADABIDI)
|
||||
|| e.test(m_aMirror>= num_attrs, E_BADAMIRROR)
|
||||
|| e.test(m_aCollision && m_aCollision >= num_attrs - 5, E_BADACOLLISION)
|
||||
|| e.test(m_numPasses > 128, E_BADNUMPASSES) || e.test(passes_start >= silf_end, E_BADPASSESSTART)
|
||||
|| e.test(m_pPass < m_sPass, E_BADPASSBOUND) || e.test(m_pPass > m_numPasses, E_BADPPASS) || e.test(m_sPass > m_numPasses, E_BADSPASS)
|
||||
|| e.test(m_jPass < m_pPass, E_BADJPASSBOUND) || e.test(m_jPass > m_numPasses, E_BADJPASS)
|
||||
@ -168,11 +175,12 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
|
||||
if (e.test(p + sizeof(uint16) >= passes_start, E_BADPASSESSTART)) { releaseBuffers(); return face.error(e); }
|
||||
m_numPseudo = be::read<uint16>(p);
|
||||
be::skip<uint16>(p, 3); // searchPseudo, pseudoSelector, pseudoShift
|
||||
if (e.test(p + m_numPseudo*(sizeof(uint32) + sizeof(uint16)) >= passes_start, E_BADNUMPSEUDO))
|
||||
m_pseudos = new Pseudo[m_numPseudo];
|
||||
if (e.test(p + m_numPseudo*(sizeof(uint32) + sizeof(uint16)) >= passes_start, E_BADNUMPSEUDO)
|
||||
|| e.test(!m_pseudos, E_OUTOFMEM))
|
||||
{
|
||||
releaseBuffers(); return face.error(e);
|
||||
}
|
||||
m_pseudos = new Pseudo[m_numPseudo];
|
||||
for (int i = 0; i < m_numPseudo; i++)
|
||||
{
|
||||
m_pseudos[i].uid = be::read<uint32>(p);
|
||||
@ -180,9 +188,11 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
|
||||
}
|
||||
|
||||
const size_t clen = readClassMap(p, passes_start - p, version, e);
|
||||
if (e || e.test(p + clen > passes_start, E_BADPASSESSTART)) { releaseBuffers(); return face.error(e); }
|
||||
|
||||
m_passes = new Pass[m_numPasses];
|
||||
if (e || e.test(p + clen > passes_start, E_BADPASSESSTART)
|
||||
|| e.test(!m_passes, E_OUTOFMEM))
|
||||
{ releaseBuffers(); return face.error(e); }
|
||||
|
||||
for (size_t i = 0; i < m_numPasses; ++i)
|
||||
{
|
||||
const byte * const pass_start = silf_start + be::read<uint32>(o_passes),
|
||||
@ -192,8 +202,15 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
|
||||
releaseBuffers(); return face.error(e);
|
||||
}
|
||||
|
||||
enum passtype pt = PASS_TYPE_UNKNOWN;
|
||||
if (i >= m_jPass) pt = PASS_TYPE_JUSTIFICATION;
|
||||
else if (i >= m_pPass) pt = PASS_TYPE_POSITIONING;
|
||||
else if (i >= m_sPass) pt = PASS_TYPE_SUBSTITUTE;
|
||||
else pt = PASS_TYPE_LINEBREAK;
|
||||
|
||||
m_passes[i].init(this);
|
||||
if (!m_passes[i].readPass(pass_start, pass_end - pass_start, pass_start - silf_start, face, e))
|
||||
if (!m_passes[i].readPass(pass_start, pass_end - pass_start, pass_start - silf_start, face, pt,
|
||||
version, e))
|
||||
{
|
||||
releaseBuffers();
|
||||
return false;
|
||||
@ -373,7 +390,7 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
|
||||
|
||||
if (!(seg->dir() & 2))
|
||||
seg->bidiPass(m_aBidi, seg->dir() & 1, m_aMirror);
|
||||
else if (m_aMirror)
|
||||
else if (m_aMirror && (seg->dir() & 1))
|
||||
{
|
||||
Slot * s;
|
||||
for (s = seg->first(); s; s = s->next())
|
||||
@ -403,8 +420,9 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
|
||||
#endif
|
||||
|
||||
// test whether to reorder, prepare for positioning
|
||||
if (i >= 32 || (seg->passBits() & (1 << i)) == 0)
|
||||
m_passes[i].runGraphite(m, fsm);
|
||||
if ((i >= 32 || (seg->passBits() & (1 << i)) == 0 || (m_passes[i].flags() & 7))
|
||||
&& !m_passes[i].runGraphite(m, fsm))
|
||||
return false;
|
||||
// only subsitution passes can change segment length, cached subsegments are short for their text
|
||||
if (m.status() != vm::Machine::finished
|
||||
|| (i < m_pPass && (seg->slotCount() > initSize * MAX_SEG_GROWTH_FACTOR
|
||||
|
@ -29,6 +29,7 @@ of the License or (at your option) any later version.
|
||||
#include "inc/Silf.h"
|
||||
#include "inc/CharInfo.h"
|
||||
#include "inc/Rule.h"
|
||||
#include "inc/Collider.h"
|
||||
|
||||
|
||||
using namespace graphite2;
|
||||
@ -85,19 +86,26 @@ void Slot::update(int /*numGrSlots*/, int numCharInfo, Position &relpos)
|
||||
m_position = m_position + relpos;
|
||||
}
|
||||
|
||||
Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin)
|
||||
Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool isFinal)
|
||||
{
|
||||
SlotCollision *coll = NULL;
|
||||
if (attrLevel && m_attLevel > attrLevel) return Position(0, 0);
|
||||
float scale = 1.0;
|
||||
float scale = font ? font->scale() : 1.0f;
|
||||
Position shift(m_shift.x * ((seg->dir() & 1) * -2 + 1) + m_just, m_shift.y);
|
||||
float tAdvance = m_advance.x + m_just;
|
||||
if (isFinal && (coll = seg->collisionInfo(this)))
|
||||
{
|
||||
const Position &collshift = coll->offset();
|
||||
if (!(coll->flags() & SlotCollision::COLL_KERN) || (seg->dir() & 1))
|
||||
shift = shift + collshift;
|
||||
}
|
||||
const GlyphFace * glyphFace = seg->getFace()->glyphs().glyphSafe(glyph());
|
||||
if (font)
|
||||
{
|
||||
scale = font->scale();
|
||||
shift *= scale;
|
||||
if (font->isHinted() && glyphFace)
|
||||
tAdvance = (m_advance.x - glyphFace->theAdvance().x + m_just) * scale + font->advance(m_glyphid);
|
||||
tAdvance = (m_advance.x - glyphFace->theAdvance().x + m_just) * scale + font->advance(glyph());
|
||||
else
|
||||
tAdvance *= scale;
|
||||
}
|
||||
@ -107,15 +115,15 @@ Position Slot::finalise(const Segment *seg, const Font *font, Position & base, R
|
||||
if (!m_parent)
|
||||
{
|
||||
res = base + Position(tAdvance, m_advance.y * scale);
|
||||
clusterMin = base.x;
|
||||
clusterMin = m_position.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
float tAdv;
|
||||
m_position += (m_attach - m_with) * scale;
|
||||
tAdv = m_advance.x >= 0.5 ? m_position.x + tAdvance - shift.x : 0.f;
|
||||
tAdv = m_advance.x >= 0.5f ? m_position.x + tAdvance - shift.x : 0.f;
|
||||
res = Position(tAdv, 0);
|
||||
if ((m_advance.x >= 0.5 || m_position.x < 0) && m_position.x < clusterMin) clusterMin = m_position.x;
|
||||
if ((m_advance.x >= 0.5f || m_position.x < 0) && m_position.x < clusterMin) clusterMin = m_position.x;
|
||||
}
|
||||
|
||||
if (glyphFace)
|
||||
@ -126,19 +134,19 @@ Position Slot::finalise(const Segment *seg, const Font *font, Position & base, R
|
||||
|
||||
if (m_child && m_child != this && m_child->attachedTo() == this)
|
||||
{
|
||||
Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin);
|
||||
if ((!m_parent || m_advance.x >= 0.5) && tRes.x > res.x) res = tRes;
|
||||
Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, isFinal);
|
||||
if ((!m_parent || m_advance.x >= 0.5f) && tRes.x > res.x) res = tRes;
|
||||
}
|
||||
|
||||
if (m_parent && m_sibling && m_sibling != this && m_sibling->attachedTo() == m_parent)
|
||||
{
|
||||
Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin);
|
||||
Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, isFinal);
|
||||
if (tRes.x > res.x) res = tRes;
|
||||
}
|
||||
|
||||
if (!m_parent && clusterMin < base.x)
|
||||
{
|
||||
Position adj = Position(base.x - clusterMin, 0.);
|
||||
Position adj = Position(m_position.x - clusterMin, 0.);
|
||||
res += adj;
|
||||
m_position += adj;
|
||||
if (m_child) m_child->floodShift(adj);
|
||||
@ -151,7 +159,7 @@ int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel)
|
||||
Position base;
|
||||
Rect bbox = seg->theGlyphBBoxTemporary(glyph());
|
||||
float clusterMin = 0.;
|
||||
Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin);
|
||||
Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin, false);
|
||||
|
||||
switch (metrics(metric))
|
||||
{
|
||||
@ -180,6 +188,8 @@ int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel)
|
||||
}
|
||||
}
|
||||
|
||||
#define SLOTGETCOLATTR(x) { SlotCollision *c = seg->collisionInfo(this); return c ? int(c-> x) : 0; }
|
||||
|
||||
int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
|
||||
{
|
||||
if (!this) return 0;
|
||||
@ -211,7 +221,7 @@ int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
|
||||
case gr_slatBreak : return seg->charinfo(m_original)->breakWeight();
|
||||
case gr_slatCompRef : return 0;
|
||||
case gr_slatDir : if (m_bidiCls == -1)
|
||||
const_cast<Slot *>(this)->setBidiClass(seg->glyphAttr(gid(), seg->silf()->aBidi()));
|
||||
const_cast<Slot *>(this)->setBidiClass(int8(seg->glyphAttr(gid(), seg->silf()->aBidi())));
|
||||
return m_bidiCls;
|
||||
case gr_slatInsert : return isInsertBefore();
|
||||
case gr_slatPosX : return int(m_position.x); // but need to calculate it
|
||||
@ -224,10 +234,42 @@ int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
|
||||
case gr_slatUserDefn : return m_userAttr[subindex];
|
||||
case gr_slatSegSplit : return seg->charinfo(m_original)->flags() & 3;
|
||||
case gr_slatBidiLevel: return m_bidiLevel;
|
||||
default : return 0;
|
||||
case gr_slatColFlags : { SlotCollision *c = seg->collisionInfo(this); return c ? c->flags() : 0; }
|
||||
case gr_slatColLimitblx : SLOTGETCOLATTR(limit().bl.x)
|
||||
case gr_slatColLimitbly : SLOTGETCOLATTR(limit().bl.y)
|
||||
case gr_slatColLimittrx : SLOTGETCOLATTR(limit().tr.x)
|
||||
case gr_slatColLimittry : SLOTGETCOLATTR(limit().tr.y)
|
||||
case gr_slatColShiftx : SLOTGETCOLATTR(offset().x)
|
||||
case gr_slatColShifty : SLOTGETCOLATTR(offset().y)
|
||||
case gr_slatColMargin : SLOTGETCOLATTR(margin())
|
||||
case gr_slatColMarginWt : SLOTGETCOLATTR(marginWt())
|
||||
case gr_slatColExclGlyph : SLOTGETCOLATTR(exclGlyph())
|
||||
case gr_slatColExclOffx : SLOTGETCOLATTR(exclOffset().x)
|
||||
case gr_slatColExclOffy : SLOTGETCOLATTR(exclOffset().y)
|
||||
case gr_slatSeqClass : SLOTGETCOLATTR(seqClass())
|
||||
case gr_slatSeqProxClass : SLOTGETCOLATTR(seqProxClass())
|
||||
case gr_slatSeqOrder : SLOTGETCOLATTR(seqOrder())
|
||||
case gr_slatSeqAboveXoff : SLOTGETCOLATTR(seqAboveXoff())
|
||||
case gr_slatSeqAboveWt : SLOTGETCOLATTR(seqAboveWt())
|
||||
case gr_slatSeqBelowXlim : SLOTGETCOLATTR(seqBelowXlim())
|
||||
case gr_slatSeqBelowWt : SLOTGETCOLATTR(seqBelowWt())
|
||||
case gr_slatSeqValignHt : SLOTGETCOLATTR(seqValignHt())
|
||||
case gr_slatSeqValignWt : SLOTGETCOLATTR(seqValignWt())
|
||||
default : return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define SLOTCOLSETATTR(x) { \
|
||||
SlotCollision *c = seg->collisionInfo(this); \
|
||||
if (c) { c-> x ; c->setFlags(c->flags() & ~SlotCollision::COLL_KNOWN); } \
|
||||
break; }
|
||||
#define SLOTCOLSETCOMPLEXATTR(t, y, x) { \
|
||||
SlotCollision *c = seg->collisionInfo(this); \
|
||||
if (c) { \
|
||||
const t &s = c-> y; \
|
||||
c-> x ; c->setFlags(c->flags() & ~SlotCollision::COLL_KNOWN); } \
|
||||
break; }
|
||||
|
||||
void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map)
|
||||
{
|
||||
if (!this) return;
|
||||
@ -252,9 +294,9 @@ void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, cons
|
||||
if (idx < map.size() && map[idx])
|
||||
{
|
||||
Slot *other = map[idx];
|
||||
if (other == this) break;
|
||||
if (other == this || other == m_parent) break;
|
||||
if (m_parent) m_parent->removeChild(this);
|
||||
if (other->child(this))
|
||||
if (!other->isChildOf(this) && other->child(this))
|
||||
{
|
||||
attachTo(other);
|
||||
if (((seg->dir() & 1) != 0) ^ (idx > subindex))
|
||||
@ -280,7 +322,7 @@ void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, cons
|
||||
seg->charinfo(m_original)->breakWeight(value);
|
||||
break;
|
||||
case gr_slatCompRef : break; // not sure what to do here
|
||||
case gr_slatDir : m_bidiCls = value; break;
|
||||
case gr_slatDir : m_bidiCls = int8(value); break;
|
||||
case gr_slatInsert :
|
||||
markInsertBefore(value? true : false);
|
||||
break;
|
||||
@ -293,6 +335,29 @@ void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, cons
|
||||
case gr_slatJWidth : just(value); break;
|
||||
case gr_slatSegSplit : seg->charinfo(m_original)->addflags(value & 3); break;
|
||||
case gr_slatUserDefn : m_userAttr[subindex] = value; break;
|
||||
case gr_slatColFlags : {
|
||||
SlotCollision *c = seg->collisionInfo(this);
|
||||
if (c)
|
||||
c->setFlags(value);
|
||||
break; }
|
||||
case gr_slatColLimitblx : SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(Position(value, s.bl.y), s.tr)))
|
||||
case gr_slatColLimitbly : SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(Position(s.bl.x, value), s.tr)))
|
||||
case gr_slatColLimittrx : SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(s.bl, Position(value, s.tr.y))))
|
||||
case gr_slatColLimittry : SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(s.bl, Position(s.tr.x, value))))
|
||||
case gr_slatColMargin : SLOTCOLSETATTR(setMargin(value))
|
||||
case gr_slatColMarginWt : SLOTCOLSETATTR(setMarginWt(value))
|
||||
case gr_slatColExclGlyph : SLOTCOLSETATTR(setExclGlyph(value))
|
||||
case gr_slatColExclOffx : SLOTCOLSETCOMPLEXATTR(Position, exclOffset(), setExclOffset(Position(value, s.y)))
|
||||
case gr_slatColExclOffy : SLOTCOLSETCOMPLEXATTR(Position, exclOffset(), setExclOffset(Position(s.x, value)))
|
||||
case gr_slatSeqClass : SLOTCOLSETATTR(setSeqClass(value))
|
||||
case gr_slatSeqProxClass : SLOTCOLSETATTR(setSeqProxClass(value))
|
||||
case gr_slatSeqOrder : SLOTCOLSETATTR(setSeqOrder(value))
|
||||
case gr_slatSeqAboveXoff : SLOTCOLSETATTR(setSeqAboveXoff(value))
|
||||
case gr_slatSeqAboveWt : SLOTCOLSETATTR(setSeqAboveWt(value))
|
||||
case gr_slatSeqBelowXlim : SLOTCOLSETATTR(setSeqBelowXlim(value))
|
||||
case gr_slatSeqBelowWt : SLOTCOLSETATTR(setSeqBelowWt(value))
|
||||
case gr_slatSeqValignHt : SLOTCOLSETATTR(setSeqValignHt(value))
|
||||
case gr_slatSeqValignWt : SLOTCOLSETATTR(setSeqValignWt(value))
|
||||
default :
|
||||
break;
|
||||
}
|
||||
@ -374,6 +439,7 @@ bool Slot::removeSibling(Slot *ap)
|
||||
else if (ap == m_sibling)
|
||||
{
|
||||
m_sibling = m_sibling->nextSibling();
|
||||
ap->sibling(NULL);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -425,3 +491,29 @@ void SlotJustify::LoadSlot(const Slot *s, const Segment *seg)
|
||||
v[3] = seg->glyphAttr(s->gid(), justs->attrWeight());
|
||||
}
|
||||
}
|
||||
|
||||
Slot * Slot::nextInCluster(const Slot *s) const
|
||||
{
|
||||
Slot *base;
|
||||
if (s->firstChild())
|
||||
return s->firstChild();
|
||||
else if (s->nextSibling())
|
||||
return s->nextSibling();
|
||||
while ((base = s->attachedTo()))
|
||||
{
|
||||
if (base->firstChild() == s && base->nextSibling())
|
||||
return base->nextSibling();
|
||||
s = base;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Slot::isChildOf(const Slot *base) const
|
||||
{
|
||||
if (m_parent == base)
|
||||
return true;
|
||||
else if (!m_parent)
|
||||
return false;
|
||||
else
|
||||
return m_parent->isChildOf(base);
|
||||
}
|
||||
|
@ -873,11 +873,11 @@ const void * FindCmapSubtable(const void * pCmap, int nPlatformId, /* =3 */ int
|
||||
/*----------------------------------------------------------------------------------------------
|
||||
Check the Microsoft Unicode subtable for expected values
|
||||
----------------------------------------------------------------------------------------------*/
|
||||
bool CheckCmapSubtable4(const void * pCmapSubtable4)
|
||||
bool CheckCmapSubtable4(const void * pCmapSubtable4 /*, unsigned int maxgid*/)
|
||||
{
|
||||
if (!pCmapSubtable4) return false;
|
||||
const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable4);
|
||||
// Bob H says ome freeware TT fonts have version 1 (eg, CALIGULA.TTF)
|
||||
// Bob H say some freeware TT fonts have version 1 (eg, CALIGULA.TTF)
|
||||
// so don't check subtable version. 21 Mar 2002 spec changes version to language.
|
||||
if (be::swap(pTable->format) != 4) return false;
|
||||
const Sfnt::CmapSubTableFormat4 * pTable4 = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtable4);
|
||||
@ -889,7 +889,37 @@ bool CheckCmapSubtable4(const void * pCmapSubtable4)
|
||||
return false;
|
||||
// check last range is properly terminated
|
||||
uint16 chEnd = be::peek<uint16>(pTable4->end_code + nRanges - 1);
|
||||
return (chEnd == 0xFFFF);
|
||||
if (chEnd != 0xFFFF)
|
||||
return false;
|
||||
#if 0
|
||||
int lastend = -1;
|
||||
for (int i = 0; i < nRanges; ++i)
|
||||
{
|
||||
uint16 end = be::peek<uint16>(pTable4->end_code + i);
|
||||
uint16 start = be::peek<uint16>(pTable4->end_code + nRanges + 1 + i);
|
||||
int16 delta = be::peek<int16>(pTable4->end_code + 2*nRanges + 1 + i);
|
||||
uint16 offset = be::peek<uint16>(pTable4->end_code + 3*nRanges + 1 + i);
|
||||
if (lastend >= end || lastend >= start)
|
||||
return false;
|
||||
if (offset)
|
||||
{
|
||||
const uint16 *gstart = pTable4->end_code + 3*nRanges + 1 + i + (offset >> 1);
|
||||
const uint16 *gend = gstart + end - start;
|
||||
if ((char *)gend >= (char *)pCmapSubtable4 + length)
|
||||
return false;
|
||||
while (gstart <= gend)
|
||||
{
|
||||
uint16 g = be::peek<uint16>(gstart++);
|
||||
if (g && ((g + delta) & 0xFFFF) > maxgid)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (((delta + end) & 0xFFFF) > maxgid)
|
||||
return false;
|
||||
lastend = end;
|
||||
}
|
||||
#endif
|
||||
return true;;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------------------------
|
||||
@ -1032,7 +1062,7 @@ unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnico
|
||||
/*----------------------------------------------------------------------------------------------
|
||||
Check the Microsoft UCS-4 subtable for expected values.
|
||||
----------------------------------------------------------------------------------------------*/
|
||||
bool CheckCmapSubtable12(const void *pCmapSubtable12)
|
||||
bool CheckCmapSubtable12(const void *pCmapSubtable12 /*, unsigned int maxgid*/)
|
||||
{
|
||||
if (!pCmapSubtable12) return false;
|
||||
const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable12);
|
||||
@ -1042,9 +1072,19 @@ bool CheckCmapSubtable12(const void *pCmapSubtable12)
|
||||
uint32 length = be::swap(pTable12->length);
|
||||
if (length < sizeof(Sfnt::CmapSubTableFormat12))
|
||||
return false;
|
||||
|
||||
return (length == (sizeof(Sfnt::CmapSubTableFormat12) + (be::swap(pTable12->num_groups) - 1)
|
||||
* sizeof(uint32) * 3));
|
||||
uint32 num_groups = be::swap(pTable12->num_groups);
|
||||
if (length != (sizeof(Sfnt::CmapSubTableFormat12) + (num_groups - 1) * sizeof(uint32) * 3))
|
||||
return false;
|
||||
#if 0
|
||||
for (unsigned int i = 0; i < num_groups; ++i)
|
||||
{
|
||||
if (be::swap(pTable12->group[i].end_char_code) - be::swap(pTable12->group[i].start_char_code) + be::swap(pTable12->group[i].start_glyph_id) > maxgid)
|
||||
return false;
|
||||
if (i > 0 && be::swap(pTable12->group[i].start_char_code) <= be::swap(pTable12->group[i-1].end_char_code))
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------------------------
|
||||
@ -1145,6 +1185,7 @@ size_t LocaLookup(gid16 nGlyphId,
|
||||
const void * pHead) // throw (std::out_of_range)
|
||||
{
|
||||
const Sfnt::FontHeader * pTable = reinterpret_cast<const Sfnt::FontHeader *>(pHead);
|
||||
size_t res = -2;
|
||||
|
||||
// CheckTable verifies the index_to_loc_format is valid
|
||||
if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::ShortIndexLocFormat)
|
||||
@ -1152,21 +1193,24 @@ size_t LocaLookup(gid16 nGlyphId,
|
||||
if (nGlyphId < (lLocaSize >> 1) - 1) // allow sentinel value to be accessed
|
||||
{
|
||||
const uint16 * pShortTable = reinterpret_cast<const uint16 *>(pLoca);
|
||||
return (be::peek<uint16>(pShortTable + nGlyphId) << 1);
|
||||
res = be::peek<uint16>(pShortTable + nGlyphId) << 1;
|
||||
if (res == static_cast<size_t>(be::peek<uint16>(pShortTable + nGlyphId + 1) << 1))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat)
|
||||
else if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat)
|
||||
{ // loca entries are four bytes
|
||||
if (nGlyphId < (lLocaSize >> 2) - 1)
|
||||
{
|
||||
const uint32 * pLongTable = reinterpret_cast<const uint32 *>(pLoca);
|
||||
return be::peek<uint32>(pLongTable + nGlyphId);
|
||||
res = be::peek<uint32>(pLongTable + nGlyphId);
|
||||
if (res == static_cast<size_t>(be::peek<uint32>(pLongTable + nGlyphId + 1)))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// only get here if glyph id was bad
|
||||
return -1;
|
||||
return res;
|
||||
//throw std::out_of_range("glyph id out of range for font");
|
||||
}
|
||||
|
||||
@ -1177,7 +1221,7 @@ size_t LocaLookup(gid16 nGlyphId,
|
||||
void * GlyfLookup(const void * pGlyf, size_t nGlyfOffset, size_t nTableLen)
|
||||
{
|
||||
const uint8 * pByte = reinterpret_cast<const uint8 *>(pGlyf);
|
||||
if (nGlyfOffset == size_t(-1) || nGlyfOffset >= nTableLen)
|
||||
if (nGlyfOffset == size_t(-1) || nGlyfOffset == size_t(-2) || nGlyfOffset >= nTableLen)
|
||||
return NULL;
|
||||
return const_cast<uint8 *>(pByte + nGlyfOffset);
|
||||
}
|
||||
|
@ -51,15 +51,19 @@ $(_NS)_SOURCES = \
|
||||
$($(_NS)_BASE)/src/CachedFace.cpp \
|
||||
$($(_NS)_BASE)/src/CmapCache.cpp \
|
||||
$($(_NS)_BASE)/src/Code.cpp \
|
||||
$($(_NS)_BASE)/src/Collider.cpp \
|
||||
$($(_NS)_BASE)/src/Decompressor.cpp \
|
||||
$($(_NS)_BASE)/src/Face.cpp \
|
||||
$($(_NS)_BASE)/src/FeatureMap.cpp \
|
||||
$($(_NS)_BASE)/src/FileFace.cpp \
|
||||
$($(_NS)_BASE)/src/Font.cpp \
|
||||
$($(_NS)_BASE)/src/GlyphCache.cpp \
|
||||
$($(_NS)_BASE)/src/GlyphFace.cpp \
|
||||
$($(_NS)_BASE)/src/Intervals.cpp \
|
||||
$($(_NS)_BASE)/src/Justifier.cpp \
|
||||
$($(_NS)_BASE)/src/NameTable.cpp \
|
||||
$($(_NS)_BASE)/src/Pass.cpp \
|
||||
$($(_NS)_BASE)/src/Position.cpp \
|
||||
$($(_NS)_BASE)/src/SegCache.cpp \
|
||||
$($(_NS)_BASE)/src/SegCacheEntry.cpp \
|
||||
$($(_NS)_BASE)/src/SegCacheStore.cpp \
|
||||
@ -74,10 +78,14 @@ $(_NS)_PRIVATE_HEADERS = \
|
||||
$($(_NS)_BASE)/src/inc/bits.h \
|
||||
$($(_NS)_BASE)/src/inc/debug.h \
|
||||
$($(_NS)_BASE)/src/inc/json.h \
|
||||
$($(_NS)_BASE)/src/inc/locale2lcid.h \
|
||||
$($(_NS)_BASE)/src/inc/Bidi.h \
|
||||
$($(_NS)_BASE)/src/inc/CachedFace.h \
|
||||
$($(_NS)_BASE)/src/inc/CharInfo.h \
|
||||
$($(_NS)_BASE)/src/inc/CmapCache.h \
|
||||
$($(_NS)_BASE)/src/inc/Code.h \
|
||||
$($(_NS)_BASE)/src/inc/Collider.h \
|
||||
$($(_NS)_BASE)/src/inc/Decompressor.h \
|
||||
$($(_NS)_BASE)/src/inc/Endian.h \
|
||||
$($(_NS)_BASE)/src/inc/Error.h \
|
||||
$($(_NS)_BASE)/src/inc/Face.h \
|
||||
@ -87,6 +95,7 @@ $(_NS)_PRIVATE_HEADERS = \
|
||||
$($(_NS)_BASE)/src/inc/Font.h \
|
||||
$($(_NS)_BASE)/src/inc/GlyphCache.h \
|
||||
$($(_NS)_BASE)/src/inc/GlyphFace.h \
|
||||
$($(_NS)_BASE)/src/inc/Intervals.h \
|
||||
$($(_NS)_BASE)/src/inc/List.h \
|
||||
$($(_NS)_BASE)/src/inc/locale2lcid.h \
|
||||
$($(_NS)_BASE)/src/inc/Machine.h \
|
||||
@ -101,6 +110,7 @@ $(_NS)_PRIVATE_HEADERS = \
|
||||
$($(_NS)_BASE)/src/inc/SegCacheEntry.h \
|
||||
$($(_NS)_BASE)/src/inc/SegCacheStore.h \
|
||||
$($(_NS)_BASE)/src/inc/Segment.h \
|
||||
$($(_NS)_BASE)/src/inc/Shrinker.h \
|
||||
$($(_NS)_BASE)/src/inc/Silf.h \
|
||||
$($(_NS)_BASE)/src/inc/Slot.h \
|
||||
$($(_NS)_BASE)/src/inc/Sparse.h \
|
||||
|
@ -46,7 +46,7 @@ namespace
|
||||
#ifdef GRAPHITE2_TELEMETRY
|
||||
telemetry::category _misc_cat(face.tele.misc);
|
||||
#endif
|
||||
Face::Table silf(face, Tag::Silf);
|
||||
Face::Table silf(face, Tag::Silf, 0x00050000);
|
||||
if (silf) options &= ~gr_face_dumbRendering;
|
||||
else if (!(options & gr_face_dumbRendering))
|
||||
return false;
|
||||
|
@ -32,6 +32,7 @@ of the License or (at your option) any later version.
|
||||
#include "inc/Slot.h"
|
||||
#include "inc/Segment.h"
|
||||
#include "inc/json.h"
|
||||
#include "inc/Collider.h"
|
||||
|
||||
#if defined _WIN32
|
||||
#include "windows.h"
|
||||
@ -184,6 +185,7 @@ json & graphite2::operator << (json & j, const dslot & ds) throw()
|
||||
assert(ds.second);
|
||||
const Segment & seg = *ds.first;
|
||||
const Slot & s = *ds.second;
|
||||
const SlotCollision *cslot = seg.collisionInfo(ds.second);
|
||||
|
||||
j << json::object
|
||||
<< "id" << objectid(ds)
|
||||
@ -220,6 +222,28 @@ json & graphite2::operator << (json & j, const dslot & ds) throw()
|
||||
j << objectid(dslot(&seg, c));
|
||||
j << json::close;
|
||||
}
|
||||
if (cslot)
|
||||
{
|
||||
// Note: the reason for using Positions to lump together related attributes is to make the
|
||||
// JSON output slightly more compact.
|
||||
j << "collision" << json::flat << json::object
|
||||
// << "shift" << cslot->shift() -- not used pass level, only within the collision routine itself
|
||||
<< "offset" << cslot->offset()
|
||||
<< "limit" << cslot->limit()
|
||||
<< "flags" << cslot->flags()
|
||||
<< "margin" << Position(cslot->margin(), cslot->marginWt())
|
||||
<< "exclude" << cslot->exclGlyph()
|
||||
<< "excludeoffset" << cslot->exclOffset();
|
||||
if (cslot->seqOrder() != 0)
|
||||
{
|
||||
j << "seqclass" << Position(cslot->seqClass(), cslot->seqProxClass())
|
||||
<< "seqorder" << cslot->seqOrder()
|
||||
<< "seqabove" << Position(cslot->seqAboveXoff(), cslot->seqAboveWt())
|
||||
<< "seqbelow" << Position(cslot->seqBelowXlim(), cslot->seqBelowWt())
|
||||
<< "seqvalign" << Position(cslot->seqValignHt(), cslot->seqValignWt());
|
||||
}
|
||||
j << json::close;
|
||||
}
|
||||
return j << json::close;
|
||||
}
|
||||
|
||||
|
@ -48,10 +48,6 @@ namespace
|
||||
delete pRes;
|
||||
return NULL;
|
||||
}
|
||||
// run the line break passes
|
||||
// run the substitution passes
|
||||
pRes->prepare_pos(font);
|
||||
// run the positioning passes
|
||||
pRes->finalise(font);
|
||||
|
||||
return static_cast<gr_segment*>(pRes);
|
||||
|
@ -103,11 +103,11 @@ float gr_slot_advance_X(const gr_slot* p/*not NULL*/, const gr_face *face, const
|
||||
return res;
|
||||
}
|
||||
|
||||
float gr_slot_advance_Y(const gr_slot *p/*not NULL*/, const gr_face *face, const gr_font *font)
|
||||
float gr_slot_advance_Y(const gr_slot *p/*not NULL*/, GR_MAYBE_UNUSED const gr_face *face, const gr_font *font)
|
||||
{
|
||||
assert(p);
|
||||
float res = p->advancePos().y;
|
||||
if (font && (face || !face))
|
||||
if (font)
|
||||
return res * font->scale();
|
||||
else
|
||||
return res;
|
||||
|
@ -41,6 +41,14 @@ 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
|
||||
@ -56,10 +64,12 @@ public:
|
||||
jump_past_end,
|
||||
arguments_exhausted,
|
||||
missing_return,
|
||||
nested_context_item
|
||||
nested_context_item,
|
||||
underfull_stack
|
||||
};
|
||||
|
||||
private:
|
||||
static byte * local_memory;
|
||||
class decoder;
|
||||
|
||||
instr * _code;
|
||||
@ -79,7 +89,8 @@ private:
|
||||
public:
|
||||
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 &);
|
||||
uint8 pre_context, uint16 rule_length, const Silf &, const Face &,
|
||||
enum passtype pt, byte * & _out = local_memory);
|
||||
Code(const Machine::Code &) throw();
|
||||
~Code() throw();
|
||||
|
||||
@ -92,12 +103,14 @@ public:
|
||||
bool immutable() const throw();
|
||||
bool deletes() const throw();
|
||||
size_t maxRef() const throw();
|
||||
void externalProgramMoved(ptrdiff_t) throw();
|
||||
|
||||
int32 run(Machine &m, slotref * & map) const;
|
||||
|
||||
CLASS_NEW_DELETE;
|
||||
};
|
||||
|
||||
|
||||
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),
|
||||
@ -171,5 +184,14 @@ inline size_t Machine::Code::maxRef() const throw()
|
||||
return _max_ref;
|
||||
}
|
||||
|
||||
inline void Machine::Code::externalProgramMoved(ptrdiff_t dist) throw()
|
||||
{
|
||||
if (_code && !_own)
|
||||
{
|
||||
_code += dist / sizeof(instr);
|
||||
_data += dist;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace vm
|
||||
} // namespace graphite2
|
||||
|
220
gfx/graphite2/src/inc/Collider.h
Normal file
220
gfx/graphite2/src/inc/Collider.h
Normal file
@ -0,0 +1,220 @@
|
||||
/* 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/List.h"
|
||||
#include "inc/Slot.h"
|
||||
#include "inc/Position.h"
|
||||
#include "inc/Intervals.h"
|
||||
#include "inc/debug.h"
|
||||
//#include "inc/Segment.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_TEMPLOCK = 128, // 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;
|
||||
|
||||
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
|
||||
|
||||
class BBox;
|
||||
class SlantBox;
|
||||
|
||||
class ShiftCollider
|
||||
{
|
||||
public:
|
||||
typedef std::pair<float, float> fpair;
|
||||
typedef Vector<fpair> vfpairs;
|
||||
typedef vfpairs::iterator ivfpairs;
|
||||
|
||||
ShiftCollider(GR_MAYBE_UNUSED json *dbgout)
|
||||
{
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
for (int i = 0; i < 4; ++i)
|
||||
_ranges[i].setdebug(dbgout);
|
||||
#endif
|
||||
}
|
||||
~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 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
|
||||
|
||||
class KernCollider
|
||||
{
|
||||
public:
|
||||
KernCollider(GR_MAYBE_UNUSED json *dbg) : _miny(-1e38f), _maxy(1e38f) { };
|
||||
~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, float margin, 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
|
||||
|
||||
#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; }
|
||||
|
||||
|
||||
}; // end of namespace graphite2
|
||||
|
52
gfx/graphite2/src/inc/Decompressor.h
Normal file
52
gfx/graphite2/src/inc/Decompressor.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* Copyright (c) 2012, Siyuan Fu <fusiyuan2010@gmail.com>
|
||||
Copyright (c) 2015, SIL International
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace shrinker
|
||||
{
|
||||
|
||||
int decompress(void const *in, size_t in_size, void *out, size_t out_size);
|
||||
/*
|
||||
in: inbuf --- compressed data
|
||||
out: outbuf --- decompressed data to place in
|
||||
size: decompressed(original) data size should be
|
||||
|
||||
return value:
|
||||
positive integer means decompress success and it's the sizeof decompressed data,
|
||||
which should be equal to size.
|
||||
or -1 means decompress failed
|
||||
*/
|
||||
|
||||
} // end of namespace shrinker
|
||||
|
||||
|
@ -111,16 +111,23 @@ enum errors {
|
||||
E_BADRULEMAPPING = 50, // The structure of the rule mapping is bad
|
||||
E_BADRANGE = 51, // Bad column range structure including a glyph in more than one column
|
||||
E_BADRULENUM = 52, // A reference to a rule is out of range (too high)
|
||||
E_BADACOLLISION = 53, // Bad Silf table collision attribute number (too high)
|
||||
E_BADEMPTYPASS = 54, // Can't have empty passes (no rules) except for collision passes
|
||||
E_BADSILFVERSION = 55, // The Silf table has a bad version (probably too high)
|
||||
E_BADCOLLISIONPASS = 56, // Collision flags set on a non positioning pass
|
||||
// Code errors
|
||||
E_CODEFAILURE = 60, // Base code error. The following subcodes must align with Machine::Code::status_t in Code.h
|
||||
E_CODEALLOC = 61, // Out of memory
|
||||
E_INVALIDOPCODE = 62, // Invalid op code
|
||||
E_UNIMPOPCODE = 63, // Unimplemented op code encountered
|
||||
E_OUTOFRANGECODE = 64, // Code argument out of range
|
||||
E_BADJUMPCODE = 65, // Code jumps past end of op codes
|
||||
E_CODEBADARGS = 66, // Code arguments exhausted
|
||||
E_CODENORETURN = 67, // Missing return type op code at end of code
|
||||
E_CODENESTEDCTXT = 68 // Nested context encountered in code
|
||||
E_CODEALLOC = 61, // Out of memory
|
||||
E_INVALIDOPCODE = 62, // Invalid op code
|
||||
E_UNIMPOPCODE = 63, // Unimplemented op code encountered
|
||||
E_OUTOFRANGECODE = 64, // Code argument out of range
|
||||
E_BADJUMPCODE = 65, // Code jumps past end of op codes
|
||||
E_CODEBADARGS = 66, // Code arguments exhausted
|
||||
E_CODENORETURN = 67, // Missing return type op code at end of code
|
||||
E_CODENESTEDCTXT = 68, // Nested context encountered in code
|
||||
// Compression errors
|
||||
E_BADSCHEME = 69,
|
||||
E_SHRINKERFAILED = 70,
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -170,10 +170,13 @@ class Face::Table
|
||||
const Face * _f;
|
||||
mutable const byte * _p;
|
||||
uint32 _sz;
|
||||
bool _compressed;
|
||||
|
||||
Error decompress();
|
||||
|
||||
public:
|
||||
Table() throw();
|
||||
Table(const Face & face, const Tag n) throw();
|
||||
Table(const Face & face, const Tag n, uint32 version=0xffffffff) throw();
|
||||
Table(const Table & rhs) throw();
|
||||
~Table() throw();
|
||||
|
||||
@ -185,13 +188,13 @@ public:
|
||||
|
||||
inline
|
||||
Face::Table::Table() throw()
|
||||
: _f(0), _p(0), _sz(0)
|
||||
: _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)
|
||||
: _f(rhs._f), _p(rhs._p), _sz(rhs._sz), _compressed(rhs._compressed)
|
||||
{
|
||||
rhs._p = 0;
|
||||
}
|
||||
@ -199,7 +202,9 @@ Face::Table::Table(const Table & rhs) throw()
|
||||
inline
|
||||
Face::Table::~Table() throw()
|
||||
{
|
||||
if (_p && _f->m_ops.release_table)
|
||||
if (_compressed)
|
||||
free(const_cast<byte *>(_p));
|
||||
else if (_p && _f->m_ops.release_table)
|
||||
(*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
|
||||
}
|
||||
|
||||
|
@ -117,9 +117,8 @@ class NameAndFeatureRef
|
||||
class FeatureMap
|
||||
{
|
||||
public:
|
||||
FeatureMap() : m_numFeats(0), m_feats(NULL), m_pNamedFeats(NULL),
|
||||
m_defaultFeatures(NULL) {}
|
||||
~FeatureMap() { delete [] m_feats; delete[] m_pNamedFeats; delete m_defaultFeatures; }
|
||||
FeatureMap() : m_numFeats(0), m_feats(NULL), m_pNamedFeats(NULL) {}
|
||||
~FeatureMap() { delete [] m_feats; delete[] m_pNamedFeats; }
|
||||
|
||||
bool readFeats(const Face & face);
|
||||
const FeatureRef *findFeatureRef(uint32 name) const;
|
||||
@ -135,7 +134,7 @@ friend class SillMap;
|
||||
|
||||
FeatureRef *m_feats;
|
||||
NameAndFeatureRef* m_pNamedFeats; //owned
|
||||
FeatureVal* m_defaultFeatures; //owned
|
||||
FeatureVal m_defaultFeatures; //owned
|
||||
|
||||
private: //defensive on m_feats, m_pNamedFeats, and m_defaultFeatures
|
||||
FeatureMap(const FeatureMap&);
|
||||
|
@ -29,14 +29,65 @@ of the License or (at your option) any later version.
|
||||
|
||||
#include "graphite2/Font.h"
|
||||
#include "inc/Main.h"
|
||||
#include "inc/Position.h"
|
||||
#include "inc/GlyphFace.h"
|
||||
|
||||
namespace graphite2 {
|
||||
|
||||
class Face;
|
||||
class FeatureVal;
|
||||
class GlyphFace;
|
||||
class Segment;
|
||||
|
||||
|
||||
class SlantBox
|
||||
{
|
||||
public:
|
||||
SlantBox(float psi = 0., float pdi = 0., float psa = 0., float pda = 0.) : si(psi), di(pdi), sa(psa), da(pda) {};
|
||||
float width() const { return sa - si; }
|
||||
float height() const { return da - di; }
|
||||
float si; // min
|
||||
float di; // min
|
||||
float sa; // max
|
||||
float da; // max
|
||||
};
|
||||
|
||||
static SlantBox nullSlant(0, 0, 0, 0);
|
||||
|
||||
class BBox
|
||||
{
|
||||
public:
|
||||
BBox(float pxi = 0, float pyi = 0., float pxa = 0., float pya = 0.) : xi(pxi), yi(pyi), xa(pxa), ya(pya) {};
|
||||
float width() const { return xa - xi; }
|
||||
float height() const { return ya - yi; }
|
||||
float xi; // min
|
||||
float yi; // min
|
||||
float xa; // max
|
||||
float ya; // max
|
||||
};
|
||||
|
||||
static BBox nullBBox(0, 0, 0, 0);
|
||||
|
||||
class GlyphBox
|
||||
{
|
||||
GlyphBox(const GlyphBox &);
|
||||
GlyphBox & operator = (const GlyphBox &);
|
||||
|
||||
public:
|
||||
GlyphBox(uint8 numsubs, unsigned short bitmap, Rect *slanted) : _num(numsubs), _bitmap(bitmap), _slant(*slanted) {};
|
||||
|
||||
void addSubBox(int subindex, int boundary, Rect *val) { _subs[subindex * 2 + boundary] = *val; }
|
||||
Rect &subVal(int subindex, int boundary) { return _subs[subindex * 2 + boundary]; }
|
||||
const Rect &slant() const { return _slant; }
|
||||
uint8 num() const { return _num; }
|
||||
const Rect *subs() const { return _subs; }
|
||||
|
||||
private:
|
||||
uint8 _num;
|
||||
unsigned short _bitmap;
|
||||
Rect _slant;
|
||||
Rect _subs[1];
|
||||
};
|
||||
|
||||
class GlyphCache
|
||||
{
|
||||
class Loader;
|
||||
@ -44,6 +95,8 @@ class GlyphCache
|
||||
GlyphCache(const GlyphCache&);
|
||||
GlyphCache& operator=(const GlyphCache&);
|
||||
|
||||
static const Rect nullRect;
|
||||
|
||||
public:
|
||||
GlyphCache(const Face & face, const uint32 face_options);
|
||||
~GlyphCache();
|
||||
@ -54,12 +107,22 @@ public:
|
||||
|
||||
const GlyphFace *glyph(unsigned short glyphid) const; //result may be changed by subsequent call with a different glyphid
|
||||
const GlyphFace *glyphSafe(unsigned short glyphid) const;
|
||||
float getBoundingMetric(unsigned short glyphid, uint8 metric) const;
|
||||
uint8 numSubBounds(unsigned short glyphid) const;
|
||||
float getSubBoundingMetric(unsigned short glyphid, uint8 subindex, uint8 metric) const;
|
||||
const Rect & slant(unsigned short glyphid) const { return _boxes[glyphid] ? _boxes[glyphid]->slant() : nullRect; }
|
||||
const SlantBox & getBoundingSlantBox(unsigned short glyphid) const;
|
||||
const BBox & getBoundingBBox(unsigned short glyphid) const;
|
||||
const SlantBox & getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const;
|
||||
const BBox & getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const;
|
||||
bool check(unsigned short glyphid) const;
|
||||
|
||||
CLASS_NEW_DELETE;
|
||||
|
||||
private:
|
||||
const Loader * _glyph_loader;
|
||||
const GlyphFace * * _glyphs;
|
||||
GlyphBox * * _boxes;
|
||||
unsigned short _num_glyphs,
|
||||
_num_attrs,
|
||||
_upem;
|
||||
@ -83,10 +146,82 @@ unsigned short GlyphCache::unitsPerEm() const throw()
|
||||
return _upem;
|
||||
}
|
||||
|
||||
inline
|
||||
bool GlyphCache::check(unsigned short glyphid) const
|
||||
{
|
||||
return glyphid < _num_glyphs;
|
||||
}
|
||||
|
||||
inline
|
||||
const GlyphFace *GlyphCache::glyphSafe(unsigned short glyphid) const
|
||||
{
|
||||
return glyphid < _num_glyphs ? glyph(glyphid) : NULL;
|
||||
}
|
||||
|
||||
inline
|
||||
float GlyphCache::getBoundingMetric(unsigned short glyphid, uint8 metric) const
|
||||
{
|
||||
if (glyphid >= _num_glyphs) return 0.;
|
||||
switch (metric) {
|
||||
case 0: return (float)(glyph(glyphid)->theBBox().bl.x); // x_min
|
||||
case 1: return (float)(glyph(glyphid)->theBBox().bl.y); // y_min
|
||||
case 2: return (float)(glyph(glyphid)->theBBox().tr.x); // x_max
|
||||
case 3: return (float)(glyph(glyphid)->theBBox().tr.y); // y_max
|
||||
case 4: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().bl.x : 0.f); // sum_min
|
||||
case 5: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().bl.y : 0.f); // diff_min
|
||||
case 6: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().tr.x : 0.f); // sum_max
|
||||
case 7: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().tr.y : 0.f); // diff_max
|
||||
default: return 0.;
|
||||
}
|
||||
}
|
||||
|
||||
inline const SlantBox &GlyphCache::getBoundingSlantBox(unsigned short glyphid) const
|
||||
{
|
||||
return _boxes[glyphid] ? *(SlantBox *)(&(_boxes[glyphid]->slant())) : nullSlant;
|
||||
}
|
||||
|
||||
inline const BBox &GlyphCache::getBoundingBBox(unsigned short glyphid) const
|
||||
{
|
||||
return *(BBox *)(&(glyph(glyphid)->theBBox()));
|
||||
}
|
||||
|
||||
inline
|
||||
float GlyphCache::getSubBoundingMetric(unsigned short glyphid, uint8 subindex, uint8 metric) const
|
||||
{
|
||||
GlyphBox *b = _boxes[glyphid];
|
||||
if (b == NULL || subindex >= b->num()) return 0;
|
||||
|
||||
switch (metric) {
|
||||
case 0: return b->subVal(subindex, 0).bl.x;
|
||||
case 1: return b->subVal(subindex, 0).bl.y;
|
||||
case 2: return b->subVal(subindex, 0).tr.x;
|
||||
case 3: return b->subVal(subindex, 0).tr.y;
|
||||
case 4: return b->subVal(subindex, 1).bl.x;
|
||||
case 5: return b->subVal(subindex, 1).bl.y;
|
||||
case 6: return b->subVal(subindex, 1).tr.x;
|
||||
case 7: return b->subVal(subindex, 1).tr.y;
|
||||
default: return 0.;
|
||||
}
|
||||
}
|
||||
|
||||
inline const SlantBox &GlyphCache::getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const
|
||||
{
|
||||
GlyphBox *b = _boxes[glyphid];
|
||||
// if (b == NULL || subindex >= b->num()) return nullSlant;
|
||||
return *(SlantBox *)(b->subs() + 2 * subindex + 1);
|
||||
}
|
||||
|
||||
inline const BBox &GlyphCache::getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const
|
||||
{
|
||||
GlyphBox *b = _boxes[glyphid];
|
||||
// if (b == NULL || subindex >= b->num()) return nullBBox;
|
||||
return *(BBox *)(b->subs() + 2 * subindex);
|
||||
}
|
||||
|
||||
inline
|
||||
uint8 GlyphCache::numSubBounds(unsigned short glyphid) const
|
||||
{
|
||||
return _boxes[glyphid] ? _boxes[glyphid]->num() : 0;
|
||||
}
|
||||
|
||||
} // namespace graphite2
|
||||
|
231
gfx/graphite2/src/inc/Intervals.h
Normal file
231
gfx/graphite2/src/inc/Intervals.h
Normal file
@ -0,0 +1,231 @@
|
||||
/* 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)
|
||||
{
|
||||
_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
|
@ -70,6 +70,7 @@ public:
|
||||
size_t capacity() const{ return m_end - m_first; }
|
||||
|
||||
void reserve(size_t n);
|
||||
void resize(size_t n, const T & v = T());
|
||||
|
||||
reference front() { assert(size() > 0); return *begin(); }
|
||||
const_reference front() const { assert(size() > 0); return *begin(); }
|
||||
@ -82,7 +83,7 @@ public:
|
||||
|
||||
void assign(size_t n, const T& u) { clear(); insert(begin(), n, u); }
|
||||
void assign(const_iterator first, const_iterator last) { clear(); insert(begin(), first, last); }
|
||||
iterator insert(iterator p, const T & x) { p = _insert_default(p, 1); *p = x; return p; }
|
||||
iterator insert(iterator p, const T & x) { p = _insert_default(p, 1); new (p) T(x); return p; }
|
||||
void insert(iterator p, size_t n, const T & x);
|
||||
void insert(iterator p, const_iterator first, const_iterator last);
|
||||
void pop_back() { assert(size() > 0); --m_last; }
|
||||
@ -109,13 +110,21 @@ void Vector<T>::reserve(size_t n)
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline
|
||||
void Vector<T>::resize(size_t n, const T & v) {
|
||||
const ptrdiff_t d = n-size();
|
||||
if (d < 0) erase(end()+d, end());
|
||||
else if (d > 0) insert(end(), d, v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
typename Vector<T>::iterator Vector<T>::_insert_default(iterator p, size_t n)
|
||||
{
|
||||
assert(begin() <= p && p <= end());
|
||||
const ptrdiff_t i = p - begin();
|
||||
reserve((size() + n + 7) >> 3 << 3);
|
||||
reserve(((size() + n + 7) >> 3) << 3);
|
||||
p = begin() + i;
|
||||
// Move tail if there is one
|
||||
if (p != end()) memmove(p + n, p, distance(p,end())*sizeof(T));
|
||||
|
@ -110,6 +110,8 @@ enum opcode {
|
||||
PUSH_PROC_STATE, PUSH_VERSION,
|
||||
PUT_SUBS, PUT_SUBS2, PUT_SUBS3,
|
||||
PUT_GLYPH, PUSH_GLYPH_ATTR, PUSH_ATT_TO_GLYPH_ATTR,
|
||||
BITOR, BITAND, BITNOT,
|
||||
BITSET, SET_FEAT,
|
||||
MAX_OPCODE,
|
||||
// private opcodes for internal use only, comes after all other on disk opcodes
|
||||
TEMP_COPY = MAX_OPCODE
|
||||
@ -148,7 +150,7 @@ public:
|
||||
|
||||
SlotMap & slotMap() const throw();
|
||||
status_t status() const throw();
|
||||
operator bool () const throw();
|
||||
// operator bool () const throw();
|
||||
|
||||
private:
|
||||
void check_final_stack(const stack_t * const sp);
|
||||
|
@ -125,3 +125,8 @@ inline T max(const T a, const T b)
|
||||
#else
|
||||
#define GR_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4800)
|
||||
#pragma warning(once: 4355)
|
||||
#endif
|
||||
|
@ -39,6 +39,11 @@ struct RuleEntry;
|
||||
struct State;
|
||||
class FiniteStateMachine;
|
||||
class Error;
|
||||
class ShiftCollider;
|
||||
class KernCollider;
|
||||
class json;
|
||||
|
||||
enum passtype;
|
||||
|
||||
class Pass
|
||||
{
|
||||
@ -46,10 +51,11 @@ public:
|
||||
Pass();
|
||||
~Pass();
|
||||
|
||||
bool readPass(const byte * pPass, size_t pass_length, size_t subtable_base, Face & face, Error &e);
|
||||
void runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const;
|
||||
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) const;
|
||||
void init(Silf *silf) { m_silf = silf; }
|
||||
byte spaceContextuals() const { return (m_flags & 0x0E) >> 1; }
|
||||
byte flags() const { return m_flags; }
|
||||
|
||||
CLASS_NEW_DELETE
|
||||
private:
|
||||
@ -61,7 +67,7 @@ private:
|
||||
const byte *precontext, const uint16 * sort_key,
|
||||
const uint16 * o_constraint, const byte *constraint_data,
|
||||
const uint16 * o_action, const byte * action_data,
|
||||
Face &, Error &e);
|
||||
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;
|
||||
@ -69,13 +75,23 @@ private:
|
||||
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;
|
||||
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;
|
||||
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, KernCollider &coll, 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_flags;
|
||||
byte m_iMaxLoop;
|
||||
@ -88,6 +104,7 @@ private:
|
||||
uint16 m_numColumns;
|
||||
byte m_minPreCtxt;
|
||||
byte m_maxPreCtxt;
|
||||
byte m_colThreshold;
|
||||
vm::Machine::Code m_cPConstraint;
|
||||
|
||||
private: //defensive
|
||||
|
@ -50,7 +50,16 @@ public :
|
||||
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;
|
||||
|
@ -53,8 +53,6 @@ private:
|
||||
|
||||
inline Rule::~Rule()
|
||||
{
|
||||
delete constraint;
|
||||
delete action;
|
||||
}
|
||||
|
||||
|
||||
|
@ -40,6 +40,7 @@ of the License or (at your option) any later version.
|
||||
#include "inc/Position.h"
|
||||
#include "inc/List.h"
|
||||
#include "inc/Bidi.h"
|
||||
#include "inc/Collider.h"
|
||||
|
||||
#define MAX_SEG_GROWTH_FACTOR 256
|
||||
|
||||
@ -86,6 +87,11 @@ class Segment
|
||||
Segment& operator=(const Segment&);
|
||||
|
||||
public:
|
||||
|
||||
enum {
|
||||
SEG_INITCOLLISIONS = 1
|
||||
};
|
||||
|
||||
unsigned int slotCount() const { return m_numGlyphs; } //one slot per glyph
|
||||
void extendLength(int num) { m_numGlyphs += num; }
|
||||
Position advance() const { return m_advance; }
|
||||
@ -107,6 +113,8 @@ public:
|
||||
Slot * endSlot, const Slot * srcSlot,
|
||||
const size_t numGlyphs);
|
||||
#endif
|
||||
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; }
|
||||
@ -116,13 +124,20 @@ public:
|
||||
void freeSlot(Slot *);
|
||||
SlotJustify *newJustify();
|
||||
void freeJustify(SlotJustify *aJustify);
|
||||
Position positionSlots(const Font *font, Slot *first=0, Slot *last=0);
|
||||
Position positionSlots(const Font *font=0, Slot *first=0, Slot *last=0, bool isFinal = true);
|
||||
void associateChars(int offset, int 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 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]);
|
||||
} }
|
||||
void dir(int8 val) { m_dir = val; }
|
||||
unsigned int passBits() const { return m_passBits; }
|
||||
void mergePassBits(const unsigned int val) { m_passBits &= val; }
|
||||
@ -141,14 +156,16 @@ public:
|
||||
bool hasJustification() const { return m_justifies.size() != 0; }
|
||||
|
||||
bool isWhitespace(const int cid) const;
|
||||
bool hasCollisionInfo() const { return m_collisions != 0; }
|
||||
SlotCollision *collisionInfo(const Slot *s) const { return m_collisions ? m_collisions + s->index() : NULL; }
|
||||
|
||||
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 prepare_pos(const Font *font);
|
||||
void finalise(const Font *font);
|
||||
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
|
||||
@ -159,6 +176,7 @@ private:
|
||||
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; // Array of SlotCollisions for each slot
|
||||
const Face * m_face; // GrFace
|
||||
const Silf * m_silf;
|
||||
Slot * m_first; // first slot in segment
|
||||
@ -169,6 +187,7 @@ private:
|
||||
m_passBits; // if bit set then skip pass
|
||||
int m_defaultOriginal; // number of whitespace chars in the string
|
||||
int8 m_dir;
|
||||
uint8 m_flags; // General purpose flags
|
||||
};
|
||||
|
||||
|
||||
@ -179,7 +198,7 @@ void Segment::finalise(const Font *font)
|
||||
if (!m_first) return;
|
||||
|
||||
m_advance = positionSlots(font);
|
||||
associateChars(0, m_numCharinfo);
|
||||
//associateChars(0, m_numCharinfo);
|
||||
linkClusters(m_first, m_last);
|
||||
}
|
||||
|
||||
|
119
gfx/graphite2/src/inc/Shrinker.h
Normal file
119
gfx/graphite2/src/inc/Shrinker.h
Normal file
@ -0,0 +1,119 @@
|
||||
/* Copyright (c) 2012, Siyuan Fu <fusiyuan2010@gmail.com>
|
||||
Copyright (c) 2015, SIL International
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
|
||||
#include <iterator>
|
||||
|
||||
//the code from LZ4
|
||||
#if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
|
||||
# define expect(expr,value) (__builtin_expect ((expr),(value)) )
|
||||
#else
|
||||
# define expect(expr,value) (expr)
|
||||
#endif
|
||||
#define likely(expr) expect((expr) != 0, 1)
|
||||
#define unlikely(expr) expect((expr) != 0, 0)
|
||||
////////////////////
|
||||
|
||||
|
||||
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;
|
||||
|
||||
template<int S>
|
||||
inline
|
||||
void unaligned_copy(void * d, void const * s) {
|
||||
::memcpy(d, s, S);
|
||||
}
|
||||
|
||||
inline
|
||||
u8 * memcpy_nooverlap(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 * memcpy_nooverlap_surpass(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;
|
||||
while (n--) {*d++ = *s++; }
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
u8 * memcpy_(u8 * d, u8 const * s, size_t n) {
|
||||
if (likely(d>s+sizeof(unsigned long)))
|
||||
return memcpy_nooverlap(d,s,n);
|
||||
else while (n--) *d++ = *s++;
|
||||
return d;
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
|
@ -85,6 +85,7 @@ public:
|
||||
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; }
|
||||
@ -114,13 +115,10 @@ private:
|
||||
uint8 m_sPass, m_pPass, m_jPass, m_bPass,
|
||||
m_flags;
|
||||
|
||||
uint8 m_aPseudo, m_aBreak, m_aUser, m_aBidi, m_aMirror, m_aPassBits,
|
||||
m_iMaxComp;
|
||||
uint16 m_aLig,
|
||||
m_numPseudo,
|
||||
m_nClass,
|
||||
m_nLinear,
|
||||
m_gEndLine;
|
||||
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();
|
||||
|
@ -75,6 +75,7 @@ public:
|
||||
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; }
|
||||
@ -98,7 +99,7 @@ public:
|
||||
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);
|
||||
Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool isFinal);
|
||||
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; }
|
||||
@ -122,8 +123,10 @@ public:
|
||||
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);
|
||||
bool removeSibling(Slot *ap);
|
||||
@ -132,6 +135,8 @@ public:
|
||||
void floodShift(Position adj);
|
||||
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
|
||||
|
||||
|
@ -137,11 +137,11 @@ public:
|
||||
////////////////////////////////// cmap lookup tools
|
||||
const void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3,
|
||||
int nEncodingId = 1, size_t length = 0);
|
||||
bool CheckCmapSubtable4(const void * pCmap31);
|
||||
bool CheckCmapSubtable4(const void * pCmap31 /*, 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);
|
||||
bool CheckCmapSubtable12(const void *pCmap310 /*, 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);
|
||||
|
@ -29,15 +29,63 @@ of the License or (at your option) any later version.
|
||||
namespace graphite2
|
||||
{
|
||||
|
||||
|
||||
#if defined GRAPHITE2_BUILTINS && (defined __GNUC__ || defined __clang__)
|
||||
|
||||
template<typename T>
|
||||
inline unsigned int bit_set_count(T v)
|
||||
{
|
||||
v = v - ((v >> 1) & T(~T(0)/3)); // temp
|
||||
v = (v & T(~T(0)/15*3)) + ((v >> 2) & T(~T(0)/15*3)); // temp
|
||||
v = (v + (v >> 4)) & T(~T(0)/255*15); // temp
|
||||
return (T)(v * T(~T(0)/255)) >> (sizeof(T)-1)*8; // count
|
||||
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)
|
||||
{
|
||||
v = v - ((v >> 1) & T(~(0UL)/3)); // temp
|
||||
v = (v & T(~(0UL)/15*3)) + ((v >> 2) & T(~(0UL)/15*3)); // temp
|
||||
v = (v + (v >> 4)) & T(~(0UL)/255*15); // temp
|
||||
return (T)(v * T(~(0UL)/255)) >> (sizeof(T)-1)*8; // count
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
template<int S>
|
||||
inline unsigned long _mask_over_val(unsigned long v)
|
||||
@ -87,4 +135,12 @@ inline T zero_bytes(const T x, unsigned char 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
|
||||
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ struct objectid
|
||||
|
||||
|
||||
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();
|
||||
@ -68,6 +69,13 @@ json & operator << (json & j, const Position & p) throw()
|
||||
}
|
||||
|
||||
|
||||
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()
|
||||
{
|
||||
|
@ -29,9 +29,11 @@ of the License or (at your option) any later version.
|
||||
// Author: Tim Eves
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "inc/Main.h"
|
||||
#include <cassert>
|
||||
#include <stdio.h>
|
||||
#include "inc/List.h"
|
||||
|
||||
namespace graphite2 {
|
||||
|
||||
@ -49,6 +51,7 @@ class json
|
||||
* _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();
|
||||
@ -64,6 +67,10 @@ public:
|
||||
typedef bool boolean;
|
||||
static const _null_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();
|
||||
|
@ -43,7 +43,7 @@ of the License or (at your option) any later version.
|
||||
// level - any byte
|
||||
static const opcode_t opcode_table[] =
|
||||
{
|
||||
{{do2(nop)}, 0, "NOP"},
|
||||
{{do2(nop)}, 0, "NOP"},
|
||||
|
||||
{{do2(push_byte)}, 1, "PUSH_BYTE"}, // number
|
||||
{{do2(push_byte_u)}, 1, "PUSH_BYTE_U"}, // number
|
||||
@ -114,6 +114,11 @@ static const opcode_t opcode_table[] =
|
||||
{{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"},
|
||||
{{do2(set_feat)}, 2, "SET_FEAT"},
|
||||
// private opcodes for internal use only, comes after all other on disk opcodes.
|
||||
{{do_(temp_copy), NILOP}, 0, "TEMP_COPY"}
|
||||
};
|
||||
|
@ -241,20 +241,24 @@ ENDOP
|
||||
STARTOP(put_copy)
|
||||
declare_params(1);
|
||||
const int slot_ref = int8(*param);
|
||||
if (is && (slot_ref ||is != *map))
|
||||
if (is)
|
||||
{
|
||||
int16 *tempUserAttrs = is->userAttrs();
|
||||
slotref ref = slotat(slot_ref);
|
||||
if (ref)
|
||||
if (ref && ref != is)
|
||||
{
|
||||
memcpy(tempUserAttrs, ref->userAttrs(), seg.numAttrs() * sizeof(uint16));
|
||||
int16 *tempUserAttrs = is->userAttrs();
|
||||
if (is->attachedTo() || is->firstChild()) DIE
|
||||
Slot *prev = is->prev();
|
||||
Slot *next = is->next();
|
||||
memcpy(is, slotat(slot_ref), sizeof(Slot));
|
||||
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);
|
||||
is->sibling(NULL);
|
||||
if (is->attachedTo())
|
||||
is->attachedTo()->child(is);
|
||||
}
|
||||
is->markCopied(false);
|
||||
is->markDeleted(false);
|
||||
@ -316,7 +320,7 @@ STARTOP(insert)
|
||||
ENDOP
|
||||
|
||||
STARTOP(delete_)
|
||||
if (!is) DIE
|
||||
if (!is || is->isDeleted()) DIE
|
||||
is->markDeleted(true);
|
||||
if (is->prev())
|
||||
is->prev()->next(is->next());
|
||||
@ -644,3 +648,37 @@ STARTOP(temp_copy)
|
||||
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
|
||||
|
||||
|
@ -30,6 +30,7 @@ of the License or (at your option) any later version.
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits>
|
||||
#include "inc/json.h"
|
||||
|
||||
using namespace graphite2;
|
||||
@ -116,7 +117,20 @@ json & json::operator << (json::string s) throw()
|
||||
return *this;
|
||||
}
|
||||
|
||||
json & json::operator << (json::number f) throw() { context(seq); fprintf(_stream, "%g", f); return *this; }
|
||||
json & json::operator << (json::number f) throw()
|
||||
{
|
||||
context(seq);
|
||||
if (std::numeric_limits<json::number>::infinity() == f)
|
||||
fputs("Infinity", _stream);
|
||||
else if (-std::numeric_limits<json::number>::infinity() == f)
|
||||
fputs("-Infinity", _stream);
|
||||
else if (std::numeric_limits<json::number>::quiet_NaN() == f ||
|
||||
std::numeric_limits<json::number>::signaling_NaN() == f)
|
||||
fputs("NaN", _stream);
|
||||
else
|
||||
fprintf(_stream, "%g", f);
|
||||
return *this;
|
||||
}
|
||||
json & json::operator << (json::integer d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; }
|
||||
json & json::operator << (long unsigned d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; }
|
||||
json & json::operator << (json::boolean b) throw() { context(seq); fputs(b ? "true" : "false", _stream); return *this; }
|
||||
|
@ -27,6 +27,8 @@ UNIFIED_SOURCES += [
|
||||
'CachedFace.cpp',
|
||||
'CmapCache.cpp',
|
||||
'Code.cpp',
|
||||
'Collider.cpp',
|
||||
'Decompressor.cpp',
|
||||
'Face.cpp',
|
||||
'FeatureMap.cpp',
|
||||
'FileFace.cpp',
|
||||
@ -40,10 +42,12 @@ UNIFIED_SOURCES += [
|
||||
'gr_logging.cpp',
|
||||
'gr_segment.cpp',
|
||||
'gr_slot.cpp',
|
||||
'Intervals.cpp',
|
||||
'json.cpp',
|
||||
'Justifier.cpp',
|
||||
'NameTable.cpp',
|
||||
'Pass.cpp',
|
||||
'Position.cpp',
|
||||
'SegCache.cpp',
|
||||
'SegCacheEntry.cpp',
|
||||
'SegCacheStore.cpp',
|
||||
|
Loading…
Reference in New Issue
Block a user