2489 lines
91 KiB
Diff
2489 lines
91 KiB
Diff
|
|
# HG changeset patch
|
|
# User Jonathan Kew <jkew@mozilla.com>
|
|
# Date 1460660890 -3600
|
|
# Node ID 7330633d20ffb33941e41ea0666c4099b6e6d317
|
|
# Parent 5c312182da9020504103aa329360abaffa7e232d
|
|
Bug 1262846 (patch for ESR trees) - Update Graphite2 library to 1.3.8. r=jrmuizel a=sledru
|
|
|
|
diff --git a/gfx/graphite2/README.mozilla b/gfx/graphite2/README.mozilla
|
|
--- a/gfx/graphite2/README.mozilla
|
|
+++ b/gfx/graphite2/README.mozilla
|
|
@@ -1,3 +1,3 @@
|
|
-This directory contains the Graphite2 library release 1.3.6 from
|
|
-https://github.com/silnrsi/graphite/releases/download/1.3.6/graphite-minimal-1.3.6.tgz
|
|
+This directory contains the Graphite2 library release 1.3.8 from
|
|
+https://github.com/silnrsi/graphite/releases/download/1.3.8/graphite2-minimal-1.3.8.tgz
|
|
See gfx/graphite2/moz-gr-update.sh for update procedure.
|
|
diff --git a/gfx/graphite2/include/graphite2/Font.h b/gfx/graphite2/include/graphite2/Font.h
|
|
--- a/gfx/graphite2/include/graphite2/Font.h
|
|
+++ b/gfx/graphite2/include/graphite2/Font.h
|
|
@@ -25,17 +25,17 @@
|
|
either version 2 of the License or (at your option) any later version.
|
|
*/
|
|
#pragma once
|
|
|
|
#include "graphite2/Types.h"
|
|
|
|
#define GR2_VERSION_MAJOR 1
|
|
#define GR2_VERSION_MINOR 3
|
|
-#define GR2_VERSION_BUGFIX 6
|
|
+#define GR2_VERSION_BUGFIX 8
|
|
|
|
#ifdef __cplusplus
|
|
extern "C"
|
|
{
|
|
#endif
|
|
|
|
typedef struct gr_face gr_face;
|
|
typedef struct gr_font gr_font;
|
|
diff --git a/gfx/graphite2/moz-gr-update.sh b/gfx/graphite2/moz-gr-update.sh
|
|
--- a/gfx/graphite2/moz-gr-update.sh
|
|
+++ b/gfx/graphite2/moz-gr-update.sh
|
|
@@ -14,17 +14,17 @@
|
|
RELEASE=$1
|
|
|
|
if [ "x$RELEASE" == "x" ]
|
|
then
|
|
echo "Must provide the version number to be used."
|
|
exit 1
|
|
fi
|
|
|
|
-TARBALL="https://github.com/silnrsi/graphite/releases/download/$RELEASE/graphite-minimal-$RELEASE.tgz"
|
|
+TARBALL="https://github.com/silnrsi/graphite/releases/download/$RELEASE/graphite2-minimal-$RELEASE.tgz"
|
|
|
|
foo=`basename $0`
|
|
TMPFILE=`mktemp -t ${foo}` || exit 1
|
|
|
|
curl -L "$TARBALL" -o "$TMPFILE"
|
|
tar -x -z -C gfx/graphite2/ --strip-components 1 -f "$TMPFILE" || exit 1
|
|
rm "$TMPFILE"
|
|
|
|
diff --git a/gfx/graphite2/src/CachedFace.cpp b/gfx/graphite2/src/CachedFace.cpp
|
|
--- a/gfx/graphite2/src/CachedFace.cpp
|
|
+++ b/gfx/graphite2/src/CachedFace.cpp
|
|
@@ -64,20 +64,20 @@ bool CachedFace::runGraphite(Segment *se
|
|
return false;
|
|
|
|
assert(m_cacheStore);
|
|
// find where the segment can be broken
|
|
Slot * subSegStartSlot = seg->first();
|
|
Slot * subSegEndSlot = subSegStartSlot;
|
|
uint16 cmapGlyphs[eMaxSpliceSize];
|
|
int subSegStart = 0;
|
|
- for (unsigned int i = 0; i < seg->charInfoCount(); ++i)
|
|
+ for (unsigned int i = 0; i < seg->charInfoCount() && subSegEndSlot; ++i)
|
|
{
|
|
const unsigned int length = i - subSegStart + 1;
|
|
- if (length < eMaxSpliceSize)
|
|
+ if (length < eMaxSpliceSize && subSegEndSlot->gid() < m_cacheStore->maxCmapGid())
|
|
cmapGlyphs[length-1] = subSegEndSlot->gid();
|
|
else return false;
|
|
const bool spaceOnly = m_cacheStore->isSpaceGlyph(subSegEndSlot->gid());
|
|
// at this stage the character to slot mapping is still 1 to 1
|
|
const int breakWeight = seg->charinfo(i)->breakWeight(),
|
|
nextBreakWeight = (i + 1 < seg->charInfoCount())?
|
|
seg->charinfo(i+1)->breakWeight() : 0;
|
|
const uint8 f = seg->charinfo(i)->flags();
|
|
diff --git a/gfx/graphite2/src/Code.cpp b/gfx/graphite2/src/Code.cpp
|
|
--- a/gfx/graphite2/src/Code.cpp
|
|
+++ b/gfx/graphite2/src/Code.cpp
|
|
@@ -61,93 +61,88 @@ inline bool is_return(const instr i) {
|
|
const instr pop_ret = *opmap[POP_RET].impl,
|
|
ret_zero = *opmap[RET_ZERO].impl,
|
|
ret_true = *opmap[RET_TRUE].impl;
|
|
return i == pop_ret || i == ret_zero || i == ret_true;
|
|
}
|
|
|
|
struct context
|
|
{
|
|
- context(uint8 ref=0) : codeRef(ref) {flags.changed=false; flags.referenced=false; flags.inserted=false;}
|
|
+ context(uint8 ref=0) : codeRef(ref) {flags.changed=false; flags.referenced=false;}
|
|
struct {
|
|
uint8 changed:1,
|
|
- referenced:1,
|
|
- inserted:1;
|
|
+ referenced:1;
|
|
} flags;
|
|
uint8 codeRef;
|
|
};
|
|
|
|
} // end namespace
|
|
|
|
|
|
class Machine::Code::decoder
|
|
{
|
|
public:
|
|
struct limits;
|
|
- struct analysis
|
|
- {
|
|
- static const int NUMCONTEXTS = 256;
|
|
- uint8 slotref;
|
|
- context contexts[NUMCONTEXTS];
|
|
- byte max_ref;
|
|
-
|
|
- analysis() : slotref(0), max_ref(0) {};
|
|
- void set_ref(int index, bool incinsert=false) throw();
|
|
- void set_noref(int index) throw();
|
|
- void set_changed(int index) throw();
|
|
-
|
|
- };
|
|
+ static const int NUMCONTEXTS = 256;
|
|
|
|
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);
|
|
- byte max_ref() { return _analysis.max_ref; }
|
|
- int pre_context() const { return _pre_context; }
|
|
+ byte max_ref() { return _max_ref; }
|
|
+ int out_index() const { return _out_index; }
|
|
|
|
private:
|
|
+ void set_ref(int index) throw();
|
|
+ void set_noref(int index) throw();
|
|
+ void set_changed(int index) throw();
|
|
opcode fetch_opcode(const byte * bc);
|
|
void analyse_opcode(const opcode, const int8 * const dp) throw();
|
|
bool emit_opcode(opcode opc, const byte * & bc);
|
|
- bool validate_opcode(const opcode opc, const byte * const bc);
|
|
+ bool validate_opcode(const byte opc, const byte * const bc);
|
|
bool valid_upto(const uint16 limit, const uint16 x) const throw();
|
|
bool test_context() const throw();
|
|
+ bool test_ref(int8 index) const throw();
|
|
void failure(const status_t s) const throw() { _code.failure(s); }
|
|
|
|
Code & _code;
|
|
- int _pre_context;
|
|
- uint16 _rule_length;
|
|
+ int _out_index;
|
|
+ uint16 _out_length;
|
|
instr * _instr;
|
|
byte * _data;
|
|
limits & _max;
|
|
- analysis _analysis;
|
|
enum passtype _passtype;
|
|
int _stack_depth;
|
|
bool _in_ctxt_item;
|
|
+ int16 _slotref;
|
|
+ context _contexts[NUMCONTEXTS];
|
|
+ byte _max_ref;
|
|
};
|
|
|
|
|
|
struct Machine::Code::decoder::limits
|
|
{
|
|
const byte * bytecode;
|
|
const uint8 pre_context;
|
|
const uint16 rule_length,
|
|
classes,
|
|
glyf_attrs,
|
|
features;
|
|
const byte attrid[gr_slatMax];
|
|
};
|
|
|
|
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),
|
|
+ _out_index(code._constraint ? 0 : lims.pre_context),
|
|
+ _out_length(code._constraint ? 1 : lims.rule_length),
|
|
_instr(code._code), _data(code._data), _max(lims), _passtype(pt),
|
|
_stack_depth(0),
|
|
- _in_ctxt_item(false)
|
|
+ _in_ctxt_item(false),
|
|
+ _slotref(0),
|
|
+ _max_ref(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,
|
|
enum passtype pt, byte * * const _out)
|
|
: _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded),
|
|
@@ -163,17 +158,17 @@ Machine::Code::Code(bool is_constraint,
|
|
return;
|
|
}
|
|
assert(bytecode_end > bytecode_begin);
|
|
const opcode_t * op_to_fn = Machine::getOpcodeTable();
|
|
|
|
// Allocate code and data target buffers, these sizes are a worst case
|
|
// estimate. Once we know their real sizes the we'll shrink them.
|
|
if (_out) _code = reinterpret_cast<instr *>(*_out);
|
|
- else _code = static_cast<instr *>(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin)));
|
|
+ else _code = static_cast<instr *>(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin, 1, is_constraint ? 0 : rule_length)));
|
|
_data = reinterpret_cast<byte *>(_code + (bytecode_end - bytecode_begin));
|
|
|
|
if (!_code || !_data) {
|
|
failure(alloc_failed);
|
|
return;
|
|
}
|
|
|
|
decoder::limits lims = {
|
|
@@ -266,23 +261,23 @@ bool Machine::Code::decoder::load(const
|
|
return bool(_code);
|
|
}
|
|
|
|
// Validation check and fixups.
|
|
//
|
|
|
|
opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
|
|
{
|
|
- const opcode opc = opcode(*bc++);
|
|
+ const byte opc = *bc++;
|
|
|
|
// Do some basic sanity checks based on what we know about the opcode
|
|
if (!validate_opcode(opc, bc)) return MAX_OPCODE;
|
|
|
|
// And check it's arguments as far as possible
|
|
- switch (opc)
|
|
+ switch (opcode(opc))
|
|
{
|
|
case NOP :
|
|
break;
|
|
case PUSH_BYTE :
|
|
case PUSH_BYTEU :
|
|
case PUSH_SHORT :
|
|
case PUSH_SHORTU :
|
|
case PUSH_LONG :
|
|
@@ -319,47 +314,57 @@ opcode Machine::Code::decoder::fetch_opc
|
|
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;
|
|
+ ++_out_index;
|
|
+ if (_out_index < -1 || _out_index > _out_length || _slotref > _max.rule_length)
|
|
+ failure(out_of_range_data);
|
|
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]));
|
|
+ test_ref(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_ref(int8(bc[0]));
|
|
test_context();
|
|
break;
|
|
case INSERT :
|
|
if (_passtype >= PASS_TYPE_POSITIONING)
|
|
failure(invalid_opcode);
|
|
- else
|
|
- --_pre_context;
|
|
+ ++_out_length;
|
|
+ if (_out_index < 0) ++_out_index;
|
|
+ if (_out_index < -1 || _out_index >= _out_length)
|
|
+ failure(out_of_range_data);
|
|
break;
|
|
case DELETE :
|
|
if (_passtype >= PASS_TYPE_POSITIONING)
|
|
failure(invalid_opcode);
|
|
- test_context();
|
|
+ if (_out_index < _max.pre_context)
|
|
+ failure(out_of_range_data);
|
|
+ --_out_index;
|
|
+ --_out_length;
|
|
+ if (_out_index < -1 || _out_index > _out_length)
|
|
+ failure(out_of_range_data);
|
|
break;
|
|
case ASSOC :
|
|
+ if (bc[0] == 0)
|
|
+ failure(out_of_range_data);
|
|
for (uint8 num = bc[0]; num; --num)
|
|
- valid_upto(_rule_length, _pre_context + int8(bc[num]));
|
|
+ test_ref(int8(bc[num]));
|
|
test_context();
|
|
break;
|
|
case CNTXT_ITEM :
|
|
valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
|
|
if (bc + 2 + bc[1] >= _max.bytecode) failure(jump_past_end);
|
|
if (_in_ctxt_item) failure(nested_context_item);
|
|
break;
|
|
case ATTR_SET :
|
|
@@ -378,52 +383,43 @@ opcode Machine::Code::decoder::fetch_opc
|
|
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]));
|
|
+ test_ref(int8(bc[1]));
|
|
if (attrCode(bc[0]) == gr_slatUserDefn) // use IATTR for user attributes
|
|
failure(out_of_range_data);
|
|
break;
|
|
case PUSH_GLYPH_ATTR_OBS :
|
|
+ case PUSH_ATT_TO_GATTR_OBS :
|
|
++_stack_depth;
|
|
valid_upto(_max.glyf_attrs, bc[0]);
|
|
- valid_upto(_rule_length, _pre_context + int8(bc[1]));
|
|
+ test_ref(int8(bc[1]));
|
|
break;
|
|
+ case PUSH_ATT_TO_GLYPH_METRIC :
|
|
case PUSH_GLYPH_METRIC :
|
|
++_stack_depth;
|
|
valid_upto(kgmetDescent, bc[0]);
|
|
- valid_upto(_rule_length, _pre_context + int8(bc[1]));
|
|
+ test_ref(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
|
|
+ test_ref(int8(bc[1]));
|
|
break;
|
|
case PUSH_ISLOT_ATTR :
|
|
++_stack_depth;
|
|
if (valid_upto(gr_slatMax, bc[0]))
|
|
{
|
|
- valid_upto(_rule_length, _pre_context + int8(bc[1]));
|
|
+ test_ref(int8(bc[1]));
|
|
valid_upto(_max.attrid[bc[0]], bc[2]);
|
|
}
|
|
break;
|
|
case PUSH_IGLYPH_ATTR :// not implemented
|
|
++_stack_depth;
|
|
break;
|
|
case POP_RET :
|
|
if (--_stack_depth < 0)
|
|
@@ -442,118 +438,107 @@ opcode Machine::Code::decoder::fetch_opc
|
|
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]));
|
|
+ test_ref(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]));
|
|
+ test_ref(int8(bc[2]));
|
|
+ break;
|
|
+ case SET_FEAT :
|
|
+ valid_upto(_max.features, bc[0]);
|
|
+ test_ref(int8(bc[1]));
|
|
break;
|
|
default:
|
|
failure(invalid_opcode);
|
|
break;
|
|
}
|
|
|
|
- return bool(_code) ? opc : MAX_OPCODE;
|
|
+ return bool(_code) ? opcode(opc) : MAX_OPCODE;
|
|
}
|
|
|
|
|
|
void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg) throw()
|
|
{
|
|
- if (_code._constraint) return;
|
|
-
|
|
switch (opc)
|
|
{
|
|
case DELETE :
|
|
_code._delete = true;
|
|
break;
|
|
+ case ASSOC :
|
|
+ set_changed(0);
|
|
+// for (uint8 num = arg[0]; num; --num)
|
|
+// _analysis.set_noref(num);
|
|
+ break;
|
|
case PUT_GLYPH_8BIT_OBS :
|
|
case PUT_GLYPH :
|
|
_code._modify = true;
|
|
- _analysis.set_changed(0);
|
|
+ set_changed(0);
|
|
break;
|
|
case ATTR_SET :
|
|
case ATTR_ADD :
|
|
+ case ATTR_SUB :
|
|
case ATTR_SET_SLOT :
|
|
case IATTR_SET_SLOT :
|
|
case IATTR_SET :
|
|
case IATTR_ADD :
|
|
case IATTR_SUB :
|
|
- _analysis.set_noref(0);
|
|
+ set_noref(0);
|
|
break;
|
|
case NEXT :
|
|
case COPY_NEXT :
|
|
- if (!_analysis.contexts[_analysis.slotref].flags.inserted)
|
|
- ++_analysis.slotref;
|
|
- _analysis.contexts[_analysis.slotref] = context(_code._instr_count+1);
|
|
+ ++_slotref;
|
|
+ _contexts[_slotref] = context(_code._instr_count+1);
|
|
// if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
|
|
break;
|
|
case INSERT :
|
|
- _analysis.contexts[_analysis.slotref].flags.inserted = true;
|
|
+ if (_slotref >= 0) --_slotref;
|
|
_code._modify = true;
|
|
break;
|
|
case PUT_SUBS_8BIT_OBS : // slotref on 1st parameter
|
|
case PUT_SUBS :
|
|
_code._modify = true;
|
|
- _analysis.set_changed(0);
|
|
+ set_changed(0);
|
|
GR_FALLTHROUGH;
|
|
// no break
|
|
case PUT_COPY :
|
|
- {
|
|
- if (arg[0] != 0) { _analysis.set_changed(0); _code._modify = true; }
|
|
- if (arg[0] <= 0 && -arg[0] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
|
|
- _analysis.set_ref(arg[0], true);
|
|
- else if (arg[0] > 0)
|
|
- _analysis.set_ref(arg[0], true);
|
|
+ if (arg[0] != 0) { set_changed(0); _code._modify = true; }
|
|
+ set_ref(arg[0]);
|
|
break;
|
|
- }
|
|
- case PUSH_ATT_TO_GATTR_OBS : // slotref on 2nd parameter
|
|
- if (_code._constraint) return;
|
|
- GR_FALLTHROUGH;
|
|
- // no break
|
|
case PUSH_GLYPH_ATTR_OBS :
|
|
case PUSH_SLOT_ATTR :
|
|
case PUSH_GLYPH_METRIC :
|
|
+ case PUSH_ATT_TO_GATTR_OBS :
|
|
case PUSH_ATT_TO_GLYPH_METRIC :
|
|
case PUSH_ISLOT_ATTR :
|
|
case PUSH_FEAT :
|
|
- if (arg[1] <= 0 && -arg[1] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
|
|
- _analysis.set_ref(arg[1], true);
|
|
- else if (arg[1] > 0)
|
|
- _analysis.set_ref(arg[1], true);
|
|
+ case SET_FEAT :
|
|
+ set_ref(arg[1]);
|
|
break;
|
|
case PUSH_ATT_TO_GLYPH_ATTR :
|
|
- if (_code._constraint) return;
|
|
- GR_FALLTHROUGH;
|
|
- // no break
|
|
case PUSH_GLYPH_ATTR :
|
|
- if (arg[2] <= 0 && -arg[2] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
|
|
- _analysis.set_ref(arg[2], true);
|
|
- else if (arg[2] > 0)
|
|
- _analysis.set_ref(arg[2], true);
|
|
- break;
|
|
- case ASSOC : // slotrefs in varargs
|
|
+ set_ref(arg[2]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
bool Machine::Code::decoder::emit_opcode(opcode opc, const byte * & bc)
|
|
@@ -579,81 +564,89 @@ bool Machine::Code::decoder::emit_opcode
|
|
_data += param_sz;
|
|
_code._data_size += param_sz;
|
|
}
|
|
|
|
// recursively decode a context item so we can split the skip into
|
|
// instruction and data portions.
|
|
if (opc == CNTXT_ITEM)
|
|
{
|
|
- assert(_pre_context == 0);
|
|
+ assert(_out_index == 0);
|
|
_in_ctxt_item = true;
|
|
- _pre_context = _max.pre_context + int8(_data[-2]);
|
|
- _rule_length = _max.rule_length;
|
|
+ _out_index = _max.pre_context + int8(_data[-2]);
|
|
+ _slotref = int8(_data[-2]);
|
|
+ _out_length = _max.rule_length;
|
|
|
|
const size_t ctxt_start = _code._instr_count;
|
|
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;
|
|
+ _out_length = 1;
|
|
+ _out_index = 0;
|
|
+ _slotref = 0;
|
|
_in_ctxt_item = false;
|
|
}
|
|
else
|
|
{
|
|
- _pre_context = 0;
|
|
+ _out_index = 0;
|
|
+ _slotref = 0;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return bool(_code);
|
|
}
|
|
|
|
|
|
void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end)
|
|
{
|
|
// insert TEMP_COPY commands for slots that need them (that change and are referenced later)
|
|
int tempcount = 0;
|
|
if (_code._constraint) return;
|
|
|
|
const instr temp_copy = Machine::getOpcodeTable()[TEMP_COPY].impl[0];
|
|
- for (const context * c = _analysis.contexts, * const ce = c + _analysis.slotref; c != ce; ++c)
|
|
+ for (const context * c = _contexts, * const ce = c + _slotref; c < ce; ++c)
|
|
{
|
|
if (!c->flags.referenced || !c->flags.changed) continue;
|
|
|
|
instr * const tip = code + c->codeRef + tempcount;
|
|
memmove(tip+1, tip, (code_end - tip) * sizeof(instr));
|
|
*tip = temp_copy;
|
|
++code_end;
|
|
++tempcount;
|
|
_code._delete = true;
|
|
}
|
|
|
|
_code._instr_count = code_end - code;
|
|
}
|
|
|
|
|
|
inline
|
|
-bool Machine::Code::decoder::validate_opcode(const opcode opc, const byte * const bc)
|
|
+bool Machine::Code::decoder::validate_opcode(const byte opc, const byte * const bc)
|
|
{
|
|
if (opc >= MAX_OPCODE)
|
|
{
|
|
failure(invalid_opcode);
|
|
return false;
|
|
}
|
|
const opcode_t & op = Machine::getOpcodeTable()[opc];
|
|
+ if (op.impl[_code._constraint] == 0)
|
|
+ {
|
|
+ failure(unimplemented_opcode_used);
|
|
+ return false;
|
|
+ }
|
|
if (op.param_sz == VARARGS && bc >= _max.bytecode)
|
|
{
|
|
failure(arguments_exhausted);
|
|
return false;
|
|
}
|
|
const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
|
|
if (bc - 1 + param_sz >= _max.bytecode)
|
|
{
|
|
@@ -666,56 +659,69 @@ bool Machine::Code::decoder::validate_op
|
|
|
|
bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
|
|
{
|
|
const bool t = (limit != 0) && (x < limit);
|
|
if (!t) failure(out_of_range_data);
|
|
return t;
|
|
}
|
|
|
|
+inline
|
|
+bool Machine::Code::decoder::test_ref(int8 index) const throw()
|
|
+{
|
|
+ if (_code._constraint && !_in_ctxt_item)
|
|
+ {
|
|
+ if (index > 0 || -index > _max.pre_context)
|
|
+ {
|
|
+ failure(out_of_range_data);
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ return valid_upto(_max.rule_length, _slotref + _max.pre_context + index);
|
|
+ return true;
|
|
+}
|
|
+
|
|
bool Machine::Code::decoder::test_context() const throw()
|
|
{
|
|
- if (_pre_context >= _rule_length || _analysis.slotref >= analysis::NUMCONTEXTS - 1)
|
|
+ if (_out_index >= _out_length || _out_index < 0 || _slotref >= NUMCONTEXTS - 1)
|
|
{
|
|
failure(out_of_range_data);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
inline
|
|
void Machine::Code::failure(const status_t s) throw() {
|
|
release_buffers();
|
|
_status = s;
|
|
}
|
|
|
|
|
|
inline
|
|
-void Machine::Code::decoder::analysis::set_ref(int index, bool incinsert) throw() {
|
|
- if (incinsert && contexts[slotref].flags.inserted) --index;
|
|
- if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
|
|
- contexts[index + slotref].flags.referenced = true;
|
|
- if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
|
|
+void Machine::Code::decoder::set_ref(int index) throw() {
|
|
+ if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
|
|
+ _contexts[index + _slotref].flags.referenced = true;
|
|
+ if (index + _slotref > _max_ref) _max_ref = index + _slotref;
|
|
}
|
|
|
|
|
|
inline
|
|
-void Machine::Code::decoder::analysis::set_noref(int index) throw() {
|
|
- if (contexts[slotref].flags.inserted) --index;
|
|
- if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
|
|
- if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
|
|
+void Machine::Code::decoder::set_noref(int index) throw() {
|
|
+ if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
|
|
+ if (index + _slotref > _max_ref) _max_ref = index + _slotref;
|
|
}
|
|
|
|
|
|
inline
|
|
-void Machine::Code::decoder::analysis::set_changed(int index) throw() {
|
|
- if (contexts[slotref].flags.inserted) --index;
|
|
- if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
|
|
- contexts[index + slotref].flags.changed = true;
|
|
- if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
|
|
+void Machine::Code::decoder::set_changed(int index) throw() {
|
|
+ if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
|
|
+ _contexts[index + _slotref].flags.changed= true;
|
|
+ if (index + _slotref > _max_ref) _max_ref = index + _slotref;
|
|
}
|
|
|
|
|
|
void Machine::Code::release_buffers() throw()
|
|
{
|
|
if (_own)
|
|
free(_code);
|
|
_code = 0;
|
|
diff --git a/gfx/graphite2/src/Collider.cpp b/gfx/graphite2/src/Collider.cpp
|
|
--- a/gfx/graphite2/src/Collider.cpp
|
|
+++ b/gfx/graphite2/src/Collider.cpp
|
|
@@ -21,17 +21,17 @@
|
|
|
|
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 <limits>
|
|
-#include <math.h>
|
|
+#include <cmath>
|
|
#include <string>
|
|
#include <functional>
|
|
#include "inc/Collider.h"
|
|
#include "inc/Segment.h"
|
|
#include "inc/Slot.h"
|
|
#include "inc/GlyphCache.h"
|
|
#include "inc/Sparse.h"
|
|
|
|
@@ -824,43 +824,43 @@ bool KernCollider::initSlot(Segment *seg
|
|
if (margin < 10) margin = 10;
|
|
|
|
_limit = limit;
|
|
_offsetPrev = offsetPrev; // kern from a previous pass
|
|
|
|
// Calculate the height of the glyph and how many horizontal slices to use.
|
|
if (_maxy >= 1e37f)
|
|
{
|
|
- _maxy = ymax;
|
|
- _miny = ymin;
|
|
_sliceWidth = margin / 1.5f;
|
|
+ _maxy = ymax + margin;
|
|
+ _miny = ymin - margin;
|
|
numSlices = int((_maxy - _miny + 2) / (_sliceWidth / 1.5f) + 1.f); // +2 helps with rounding errors
|
|
_edges.clear();
|
|
_edges.insert(_edges.begin(), numSlices, (dir & 1) ? 1e38f : -1e38f);
|
|
_xbound = (dir & 1) ? (float)1e38f : (float)-1e38f;
|
|
}
|
|
else if (_maxy != ymax || _miny != ymin)
|
|
{
|
|
if (_miny != ymin)
|
|
{
|
|
- numSlices = int((ymin - _miny) / _sliceWidth - 1);
|
|
+ numSlices = int((ymin - margin - _miny) / _sliceWidth - 1);
|
|
_miny += numSlices * _sliceWidth;
|
|
if (numSlices < 0)
|
|
_edges.insert(_edges.begin(), -numSlices, (dir & 1) ? 1e38f : -1e38f);
|
|
else if ((unsigned)numSlices < _edges.size()) // this shouldn't fire since we always grow the range
|
|
{
|
|
Vector<float>::iterator e = _edges.begin();
|
|
while (numSlices--)
|
|
++e;
|
|
_edges.erase(_edges.begin(), e);
|
|
}
|
|
}
|
|
if (_maxy != ymax)
|
|
{
|
|
- numSlices = int((ymax - _miny) / _sliceWidth + 1);
|
|
+ numSlices = int((ymax + margin - _miny) / _sliceWidth + 1);
|
|
_maxy = numSlices * _sliceWidth + _miny;
|
|
if (numSlices > (int)_edges.size())
|
|
_edges.insert(_edges.end(), numSlices - _edges.size(), (dir & 1) ? 1e38f : -1e38f);
|
|
else if (numSlices < (int)_edges.size()) // this shouldn't fire since we always grow the range
|
|
{
|
|
while ((int)_edges.size() > numSlices)
|
|
_edges.pop_back();
|
|
}
|
|
@@ -930,53 +930,60 @@ bool KernCollider::initSlot(Segment *seg
|
|
// Return false if we know there is no collision, true if we think there might be one.
|
|
bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, GR_MAYBE_UNUSED json * const dbgout)
|
|
{
|
|
int rtl = (dir & 1) * 2 - 1;
|
|
if (!seg->getFace()->glyphs().check(slot->gid()))
|
|
return false;
|
|
const Rect &bb = seg->theGlyphBBoxTemporary(slot->gid());
|
|
const float sx = slot->origin().x + currShift.x;
|
|
- float x = sx + (rtl > 0 ? bb.tr.x : bb.bl.x);
|
|
+ float x = (sx + (rtl > 0 ? bb.tr.x : bb.bl.x)) * rtl;
|
|
// this isn't going to reduce _mingap so skip
|
|
- if ((rtl > 0 && x < _xbound - _mingap - currSpace) || (rtl <= 0 && x > _xbound + _mingap + currSpace))
|
|
+ if (x < rtl * (_xbound - _mingap - currSpace))
|
|
return false;
|
|
|
|
const float sy = slot->origin().y + currShift.y;
|
|
- int smin = max(0, int((bb.bl.y + (1 - _miny + sy)) / _sliceWidth + 1));
|
|
- int smax = min((int)_edges.size() - 1, int((bb.tr.y + (1 - _miny + sy)) / _sliceWidth + 1));
|
|
+ int smin = max(1, int((bb.bl.y + (1 - _miny + sy)) / _sliceWidth + 1)) - 1;
|
|
+ int smax = min((int)_edges.size() - 2, int((bb.tr.y + (1 - _miny + sy)) / _sliceWidth + 1)) + 1;
|
|
+ if (smin > smax)
|
|
+ return false;
|
|
bool collides = false;
|
|
+ float below = smin > 0 ? _edges[smin-1] * rtl : 1e38f;
|
|
+ float here = _edges[smin] * rtl;
|
|
+ float above = smin < (int)_edges.size() - 1 ? _edges[smin+1] * rtl : 1e38f;
|
|
|
|
for (int i = smin; i <= smax; ++i)
|
|
{
|
|
float t;
|
|
float y = (float)(_miny - 1 + (i + .5f) * _sliceWidth); // vertical center of slice
|
|
- if (x * rtl > _edges[i] * rtl - _mingap - currSpace)
|
|
+ if ( (x > here - _mingap - currSpace)
|
|
+ || (x > below - _mingap - currSpace)
|
|
+ || (x > above - _mingap - currSpace))
|
|
{
|
|
// 2 * currSpace to account for the space that is already separating them and the space we want to add
|
|
- float m = get_edge(seg, slot, currShift, y, _sliceWidth, rtl > 0) + 2 * rtl * currSpace;
|
|
- t = rtl * (_edges[i] - m);
|
|
+ float m = get_edge(seg, slot, currShift, y, _sliceWidth, rtl > 0) * rtl + 2 * currSpace;
|
|
// Check slices above and below (if any).
|
|
- if (i < (int)_edges.size() - 1) t = min(t, rtl * (_edges[i+1] - m));
|
|
- if (i > 0) t = min(t, rtl * (_edges[i-1] - m));
|
|
+ t = min(min(here, below), above) - m;
|
|
// _mingap is positive to shrink
|
|
if (t < _mingap)
|
|
{
|
|
_mingap = t;
|
|
collides = true;
|
|
}
|
|
#if !defined GRAPHITE2_NTRACING
|
|
// Debugging - remember the closest neighboring edge for this slice.
|
|
- if (rtl * m > rtl * _nearEdges[i])
|
|
+ if (m > rtl * _nearEdges[i])
|
|
{
|
|
_slotNear[i] = slot;
|
|
- _nearEdges[i] = m;
|
|
+ _nearEdges[i] = m * rtl;
|
|
}
|
|
#endif
|
|
}
|
|
+ below = here; here = above;
|
|
+ above = i < (int)_edges.size() - 2 ? _edges[i+2] * rtl : 1e38f;
|
|
}
|
|
return collides; // note that true is not a necessarily reliable value
|
|
|
|
} // end of KernCollider::mergeSlot
|
|
|
|
|
|
// Return the amount to kern by.
|
|
Position KernCollider::resolve(GR_MAYBE_UNUSED Segment *seg, GR_MAYBE_UNUSED Slot *slot,
|
|
diff --git a/gfx/graphite2/src/Face.cpp b/gfx/graphite2/src/Face.cpp
|
|
--- a/gfx/graphite2/src/Face.cpp
|
|
+++ b/gfx/graphite2/src/Face.cpp
|
|
@@ -178,17 +178,18 @@ bool Face::runGraphite(Segment *seg, con
|
|
if ((seg->dir() & 3) == 3 && aSilf->bidiPass() == 0xFF)
|
|
seg->doMirror(aSilf->aMirror());
|
|
bool res = aSilf->runGraphite(seg, 0, aSilf->positionPass(), true);
|
|
if (res)
|
|
{
|
|
seg->associateChars(0, seg->charInfoCount());
|
|
if (aSilf->flags() & 0x20)
|
|
res &= seg->initCollisions();
|
|
- res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
|
|
+ if (res)
|
|
+ res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
|
|
}
|
|
|
|
#if !defined GRAPHITE2_NTRACING
|
|
if (dbgout)
|
|
{
|
|
seg->positionSlots(0, 0, 0, aSilf->dir());
|
|
*dbgout << json::item
|
|
<< json::close // Close up the passes array
|
|
@@ -226,17 +227,17 @@ const Silf *Face::chooseSilf(uint32 scri
|
|
return m_silfs;
|
|
}
|
|
|
|
uint16 Face::findPseudo(uint32 uid) const
|
|
{
|
|
return (m_numSilf) ? m_silfs[0].findPseudo(uid) : 0;
|
|
}
|
|
|
|
-uint16 Face::getGlyphMetric(uint16 gid, uint8 metric) const
|
|
+int32 Face::getGlyphMetric(uint16 gid, uint8 metric) const
|
|
{
|
|
switch (metrics(metric))
|
|
{
|
|
case kgmetAscent : return m_ascent;
|
|
case kgmetDescent : return m_descent;
|
|
default:
|
|
if (gid >= glyphs().numGlyphs()) return 0;
|
|
return glyphs().glyph(gid)->getMetric(metric);
|
|
@@ -277,17 +278,17 @@ Face::Table::Table(const Face & face, co
|
|
: _f(&face), _compressed(false)
|
|
{
|
|
size_t sz = 0;
|
|
_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
|
|
+ releaseBuffers(); // Make sure we release the table buffer even if the table failed it's checks
|
|
return;
|
|
}
|
|
|
|
if (be::peek<uint32>(_p) >= version)
|
|
decompress();
|
|
}
|
|
|
|
void Face::Table::releaseBuffers()
|
|
@@ -324,17 +325,18 @@ Error Face::Table::decompress()
|
|
switch(compression(hdr >> 27))
|
|
{
|
|
case NONE: return e;
|
|
|
|
case LZ4:
|
|
{
|
|
uncompressed_size = hdr & 0x07ffffff;
|
|
uncompressed_table = gralloc<byte>(uncompressed_size);
|
|
- if (!e.test(!uncompressed_table, E_OUTOFMEM))
|
|
+ if (!e.test(!uncompressed_table || uncompressed_size < 4, E_OUTOFMEM))
|
|
+ memset(uncompressed_table, 0, 4); // make sure version number is initialised
|
|
// coverity[forward_null : FALSE] - uncompressed_table has been checked so can't be null
|
|
// coverity[checked_return : FALSE] - we test e later
|
|
e.test(lz4::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
e.error(E_BADSCHEME);
|
|
diff --git a/gfx/graphite2/src/GlyphCache.cpp b/gfx/graphite2/src/GlyphCache.cpp
|
|
--- a/gfx/graphite2/src/GlyphCache.cpp
|
|
+++ b/gfx/graphite2/src/GlyphCache.cpp
|
|
@@ -111,18 +111,20 @@ private:
|
|
_num_glyphs_attributes,
|
|
_num_attrs; // number of glyph attributes per glyph
|
|
};
|
|
|
|
|
|
|
|
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),
|
|
+ _glyphs(_glyph_loader && *_glyph_loader && _glyph_loader->num_glyphs()
|
|
+ ? grzeroalloc<const GlyphFace *>(_glyph_loader->num_glyphs()) : 0),
|
|
+ _boxes(_glyph_loader && _glyph_loader->has_boxes() && _glyph_loader->num_glyphs()
|
|
+ ? 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];
|
|
@@ -139,17 +141,17 @@ GlyphCache::GlyphCache(const Face & face
|
|
for (uint16 gid = 1; loaded && gid != _num_glyphs; ++gid)
|
|
_glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid], &numsubs);
|
|
|
|
if (!loaded)
|
|
{
|
|
_glyphs[0] = 0;
|
|
delete [] glyphs;
|
|
}
|
|
- else if (numsubs > 0)
|
|
+ else if (numsubs > 0 && _boxes)
|
|
{
|
|
GlyphBox * boxes = (GlyphBox *)gralloc<char>(_num_glyphs * sizeof(GlyphBox) + numsubs * 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]);
|
|
@@ -204,16 +206,18 @@ GlyphCache::~GlyphCache()
|
|
free(_boxes[0]);
|
|
free(_boxes);
|
|
}
|
|
delete _glyph_loader;
|
|
}
|
|
|
|
const GlyphFace *GlyphCache::glyph(unsigned short glyphid) const //result may be changed by subsequent call with a different glyphid
|
|
{
|
|
+ if (glyphid >= numGlyphs())
|
|
+ return _glyphs[0];
|
|
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, &numsubs);
|
|
if (!p)
|
|
{
|
|
@@ -280,26 +284,27 @@ GlyphCache::Loader::Loader(const Face &
|
|
_long_fmt = flags & 1;
|
|
int tmpnumgattrs = (m_pGloc.size()
|
|
- (p - m_pGloc)
|
|
- sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0))
|
|
/ (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1;
|
|
|
|
if (version >= 0x00020000 || tmpnumgattrs < 0 || tmpnumgattrs > 65535
|
|
|| _num_attrs == 0 || _num_attrs > 0x3000 // is this hard limit appropriate?
|
|
- || _num_glyphs_graphics > tmpnumgattrs)
|
|
+ || _num_glyphs_graphics > tmpnumgattrs
|
|
+ || m_pGlat.size() < 4)
|
|
{
|
|
_head = Face::Table();
|
|
return;
|
|
}
|
|
|
|
_num_glyphs_attributes = static_cast<unsigned short>(tmpnumgattrs);
|
|
p = m_pGlat;
|
|
version = be::read<uint32>(p);
|
|
- if (version >= 0x00040000) // reject Glat tables that are too new
|
|
+ if (version >= 0x00040000 || (version >= 0x00030000 && m_pGlat.size() < 8)) // reject Glat tables that are too new
|
|
{
|
|
_head = Face::Table();
|
|
return;
|
|
}
|
|
else if (version >= 0x00030000)
|
|
{
|
|
unsigned int glatflags = be::read<uint32>(p);
|
|
_has_boxes = glatflags & 1;
|
|
@@ -381,22 +386,24 @@ const GlyphFace * GlyphCache::Loader::re
|
|
}
|
|
else
|
|
{
|
|
be::skip<uint16>(gloc, glyphid);
|
|
glocs = be::read<uint16>(gloc);
|
|
gloce = be::peek<uint16>(gloc);
|
|
}
|
|
|
|
- if (glocs >= m_pGlat.size() || gloce > m_pGlat.size())
|
|
+ if (glocs >= m_pGlat.size() - 1 || gloce > m_pGlat.size())
|
|
return 0;
|
|
|
|
const uint32 glat_version = be::peek<uint32>(m_pGlat);
|
|
- if (glat_version == 0x00030000)
|
|
+ if (glat_version >= 0x00030000)
|
|
{
|
|
+ if (glocs >= gloce)
|
|
+ return 0;
|
|
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;
|
|
}
|
|
@@ -449,29 +456,31 @@ GlyphBox * GlyphCache::Loader::read_box(
|
|
}
|
|
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())
|
|
+ if (gloce > m_pGlat.size() || glocs + 6 >= gloce)
|
|
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);
|
|
+ if (glocs + 6 + num * 8 >= gloce)
|
|
+ return 0;
|
|
|
|
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));
|
|
diff --git a/gfx/graphite2/src/GlyphFace.cpp b/gfx/graphite2/src/GlyphFace.cpp
|
|
--- a/gfx/graphite2/src/GlyphFace.cpp
|
|
+++ b/gfx/graphite2/src/GlyphFace.cpp
|
|
@@ -24,25 +24,25 @@ Mozilla Public License (http://mozilla.o
|
|
License, as published by the Free Software Foundation, either version 2
|
|
of the License or (at your option) any later version.
|
|
*/
|
|
#include "inc/GlyphFace.h"
|
|
|
|
|
|
using namespace graphite2;
|
|
|
|
-uint16 GlyphFace::getMetric(uint8 metric) const
|
|
+int32 GlyphFace::getMetric(uint8 metric) const
|
|
{
|
|
switch (metrics(metric))
|
|
{
|
|
- case kgmetLsb : return static_cast<uint16>(m_bbox.bl.x);
|
|
- case kgmetRsb : return static_cast<uint16>(m_advance.x - m_bbox.tr.x);
|
|
- case kgmetBbTop : return static_cast<uint16>(m_bbox.tr.y);
|
|
- case kgmetBbBottom : return static_cast<uint16>(m_bbox.bl.y);
|
|
- case kgmetBbLeft : return static_cast<uint16>(m_bbox.bl.x);
|
|
- case kgmetBbRight : return static_cast<uint16>(m_bbox.tr.x);
|
|
- case kgmetBbHeight : return static_cast<uint16>(m_bbox.tr.y - m_bbox.bl.y);
|
|
- case kgmetBbWidth : return static_cast<uint16>(m_bbox.tr.x - m_bbox.bl.x);
|
|
- case kgmetAdvWidth : return static_cast<uint16>(m_advance.x);
|
|
- case kgmetAdvHeight : return static_cast<uint16>(m_advance.y);
|
|
+ case kgmetLsb : return m_bbox.bl.x;
|
|
+ case kgmetRsb : return m_advance.x - m_bbox.tr.x;
|
|
+ case kgmetBbTop : return m_bbox.tr.y;
|
|
+ case kgmetBbBottom : return m_bbox.bl.y;
|
|
+ case kgmetBbLeft : return m_bbox.bl.x;
|
|
+ case kgmetBbRight : return m_bbox.tr.x;
|
|
+ case kgmetBbHeight : return m_bbox.tr.y - m_bbox.bl.y;
|
|
+ case kgmetBbWidth : return m_bbox.tr.x - m_bbox.bl.x;
|
|
+ case kgmetAdvWidth : return m_advance.x;
|
|
+ case kgmetAdvHeight : return m_advance.y;
|
|
default : return 0;
|
|
}
|
|
}
|
|
diff --git a/gfx/graphite2/src/Justifier.cpp b/gfx/graphite2/src/Justifier.cpp
|
|
--- a/gfx/graphite2/src/Justifier.cpp
|
|
+++ b/gfx/graphite2/src/Justifier.cpp
|
|
@@ -95,62 +95,63 @@ float Segment::justify(Slot *pSlot, cons
|
|
|
|
end = pLast->nextSibling();
|
|
pFirst = pFirst->nextSibling();
|
|
|
|
int icount = 0;
|
|
int numLevels = silf()->numJustLevels();
|
|
if (!numLevels)
|
|
{
|
|
- for (s = pSlot; s != end; s = s->next())
|
|
+ for (s = pSlot; s && s != end; s = s->nextSibling())
|
|
{
|
|
CharInfo *c = charinfo(s->before());
|
|
if (isWhitespace(c->unicodeChar()))
|
|
{
|
|
s->setJustify(this, 0, 3, 1);
|
|
s->setJustify(this, 0, 2, 1);
|
|
s->setJustify(this, 0, 0, -1);
|
|
++icount;
|
|
}
|
|
}
|
|
if (!icount)
|
|
{
|
|
- for (s = pSlot; s != end; s = s->nextSibling())
|
|
+ for (s = pSlot; s && s != end; s = s->nextSibling())
|
|
{
|
|
s->setJustify(this, 0, 3, 1);
|
|
s->setJustify(this, 0, 2, 1);
|
|
s->setJustify(this, 0, 0, -1);
|
|
}
|
|
}
|
|
++numLevels;
|
|
}
|
|
|
|
Vector<JustifyTotal> stats(numLevels);
|
|
- for (s = pFirst; s != end; s = s->nextSibling())
|
|
+ for (s = pFirst; s && s != end; s = s->nextSibling())
|
|
{
|
|
float w = s->origin().x / scale + s->advance() - base;
|
|
if (w > currWidth) currWidth = w;
|
|
for (int j = 0; j < numLevels; ++j)
|
|
stats[j].accumulate(s, this, j);
|
|
s->just(0);
|
|
}
|
|
|
|
for (int i = (width < 0.0f) ? -1 : numLevels - 1; i >= 0; --i)
|
|
{
|
|
float diff;
|
|
float error = 0.;
|
|
float diffpw;
|
|
int tWeight = stats[i].weight();
|
|
+ if (tWeight == 0) continue;
|
|
|
|
do {
|
|
error = 0.;
|
|
diff = width - currWidth;
|
|
diffpw = diff / tWeight;
|
|
tWeight = 0;
|
|
- for (s = pFirst; s != end; s = s->nextSibling()) // don't include final glyph
|
|
+ for (s = pFirst; s && s != end; s = s->nextSibling()) // don't include final glyph
|
|
{
|
|
int w = s->getJustify(this, i, 3);
|
|
float pref = diffpw * w + error;
|
|
int step = s->getJustify(this, i, 2);
|
|
if (!step) step = 1; // handle lazy font developers
|
|
if (pref > 0)
|
|
{
|
|
float max = uint16(s->getJustify(this, i, 0));
|
|
diff --git a/gfx/graphite2/src/NameTable.cpp b/gfx/graphite2/src/NameTable.cpp
|
|
--- a/gfx/graphite2/src/NameTable.cpp
|
|
+++ b/gfx/graphite2/src/NameTable.cpp
|
|
@@ -42,25 +42,26 @@ NameTable::NameTable(const void* data, s
|
|
memcpy(pdata, data, length);
|
|
m_table = reinterpret_cast<const TtfUtil::Sfnt::FontNames*>(pdata);
|
|
|
|
if ((length > sizeof(TtfUtil::Sfnt::FontNames)) &&
|
|
(length > sizeof(TtfUtil::Sfnt::FontNames) +
|
|
sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1)))
|
|
{
|
|
uint16 offset = be::swap<uint16>(m_table->string_offset);
|
|
- m_nameData = reinterpret_cast<const uint8*>(pdata) + offset;
|
|
- setPlatformEncoding(platformId, encodingID);
|
|
- m_nameDataLength = length - offset;
|
|
+ if (offset < length)
|
|
+ {
|
|
+ m_nameData = reinterpret_cast<const uint8*>(pdata) + offset;
|
|
+ setPlatformEncoding(platformId, encodingID);
|
|
+ m_nameDataLength = length - offset;
|
|
+ return;
|
|
+ }
|
|
}
|
|
- else
|
|
- {
|
|
- free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table));
|
|
- m_table = NULL;
|
|
- }
|
|
+ free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table));
|
|
+ m_table = NULL;
|
|
}
|
|
|
|
uint16 NameTable::setPlatformEncoding(uint16 platformId, uint16 encodingID)
|
|
{
|
|
if (!m_nameData) return 0;
|
|
uint16 i = 0;
|
|
uint16 count = be::swap<uint16>(m_table->count);
|
|
for (; i < count; i++)
|
|
@@ -139,28 +140,36 @@ void* NameTable::getName(uint16& languag
|
|
uint16 offset = be::swap<uint16>(nameRecord.offset);
|
|
if(offset + utf16Length > m_nameDataLength)
|
|
{
|
|
languageId = 0;
|
|
length = 0;
|
|
return NULL;
|
|
}
|
|
utf16Length >>= 1; // in utf16 units
|
|
- utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length);
|
|
+ utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length + 1);
|
|
if (!utf16Name)
|
|
{
|
|
languageId = 0;
|
|
length = 0;
|
|
return NULL;
|
|
}
|
|
const uint8* pName = m_nameData + offset;
|
|
for (size_t i = 0; i < utf16Length; i++)
|
|
{
|
|
utf16Name[i] = be::read<uint16>(pName);
|
|
}
|
|
+ utf16Name[utf16Length] = 0;
|
|
+ if (!utf16::validate(utf16Name, utf16Name + utf16Length))
|
|
+ {
|
|
+ free(utf16Name);
|
|
+ languageId = 0;
|
|
+ length = 0;
|
|
+ return NULL;
|
|
+ }
|
|
switch (enc)
|
|
{
|
|
case gr_utf8:
|
|
{
|
|
utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1);
|
|
if (!uniBuffer)
|
|
{
|
|
free(utf16Name);
|
|
diff --git a/gfx/graphite2/src/Pass.cpp b/gfx/graphite2/src/Pass.cpp
|
|
--- a/gfx/graphite2/src/Pass.cpp
|
|
+++ b/gfx/graphite2/src/Pass.cpp
|
|
@@ -96,17 +96,17 @@ bool Pass::readPass(const byte * const p
|
|
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
|
|
const byte flags = be::read<byte>(p);
|
|
if (e.test((flags & 0x1f) &&
|
|
- (pt < PASS_TYPE_POSITIONING || !m_silf->aCollision() || !face.glyphs().hasBoxes()),
|
|
+ (pt < PASS_TYPE_POSITIONING || !m_silf->aCollision() || !face.glyphs().hasBoxes() || !(m_silf->flags() & 0x20)),
|
|
E_BADCOLLISIONPASS))
|
|
return face.error(e);
|
|
m_numCollRuns = flags & 0x7;
|
|
m_kernColls = (flags >> 3) & 0x3;
|
|
m_isReverseDir = (flags >> 5) & 0x1;
|
|
m_iMaxLoop = be::read<byte>(p);
|
|
if (m_iMaxLoop < 1) m_iMaxLoop = 1;
|
|
be::skip<byte>(p,2); // skip maxContext & maxBackup
|
|
@@ -226,17 +226,21 @@ bool Pass::readRules(const byte * rule_m
|
|
// Load rules.
|
|
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];
|
|
- const size_t prog_pool_sz = vm::Machine::Code::estimateCodeDataOut(ac_end - ac_data + rc_end - rc_data);
|
|
+ int totalSlots = 0;
|
|
+ const uint16 *tsort = sort_key;
|
|
+ for (int i = 0; i < m_numRules; ++i)
|
|
+ totalSlots += be::peek<uint16>(--tsort);
|
|
+ const size_t prog_pool_sz = vm::Machine::Code::estimateCodeDataOut(ac_end - ac_data + rc_end - rc_data, 2 * m_numRules, totalSlots);
|
|
m_progs = gralloc<byte>(prog_pool_sz);
|
|
byte * prog_pool_free = m_progs,
|
|
* prog_pool_end = m_progs + prog_pool_sz;
|
|
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; r >= m_rules; --n, --r, ac_end = ac_begin, rc_end = rc_begin)
|
|
{
|
|
@@ -249,17 +253,17 @@ bool Pass::readRules(const byte * rule_m
|
|
if (r->sort > 63 || r->preContext >= r->sort || r->preContext > m_maxPreCtxt || r->preContext < m_minPreCtxt)
|
|
return false;
|
|
ac_begin = ac_data + be::peek<uint16>(--o_action);
|
|
--o_constraint;
|
|
rc_begin = be::peek<uint16>(o_constraint) ? rc_data + be::peek<uint16>(o_constraint) : rc_end;
|
|
|
|
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
|
|
- || vm::Machine::Code::estimateCodeDataOut(ac_end - ac_begin + rc_end - rc_begin) > size_t(prog_pool_end - prog_pool_free))
|
|
+ || vm::Machine::Code::estimateCodeDataOut(ac_end - ac_begin + rc_end - rc_begin, 2, r->sort) > size_t(prog_pool_end - prog_pool_free))
|
|
return false;
|
|
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)
|
|
|| e.test(r->constraint->status() != Code::loaded, r->constraint->status() + E_CODEFAILURE)
|
|
|| e.test(!r->constraint->immutable(), E_MUTABLECCODE))
|
|
@@ -330,17 +334,17 @@ bool Pass::readStates(const byte * start
|
|
|
|
// load state transition table.
|
|
for (uint16 * t = m_transitions,
|
|
* const t_end = t + m_numTransition*m_numColumns; t != t_end; ++t)
|
|
{
|
|
*t = be::read<uint16>(states);
|
|
if (e.test(*t >= m_numStates, E_BADSTATE))
|
|
{
|
|
- face.error_context((face.error_context() & 0xFFFF00) + EC_ATRANS + (((t - m_transitions) / m_numColumns) << 24));
|
|
+ face.error_context((face.error_context() & 0xFFFF00) + EC_ATRANS + (((t - m_transitions) / m_numColumns) << 8));
|
|
return face.error(e);
|
|
}
|
|
}
|
|
|
|
State * s = m_states,
|
|
* const success_begin = m_states + m_numStates - m_numSuccess;
|
|
const RuleEntry * rule_map_end = m_ruleMap + be::peek<uint16>(o_rule_map + m_numSuccess*sizeof(uint16));
|
|
for (size_t n = m_numStates; n; --n, ++s)
|
|
@@ -351,17 +355,18 @@ bool Pass::readStates(const byte * start
|
|
if (e.test(begin >= rule_map_end || end > rule_map_end || begin > end, E_BADRULEMAPPING))
|
|
{
|
|
face.error_context((face.error_context() & 0xFFFF00) + EC_ARULEMAP + (n << 24));
|
|
return face.error(e);
|
|
}
|
|
s->rules = begin;
|
|
s->rules_end = (end - begin <= FiniteStateMachine::MAX_RULES)? end :
|
|
begin + FiniteStateMachine::MAX_RULES;
|
|
- qsort(begin, end - begin, sizeof(RuleEntry), &cmpRuleEntry);
|
|
+ if (begin) // keep UBSan happy can't call qsort with null begin
|
|
+ qsort(begin, end - begin, sizeof(RuleEntry), &cmpRuleEntry);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Pass::readRanges(const byte * ranges, size_t num_ranges, Error &e)
|
|
{
|
|
m_cols = gralloc<uint16>(m_numGlyphs);
|
|
@@ -449,19 +454,19 @@ bool Pass::runFSM(FiniteStateMachine& fs
|
|
if (fsm.slots.context() < m_minPreCtxt)
|
|
return false;
|
|
|
|
uint16 state = m_startStates[m_maxPreCtxt - fsm.slots.context()];
|
|
uint8 free_slots = SlotMap::MAX_SLOTS;
|
|
do
|
|
{
|
|
fsm.slots.pushSlot(slot);
|
|
- if (--free_slots == 0
|
|
- || slot->gid() >= m_numGlyphs
|
|
+ if (slot->gid() >= m_numGlyphs
|
|
|| m_cols[slot->gid()] == 0xffffU
|
|
+ || --free_slots == 0
|
|
|| state >= m_numTransition)
|
|
return free_slots != 0;
|
|
|
|
const uint16 * transitions = m_transitions + state*m_numColumns;
|
|
state = transitions[m_cols[slot->gid()]];
|
|
if (state >= m_successStart)
|
|
fsm.rules.accumulate_rules(m_states[state]);
|
|
|
|
@@ -627,37 +632,40 @@ bool Pass::testPassConstraint(Machine &
|
|
}
|
|
|
|
|
|
bool Pass::testConstraint(const Rule & r, Machine & m) const
|
|
{
|
|
const uint16 curr_context = m.slotMap().context();
|
|
if (unsigned(r.sort - r.preContext) > m.slotMap().size() - curr_context
|
|
|| curr_context - r.preContext < 0) return false;
|
|
+
|
|
+ vm::slotref * map = m.slotMap().begin() + curr_context - r.preContext;
|
|
+ if (map[r.sort - 1] == 0)
|
|
+ return false;
|
|
+
|
|
if (!*r.constraint) return true;
|
|
assert(r.constraint->constraint());
|
|
-
|
|
- vm::slotref * map = m.slotMap().begin() + curr_context - r.preContext;
|
|
for (int n = r.sort; n && map; --n, ++map)
|
|
{
|
|
if (!*map) continue;
|
|
const int32 ret = r.constraint->run(m, map);
|
|
if (!ret || m.status() != Machine::finished)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void SlotMap::collectGarbage(Slot * &aSlot)
|
|
{
|
|
for(Slot **s = begin(), *const *const se = end() - 1; s != se; ++s) {
|
|
Slot *& slot = *s;
|
|
- if(slot->isDeleted() || slot->isCopied())
|
|
+ if(slot && (slot->isDeleted() || slot->isCopied()))
|
|
{
|
|
if (slot == aSlot)
|
|
aSlot = slot->prev() ? slot->prev() : slot->next();
|
|
segment.freeSlot(slot);
|
|
}
|
|
}
|
|
}
|
|
|
|
@@ -848,17 +856,16 @@ bool Pass::collisionShift(Segment *seg,
|
|
}
|
|
}
|
|
}
|
|
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)
|
|
@@ -871,17 +878,17 @@ bool Pass::collisionKern(Segment *seg, i
|
|
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);
|
|
+ resolveKern(seg, s, start, 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)
|
|
@@ -1010,17 +1017,17 @@ bool Pass::resolveCollisions(Segment *se
|
|
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 Pass::resolveKern(Segment *seg, Slot *slotFix, GR_MAYBE_UNUSED Slot *start, 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())
|
|
@@ -1030,16 +1037,17 @@ float Pass::resolveKern(Segment *seg, Sl
|
|
|
|
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;
|
|
+ KernCollider coll(dbgout);
|
|
|
|
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());
|
|
diff --git a/gfx/graphite2/src/Segment.cpp b/gfx/graphite2/src/Segment.cpp
|
|
--- a/gfx/graphite2/src/Segment.cpp
|
|
+++ b/gfx/graphite2/src/Segment.cpp
|
|
@@ -419,16 +419,19 @@ Position Segment::positionSlots(const Fo
|
|
reverseSlots();
|
|
temp = iStart;
|
|
iStart = iEnd;
|
|
iEnd = temp;
|
|
}
|
|
if (!iStart) iStart = m_first;
|
|
if (!iEnd) iEnd = m_last;
|
|
|
|
+ if (!iStart || !iEnd) // only true for empty segments
|
|
+ return currpos;
|
|
+
|
|
if (isRtl)
|
|
{
|
|
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, isRtl, isFinal);
|
|
}
|
|
}
|
|
@@ -526,11 +529,14 @@ void Segment::doMirror(uint16 aMirror)
|
|
}
|
|
|
|
bool Segment::initCollisions()
|
|
{
|
|
m_collisions = grzeroalloc<SlotCollision>(slotCount());
|
|
if (!m_collisions) return false;
|
|
|
|
for (Slot *p = m_first; p; p = p->next())
|
|
- ::new (collisionInfo(p)) SlotCollision(this, p);
|
|
+ if (p->index() < slotCount())
|
|
+ ::new (collisionInfo(p)) SlotCollision(this, p);
|
|
+ else
|
|
+ return false;
|
|
return true;
|
|
}
|
|
diff --git a/gfx/graphite2/src/Silf.cpp b/gfx/graphite2/src/Silf.cpp
|
|
--- a/gfx/graphite2/src/Silf.cpp
|
|
+++ b/gfx/graphite2/src/Silf.cpp
|
|
@@ -350,20 +350,20 @@ uint16 Silf::getClassGlyph(uint16 cid, u
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi) const
|
|
{
|
|
assert(seg != 0);
|
|
- SlotMap map(*seg, m_dir);
|
|
+ unsigned int maxSize = seg->slotCount() * MAX_SEG_GROWTH_FACTOR;
|
|
+ SlotMap map(*seg, m_dir, maxSize);
|
|
FiniteStateMachine fsm(map, seg->getFace()->logger());
|
|
vm::Machine m(map);
|
|
- unsigned int initSize = seg->slotCount();
|
|
uint8 lbidi = m_bPass;
|
|
#if !defined GRAPHITE2_NTRACING
|
|
json * const dbgout = seg->getFace()->logger();
|
|
#endif
|
|
|
|
if (lastPass == 0)
|
|
{
|
|
if (firstPass == lastPass && lbidi == 0xFF)
|
|
@@ -419,13 +419,13 @@ bool Silf::runGraphite(Segment *seg, uin
|
|
|
|
// test whether to reorder, prepare for positioning
|
|
bool reverse = (lbidi == 0xFF) && (seg->currdir() != ((m_dir & 1) ^ m_passes[i].reverseDir()));
|
|
if ((i >= 32 || (seg->passBits() & (1 << i)) == 0 || m_passes[i].collisionLoops())
|
|
&& !m_passes[i].runGraphite(m, fsm, reverse))
|
|
return false;
|
|
// only subsitution passes can change segment length, cached subsegments are short for their text
|
|
if (m.status() != vm::Machine::finished
|
|
- || (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize))
|
|
+ || (seg->slotCount() && seg->slotCount() > maxSize))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
diff --git a/gfx/graphite2/src/Slot.cpp b/gfx/graphite2/src/Slot.cpp
|
|
--- a/gfx/graphite2/src/Slot.cpp
|
|
+++ b/gfx/graphite2/src/Slot.cpp
|
|
@@ -80,20 +80,20 @@ void Slot::set(const Slot & orig, int ch
|
|
|
|
void Slot::update(int /*numGrSlots*/, int numCharInfo, Position &relpos)
|
|
{
|
|
m_before += numCharInfo;
|
|
m_after += numCharInfo;
|
|
m_position = m_position + relpos;
|
|
}
|
|
|
|
-Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal)
|
|
+Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal, int depth)
|
|
{
|
|
SlotCollision *coll = NULL;
|
|
- if (attrLevel && m_attLevel > attrLevel) return Position(0, 0);
|
|
+ if (depth > 100 || (attrLevel && m_attLevel > attrLevel)) return Position(0, 0);
|
|
float scale = font ? font->scale() : 1.0f;
|
|
Position shift(m_shift.x * (rtl * -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) || rtl)
|
|
shift = shift + collshift;
|
|
@@ -128,23 +128,23 @@ Position Slot::finalise(const Segment *s
|
|
if (glyphFace)
|
|
{
|
|
Rect ourBbox = glyphFace->theBBox() * scale + m_position;
|
|
bbox = bbox.widen(ourBbox);
|
|
}
|
|
|
|
if (m_child && m_child != this && m_child->attachedTo() == this)
|
|
{
|
|
- Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, rtl, isFinal);
|
|
+ Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, rtl, isFinal, depth + 1);
|
|
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, rtl, isFinal);
|
|
+ Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, rtl, isFinal, depth + 1);
|
|
if (tRes.x > res.x) res = tRes;
|
|
}
|
|
|
|
if (!m_parent && clusterMin < base.x)
|
|
{
|
|
Position adj = Position(m_position.x - clusterMin, 0.);
|
|
res += adj;
|
|
m_position += adj;
|
|
@@ -160,35 +160,35 @@ int32 Slot::clusterMetric(const Segment
|
|
return 0;
|
|
Rect bbox = seg->theGlyphBBoxTemporary(glyph());
|
|
float clusterMin = 0.;
|
|
Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin, rtl, false);
|
|
|
|
switch (metrics(metric))
|
|
{
|
|
case kgmetLsb :
|
|
- return static_cast<uint32>(bbox.bl.x);
|
|
+ return bbox.bl.x;
|
|
case kgmetRsb :
|
|
- return static_cast<uint32>(res.x - bbox.tr.x);
|
|
+ return res.x - bbox.tr.x;
|
|
case kgmetBbTop :
|
|
- return static_cast<uint32>(bbox.tr.y);
|
|
+ return bbox.tr.y;
|
|
case kgmetBbBottom :
|
|
- return static_cast<uint32>(bbox.bl.y);
|
|
+ return bbox.bl.y;
|
|
case kgmetBbLeft :
|
|
- return static_cast<uint32>(bbox.bl.x);
|
|
+ return bbox.bl.x;
|
|
case kgmetBbRight :
|
|
- return static_cast<uint32>(bbox.tr.x);
|
|
+ return bbox.tr.x;
|
|
case kgmetBbWidth :
|
|
- return static_cast<uint32>(bbox.tr.x - bbox.bl.x);
|
|
+ return bbox.tr.x - bbox.bl.x;
|
|
case kgmetBbHeight :
|
|
- return static_cast<uint32>(bbox.tr.y - bbox.bl.y);
|
|
+ return bbox.tr.y - bbox.bl.y;
|
|
case kgmetAdvWidth :
|
|
- return static_cast<uint32>(res.x);
|
|
+ return res.x;
|
|
case kgmetAdvHeight :
|
|
- return static_cast<uint32>(res.y);
|
|
+ return res.y;
|
|
default :
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#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
|
|
@@ -290,19 +290,32 @@ void Slot::setAttr(Segment *seg, attrCod
|
|
case gr_slatAdvX : m_advance.x = value; break;
|
|
case gr_slatAdvY : m_advance.y = value; break;
|
|
case gr_slatAttTo :
|
|
{
|
|
const uint16 idx = uint16(value);
|
|
if (idx < map.size() && map[idx])
|
|
{
|
|
Slot *other = map[idx];
|
|
- if (other == this || other == m_parent) break;
|
|
- if (m_parent) m_parent->removeChild(this);
|
|
- if (!other->isChildOf(this) && other->child(this))
|
|
+ if (other == this || other == m_parent || other->isCopied()) break;
|
|
+ if (m_parent) { m_parent->removeChild(this); attachTo(NULL); }
|
|
+ Slot *pOther = other;
|
|
+ int count = 0;
|
|
+ bool foundOther = false;
|
|
+ while (pOther)
|
|
+ {
|
|
+ ++count;
|
|
+ if (pOther == this) foundOther = true;
|
|
+ pOther = pOther->attachedTo();
|
|
+ }
|
|
+ for (pOther = m_child; pOther; pOther = pOther->m_child)
|
|
+ ++count;
|
|
+ for (pOther = m_sibling; pOther; pOther = pOther->m_sibling)
|
|
+ ++count;
|
|
+ if (count < 100 && !foundOther && other->child(this))
|
|
{
|
|
attachTo(other);
|
|
if ((map.dir() != 0) ^ (idx > subindex))
|
|
m_with = Position(advance(), 0);
|
|
else // normal match to previous root
|
|
m_attach = Position(other->advance(), 0);
|
|
}
|
|
}
|
|
@@ -416,41 +429,34 @@ bool Slot::sibling(Slot *ap)
|
|
m_sibling = ap;
|
|
else
|
|
return m_sibling->sibling(ap);
|
|
return true;
|
|
}
|
|
|
|
bool Slot::removeChild(Slot *ap)
|
|
{
|
|
- if (this == ap || !m_child) return false;
|
|
+ if (this == ap || !m_child || !ap) return false;
|
|
else if (ap == m_child)
|
|
{
|
|
Slot *nSibling = m_child->nextSibling();
|
|
- m_child->removeSibling(nSibling);
|
|
+ m_child->nextSibling(NULL);
|
|
m_child = nSibling;
|
|
return true;
|
|
}
|
|
- else
|
|
- return m_child->removeSibling(ap);
|
|
- return true;
|
|
-}
|
|
-
|
|
-bool Slot::removeSibling(Slot *ap)
|
|
-{
|
|
- if (this == ap || !m_sibling) return false;
|
|
- else if (ap == m_sibling)
|
|
+ for (Slot *p = m_child; p; p = p->m_sibling)
|
|
{
|
|
- m_sibling = m_sibling->nextSibling();
|
|
- if (m_sibling) ap->removeSibling(m_sibling);
|
|
- return true;
|
|
+ if (p->m_sibling && p->m_sibling == ap)
|
|
+ {
|
|
+ p->m_sibling = p->m_sibling->m_sibling;
|
|
+ ap->nextSibling(NULL);
|
|
+ return true;
|
|
+ }
|
|
}
|
|
- else
|
|
- return m_sibling->removeSibling(ap);
|
|
- return true;
|
|
+ return false;
|
|
}
|
|
|
|
void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph)
|
|
{
|
|
m_glyphid = glyphid;
|
|
m_bidiCls = -1;
|
|
if (!theGlyph)
|
|
{
|
|
@@ -475,21 +481,23 @@ void Slot::setGlyph(Segment *seg, uint16
|
|
if (seg->silf()->aPassBits())
|
|
{
|
|
seg->mergePassBits(theGlyph->attrs()[seg->silf()->aPassBits()]);
|
|
if (seg->silf()->numPasses() > 16)
|
|
seg->mergePassBits(theGlyph->attrs()[seg->silf()->aPassBits()+1] << 16);
|
|
}
|
|
}
|
|
|
|
-void Slot::floodShift(Position adj)
|
|
+void Slot::floodShift(Position adj, int depth)
|
|
{
|
|
+ if (depth > 100)
|
|
+ return;
|
|
m_position += adj;
|
|
- if (m_child) m_child->floodShift(adj);
|
|
- if (m_sibling) m_sibling->floodShift(adj);
|
|
+ if (m_child) m_child->floodShift(adj, depth + 1);
|
|
+ if (m_sibling) m_sibling->floodShift(adj, depth + 1);
|
|
}
|
|
|
|
void SlotJustify::LoadSlot(const Slot *s, const Segment *seg)
|
|
{
|
|
for (int i = seg->silf()->numJustLevels() - 1; i >= 0; --i)
|
|
{
|
|
Justinfo *justs = seg->silf()->justAttrs() + i;
|
|
int16 *v = values + i * NUMJUSTPARAMS;
|
|
@@ -514,15 +522,14 @@ Slot * Slot::nextInCluster(const Slot *s
|
|
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);
|
|
+ for (Slot *p = m_parent; p; p = p->m_parent)
|
|
+ if (p == base)
|
|
+ return true;
|
|
+ return false;
|
|
}
|
|
+
|
|
diff --git a/gfx/graphite2/src/TtfUtil.cpp b/gfx/graphite2/src/TtfUtil.cpp
|
|
--- a/gfx/graphite2/src/TtfUtil.cpp
|
|
+++ b/gfx/graphite2/src/TtfUtil.cpp
|
|
@@ -891,25 +891,27 @@ const void * FindCmapSubtable(const void
|
|
----------------------------------------------------------------------------------------------*/
|
|
bool CheckCmapSubtable4(const void * pCmapSubtable4, const void * pCmapEnd /*, unsigned int maxgid*/)
|
|
{
|
|
size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable4;
|
|
if (!pCmapSubtable4) return false;
|
|
const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable4);
|
|
// 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;
|
|
+ if (table_len < sizeof(*pTable) || be::swap(pTable->format) != 4) return false;
|
|
const Sfnt::CmapSubTableFormat4 * pTable4 = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtable4);
|
|
+ if (table_len < sizeof(*pTable4))
|
|
+ return false;
|
|
uint16 length = be::swap(pTable4->length);
|
|
if (length > table_len)
|
|
return false;
|
|
if (length < sizeof(Sfnt::CmapSubTableFormat4))
|
|
return false;
|
|
uint16 nRanges = be::swap(pTable4->seg_count_x2) >> 1;
|
|
- if (length < sizeof(Sfnt::CmapSubTableFormat4) + 4 * nRanges * sizeof(uint16))
|
|
+ if (!nRanges || length < sizeof(Sfnt::CmapSubTableFormat4) + 4 * nRanges * sizeof(uint16))
|
|
return false;
|
|
// check last range is properly terminated
|
|
uint16 chEnd = be::peek<uint16>(pTable4->end_code + nRanges - 1);
|
|
if (chEnd != 0xFFFF)
|
|
return false;
|
|
#if 0
|
|
int lastend = -1;
|
|
for (int i = 0; i < nRanges; ++i)
|
|
@@ -999,17 +1001,17 @@ gid16 CmapSubtable4Lookup(const void * p
|
|
uint16 idRangeOffset = be::peek<uint16>(pMid += nSeg);
|
|
|
|
if (idRangeOffset == 0)
|
|
return (uint16)(idDelta + nUnicodeId); // must use modulus 2^16
|
|
|
|
// Look up value in glyphIdArray
|
|
const ptrdiff_t offset = (nUnicodeId - chStart) + (idRangeOffset >> 1) +
|
|
(pMid - reinterpret_cast<const uint16 *>(pTable));
|
|
- if (offset * 2 >= be::swap<uint16>(pTable->length))
|
|
+ if (offset * 2 + 1 >= be::swap<uint16>(pTable->length))
|
|
return 0;
|
|
gid16 nGlyphId = be::peek<uint16>(reinterpret_cast<const uint16 *>(pTable)+offset);
|
|
// If this value is 0, return 0. Else add the idDelta
|
|
return nGlyphId ? nGlyphId + idDelta : 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
@@ -1081,19 +1083,21 @@ unsigned int CmapSubtable4NextCodepoint(
|
|
/*----------------------------------------------------------------------------------------------
|
|
Check the Microsoft UCS-4 subtable for expected values.
|
|
----------------------------------------------------------------------------------------------*/
|
|
bool CheckCmapSubtable12(const void *pCmapSubtable12, const void *pCmapEnd /*, unsigned int maxgid*/)
|
|
{
|
|
size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable12;
|
|
if (!pCmapSubtable12) return false;
|
|
const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable12);
|
|
- if (be::swap(pTable->format) != 12)
|
|
+ if (table_len < sizeof(*pTable) || be::swap(pTable->format) != 12)
|
|
return false;
|
|
const Sfnt::CmapSubTableFormat12 * pTable12 = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmapSubtable12);
|
|
+ if (table_len < sizeof(*pTable12))
|
|
+ return false;
|
|
uint32 length = be::swap(pTable12->length);
|
|
if (length > table_len)
|
|
return false;
|
|
if (length < sizeof(Sfnt::CmapSubTableFormat12))
|
|
return false;
|
|
uint32 num_groups = be::swap(pTable12->num_groups);
|
|
if (num_groups > 0x10000000 || length != (sizeof(Sfnt::CmapSubTableFormat12) + (num_groups - 1) * sizeof(uint32) * 3))
|
|
return false;
|
|
diff --git a/gfx/graphite2/src/inc/Code.h b/gfx/graphite2/src/inc/Code.h
|
|
--- a/gfx/graphite2/src/inc/Code.h
|
|
+++ b/gfx/graphite2/src/inc/Code.h
|
|
@@ -81,17 +81,17 @@ private:
|
|
_modify,
|
|
_delete;
|
|
mutable bool _own;
|
|
|
|
void release_buffers() throw ();
|
|
void failure(const status_t) throw();
|
|
|
|
public:
|
|
- static size_t estimateCodeDataOut(size_t num_bytecodes);
|
|
+ static size_t estimateCodeDataOut(size_t num_bytecodes, int nRules, int nSlots);
|
|
|
|
Code() throw();
|
|
Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
|
|
uint8 pre_context, uint16 rule_length, const Silf &, const Face &,
|
|
enum passtype pt, byte * * const _out = 0);
|
|
Code(const Machine::Code &) throw();
|
|
~Code() throw();
|
|
|
|
@@ -107,19 +107,21 @@ public:
|
|
void externalProgramMoved(ptrdiff_t) throw();
|
|
|
|
int32 run(Machine &m, slotref * & map) const;
|
|
|
|
CLASS_NEW_DELETE;
|
|
};
|
|
|
|
inline
|
|
-size_t Machine::Code::estimateCodeDataOut(size_t n_bc)
|
|
+size_t Machine::Code::estimateCodeDataOut(size_t n_bc, int nRules, int nSlots)
|
|
{
|
|
- return (n_bc + 1) * (sizeof(instr)+sizeof(byte));
|
|
+ // max is: all codes are instructions + 1 for each rule + max tempcopies
|
|
+ // allocate space for separate maximal code and data then merge them later
|
|
+ return (n_bc + nRules + nSlots) * sizeof(instr) + n_bc * sizeof(byte);
|
|
}
|
|
|
|
|
|
inline Machine::Code::Code() throw()
|
|
: _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0),
|
|
_status(loaded), _constraint(false), _modify(false), _delete(false),
|
|
_own(false)
|
|
{
|
|
diff --git a/gfx/graphite2/src/inc/Face.h b/gfx/graphite2/src/inc/Face.h
|
|
--- a/gfx/graphite2/src/inc/Face.h
|
|
+++ b/gfx/graphite2/src/inc/Face.h
|
|
@@ -82,17 +82,17 @@ public:
|
|
uint16 languageForLocale(const char * locale) const;
|
|
|
|
// Features
|
|
uint16 numFeatures() const;
|
|
const FeatureRef * featureById(uint32 id) const;
|
|
const FeatureRef * feature(uint16 index) const;
|
|
|
|
// Glyph related
|
|
- uint16 getGlyphMetric(uint16 gid, uint8 metric) const;
|
|
+ int32 getGlyphMetric(uint16 gid, uint8 metric) const;
|
|
uint16 findPseudo(uint32 uid) const;
|
|
|
|
// Errors
|
|
unsigned int error() const { return m_error; }
|
|
bool error(Error e) { m_error = e.error(); return false; }
|
|
unsigned int error_context() const { return m_error; }
|
|
void error_context(unsigned int errcntxt) { m_errcntxt = errcntxt; }
|
|
|
|
diff --git a/gfx/graphite2/src/inc/GlyphFace.h b/gfx/graphite2/src/inc/GlyphFace.h
|
|
--- a/gfx/graphite2/src/inc/GlyphFace.h
|
|
+++ b/gfx/graphite2/src/inc/GlyphFace.h
|
|
@@ -46,17 +46,17 @@ class GlyphFace
|
|
public:
|
|
GlyphFace();
|
|
template<typename I>
|
|
GlyphFace(const Rect & bbox, const Position & adv, I first, const I last);
|
|
|
|
const Position & theAdvance() const;
|
|
const Rect & theBBox() const { return m_bbox; }
|
|
const sparse & attrs() const { return m_attrs; }
|
|
- uint16 getMetric(uint8 metric) const;
|
|
+ int32 getMetric(uint8 metric) const;
|
|
|
|
CLASS_NEW_DELETE;
|
|
private:
|
|
Rect m_bbox; // bounding box metrics in design units
|
|
Position m_advance; // Advance width and height in design units
|
|
sparse m_attrs;
|
|
};
|
|
|
|
diff --git a/gfx/graphite2/src/inc/Machine.h b/gfx/graphite2/src/inc/Machine.h
|
|
--- a/gfx/graphite2/src/inc/Machine.h
|
|
+++ b/gfx/graphite2/src/inc/Machine.h
|
|
@@ -179,17 +179,17 @@ inline SlotMap& Machine::slotMap() const
|
|
return _map;
|
|
}
|
|
|
|
inline Machine::status_t Machine::status() const throw()
|
|
{
|
|
return _status;
|
|
}
|
|
|
|
-inline void Machine::check_final_stack(const int32 * const sp)
|
|
+inline void Machine::check_final_stack(const stack_t * const sp)
|
|
{
|
|
stack_t const * const base = _stack + STACK_GUARD,
|
|
* const limit = base + STACK_MAX;
|
|
if (sp < base) _status = stack_underflow; // This should be impossible now.
|
|
else if (sp >= limit) _status = stack_overflow; // So should this.
|
|
else if (sp != base) _status = stack_not_empty;
|
|
}
|
|
|
|
diff --git a/gfx/graphite2/src/inc/Pass.h b/gfx/graphite2/src/inc/Pass.h
|
|
--- a/gfx/graphite2/src/inc/Pass.h
|
|
+++ b/gfx/graphite2/src/inc/Pass.h
|
|
@@ -76,17 +76,17 @@ private:
|
|
void dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const;
|
|
void dumpRuleEventOutput(const FiniteStateMachine & fsm, vm::Machine & m, const Rule & r, Slot * os) const;
|
|
void adjustSlot(int delta, Slot * & slot_out, SlotMap &) const;
|
|
bool collisionShift(Segment *seg, int dir, json * const dbgout) const;
|
|
bool collisionKern(Segment *seg, int dir, json * const dbgout) const;
|
|
bool collisionFinish(Segment *seg, GR_MAYBE_UNUSED json * const dbgout) const;
|
|
bool resolveCollisions(Segment *seg, Slot *slot, Slot *start, ShiftCollider &coll, bool isRev,
|
|
int dir, bool &moved, bool &hasCol, json * const dbgout) const;
|
|
- float resolveKern(Segment *seg, Slot *slot, Slot *start, KernCollider &coll, int dir,
|
|
+ float resolveKern(Segment *seg, Slot *slot, Slot *start, int dir,
|
|
float &ymin, float &ymax, json *const dbgout) const;
|
|
|
|
const Silf * m_silf;
|
|
uint16 * m_cols;
|
|
Rule * m_rules; // rules
|
|
RuleEntry * m_ruleMap;
|
|
uint16 * m_startStates; // prectxt length
|
|
uint16 * m_transitions;
|
|
diff --git a/gfx/graphite2/src/inc/Rule.h b/gfx/graphite2/src/inc/Rule.h
|
|
--- a/gfx/graphite2/src/inc/Rule.h
|
|
+++ b/gfx/graphite2/src/inc/Rule.h
|
|
@@ -97,17 +97,17 @@ bool State::empty() const
|
|
return rules_end == rules;
|
|
}
|
|
|
|
|
|
class SlotMap
|
|
{
|
|
public:
|
|
enum {MAX_SLOTS=64};
|
|
- SlotMap(Segment & seg, uint8 direction);
|
|
+ SlotMap(Segment & seg, uint8 direction, int maxSize);
|
|
|
|
Slot * * begin();
|
|
Slot * * end();
|
|
size_t size() const;
|
|
unsigned short context() const;
|
|
void reset(Slot &, unsigned short);
|
|
|
|
Slot * const & operator[](int n) const;
|
|
@@ -116,23 +116,25 @@ public:
|
|
void collectGarbage(Slot *& aSlot);
|
|
|
|
Slot * highwater() { return m_highwater; }
|
|
void highwater(Slot *s) { m_highwater = s; m_highpassed = false; }
|
|
bool highpassed() const { return m_highpassed; }
|
|
void highpassed(bool v) { m_highpassed = v; }
|
|
|
|
uint8 dir() const { return m_dir; }
|
|
+ int decMax() { return --m_maxSize; }
|
|
|
|
Segment & segment;
|
|
private:
|
|
Slot * m_slot_map[MAX_SLOTS+1];
|
|
unsigned short m_size;
|
|
unsigned short m_precontext;
|
|
Slot * m_highwater;
|
|
+ int m_maxSize;
|
|
uint8 m_dir;
|
|
bool m_highpassed;
|
|
};
|
|
|
|
|
|
class FiniteStateMachine
|
|
{
|
|
public:
|
|
@@ -237,18 +239,19 @@ void FiniteStateMachine::Rules::accumula
|
|
return;
|
|
}
|
|
}
|
|
while (rre != rrend && out != lrend) { *out++ = *rre++; }
|
|
m_end = out;
|
|
}
|
|
|
|
inline
|
|
-SlotMap::SlotMap(Segment & seg, uint8 direction)
|
|
-: segment(seg), m_size(0), m_precontext(0), m_highwater(0), m_dir(direction), m_highpassed(false)
|
|
+SlotMap::SlotMap(Segment & seg, uint8 direction, int maxSize)
|
|
+: segment(seg), m_size(0), m_precontext(0), m_highwater(0),
|
|
+ m_maxSize(maxSize), m_dir(direction), m_highpassed(false)
|
|
{
|
|
m_slot_map[0] = 0;
|
|
}
|
|
|
|
inline
|
|
Slot * * SlotMap::begin()
|
|
{
|
|
return &m_slot_map[1]; // allow map to go 1 before slot_map when inserting
|
|
diff --git a/gfx/graphite2/src/inc/Segment.h b/gfx/graphite2/src/inc/Segment.h
|
|
--- a/gfx/graphite2/src/inc/Segment.h
|
|
+++ b/gfx/graphite2/src/inc/Segment.h
|
|
@@ -35,17 +35,17 @@ of the License or (at your option) any l
|
|
#include "inc/FeatureVal.h"
|
|
#include "inc/GlyphCache.h"
|
|
#include "inc/GlyphFace.h"
|
|
#include "inc/Slot.h"
|
|
#include "inc/Position.h"
|
|
#include "inc/List.h"
|
|
#include "inc/Collider.h"
|
|
|
|
-#define MAX_SEG_GROWTH_FACTOR 256
|
|
+#define MAX_SEG_GROWTH_FACTOR 64
|
|
|
|
namespace graphite2 {
|
|
|
|
typedef Vector<Features> FeatureList;
|
|
typedef Vector<Slot *> SlotRope;
|
|
typedef Vector<int16 *> AttributeRope;
|
|
typedef Vector<SlotJustify *> JustifyRope;
|
|
|
|
@@ -154,17 +154,17 @@ public:
|
|
int8 getSlotBidiClass(Slot *s) const;
|
|
void doMirror(uint16 aMirror);
|
|
Slot *addLineEnd(Slot *nSlot);
|
|
void delLineEnd(Slot *s);
|
|
bool hasJustification() const { return m_justifies.size() != 0; }
|
|
void reverseSlots();
|
|
|
|
bool isWhitespace(const int cid) const;
|
|
- bool hasCollisionInfo() const { return (m_flags & SEG_HASCOLLISIONS); }
|
|
+ bool hasCollisionInfo() const { return (m_flags & SEG_HASCOLLISIONS) && m_collisions; }
|
|
SlotCollision *collisionInfo(const Slot *s) const { return m_collisions ? m_collisions + s->index() : 0; }
|
|
CLASS_NEW_DELETE
|
|
|
|
public: //only used by: GrSegment* makeAndInitialize(const GrFont *font, const GrFace *face, uint32 script, const FeaturesHandle& pFeats/*must not be IsNull*/, encform enc, const void* pStart, size_t nChars, int dir);
|
|
bool read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void*pStart, size_t nChars);
|
|
void finalise(const Font *font, bool reverse=false);
|
|
float justify(Slot *pSlot, const Font *font, float width, enum justFlags flags, Slot *pFirst, Slot *pLast);
|
|
bool initCollisions();
|
|
diff --git a/gfx/graphite2/src/inc/Slot.h b/gfx/graphite2/src/inc/Slot.h
|
|
--- a/gfx/graphite2/src/inc/Slot.h
|
|
+++ b/gfx/graphite2/src/inc/Slot.h
|
|
@@ -92,17 +92,17 @@ public:
|
|
void adjKern(const Position &pos) { m_shift = m_shift + pos; m_advance = m_advance + pos; }
|
|
void origin(const Position &pos) { m_position = pos + m_shift; }
|
|
void originate(int ind) { m_original = ind; }
|
|
int original() const { return m_original; }
|
|
void before(int ind) { m_before = ind; }
|
|
void after(int ind) { m_after = ind; }
|
|
bool isBase() const { return (!m_parent); }
|
|
void update(int numSlots, int numCharInfo, Position &relpos);
|
|
- Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal);
|
|
+ Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal, int depth = 0);
|
|
bool isDeleted() const { return (m_flags & DELETED) ? true : false; }
|
|
void markDeleted(bool state) { if (state) m_flags |= DELETED; else m_flags &= ~DELETED; }
|
|
bool isCopied() const { return (m_flags & COPIED) ? true : false; }
|
|
void markCopied(bool state) { if (state) m_flags |= COPIED; else m_flags &= ~COPIED; }
|
|
bool isPositioned() const { return (m_flags & POSITIONED) ? true : false; }
|
|
void markPositioned(bool state) { if (state) m_flags |= POSITIONED; else m_flags &= ~POSITIONED; }
|
|
bool isInsertBefore() const { return !(m_flags & INSERTED); }
|
|
uint8 getBidiLevel() const { return m_bidiLevel; }
|
|
@@ -123,20 +123,19 @@ public:
|
|
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);
|
|
int32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel, bool rtl);
|
|
void positionShift(Position a) { m_position += a; }
|
|
- void floodShift(Position adj);
|
|
+ void floodShift(Position adj, int depth = 0);
|
|
float just() const { return m_just; }
|
|
void just(float j) { m_just = j; }
|
|
Slot *nextInCluster(const Slot *s) const;
|
|
bool isChildOf(const Slot *base) const;
|
|
|
|
CLASS_NEW_DELETE
|
|
|
|
private:
|
|
diff --git a/gfx/graphite2/src/inc/UtfCodec.h b/gfx/graphite2/src/inc/UtfCodec.h
|
|
--- a/gfx/graphite2/src/inc/UtfCodec.h
|
|
+++ b/gfx/graphite2/src/inc/UtfCodec.h
|
|
@@ -35,16 +35,17 @@ typedef uint32 uchar_t;
|
|
|
|
template <int N>
|
|
struct _utf_codec
|
|
{
|
|
typedef uchar_t codeunit_t;
|
|
|
|
static void put(codeunit_t * cp, const uchar_t , int8 & len) throw();
|
|
static uchar_t get(const codeunit_t * cp, int8 & len) throw();
|
|
+ static bool validate(const codeunit_t * s, const codeunit_t * e) throw();
|
|
};
|
|
|
|
|
|
template <>
|
|
struct _utf_codec<32>
|
|
{
|
|
private:
|
|
static const uchar_t limit = 0x110000;
|
|
@@ -58,16 +59,22 @@ public:
|
|
}
|
|
|
|
inline
|
|
static uchar_t get(const codeunit_t * cp, int8 & l) throw()
|
|
{
|
|
if (cp[0] < limit) { l = 1; return cp[0]; }
|
|
else { l = -1; return 0xFFFD; }
|
|
}
|
|
+
|
|
+ inline
|
|
+ static bool validate(codeunit_t * s, codeunit_t * e) throw()
|
|
+ {
|
|
+ return e > s;
|
|
+ }
|
|
};
|
|
|
|
|
|
template <>
|
|
struct _utf_codec<16>
|
|
{
|
|
private:
|
|
static const int32 lead_offset = 0xD800 - (0x10000 >> 10);
|
|
@@ -88,22 +95,31 @@ public:
|
|
}
|
|
|
|
inline
|
|
static uchar_t get(const codeunit_t * cp, int8 & l) throw()
|
|
{
|
|
const uint32 uh = cp[0];
|
|
l = 1;
|
|
|
|
- if (0xD800 > uh || uh > 0xDFFF) { return uh; }
|
|
+ if (uh < 0xD800|| uh > 0xDFFF) { return uh; }
|
|
const uint32 ul = cp[1];
|
|
- if (uh > 0xDBFF || 0xDC00 > ul || ul > 0xDFFF) { l = -1; return 0xFFFD; }
|
|
+ if (uh > 0xDBFF || ul < 0xDC00 || ul > 0xDFFF) { l = -1; return 0xFFFD; }
|
|
++l;
|
|
return (uh<<10) + ul + surrogate_offset;
|
|
}
|
|
+
|
|
+ inline
|
|
+ static bool validate(codeunit_t * s, codeunit_t * e) throw()
|
|
+ {
|
|
+ const ptrdiff_t n = e-s;
|
|
+ if (n <= 0) return n == 0;
|
|
+ const uint32 u = *(s+(n-1)); // Get the last codepoint
|
|
+ return (u < 0xD800 || u > 0xDBFF);
|
|
+ }
|
|
};
|
|
|
|
|
|
template <>
|
|
struct _utf_codec<8>
|
|
{
|
|
private:
|
|
static const int8 sz_lut[16];
|
|
@@ -143,16 +159,34 @@ public:
|
|
|
|
if (l != seq_sz || toolong)
|
|
{
|
|
l = -l;
|
|
return 0xFFFD;
|
|
}
|
|
return u;
|
|
}
|
|
+
|
|
+ inline
|
|
+ static bool validate(codeunit_t * s, codeunit_t * e) throw()
|
|
+ {
|
|
+ const ptrdiff_t n = e-s;
|
|
+ if (n <= 0) return n == 0;
|
|
+ s += (n-1);
|
|
+ if (*s < 0x80) return true;
|
|
+ if (*s >= 0xC0) return false;
|
|
+ if (n == 1) return true;
|
|
+ if (*--s < 0x80) return true;
|
|
+ if (*s >= 0xe0) return false;
|
|
+ if (n == 2 || *s >= 0xC0) return true;
|
|
+ if (*--s < 0x80) return true;
|
|
+ if (*s >= 0xF0) return false;
|
|
+ return true;
|
|
+ }
|
|
+
|
|
};
|
|
|
|
|
|
template <typename C>
|
|
class _utf_iterator
|
|
{
|
|
typedef _utf_codec<sizeof(C)*8> codec;
|
|
|
|
@@ -195,16 +229,21 @@ public:
|
|
|
|
template <typename C>
|
|
struct utf
|
|
{
|
|
typedef typename _utf_codec<sizeof(C)*8>::codeunit_t codeunit_t;
|
|
|
|
typedef _utf_iterator<C> iterator;
|
|
typedef _utf_iterator<const C> const_iterator;
|
|
+
|
|
+ inline
|
|
+ static bool validate(codeunit_t * s, codeunit_t * e) throw() {
|
|
+ return _utf_codec<sizeof(C)*8>::validate(s,e);
|
|
+ }
|
|
};
|
|
|
|
|
|
typedef utf<uint32> utf32;
|
|
typedef utf<uint16> utf16;
|
|
typedef utf<uint8> utf8;
|
|
|
|
} // namespace graphite2
|
|
diff --git a/gfx/graphite2/src/inc/opcode_table.h b/gfx/graphite2/src/inc/opcode_table.h
|
|
--- a/gfx/graphite2/src/inc/opcode_table.h
|
|
+++ b/gfx/graphite2/src/inc/opcode_table.h
|
|
@@ -113,13 +113,13 @@ static const opcode_t opcode_table[] =
|
|
{{NILOP,NILOP}, 0, "PUT_SUBS3"},
|
|
{{do_(put_glyph), NILOP}, 2, "PUT_GLYPH"}, // output_class output_class
|
|
{{do2(push_glyph_attr)}, 3, "PUSH_GLYPH_ATTR"}, // gattrnum gattrnum slot
|
|
{{do2(push_att_to_glyph_attr)}, 3, "PUSH_ATT_TO_GLYPH_ATTR"}, // gattrnum gattrnum slot
|
|
{{do2(bor)}, 0, "BITOR"},
|
|
{{do2(band)}, 0, "BITAND"},
|
|
{{do2(bnot)}, 0, "BITNOT"}, // 0x40
|
|
{{do2(setbits)}, 4, "BITSET"},
|
|
- {{do2(set_feat)}, 2, "SET_FEAT"},
|
|
+ {{do_(set_feat), NILOP}, 2, "SET_FEAT"}, // featidx slot
|
|
// private opcodes for internal use only, comes after all other on disk opcodes.
|
|
{{do_(temp_copy), NILOP}, 0, "TEMP_COPY"}
|
|
};
|
|
|
|
diff --git a/gfx/graphite2/src/inc/opcodes.h b/gfx/graphite2/src/inc/opcodes.h
|
|
--- a/gfx/graphite2/src/inc/opcodes.h
|
|
+++ b/gfx/graphite2/src/inc/opcodes.h
|
|
@@ -62,17 +62,18 @@ of the License or (at your option) any l
|
|
// ip = The current instruction pointer
|
|
// endPos = Position of advance of last cluster
|
|
// dir = writing system directionality of the font
|
|
|
|
|
|
// #define NOT_IMPLEMENTED assert(false)
|
|
#define NOT_IMPLEMENTED
|
|
|
|
-#define binop(op) const int32 a = pop(); *sp = int32(*sp) op a
|
|
+#define binop(op) const uint32 a = pop(); *sp = uint32(*sp) op a
|
|
+#define sbinop(op) const int32 a = pop(); *sp = int32(*sp) op a
|
|
#define use_params(n) dp += n
|
|
|
|
#define declare_params(n) const byte * param = dp; \
|
|
use_params(n);
|
|
|
|
#define push(n) { *++sp = n; }
|
|
#define pop() (*sp--)
|
|
#define slotat(x) (map[(x)])
|
|
@@ -125,17 +126,17 @@ STARTOP(sub)
|
|
ENDOP
|
|
|
|
STARTOP(mul)
|
|
binop(*);
|
|
ENDOP
|
|
|
|
STARTOP(div_)
|
|
if (*sp == 0) DIE;
|
|
- binop(/);
|
|
+ sbinop(/);
|
|
ENDOP
|
|
|
|
STARTOP(min_)
|
|
const int32 a = pop(), b = *sp;
|
|
if (a < b) *sp = a;
|
|
ENDOP
|
|
|
|
STARTOP(max_)
|
|
@@ -176,29 +177,29 @@ STARTOP(equal)
|
|
binop(==);
|
|
ENDOP
|
|
|
|
STARTOP(not_eq_)
|
|
binop(!=);
|
|
ENDOP
|
|
|
|
STARTOP(less)
|
|
- binop(<);
|
|
+ sbinop(<);
|
|
ENDOP
|
|
|
|
STARTOP(gtr)
|
|
- binop(>);
|
|
+ sbinop(>);
|
|
ENDOP
|
|
|
|
STARTOP(less_eq)
|
|
- binop(<=);
|
|
+ sbinop(<=);
|
|
ENDOP
|
|
|
|
STARTOP(gtr_eq)
|
|
- binop(>=);
|
|
+ sbinop(>=);
|
|
ENDOP
|
|
|
|
STARTOP(next)
|
|
if (map - &smap[0] >= int(smap.size())) DIE
|
|
if (is)
|
|
{
|
|
if (is == smap.highwater())
|
|
smap.highpassed(true);
|
|
@@ -237,17 +238,17 @@ STARTOP(put_subs_8bit_obs)
|
|
index = seg.findClassIndex(input_class, slot->gid());
|
|
is->setGlyph(&seg, seg.getClassGlyph(output_class, index));
|
|
}
|
|
ENDOP
|
|
|
|
STARTOP(put_copy)
|
|
declare_params(1);
|
|
const int slot_ref = int8(*param);
|
|
- if (is)
|
|
+ if (is && !is->isDeleted())
|
|
{
|
|
slotref ref = slotat(slot_ref);
|
|
if (ref && ref != is)
|
|
{
|
|
int16 *tempUserAttrs = is->userAttrs();
|
|
if (is->attachedTo() || is->firstChild()) DIE
|
|
Slot *prev = is->prev();
|
|
Slot *next = is->next();
|
|
@@ -262,16 +263,17 @@ STARTOP(put_copy)
|
|
is->attachedTo()->child(is);
|
|
}
|
|
is->markCopied(false);
|
|
is->markDeleted(false);
|
|
}
|
|
ENDOP
|
|
|
|
STARTOP(insert)
|
|
+ if (smap.decMax() <= 0) DIE;
|
|
Slot *newSlot = seg.newSlot();
|
|
if (!newSlot) DIE;
|
|
Slot *iss = is;
|
|
while (iss && iss->isDeleted()) iss = iss->next();
|
|
if (!iss)
|
|
{
|
|
if (seg.last())
|
|
{
|
|
@@ -550,31 +552,31 @@ ENDOP
|
|
|
|
STARTOP(iattr_add)
|
|
declare_params(2);
|
|
const attrCode slat = attrCode(uint8(param[0]));
|
|
const size_t idx = uint8(param[1]);
|
|
const int val = int(pop());
|
|
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
|
|
{
|
|
- seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
|
|
+ seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
|
|
flags |= POSITIONED;
|
|
}
|
|
int res = is->getAttr(&seg, slat, idx);
|
|
is->setAttr(&seg, slat, idx, val + res, smap);
|
|
ENDOP
|
|
|
|
STARTOP(iattr_sub)
|
|
declare_params(2);
|
|
const attrCode slat = attrCode(uint8(param[0]));
|
|
const size_t idx = uint8(param[1]);
|
|
const int val = int(pop());
|
|
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
|
|
{
|
|
- seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
|
|
+ seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
|
|
flags |= POSITIONED;
|
|
}
|
|
int res = is->getAttr(&seg, slat, idx);
|
|
is->setAttr(&seg, slat, idx, res - val, smap);
|
|
ENDOP
|
|
|
|
STARTOP(push_proc_state)
|
|
use_params(1);
|
|
|