#317: update graphite2 to 1.3.10

This commit is contained in:
Cameron Kaiser 2017-10-05 21:52:02 -07:00
parent 1ce2a83ec7
commit f4bf5ad976
28 changed files with 166 additions and 1871 deletions

View File

@ -1,6 +1,6 @@
/* GRAPHITE2 LICENSING
Copyright 2011, SIL International
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
@ -19,13 +19,8 @@
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.
Alternatively, you may use this library under the terms of the Mozilla
Public License (http://mozilla.org/MPL) or under the GNU General Public
License, as published by the Free Sofware Foundation; either version
2 of the license or (at your option) any later version.
*/
#include "inc/Rule.h"
#include "inc/Segment.h"
using namespace graphite2;

27
gfx/graphite2/ChangeLog Normal file → Executable file
View File

@ -1,3 +1,30 @@
1.3.9
. Add Collision COLL_ISSPACE to allow for visible spaces in collision avoidance
. Add segment and pass direction information to tracing output
. Bug fix rule length testing in 32-bit
. Increase slanted margin distances for collision avoidance
. Change kerning algorithm to simple outline expansion. Seems to make no visible difference.
. Add trace2svg to test tools
1.3.8
. Various bug fixes arising from fuzzing
. Fix regression that stopped piglatin from working
. Make collision avoidance kerning give more regular results
. Minor modification to clustering algorithm to handle variable width chars
1.3.7
. Bug fixes
. Start to deprecate SegCache. This will be going away in a later release.
1.3.6
. Bug fixes
1.3.5
. Bug fixes
. Security bug fix
. Fix ARM misalignment problem
. Track latest cmake
1.3.4
. Transition from Mercurial to Git
. Bug fixes

View File

@ -1,6 +1,3 @@
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.
Cherry-picked post-1.3.9 commit 1ce331d5548b98ed8b818532b2556d6f2c7a3b83 to fix
https://bugzilla.mozilla.org/show_bug.cgi?id=1345461.
This directory contains the Graphite2 library release 1.3.10 from
https://github.com/silnrsi/graphite/releases/download/1.3.10/graphite2-minimal-1.3.10.tgz
See ./gfx/graphite2/moz-gr-update.sh for update procedure.

View File

@ -30,7 +30,7 @@
#define GR2_VERSION_MAJOR 1
#define GR2_VERSION_MINOR 3
#define GR2_VERSION_BUGFIX 8
#define GR2_VERSION_BUGFIX 10
#ifdef __cplusplus
extern "C"

View File

@ -1,55 +0,0 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms
of the Mozilla Public License (http://mozilla.org/MPL) or the GNU
General Public License, as published by the Free Software Foundation,
either version 2 of the License or (at your option) any later version.
*/
#pragma once
#include <graphite2/Types.h>
#include <stdio.h>
typedef enum {
GRLOG_NONE = 0x0,
GRLOG_FACE = 0x01,
GRLOG_SEGMENT = 0x02,
GRLOG_PASS = 0x04,
GRLOG_CACHE = 0x08,
GRLOG_OPCODE = 0x80,
GRLOG_ALL = 0xFF
} GrLogMask;
// If startGraphiteLogging returns true, logging is enabled and the FILE handle
// will be closed by graphite when stopGraphiteLogging is called.
#ifdef __cplusplus
extern "C"
{
#endif
GR2_API bool graphite_start_logging(FILE * logFile, GrLogMask mask); //may not do anthing if disabled in the implementation of the engine.
GR2_API void graphite_stop_logging();
#ifdef __cplusplus
}
#endif

View File

@ -1,826 +0,0 @@
/* GRAPHITE2 LICENSING
Copyright 2011, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "inc/Main.h"
#include "inc/Slot.h"
#include "inc/Segment.h"
#include "inc/Bidi.h"
using namespace graphite2;
enum DirCode { // Hungarian: dirc
Unk = -1,
N = 0, // other neutrals (default) - ON
L = 1, // left-to-right, strong - L
R = 2, // right-to-left, strong - R
AL = 3, // Arabic letter, right-to-left, strong, AR
EN = 4, // European number, left-to-right, weak - EN
EUS = 5, // European separator, left-to-right, weak - ES
ET = 6, // European number terminator, left-to-right, weak - ET
AN = 7, // Arabic number, left-to-right, weak - AN
CUS = 8, // Common number separator, left-to-right, weak - CS
WS = 9, // white space, neutral - WS
BN = 10, // boundary neutral - BN
LRO = 11, // LTR override
RLO = 12, // RTL override
LRE = 13, // LTR embedding
RLE = 14, // RTL embedding
PDF = 15, // pop directional format
NSM = 16, // non-space mark
LRI = 17, // LRI isolate
RLI = 18, // RLI isolate
FSI = 19, // FSI isolate
PDI = 20, // pop isolate
OPP = 21, // opening paired parenthesis
CPP = 22, // closing paired parenthesis
ON = N
};
enum DirMask {
WSflag = int8(1 << 7), // keep track of WS for eos handling
WSMask = int8(~(1 << 7))
};
inline uint8 BaseClass(Slot *s) { return s->getBidiClass() & WSMask; }
unsigned int bidi_class_map[] = { 0, 1, 2, 5, 4, 8, 9, 3, 7, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0 };
// Algorithms based on Unicode reference standard code. Thanks Asmus Freitag.
void resolveWeak(Slot *start, int sos, int eos);
void resolveNeutrals(Slot *s, int baseLevel, int sos, int eos);
void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairStack &stack);
inline int calc_base_level(Slot *s)
{
int count = 0;
for ( ; s; s = s->next())
{
int cls = s->getBidiClass();
if (count)
{
switch(cls)
{
case LRI :
case RLI :
case FSI :
++count;
break;
case PDI :
--count;
}
}
else
{
switch(cls)
{
case L :
return 0;
case R :
case AL :
return 1;
case LRI :
case RLI :
case FSI :
++count;
}
}
}
return 0;
}
// inline or not?
void do_resolves(Slot *start, int level, int sos, int eos, int &bmask, Segment *seg, uint8 aMirror, BracketPairStack &stack)
{
if (bmask & 0x1F1178)
resolveWeak(start, sos, eos);
if (bmask & 0x200000)
processParens(start, seg, aMirror, level, stack);
if (bmask & 0x7E0361)
resolveNeutrals(start, level, sos, eos);
bmask = 0;
}
enum maxs
{
MAX_LEVEL = 125,
};
// returns where we are up to in processing
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 &bstack)
{
int bmask = 0;
Slot *s = start;
Slot *slast = start;
Slot *scurr = 0;
Slot *stemp;
int lnextLevel = nextLevel;
int newLevel;
int empty = 1;
for ( ; s; s = s ? s->next() : s)
{
int cls = s->getBidiClass();
bmask |= (1 << cls);
s->setBidiLevel(level);
// we keep s->prev() pointing backwards for PDI repeating
switch (cls)
{
case BN :
if (slast == s) slast = s->next(); // ignore if at front of text
continue;
case LRE :
case LRO :
case RLE :
case RLO :
switch (cls)
{
case LRE :
case LRO :
newLevel = level + (level & 1 ? 1 : 2);
break;
case RLE :
case RLO :
newLevel = level + (level & 1 ? 2 : 1);
break;
}
s->setBidiClass(BN);
if (isolerr || newLevel > MAX_LEVEL || embederr)
{
if (!isolerr) ++embederr;
break;
}
stemp = scurr;
if (scurr)
scurr->prev(0); // don't include control in string
lnextLevel = newLevel;
scurr = s;
s->setBidiLevel(newLevel); // to make it vanish
// recurse for the new subsequence. A sequence only contains text at the same level
s = process_bidi(s->next(), newLevel, level, lnextLevel, cls < LRE, 0, cisol, isolerr, embederr, 0, seg, aMirror, bstack);
// s points at PDF or end of sequence
// try to keep extending the run and not process it until we have to
if (lnextLevel != level || !s) // if the subsequence really had something in it, or we are at the end of the run
{
if (slast != scurr) // process the run now, don't try to extend it
{
// process text preceeding embedding
do_resolves(slast, level, (prelevel > level ? prelevel : level) & 1, lnextLevel & 1, bmask, seg, aMirror, bstack);
empty = 0;
nextLevel = level;
}
else if (lnextLevel != level) // the subsequence had something
{
empty = 0; // so we aren't empty either
nextLevel = lnextLevel; // but since we really are empty, pass back our level from the subsequence
}
if (s) // if still more to process
{
prelevel = lnextLevel; // future text starts out with sos of the higher subsequence
lnextLevel = level; // and eos is our level
}
slast = s ? s->next() : s;
}
else if (stemp)
stemp->prev(s);
break;
case PDF :
s->setBidiClass(BN);
s->prev(0); // unstitch us since we skip final stitching code when we return
if (isol || isolerr || init) // boundary error conditions
break;
if (embederr)
{
--embederr;
break;
}
if (slast != s)
{
scurr->prev(0); // if slast, then scurr. Terminate before here
do_resolves(slast, level, level & 1, level & 1, bmask, seg, aMirror, bstack);
empty = 0;
}
if (empty)
{
nextLevel = prelevel; // no contents? set our level to that of parent
s->setBidiLevel(prelevel);
}
return s;
case FSI :
case LRI :
case RLI :
switch (cls)
{
case FSI :
if (calc_base_level(s->next()))
newLevel = level + (level & 1 ? 2 : 1);
else
newLevel = level + (level & 1 ? 1 : 2);
break;
case LRI :
newLevel = level + (level & 1 ? 1 : 2);
break;
case RLI :
newLevel = level + (level & 1 ? 2 : 1);
break;
}
if (newLevel > MAX_LEVEL || isolerr)
{
++isolerr;
s->setBidiClass(ON | WSflag);
break;
}
++cisol;
if (scurr) scurr->prev(s);
scurr = s; // include FSI
lnextLevel = newLevel;
// recurse for the new sub sequence
s = process_bidi(s->next(), newLevel, newLevel, lnextLevel, 0, 1, cisol, isolerr, embederr, 0, seg, aMirror, bstack);
// s points at PDI
if (s)
{
bmask |= 1 << BaseClass(s); // include the PDI in the mask
s->setBidiLevel(level); // reset its level to our level
}
lnextLevel = level;
break;
case PDI :
if (isolerr)
{
--isolerr;
s->setBidiClass(ON | WSflag);
break;
}
if (init || !cisol)
{
s->setBidiClass(ON | WSflag);
break;
}
embederr = 0;
if (!isol) // we are in an embedded subsequence, we have to return through all those
{
if (empty) // if empty, reset the level to tell embedded parent
nextLevel = prelevel;
return s->prev(); // keep working up the stack pointing at this PDI until we get to an isolate entry
}
else // we are terminating an isolate sequence
{
if (slast != s) // process any remaining content in this subseqence
{
scurr->prev(0);
do_resolves(slast, level, prelevel & 1, level & 1, bmask, seg, aMirror, bstack);
}
--cisol; // pop the isol sequence from the stack
return s;
}
default :
if (dirover)
s->setBidiClass((level & 1 ? R : L) | (WSflag * (cls == WS)));
}
if (s) s->prev(0); // unstitch us
if (scurr) // stitch in text for processing
scurr->prev(s);
scurr = s; // add us to text to process
}
if (slast != s)
{
do_resolves(slast, level, (level > prelevel ? level : prelevel) & 1, lnextLevel & 1, bmask, seg, aMirror, bstack);
empty = 0;
}
if (empty || isol)
nextLevel = prelevel;
return s;
}
// === RESOLVE WEAK TYPES ================================================
enum bidi_state // possible states
{
xa, // arabic letter
xr, // right leter
xl, // left letter
ao, // arabic lett. foll by ON
ro, // right lett. foll by ON
lo, // left lett. foll by ON
rt, // ET following R
lt, // ET following L
cn, // EN, AN following AL
ra, // arabic number foll R
re, // european number foll R
la, // arabic number foll L
le, // european number foll L
ac, // CS following cn
rc, // CS following ra
rs, // CS,ES following re
lc, // CS following la
ls, // CS,ES following le
ret, // ET following re
let, // ET following le
} ;
const bidi_state stateWeak[][10] =
{
// N, L, R, AN, EN, AL,NSM, CS, ES, ET,
{ /*xa*/ ao, xl, xr, cn, cn, xa, xa, ao, ao, ao, /* arabic letter */ },
{ /*xr*/ ro, xl, xr, ra, re, xa, xr, ro, ro, rt, /* right letter */ },
{ /*xl*/ lo, xl, xr, la, le, xa, xl, lo, lo, lt, /* left letter */ },
{ /*ao*/ ao, xl, xr, cn, cn, xa, ao, ao, ao, ao, /* arabic lett. foll by ON*/ },
{ /*ro*/ ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* right lett. foll by ON */ },
{ /*lo*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* left lett. foll by ON */ },
{ /*rt*/ ro, xl, xr, ra, re, xa, rt, ro, ro, rt, /* ET following R */ },
{ /*lt*/ lo, xl, xr, la, le, xa, lt, lo, lo, lt, /* ET following L */ },
{ /*cn*/ ao, xl, xr, cn, cn, xa, cn, ac, ao, ao, /* EN, AN following AL */ },
{ /*ra*/ ro, xl, xr, ra, re, xa, ra, rc, ro, rt, /* arabic number foll R */ },
{ /*re*/ ro, xl, xr, ra, re, xa, re, rs, rs,ret, /* european number foll R */ },
{ /*la*/ lo, xl, xr, la, le, xa, la, lc, lo, lt, /* arabic number foll L */ },
{ /*le*/ lo, xl, xr, la, le, xa, le, ls, ls,let, /* european number foll L */ },
{ /*ac*/ ao, xl, xr, cn, cn, xa, ao, ao, ao, ao, /* CS following cn */ },
{ /*rc*/ ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* CS following ra */ },
{ /*rs*/ ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* CS,ES following re */ },
{ /*lc*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* CS following la */ },
{ /*ls*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* CS,ES following le */ },
{ /*ret*/ ro, xl, xr, ra, re, xa,ret, ro, ro,ret, /* ET following re */ },
{ /*let*/ lo, xl, xr, la, le, xa,let, lo, lo,let, /* ET following le */ },
};
enum bidi_action // possible actions
{
// primitives
IX = 0x100, // increment
XX = 0xF, // no-op
// actions
xxx = (XX << 4) + XX, // no-op
xIx = IX + xxx, // increment run
xxN = (XX << 4) + ON, // set current to N
xxE = (XX << 4) + EN, // set current to EN
xxA = (XX << 4) + AN, // set current to AN
xxR = (XX << 4) + R, // set current to R
xxL = (XX << 4) + L, // set current to L
Nxx = (ON << 4) + 0xF, // set run to neutral
Axx = (AN << 4) + 0xF, // set run to AN
ExE = (EN << 4) + EN, // set run to EN, set current to EN
NIx = (ON << 4) + 0xF + IX, // set run to N, increment
NxN = (ON << 4) + ON, // set run to N, set current to N
NxR = (ON << 4) + R, // set run to N, set current to R
NxE = (ON << 4) + EN, // set run to N, set current to EN
AxA = (AN << 4) + AN, // set run to AN, set current to AN
NxL = (ON << 4) + L, // set run to N, set current to L
LxL = (L << 4) + L, // set run to L, set current to L
};
const bidi_action actionWeak[][10] =
{
// N,.. L, R, AN, EN, AL, NSM, CS,..ES, ET,
{ /*xa*/ xxx, xxx, xxx, xxx, xxA, xxR, xxR, xxN, xxN, xxN, /* arabic letter */ },
{ /*xr*/ xxx, xxx, xxx, xxx, xxE, xxR, xxR, xxN, xxN, xIx, /* right leter */ },
{ /*xl*/ xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xIx, /* left letter */ },
{ /*ao*/ xxx, xxx, xxx, xxx, xxA, xxR, xxN, xxN, xxN, xxN, /* arabic lett. foll by ON */ },
{ /*ro*/ xxx, xxx, xxx, xxx, xxE, xxR, xxN, xxN, xxN, xIx, /* right lett. foll by ON */ },
{ /*lo*/ xxx, xxx, xxx, xxx, xxL, xxR, xxN, xxN, xxN, xIx, /* left lett. foll by ON */ },
{ /*rt*/ Nxx, Nxx, Nxx, Nxx, ExE, NxR, xIx, NxN, NxN, xIx, /* ET following R */ },
{ /*lt*/ Nxx, Nxx, Nxx, Nxx, LxL, NxR, xIx, NxN, NxN, xIx, /* ET following L */ },
{ /*cn*/ xxx, xxx, xxx, xxx, xxA, xxR, xxA, xIx, xxN, xxN, /* EN, AN following AL */ },
{ /*ra*/ xxx, xxx, xxx, xxx, xxE, xxR, xxA, xIx, xxN, xIx, /* arabic number foll R */ },
{ /*re*/ xxx, xxx, xxx, xxx, xxE, xxR, xxE, xIx, xIx, xxE, /* european number foll R */ },
{ /*la*/ xxx, xxx, xxx, xxx, xxL, xxR, xxA, xIx, xxN, xIx, /* arabic number foll L */ },
{ /*le*/ xxx, xxx, xxx, xxx, xxL, xxR, xxL, xIx, xIx, xxL, /* european number foll L */ },
{ /*ac*/ Nxx, Nxx, Nxx, Axx, AxA, NxR, NxN, NxN, NxN, NxN, /* CS following cn */ },
{ /*rc*/ Nxx, Nxx, Nxx, Axx, NxE, NxR, NxN, NxN, NxN, NIx, /* CS following ra */ },
{ /*rs*/ Nxx, Nxx, Nxx, Nxx, ExE, NxR, NxN, NxN, NxN, NIx, /* CS,ES following re */ },
{ /*lc*/ Nxx, Nxx, Nxx, Axx, NxL, NxR, NxN, NxN, NxN, NIx, /* CS following la */ },
{ /*ls*/ Nxx, Nxx, Nxx, Nxx, LxL, NxR, NxN, NxN, NxN, NIx, /* CS,ES following le */ },
{ /*ret*/xxx, xxx, xxx, xxx, xxE, xxR, xxE, xxN, xxN, xxE, /* ET following re */ },
{ /*let*/xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xxL, /* ET following le */ },
};
inline uint8 GetDeferredType(bidi_action a) { return (a >> 4) & 0xF; }
inline uint8 GetResolvedType(bidi_action a) { return a & 0xF; }
inline DirCode EmbeddingDirection(int l) { return l & 1 ? R : L; }
// Neutrals
enum neutral_action
{
// action to resolve previous input
nL = L, // resolve EN to L
En = 3 << 4, // resolve neutrals run to embedding level direction
Rn = R << 4, // resolve neutrals run to strong right
Ln = L << 4, // resolved neutrals run to strong left
In = (1<<8), // increment count of deferred neutrals
LnL = (1<<4)+L, // set run and EN to L
};
// ->prev() here means ->next()
void SetDeferredRunClass(Slot *s, Slot *sRun, int nval)
{
if (!sRun || s == sRun) return;
for (Slot *p = sRun; p != s; p = p->prev())
if (p->getBidiClass() == WS) p->setBidiClass(nval | WSflag);
else if (BaseClass(p) != BN) p->setBidiClass(nval | (p->getBidiClass() & WSflag));
}
void SetThisDeferredRunClass(Slot *s, Slot *sRun, int nval)
{
if (!sRun) return;
for (Slot *p = sRun, *e = s->prev(); p != e; p = p->prev())
if (p->getBidiClass() == WS) p->setBidiClass(nval | WSflag);
else if (BaseClass(p) != BN) p->setBidiClass(nval | (p->getBidiClass() & WSflag));
}
void resolveWeak(Slot *start, int sos, int eos)
{
int state = (sos & 1) ? xr : xl;
int cls;
Slot *s = start;
Slot *sRun = NULL;
Slot *sLast = s;
for ( ; s; s = s->prev())
{
sLast = s;
cls = BaseClass(s);
switch (cls)
{
case BN :
if (s == start) start = s->prev(); // skip initial BNs for NSM resolving
continue;
case LRI :
case RLI :
case FSI :
case PDI :
{
Slot *snext = s->prev();
if (snext && snext->getBidiClass() == NSM)
snext->setBidiClass(ON);
s->setBidiClass(ON | WSflag);
}
break;
case NSM :
if (s == start)
{
cls = EmbeddingDirection(sos);
s->setBidiClass(cls);
}
break;
}
bidi_action action = actionWeak[state][bidi_class_map[cls]];
int clsRun = GetDeferredType(action);
if (clsRun != XX)
{
SetDeferredRunClass(s, sRun, clsRun);
sRun = NULL;
}
int clsNew = GetResolvedType(action);
if (clsNew != XX)
s->setBidiClass(clsNew);
if (!sRun && (IX & action))
sRun = s;
state = stateWeak[state][bidi_class_map[cls]];
}
cls = EmbeddingDirection(eos);
int clsRun = GetDeferredType(actionWeak[state][bidi_class_map[cls]]);
if (clsRun != XX)
SetThisDeferredRunClass(sLast, sRun, clsRun);
}
void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairStack &stack)
{
uint8 mask = 0;
int8 lastDir = -1;
BracketPair *p;
for ( ; s; s = s->prev()) // walk the sequence
{
uint16 ogid = seg->glyphAttr(s->gid(), aMirror) || s->gid();
int cls = BaseClass(s);
switch(cls)
{
case OPP :
stack.orin(mask);
stack.push(ogid, s, lastDir, lastDir != CPP);
mask = 0;
lastDir = OPP;
break;
case CPP :
stack.orin(mask);
p = stack.scan(s->gid());
if (!p) break;
mask = 0;
stack.close(p, s);
lastDir = CPP;
break;
case L :
lastDir = L;
mask |= 1;
break;
case R :
case AL :
case AN :
case EN :
lastDir = R;
mask |= 2;
}
}
if (stack.size())
{
for (p = stack.start(); p; p =p->next()) // walk the stack
{
if (p->close() && p->mask())
{
int dir = (level & 1) + 1;
if (p->mask() & dir)
{ }
else if (p->mask() & (1 << (~level & 1))) // if inside has strong other embedding
{
int ldir = p->before();
if ((p->before() == OPP || p->before() == CPP) && p->prev())
{
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 > 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);
}
}
stack.clear();
}
}
int GetDeferredNeutrals(int action, int level)
{
action = (action >> 4) & 0xF;
if (action == (En >> 4))
return EmbeddingDirection(level);
else
return action;
}
int GetResolvedNeutrals(int action)
{
return action & 0xF;
}
// state values
enum neutral_state
{
// new temporary class
r, // R and characters resolved to R
l, // L and characters resolved to L
rn, // N preceded by right
ln, // N preceded by left
a, // AN preceded by left (the abbrev 'la' is used up above)
na, // N preceeded by a
} ;
const uint8 neutral_class_map[] = { 0, 1, 2, 0, 4, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
const int actionNeutrals[][5] =
{
// cls= N, L, R, AN, EN, state =
{ In, 0, 0, 0, 0, }, // r right
{ In, 0, 0, 0, L, }, // l left
{ In, En, Rn, Rn, Rn, }, // rn N preceded by right
{ In, Ln, En, En, LnL, }, // ln N preceded by left
{ In, 0, 0, 0, L, }, // a AN preceded by left
{ In, En, Rn, Rn, En, }, // na N preceded by a
} ;
const int stateNeutrals[][5] =
{
// cls= N, L, R, AN, EN state =
{ rn, l, r, r, r, }, // r right
{ ln, l, r, a, l, }, // l left
{ rn, l, r, r, r, }, // rn N preceded by right
{ ln, l, r, a, l, }, // ln N preceded by left
{ na, l, r, a, l, }, // a AN preceded by left
{ na, l, r, a, l, }, // na N preceded by la
} ;
void resolveNeutrals(Slot *s, int baseLevel, int sos, int eos)
{
int state = (sos & 1) ? r : l;
int cls;
Slot *sRun = NULL;
Slot *sLast = s;
int level = baseLevel;
for ( ; s; s = s->prev())
{
sLast = s;
cls = BaseClass(s);
switch (cls)
{
case BN :
continue;
case LRI :
case RLI :
case FSI :
s->setBidiClass(BN | WSflag);
continue;
default :
int action = actionNeutrals[state][neutral_class_map[cls]];
int clsRun = GetDeferredNeutrals(action, level);
if (clsRun != N)
{
SetDeferredRunClass(s, sRun, clsRun);
sRun = NULL;
}
int clsNew = GetResolvedNeutrals(action);
if (clsNew != N)
s->setBidiClass(clsNew);
if (!sRun && (action & In))
sRun = s;
state = stateNeutrals[state][neutral_class_map[cls]];
}
}
cls = EmbeddingDirection(eos);
int clsRun = GetDeferredNeutrals(actionNeutrals[state][neutral_class_map[cls]], level);
if (clsRun != N)
SetThisDeferredRunClass(sLast, sRun, clsRun);
}
const int addLevel[][4] =
{
// cls = L, R, AN, EN level =
/* even */ { 0, 1, 2, 2, }, // EVEN
/* odd */ { 1, 0, 1, 1, }, // ODD
};
void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror)
{
bool rtl = seg->dir() & 1;
int level = rtl;
Slot *slast = 0;
for ( ; s; s = s->next())
{
int cls = BaseClass(s);
s->prev(slast); // restitch the prev() side of the doubly linked list
slast = s;
if (cls == AN)
cls = AL; // use AL value as the index for AN, no property change
if (cls < 5 && cls > 0)
{
level = s->getBidiLevel();
level += addLevel[level & 1][cls - 1];
s->setBidiLevel(level);
}
if (aMirror)
{
int hasChar = seg->glyphAttr(s->gid(), aMirror + 1);
if ( ((level & 1) && (!(seg->dir() & 4) || !hasChar))
|| ((rtl ^ (level & 1)) && (seg->dir() & 4) && hasChar) )
{
unsigned short g = seg->glyphAttr(s->gid(), aMirror);
if (g) s->setGlyph(seg, g);
}
}
}
}
void resolveWhitespace(int baseLevel, Slot *s)
{
for ( ; s; s = s->prev())
{
int8 cls = s->getBidiClass();
if (cls == WS || (cls & WSflag))
s->setBidiLevel(baseLevel);
else if (cls != BN)
break;
}
}
/*
Stitch two spans together to make another span (with ends tied together).
If the level is odd then swap the order of the two spans
*/
inline
Slot * join(int level, Slot * a, Slot * b)
{
if (!a) return b;
if (level & 1) { Slot * const t = a; a = b; b = t; }
Slot * const t = b->prev();
a->prev()->next(b); b->prev(a->prev()); // splice middle
t->next(a); a->prev(t); // splice ends
return a;
}
/*
Given the first slot in a run of slots with the same bidi level, turn the run
into it's own little doubly linked list ring (a span) with the two ends joined together.
If the run is rtl then reverse its direction.
Returns the first slot after the span
*/
Slot * span(Slot * & cs, const bool rtl)
{
Slot * r = cs, * re = cs; cs = cs->next();
if (rtl)
{
Slot * t = r->next(); r->next(r->prev()); r->prev(t);
for (int l = r->getBidiLevel(); cs && (l == cs->getBidiLevel() || cs->getBidiClass() == BN); cs = cs->prev())
{
re = cs;
t = cs->next(); cs->next(cs->prev()); cs->prev(t);
}
r->next(re);
re->prev(r);
r = re;
}
else
{
for (int l = r->getBidiLevel(); cs && (l == cs->getBidiLevel() || cs->getBidiClass() == BN); cs = cs->next())
re = cs;
r->prev(re);
re->next(r);
}
if (cs) cs->prev(0);
return r;
}
inline int getlevel(const Slot *cs, const int level)
{
while (cs && cs->getBidiClass() == BN)
{ cs = cs->next(); }
if (cs)
return cs->getBidiLevel();
else
return level;
}
Slot *resolveOrder(Slot * & cs, const bool reordered, const int level)
{
Slot * r = 0;
int ls;
while (cs && level <= (ls = getlevel(cs, level) - reordered))
{
r = join(level, r, level < ls
? resolveOrder(/* updates */cs, reordered, level+1) // find span of heighest level
: span(/* updates */cs, level & 1));
}
return r;
}

View File

@ -111,6 +111,9 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
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"
LINK_FLAGS "-nodefaultlibs ${GRAPHITE_LINK_FLAGS}"
LINKER_LANGUAGE C)
if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86|i.86")
add_definitions(-mfpmath=sse -msse2)
endif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86|i.86")
if (CMAKE_COMPILER_IS_GNUCXX)
add_definitions(-Wdouble-promotion)
endif (CMAKE_COMPILER_IS_GNUCXX)
@ -135,7 +138,7 @@ endif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
set_target_properties(graphite2 PROPERTIES
COMPILE_FLAGS "-Wall -Wextra -Wno-unknown-pragmas -Wimplicit-fallthrough -Wendif-labels -Wshadow -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector"
COMPILE_FLAGS "-Wall -Wextra -Wno-unknown-pragmas -Wimplicit-fallthrough -Wendif-labels -Wshadow -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector -mfpmath=sse -msse2"
LINK_FLAGS "-nodefaultlibs"
LINKER_LANGUAGE C)
target_link_libraries(graphite2 c)

View File

@ -262,7 +262,7 @@ inline void ShiftCollider::removeBox(const Rect &box, const BBox &bb, const Slan
// Adjust the movement limits for the target to avoid having it collide
// with the given neighbor slot. Also determine if there is in fact a collision
// between the target and the given slot.
bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift,
bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const SlotCollision *cslot, const Position &currShift,
bool isAfter, // slot is logically after _target
bool sameCluster, bool &hasCol, bool isExclusion,
GR_MAYBE_UNUSED json * const dbgout )
@ -282,7 +282,7 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif
return false;
const BBox &bb = gc.getBoundingBBox(gid);
SlotCollision * cslot = seg->collisionInfo(slot);
// SlotCollision * cslot = seg->collisionInfo(slot);
int orderFlags = 0;
bool sameClass = _seqProxClass == 0 && cslot->seqClass() == _seqClass;
if (sameCluster && _seqClass
@ -306,6 +306,7 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif
float seq_above_wt = cslot->seqAboveWt();
float seq_below_wt = cslot->seqBelowWt();
float seq_valign_wt = cslot->seqValignWt();
float lmargin = _margin;
// if isAfter, invert orderFlags for diagonal orders.
if (isAfter)
{
@ -334,6 +335,7 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif
torg = _currOffset.x;
cmin = _limit.bl.x + torg;
cmax = _limit.tr.x - tbb.xi + tbb.xa + torg;
lmargin = _margin;
break;
case 1 : // y direction
vmin = max(max(bb.yi - tbb.ya + sy, tsb.di - sb.da + tx - sd), sb.si - tsb.sa - tx + ss);
@ -345,6 +347,7 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif
torg = _currOffset.y;
cmin = _limit.bl.y + torg;
cmax = _limit.tr.y - tbb.yi + tbb.ya + torg;
lmargin = _margin;
break;
case 2 : // sum - moving along the positively-sloped vector, so the boundaries are the
// negatively-sloped boundaries.
@ -357,6 +360,7 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif
torg = _currOffset.x + _currOffset.y;
cmin = _limit.bl.x + _limit.bl.y + torg;
cmax = _limit.tr.x + _limit.tr.y - tsb.si + tsb.sa + torg;
lmargin = _margin / ISQRT2;
break;
case 3 : // diff - moving along the negatively-sloped vector, so the boundaries are the
// positively-sloped boundaries.
@ -369,6 +373,7 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif
torg = _currOffset.x - _currOffset.y;
cmin = _limit.bl.x - _limit.tr.y + torg;
cmax = _limit.tr.x - _limit.bl.y - tsb.di + tsb.da + torg;
lmargin = _margin / ISQRT2;
break;
default :
continue;
@ -470,7 +475,7 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif
}
}
if (vmax < cmin - _margin || vmin > cmax + _margin || omax < otmin - _margin || omin > otmax + _margin)
if (vmax < cmin - lmargin || vmin > cmax + lmargin || omax < otmin - lmargin || omin > otmax + lmargin)
continue;
// Process sub-boxes that are defined for this glyph.
@ -509,7 +514,7 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif
omax = ssb.sa + ss;
break;
}
if (vmax < cmin - _margin || vmin > cmax + _margin || omax < otmin - _margin || omin > otmax + _margin)
if (vmax < cmin - lmargin || vmin > cmax + lmargin || omax < otmin - lmargin || omin > otmax + lmargin)
continue;
#if !defined GRAPHITE2_NTRACING
@ -517,11 +522,11 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif
dbgout->setenv(1, reinterpret_cast<void *>(j));
#endif
if (omin > otmax)
_ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
sqr(_margin - omin + otmax) * _marginWt, false);
_ranges[i].weightedAxis(i, vmin - lmargin, vmax + lmargin, 0, 0, 0, 0, 0,
sqr(lmargin - omin + otmax) * _marginWt, false);
else if (omax < otmin)
_ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
sqr(_margin - otmin + omax) * _marginWt, false);
_ranges[i].weightedAxis(i, vmin - lmargin, vmax + lmargin, 0, 0, 0, 0, 0,
sqr(lmargin - otmin + omax) * _marginWt, false);
else
_ranges[i].exclude_with_margins(vmin, vmax, i);
anyhits = true;
@ -537,11 +542,11 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif
#endif
isCol = true;
if (omin > otmax)
_ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
sqr(_margin - omin + otmax) * _marginWt, false);
_ranges[i].weightedAxis(i, vmin - lmargin, vmax + lmargin, 0, 0, 0, 0, 0,
sqr(lmargin - omin + otmax) * _marginWt, false);
else if (omax < otmin)
_ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
sqr(_margin - otmin + omax) * _marginWt, false);
_ranges[i].weightedAxis(i, vmin - lmargin, vmax + lmargin, 0, 0, 0, 0, 0,
sqr(lmargin - otmin + omax) * _marginWt, false);
else
_ranges[i].exclude_with_margins(vmin, vmax, i);
@ -556,7 +561,8 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif
exclSlot->setGlyph(seg, cslot->exclGlyph());
Position exclOrigin(slot->origin() + cslot->exclOffset());
exclSlot->origin(exclOrigin);
res &= mergeSlot(seg, exclSlot, currShift, isAfter, sameCluster, isCol, true, dbgout );
SlotCollision exclInfo(seg, exclSlot);
res &= mergeSlot(seg, exclSlot, &exclInfo, currShift, isAfter, sameCluster, isCol, true, dbgout );
seg->freeSlot(exclSlot);
}
hasCol |= isCol;
@ -752,7 +758,7 @@ static float localmin(float al, float au, float bl, float bu, float x)
}
// Return the given edge of the glyph at height y, taking any slant box into account.
static float get_edge(Segment *seg, const Slot *s, const Position &shift, float y, float width, bool isRight)
static float get_edge(Segment *seg, const Slot *s, const Position &shift, float y, float width, float margin, bool isRight)
{
const GlyphCache &gc = seg->getFace()->glyphs();
unsigned short gid = s->gid();
@ -767,15 +773,15 @@ static float get_edge(Segment *seg, const Slot *s, const Position &shift, float
{
const BBox &sbb = gc.getSubBoundingBBox(gid, i);
const SlantBox &ssb = gc.getSubBoundingSlantBox(gid, i);
if (sy + sbb.yi > y + width / 2 || sy + sbb.ya < y - width / 2)
if (sy + sbb.yi - margin > y + width / 2 || sy + sbb.ya + margin < y - width / 2)
continue;
if (isRight)
{
float x = sx + sbb.xa;
float x = sx + sbb.xa + margin;
if (x > res)
{
float td = sx - sy + ssb.da + y;
float ts = sx + sy + ssb.sa - y;
float td = sx - sy + ssb.da + margin + y;
float ts = sx + sy + ssb.sa + margin - y;
x = localmax(td - width / 2, td + width / 2, ts - width / 2, ts + width / 2, x);
if (x > res)
res = x;
@ -783,11 +789,11 @@ static float get_edge(Segment *seg, const Slot *s, const Position &shift, float
}
else
{
float x = sx + sbb.xi;
float x = sx + sbb.xi - margin;
if (x < res)
{
float td = sx - sy + ssb.di + y;
float ts = sx + sy + ssb.si - y;
float td = sx - sy + ssb.di - margin + y;
float ts = sx + sy + ssb.si - margin - y;
x = localmin(td - width / 2, td + width / 2, ts - width / 2, ts + width / 2, x);
if (x < res)
res = x;
@ -802,9 +808,9 @@ static float get_edge(Segment *seg, const Slot *s, const Position &shift, float
float td = sx - sy + y;
float ts = sx + sy - y;
if (isRight)
res = localmax(td + sb.da - width / 2, td + sb.da + width / 2, ts + sb.sa - width / 2, ts + sb.sa + width / 2, sx + bb.xa);
res = localmax(td + sb.da - width / 2, td + sb.da + width / 2, ts + sb.sa - width / 2, ts + sb.sa + width / 2, sx + bb.xa) + margin;
else
res = localmin(td + sb.di - width / 2, td + sb.di + width / 2, ts + sb.si - width / 2, ts + sb.si + width / 2, sx + bb.xi);
res = localmin(td + sb.di - width / 2, td + sb.di + width / 2, ts + sb.si - width / 2, ts + sb.si + width / 2, sx + bb.xi) - margin;
}
return res;
}
@ -865,6 +871,7 @@ bool KernCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float
_edges.pop_back();
}
}
goto done;
}
numSlices = _edges.size();
@ -896,7 +903,7 @@ bool KernCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float
float y = _miny - 1 + (i + .5f) * _sliceWidth; // vertical center of slice
if ((dir & 1) && x < _edges[i])
{
t = get_edge(seg, s, c->shift(), y, _sliceWidth, false);
t = get_edge(seg, s, c->shift(), y, _sliceWidth, margin, false);
if (t < _edges[i])
{
_edges[i] = t;
@ -906,7 +913,7 @@ bool KernCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float
}
else if (!(dir & 1) && x > _edges[i])
{
t = get_edge(seg, s, c->shift(), y, _sliceWidth, true);
t = get_edge(seg, s, c->shift(), y, _sliceWidth, margin, true);
if (t > _edges[i])
{
_edges[i] = t;
@ -916,6 +923,7 @@ bool KernCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float
}
}
}
done:
_mingap = (float)1e38;
_target = aSlot;
_margin = margin;
@ -946,22 +954,17 @@ bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift
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 here = _edges[i] * rtl;
float y = (float)(_miny - 1 + (i + .5f) * _sliceWidth); // vertical center of slice
if ( (x > here - _mingap - currSpace)
|| (x > below - _mingap - currSpace)
|| (x > above - _mingap - currSpace))
if ( (x > here - _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) * rtl + 2 * currSpace;
// Check slices above and below (if any).
t = min(min(here, below), above) - m;
float m = get_edge(seg, slot, currShift, y, _sliceWidth, 0., rtl > 0) * rtl + 2 * currSpace;
t = here - m;
// _mingap is positive to shrink
if (t < _mingap)
{
@ -977,8 +980,6 @@ bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift
}
#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
@ -987,9 +988,10 @@ bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift
// Return the amount to kern by.
Position KernCollider::resolve(GR_MAYBE_UNUSED Segment *seg, GR_MAYBE_UNUSED Slot *slot,
int dir, float margin, GR_MAYBE_UNUSED json * const dbgout)
int dir, GR_MAYBE_UNUSED json * const dbgout)
{
float resultNeeded = (1 - 2 * (dir & 1)) * (_mingap - margin);
float resultNeeded = (1 - 2 * (dir & 1)) * _mingap;
// float resultNeeded = (1 - 2 * (dir & 1)) * (_mingap - margin);
float result = min(_limit.tr.x - _offsetPrev.x, max(resultNeeded, _limit.bl.x - _offsetPrev.x));
#if !defined GRAPHITE2_NTRACING
@ -998,7 +1000,6 @@ Position KernCollider::resolve(GR_MAYBE_UNUSED Segment *seg, GR_MAYBE_UNUSED Slo
*dbgout << json::object // slot
<< "slot" << objectid(dslot(seg, _target))
<< "gid" << _target->gid()
<< "margin" << _margin
<< "limit" << _limit
<< "miny" << _miny
<< "maxy" << _maxy
@ -1093,3 +1094,7 @@ float SlotCollision::getKern(int dir) const
return 0;
}
bool SlotCollision::ignore() const
{
return ((flags() & SlotCollision::COLL_IGNORE) || (flags() & SlotCollision::COLL_ISSPACE));
}

View File

@ -51,7 +51,7 @@ bool read_sequence(u8 const * &src, u8 const * const end, u8 const * &literal, u
literal = src;
src += literal_len;
if (src > end - 2)
if (src > end - 2 || src < literal)
return false;
match_dist = *src++;
@ -85,7 +85,7 @@ int lz4::decompress(void const *in, size_t in_size, void *out, size_t out_size)
{
// Copy in literal. At this point the last full sequence must be at
// least MINMATCH + 5 from the end of the output buffer.
if (dst + align(literal_len) > dst_end - (MINMATCH+5))
if (align(literal_len) > unsigned(dst_end - dst - (MINMATCH+5)) || dst_end - dst < MINMATCH + 5)
return -1;
dst = overrun_copy(dst, literal, literal_len);
}
@ -94,7 +94,9 @@ int lz4::decompress(void const *in, size_t in_size, void *out, size_t out_size)
// decoded output.
u8 const * const pcpy = dst - match_dist;
if (pcpy < static_cast<u8*>(out)
|| dst + match_len + MINMATCH > dst_end - 5)
|| pcpy >= dst
|| match_len > unsigned(dst_end - dst - (MINMATCH+5))
|| dst_end - dst < MINMATCH + 5)
return -1;
if (dst > pcpy+sizeof(unsigned long)
&& dst + align(match_len + MINMATCH) <= dst_end)
@ -103,8 +105,8 @@ int lz4::decompress(void const *in, size_t in_size, void *out, size_t out_size)
dst = safe_copy(dst, pcpy, match_len + MINMATCH);
}
if (literal + literal_len > src_end
|| dst + literal_len > dst_end)
if (literal_len > src_end - literal
|| literal_len > dst_end - dst)
return -1;
dst = fast_copy(dst, literal, literal_len);

View File

@ -190,9 +190,10 @@ bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
#if !defined GRAPHITE2_NTRACING
if (dbgout)
{
seg->positionSlots(0, 0, 0, aSilf->dir());
seg->positionSlots(0, 0, 0, seg->currdir());
*dbgout << json::item
<< json::close // Close up the passes array
<< "outputdir" << (seg->currdir() ? "rtl" : "ltr")
<< "output" << json::array;
for(Slot * s = seg->first(); s; s = s->next())
*dbgout << dslot(seg, s);
@ -331,10 +332,12 @@ Error Face::Table::decompress()
uncompressed_size = hdr & 0x07ffffff;
uncompressed_table = gralloc<byte>(uncompressed_size);
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;
}

View File

@ -275,7 +275,8 @@ bool FeatureRef::applyValToFeature(uint32 val, Features & pDest) const
else
if (pDest.m_pMap!=&m_pFace->theSill().theFeatureMap())
return false; //incompatible
pDest.reserve(m_index + 1);
if (m_index >= pDest.size())
pDest.resize(m_index+1);
pDest[m_index] &= ~m_mask;
pDest[m_index] |= (uint32(val) << m_bits);
return true;

View File

@ -380,12 +380,16 @@ const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFa
be::skip<uint16>(gloc,2);
if (_long_fmt)
{
if (8 + glyphid * sizeof(uint32) > m_pGloc.size())
return 0;
be::skip<uint32>(gloc, glyphid);
glocs = be::read<uint32>(gloc);
gloce = be::peek<uint32>(gloc);
}
else
{
if (8 + glyphid * sizeof(uint16) > m_pGloc.size())
return 0;
be::skip<uint16>(gloc, glyphid);
glocs = be::read<uint16>(gloc);
gloce = be::peek<uint16>(gloc);

View File

@ -1,149 +0,0 @@
/* 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/GlyphFaceCache.h"
#include "graphite2/Font.h"
#include "inc/Face.h" //for the tags
#include "inc/Endian.h"
using namespace graphite2;
/*virtual*/ bool GlyphFaceCacheHeader::initialize(const Face & face, const bool dumb_font) //return result indicates success. Do not use if failed.
{
if ((m_pLoca = face.getTable(Tag::loca, &m_lLoca)) == NULL) return false;
if ((m_pHead = face.getTable(Tag::head)) == NULL) return false;
if ((m_pGlyf = face.getTable(Tag::glyf, &m_lGlyf)) == NULL) return false;
if ((m_pHmtx = face.getTable(Tag::hmtx, &m_lHmtx)) == NULL) return false;
if ((m_pHHea = face.getTable(Tag::hhea)) == NULL) return false;
const void* pMaxp = face.getTable(Tag::maxp);
if (pMaxp == NULL) return false;
m_nGlyphs = m_nGlyphsWithGraphics = (unsigned short)TtfUtil::GlyphCount(pMaxp);
if (TtfUtil::LocaLookup(m_nGlyphs-1, m_pLoca, m_lLoca, m_pHead) == size_t(-1))
return false; // This will fail if m_nGlyphs is wildly out of range.
if (!dumb_font)
{
if ((m_pGlat = face.getTable(Tag::Glat, &m_lGlat)) == NULL) return false;
m_fGlat = be::peek<uint32>(m_pGlat);
size_t lGloc;
if ((m_pGloc = face.getTable(Tag::Gloc, &lGloc)) == NULL) return false;
if (lGloc < 6) return false;
int version = be::read<uint32>(m_pGloc);
if (version != 0x00010000) return false;
const uint16 locFlags = be::read<uint16>(m_pGloc);
m_numAttrs = be::read<uint16>(m_pGloc);
if (m_numAttrs > 0x1000) return false; // is this hard limit appropriate?
if (locFlags & 1)
{
m_locFlagsUse32Bit = true;
m_nGlyphsWithAttributes = (unsigned short)((lGloc - 12) / 4);
}
else
{
m_locFlagsUse32Bit = false;
m_nGlyphsWithAttributes = (unsigned short)((lGloc - 10) / 2);
}
if (m_nGlyphsWithAttributes > m_nGlyphs)
m_nGlyphs = m_nGlyphsWithAttributes;
}
return true;
}
GlyphFaceCache* GlyphFaceCache::makeCache(const GlyphFaceCacheHeader& hdr)
{
return new (hdr) GlyphFaceCache(hdr);
}
GlyphFaceCache::GlyphFaceCache(const GlyphFaceCacheHeader& hdr)
: GlyphFaceCacheHeader(hdr)
{
unsigned int nGlyphs = numGlyphs();
for (unsigned int i = 0; i < nGlyphs; i++)
{
*glyphPtrDirect(i) = NULL;
}
}
GlyphFaceCache::~GlyphFaceCache()
{
unsigned int nGlyphs = numGlyphs();
int deltaPointers = (*glyphPtrDirect(nGlyphs-1u) - *glyphPtrDirect(0u));
if ((nGlyphs > 0u) && (deltaPointers == static_cast<int>(nGlyphs - 1)))
{
for (unsigned int i=0 ; i<nGlyphs; ++i)
{
GlyphFace *p = *glyphPtrDirect(i);
assert (p);
p->~GlyphFace();
}
free (*glyphPtrDirect(0));
}
else
{
for (unsigned int i=0 ; i<nGlyphs; ++i)
{
GlyphFace *p = *glyphPtrDirect(i);
if (p)
{
p->~GlyphFace();
free(p);
}
}
}
}
void GlyphFaceCache::loadAllGlyphs()
{
unsigned int nGlyphs = numGlyphs();
// size_t sparse_size = 0;
GlyphFace * glyphs = gralloc<GlyphFace>(nGlyphs);
for (unsigned short glyphid = 0; glyphid < nGlyphs; glyphid++)
{
GlyphFace **p = glyphPtrDirect(glyphid);
*p = &(glyphs[glyphid]);
new(*p) GlyphFace(*this, glyphid);
// sparse_size += (*p)->m_attrs._sizeof();
}
// const size_t flat_size = nGlyphs*(sizeof(uint16*) + sizeof(uint16)*numAttrs());
// assert(sparse_size <= flat_size);
}
/*virtual*/ const GlyphFace *GlyphFaceCache::glyph(unsigned short glyphid) const //result may be changed by subsequent call with a different glyphid
{
GlyphFace **p = glyphPtrDirect(glyphid);
if (*p)
return *p;
*p = (GlyphFace*)malloc(sizeof(GlyphFace));
new(*p) GlyphFace(*this, glyphid);
return *p;
}

View File

@ -59,7 +59,9 @@ Zones::Exclusion & Zones::Exclusion::operator += (Exclusion const & rhs) {
inline
uint8 Zones::Exclusion::outcode(float val) const {
float p = val;
return ((p >= xm) << 1) | (p < x);
//float d = std::numeric_limits<float>::epsilon();
float d = 0.;
return ((p - xm >= d) << 1) | (x - p > d);
}
void Zones::exclude_with_margins(float xmin, float xmax, int axis) {
@ -74,6 +76,9 @@ namespace
inline
bool separated(float a, float b) {
return a != b;
//int exp;
//float res = frexpf(fabs(a - b), &exp);
//return (*(unsigned int *)(&res) > 4);
//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;
}

0
gfx/graphite2/src/MozGrMalloc.h Normal file → Executable file
View File

View File

@ -171,7 +171,7 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
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 + 2u*m_numTransition*m_numColumns >= pass_end, E_BADPASSLENGTH)) return face.error(e);
if (e.test(2u*m_numTransition*m_numColumns >= (unsigned)(pass_end - p), E_BADPASSLENGTH)) return face.error(e);
be::skip<int16>(p, m_numTransition*m_numColumns);
be::skip<uint8>(p);
if (e.test(p != pcCode, E_BADPASSCCODEPTR)) return face.error(e);
@ -192,7 +192,7 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
m_cPConstraint = vm::Machine::Code(true, pcCode, pcCode + pass_constraint_len,
precontext[0], be::peek<uint16>(sort_keys), *m_silf, face, PASS_TYPE_UNKNOWN);
if (e.test(!m_cPConstraint, E_OUTOFMEM)
|| e.test(!m_cPConstraint, m_cPConstraint.status() + E_CODEFAILURE))
|| e.test(m_cPConstraint.status() != Code::loaded, m_cPConstraint.status() + E_CODEFAILURE))
return face.error(e);
face.error_context(face.error_context() - 1);
}
@ -523,7 +523,7 @@ void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) cons
if (r != re)
{
const int adv = doAction(r->rule->action, slot, m);
dumpRuleEventOutput(fsm, m, *r->rule, slot);
dumpRuleEventOutput(fsm, *r->rule, slot);
if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot);
adjustSlot(adv, slot, fsm.slots);
*fsm.dbgout << "cursor" << objectid(dslot(&fsm.slots.segment, slot))
@ -579,7 +579,7 @@ void Pass::dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEnt
}
void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, Machine & m, const Rule & r, Slot * const last_slot) const
void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * const last_slot) const
{
*fsm.dbgout << json::item << json::flat << json::object
<< "id" << &r - m_rules
@ -597,7 +597,7 @@ void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, Machine & m, cons
<< json::close // close "input"
<< "slots" << json::array;
const Position rsb_prepos = last_slot ? last_slot->origin() : fsm.slots.segment.advance();
fsm.slots.segment.positionSlots(0, 0, 0, m.slotMap().dir());
fsm.slots.segment.positionSlots(0, 0, 0, fsm.slots.segment.currdir());
for(Slot * slot = output_slot(fsm.slots, 0); slot != last_slot; slot = slot->next())
*fsm.dbgout << dslot(&fsm.slots.segment, slot);
@ -635,7 +635,7 @@ bool Pass::testPassConstraint(Machine & m) const
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
if (unsigned(r.sort + curr_context - r.preContext) > m.slotMap().size()
|| curr_context - r.preContext < 0) return false;
vm::slotref * map = m.slotMap().begin() + curr_context - r.preContext;
@ -879,8 +879,11 @@ bool Pass::collisionKern(Segment *seg, int dir, json * const dbgout) const
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 (!(c->flags() & SlotCollision::COLL_ISSPACE))
{
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, dir, ymin, ymax, dbgout);
@ -962,8 +965,8 @@ bool Pass::resolveCollisions(Segment *seg, Slot *slotFix, Slot *start,
{
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
if (nbor != slotFix // don't process if this is the slot of interest
&& !(cNbor->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)
@ -971,7 +974,7 @@ bool Pass::resolveCollisions(Segment *seg, Slot *slotFix, Slot *start,
|| !(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))
&& !coll.mergeSlot(seg, nbor, cNbor, 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.
@ -1052,7 +1055,7 @@ float Pass::resolveKern(Segment *seg, Slot *slotFix, GR_MAYBE_UNUSED Slot *start
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 ((bb.bl.y == 0.f && bb.tr.y == 0.f) || (cNbor->flags() & SlotCollision::COLL_ISSPACE))
{
if (m_kernColls == InWord)
break;
@ -1066,7 +1069,7 @@ float Pass::resolveKern(Segment *seg, Slot *slotFix, GR_MAYBE_UNUSED Slot *start
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))
if (nbor != slotFix && !cNbor->ignore())
{
seenEnd = true;
if (!isInit)
@ -1089,7 +1092,7 @@ float Pass::resolveKern(Segment *seg, Slot *slotFix, GR_MAYBE_UNUSED Slot *start
}
if (collides)
{
Position mv = coll.resolve(seg, slotFix, dir, cFix->margin(), dbgout);
Position mv = coll.resolve(seg, slotFix, dir, dbgout);
coll.shift(mv, dir);
Position delta = slotFix->advancePos() + mv - cFix->shift();
slotFix->advance(delta);

View File

@ -412,8 +412,9 @@ Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bo
Position currpos(0., 0.);
float clusterMin = 0.;
Rect bbox;
bool reorder = (currdir() != isRtl);
if (currdir() != isRtl)
if (reorder)
{
Slot *temp;
reverseSlots();
@ -443,6 +444,8 @@ Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bo
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
}
}
if (reorder)
reverseSlots();
return currpos;
}

View File

@ -155,8 +155,8 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
be::skip<uint32>(p, be::read<uint8>(p)); // don't use scriptTag array.
if (e.test(p + sizeof(uint16) + sizeof(uint32) >= silf_end, E_BADSCRIPTTAGS)) { releaseBuffers(); return face.error(e); }
m_gEndLine = be::read<uint16>(p); // lbGID
const byte * o_passes = p,
* const passes_start = silf_start + be::read<uint32>(p);
const byte * o_passes = p;
uint32 passes_start = be::read<uint32>(p);
const size_t num_attrs = face.glyphs().numAttrs();
if (e.test(m_aPseudo >= num_attrs, E_BADAPSEUDO)
@ -164,7 +164,7 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
|| 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_numPasses > 128, E_BADNUMPASSES) || e.test(passes_start >= lSilf, 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)
|| e.test((m_bPass != 0xFF && (m_bPass < m_jPass || m_bPass > m_numPasses)), E_BADBPASS)
@ -174,11 +174,11 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
return face.error(e);
}
be::skip<uint32>(p, m_numPasses);
if (e.test(p + sizeof(uint16) >= passes_start, E_BADPASSESSTART)) { releaseBuffers(); return face.error(e); }
if (e.test(unsigned(p - silf_start) + 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
m_pseudos = new Pseudo[m_numPseudo];
if (e.test(p + m_numPseudo*(sizeof(uint32) + sizeof(uint16)) >= passes_start, E_BADNUMPSEUDO)
if (e.test(unsigned(p - silf_start) + m_numPseudo*(sizeof(uint32) + sizeof(uint16)) >= passes_start, E_BADNUMPSEUDO)
|| e.test(!m_pseudos, E_OUTOFMEM))
{
releaseBuffers(); return face.error(e);
@ -189,20 +189,20 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
m_pseudos[i].gid = be::read<uint16>(p);
}
const size_t clen = readClassMap(p, passes_start - p, version, e);
const size_t clen = readClassMap(p, passes_start + silf_start - p, version, e);
m_passes = new Pass[m_numPasses];
if (e || e.test(p + clen > passes_start, E_BADPASSESSTART)
if (e || e.test(clen > unsigned(passes_start + silf_start - p), 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),
* const pass_end = silf_start + be::peek<uint32>(o_passes);
uint32 pass_start = be::read<uint32>(o_passes);
uint32 pass_end = be::peek<uint32>(o_passes);
face.error_context((face.error_context() & 0xFF00) + EC_ASILF + (i << 16));
if (e.test(pass_start > pass_end, E_BADPASSSTART)
|| e.test(pass_start < passes_start, E_BADPASSSTART)
|| e.test(pass_end > silf_end, E_BADPASSEND)) {
|| e.test(pass_end > lSilf, E_BADPASSEND)) {
releaseBuffers(); return face.error(e);
}
@ -213,7 +213,7 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
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, pt,
if (!m_passes[i].readPass(silf_start + pass_start, pass_end - pass_start, pass_start, face, pt,
version, e))
{
releaseBuffers();
@ -293,7 +293,8 @@ size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version, Error
if (e.test(*o + 4 > max_off, E_HIGHCLASSOFFSET) // LookupClass doesn't stretch over max_off
|| e.test(lookup[0] == 0 // A LookupClass with no looks is a suspicious thing ...
|| lookup[0] * 2 + *o + 4 > max_off // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off]
|| lookup[3] + lookup[1] != lookup[0], E_BADCLASSLOOKUPINFO)) // rangeShift: numIDs - searchRange
|| lookup[3] + lookup[1] != lookup[0], E_BADCLASSLOOKUPINFO) // rangeShift: numIDs - searchRange
|| e.test(((o[1] - *o) & 1) != 0, ERROROFFSET)) // glyphs are in pairs so difference must be even.
return ERROROFFSET;
}
@ -384,9 +385,12 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
if (dbgout)
{
*dbgout << json::item << json::object
// << "pindex" << i // for debugging
<< "id" << -1
<< "slotsdir" << (seg->currdir() ? "rtl" : "ltr")
<< "passdir" << (m_dir & 1 ? "rtl" : "ltr")
<< "slots" << json::array;
seg->positionSlots(0, 0, 0, m_dir);
seg->positionSlots(0, 0, 0, seg->currdir());
for(Slot * s = seg->first(); s; s = s->next())
*dbgout << dslot(seg, s);
*dbgout << json::close
@ -408,9 +412,12 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
if (dbgout)
{
*dbgout << json::item << json::object
// << "pindex" << i // for debugging
<< "id" << i+1
<< "slotsdir" << (seg->currdir() ? "rtl" : "ltr")
<< "passdir" << ((m_dir & 1) ^ m_passes[i].reverseDir() ? "rtl" : "ltr")
<< "slots" << json::array;
seg->positionSlots(0, 0, 0, m_dir);
seg->positionSlots(0, 0, 0, seg->currdir());
for(Slot * s = seg->first(); s; s = s->next())
*dbgout << dslot(seg, s);
*dbgout << json::close;

View File

@ -1,219 +0,0 @@
/* 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 <cstring>
#include <cstdarg>
#include "Main.h"
#include "XmlTraceLog.h"
using namespace graphite2;
#ifndef DISABLE_TRACING
/*static*/ XmlTraceLog XmlTraceLog::sm_NullLog(NULL, NULL, GRLOG_NONE);
XmlTraceLog * XmlTraceLog::sLog = &sm_NullLog;
XmlTraceLog::XmlTraceLog(FILE * file, const char * ns, GrLogMask logMask)
: m_file(file), m_depth(0), m_mask(logMask)
{
if (!m_file) return;
int deep = 0;
#ifdef ENABLE_DEEP_TRACING
deep = 1;
#endif
fprintf(m_file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<%s xmlns=\"%s\" mask=\"%x\" deep=\"%d\">",
xmlTraceLogElements[ElementTopLevel].mName, ns, logMask, deep);
m_elementStack[m_depth++] = ElementTopLevel;
m_elementEmpty = true;
m_inElement = false;
m_lastNodeText = false;
}
XmlTraceLog::~XmlTraceLog()
{
if (m_file && m_file != stdout && m_file != stderr)
{
assert(m_depth == 1);
while (m_depth > 0)
{
closeElement(m_elementStack[m_depth-1]);
}
fclose(m_file);
m_file = NULL;
}
}
void XmlTraceLog::addSingleElement(XmlTraceLogElement eId, const int value)
{
if (!m_file) return;
if (m_inElement)
{
if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask)
fprintf(m_file, ">");
}
if (xmlTraceLogElements[eId].mFlags & m_mask)
{
if (!m_lastNodeText)
{
fprintf(m_file, "\n");
for (size_t i = 0; i < m_depth; i++)
{
fprintf(m_file, " ");
}
}
fprintf(m_file, "<%s val=\"%d\"/>", xmlTraceLogElements[eId].mName, value);
}
m_inElement = false;
m_lastNodeText = false;
}
void XmlTraceLog::writeElementArray(XmlTraceLogElement eId, XmlTraceLogAttribute aId, int16 values [], size_t length)
{
if (!m_file) return;
if (xmlTraceLogElements[eId].mFlags & m_mask)
{
if(m_inElement && xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask)
{
fprintf(m_file, ">");
m_inElement = false;
}
// line break after 5 columns
for (size_t i = 0; i < length; i++)
{
if (i % 5 == 0)
{
fprintf(m_file, "\n");
for (size_t j = 0; j < m_depth; j++)
{
fprintf(m_file, " ");
}
}
fprintf(m_file, "<%s index=\"%d\" %s=\"%d\"/>", xmlTraceLogElements[eId].mName, int(i),
xmlTraceLogAttributes[aId], (int)values[i]);
}
}
}
void XmlTraceLog::writeText(const char * utf8)
{
if (!m_file) return;
if (m_inElement)
{
if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask)
{
fprintf(m_file, ">");
}
m_inElement = false;
}
if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask)
{
escapeIfNeeded(utf8);
}
m_lastNodeText = true;
}
void XmlTraceLog::writeUnicode(const uint32 code)
{
if (!m_file) return;
if (m_inElement)
{
if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask)
{
fprintf(m_file, ">");
}
m_inElement = false;
}
if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask)
{
fprintf(m_file, "&#x%02x;", code);
}
m_lastNodeText = true;
}
void XmlTraceLog::escapeIfNeeded(const char * data)
{
size_t length = strlen(data);
for (size_t i = 0; i < length; i++)
{
switch (data[i])
{
case '<':
fprintf(m_file, "&lt;");
break;
case '>':
fprintf(m_file, "&gt;");
break;
case '&':
fprintf(m_file, "&amp;");
break;
case '"':
fprintf(m_file, "&#34;");
break;
default:
fprintf(m_file, "%c", data[i]);
}
}
}
static const int MAX_MSG_LEN = 1024;
void XmlTraceLog::error(const char * msg, ...)
{
if (!m_file) return;
openElement(ElementError);
va_list args;
va_start(args, msg);
char buffer[MAX_MSG_LEN];
#ifndef NDEBUG
int len =
#endif
vsnprintf(buffer, MAX_MSG_LEN, msg, args);
assert(len + 1 < MAX_MSG_LEN);
writeText(buffer);
va_end(args);
closeElement(ElementError);
}
void XmlTraceLog::warning(const char * msg, ...)
{
if (!m_file) return;
openElement(ElementWarning);
va_list args;
va_start(args, msg);
char buffer[MAX_MSG_LEN];
#ifndef NDEBUG
int len =
#endif
vsnprintf(buffer, MAX_MSG_LEN, msg, args);
assert(len + 1 < MAX_MSG_LEN);
writeText(buffer);
va_end(args);
closeElement(ElementWarning);
}
#endif //!DISABLE_TRACING

View File

@ -1,169 +0,0 @@
/* 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 "Main.h"
#include "XmlTraceLogTags.h"
using namespace graphite2;
#ifndef DISABLE_TRACING
// start this at same line number as in XmlTraceLogTags.h
const XmlTraceLogTag graphite2::xmlTraceLogElements[NumElements] = {
XmlTraceLogTag("Graphite2Log", GRLOG_ALL),
XmlTraceLogTag("Face", GRLOG_FACE | GRLOG_PASS),
XmlTraceLogTag("Glyphs", GRLOG_FACE),
XmlTraceLogTag("GlyphFace", GRLOG_FACE),
XmlTraceLogTag("Attr", GRLOG_FACE),
XmlTraceLogTag("Silf", GRLOG_FACE | GRLOG_PASS),
XmlTraceLogTag("SilfSub", GRLOG_FACE | GRLOG_PASS),
XmlTraceLogTag("Pass", GRLOG_FACE | GRLOG_PASS),
XmlTraceLogTag("Pseudo", GRLOG_FACE | GRLOG_PASS),
XmlTraceLogTag("ClassMap", GRLOG_FACE | GRLOG_PASS),
XmlTraceLogTag("LookupClass", GRLOG_FACE | GRLOG_PASS),
XmlTraceLogTag("Lookup", GRLOG_FACE | GRLOG_PASS),
XmlTraceLogTag("Range", GRLOG_PASS),
XmlTraceLogTag("RuleMap", GRLOG_PASS),
XmlTraceLogTag("Rule", GRLOG_PASS),
XmlTraceLogTag("StartState", GRLOG_PASS),
XmlTraceLogTag("StateTransitions", GRLOG_PASS),
XmlTraceLogTag("TR", GRLOG_PASS),
XmlTraceLogTag("TD", GRLOG_PASS),
XmlTraceLogTag("Constraint", GRLOG_PASS),
XmlTraceLogTag("Constraints", GRLOG_PASS),
XmlTraceLogTag("Actions", GRLOG_PASS),
XmlTraceLogTag("Action", GRLOG_PASS),
XmlTraceLogTag("Features", GRLOG_PASS),
XmlTraceLogTag("Feature", GRLOG_PASS),
XmlTraceLogTag("FeatureSetting", GRLOG_PASS),
XmlTraceLogTag("Segment", GRLOG_SEGMENT),
XmlTraceLogTag("Slot", GRLOG_SEGMENT),
XmlTraceLogTag("Text", GRLOG_SEGMENT),
XmlTraceLogTag("OpCode", GRLOG_OPCODE),
XmlTraceLogTag("TestRule", GRLOG_OPCODE),
XmlTraceLogTag("DoRule", GRLOG_OPCODE),
XmlTraceLogTag("RunPass", GRLOG_OPCODE),
XmlTraceLogTag("Params", GRLOG_OPCODE),
XmlTraceLogTag("Push", GRLOG_OPCODE),
XmlTraceLogTag("SubSeg", GRLOG_SEGMENT),
XmlTraceLogTag("SegCache", GRLOG_CACHE),
XmlTraceLogTag("SegCacheEntry", GRLOG_CACHE),
XmlTraceLogTag("Glyph", GRLOG_CACHE),
XmlTraceLogTag("PassResult", GRLOG_OPCODE),
XmlTraceLogTag("Error", GRLOG_ALL),
XmlTraceLogTag("Warning", GRLOG_ALL)
// Nothing corresponds to NumElements
};
// start this at same line number as in XmlTraceLogTags.h
const char * graphite2::xmlTraceLogAttributes[NumAttributes] = {
"index",
"version",
"major",
"minor",
"num",
"glyphId",
"advance",
"advanceX",
"advanceY",
"attrId",
"attrVal",
"compilerMajor",
"compilerMinor",
"numPasses",//AttrNumPasses,
"subPass",//AttrSubPass,
"posPass",//AttrPosPass,
"justPass",//AttrJustPass,
"bidiPass",//AttrBidiPass,
"preContext",//AttrPreContext,
"postContext",//AttrPostContext,
"pseudoGlyph",//AttrPseudoGlyph,
"breakWeight",//AttrBreakWeight,
"directionality",//AttrDirectionality,
"numJustLevels",//AttrNumJustLevels,
"numLigCompAttr",//AttrLigComp,
"numUserDefinedAttr",//AttrUserDefn,
"maxNumLigComp",//AttrNumLigComp,
"numCriticalFeatures",//AttrNumCritFeatures,
"numScripts",//AttrNumScripts
"lineBreakglyph",//,AttrLBGlyph,
"numPseudo",
"numClasses",
"numLinear",
"passId",//AttrPassId,
"flags",//AttrFlags,
"maxRuleLoop",//AttrMaxRuleLoop,
"maxRuleContext",//AttrMaxRuleContext,
"maxBackup",//AttrMaxBackup,
"numRules",//AttrNumRules,
"numRows",//AttrNumRows,
"numTransitionStates",//AttrNumTransition,
"numSuccessStates",//AttrNumSuccess,
"numColumns",//AttrNumColumns,
"numRanges",//AttrNumRanges,
"minPrecontext",//AttrMinPrecontext,
"maxPrecontext",//AttrMaxPrecontext,
"firstId",
"lastId",
"colId",
"successId",
"ruleId",
"contextLength",
"state",
"value",
"sortKey",
"precontext",
"action",
"actionCode",
"arg1",
"arg2",
"arg3",
"arg4",
"arg5",
"arg6",
"arg7",
"arg8",
"label",
"length",
"x",
"y",
"before",
"after",
"encoding",
"name",
"result",
"default",
"accessCount",
"lastAccess",
"misses"
};
#endif

View File

@ -1,126 +0,0 @@
/* GRAPHITE2 LICENSING
Copyright 2013, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
namespace graphite2
{
class BracketPair
{
public:
BracketPair(uint16 g, Slot *s, uint8 b, BracketPair *p, BracketPair *l) : _open(s), _close(0), _parent(p), _next(0), _prev(l), _gid(g), _mask(0), _before(b) {};
uint16 gid() const { return _gid; }
Slot *open() const { return _open; }
Slot *close() const { return _close; }
uint8 mask() const { return _mask; }
int8 before() const { return _before; }
BracketPair *parent() const { return _parent; }
void close(Slot *s) { _close = s; }
BracketPair *next() const { return _next; }
BracketPair *prev() const { return _prev; }
void next(BracketPair *n) { _next = n; }
void orin(uint8 m) { _mask |= m; }
private:
Slot * _open; // Slot of opening paren
Slot * _close; // Slot of closing paren
BracketPair * _parent; // pair this pair is in or NULL
BracketPair * _next; // next pair along the string
BracketPair * _prev; // pair that closed last before we opened
uint16 _gid; // gid of closing paren
uint8 _mask; // bitmap (2 bits) of directions within the pair
int8 _before; // most recent strong type (L, R, OPP, CPP)
};
class BracketPairStack
{
public:
BracketPairStack(int s) : _stack(grzeroalloc<BracketPair>(s)), _ip(_stack - 1), _top(0), _last(0), _lastclose(0), _size(s) {}
~BracketPairStack() { free(_stack); }
public:
BracketPair *scan(uint16 gid);
void close(BracketPair *tos, Slot *s);
BracketPair *push(uint16 gid, Slot *pos, uint8 before, int prevopen);
void orin(uint8 mask);
void clear() { _ip = _stack - 1; _top = 0; _last = 0; _lastclose = 0; }
int size() const { return _size; }
BracketPair *start() const { return _stack; }
CLASS_NEW_DELETE
private:
BracketPair *_stack; // start of storage
BracketPair *_ip; // where to add the next pair
BracketPair *_top; // current parent
BracketPair *_last; // end of next() chain
BracketPair *_lastclose; // last pair to close
int _size; // capacity
};
inline BracketPair *BracketPairStack::scan(uint16 gid)
{
BracketPair *res = _top;
while (res >= _stack)
{
if (res->gid() == gid)
return res;
res = res->parent();
}
return 0;
}
inline void BracketPairStack::close(BracketPair *tos, Slot *s)
{
for ( ; _last && _last != tos && !_last->close(); _last = _last->parent())
{ }
tos->close(s);
_last->next(NULL);
_lastclose = tos;
_top = tos->parent();
}
inline BracketPair *BracketPairStack::push(uint16 gid, Slot *pos, uint8 before, int prevopen)
{
if (++_ip - _stack < _size && _stack)
{
::new (_ip) BracketPair(gid, pos, before, _top, prevopen ? _last : _lastclose);
if (_last) _last->next(_ip);
_last = _ip;
}
_top = _ip;
return _ip;
}
inline void BracketPairStack::orin(uint8 mask)
{
BracketPair *t = _top;
for ( ; t; t = t->parent())
t->orin(mask);
}
}

View File

@ -54,7 +54,8 @@ public:
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_ISSPACE = 128, // treat this glyph as a space with regard to kerning
COLL_TEMPLOCK = 256, // Lock glyphs that have been given priority positioning
////COLL_JUMPABLE = 128, // moving glyphs may jump this stationary glyph in any direction - DELETE
////COLL_OVERLAP = 256, // use maxoverlap to restrict - DELETE
};
@ -93,6 +94,7 @@ public:
SLOTCOLSETUINTPROP(seqValignWt, setSeqValignWt)
float getKern(int dir) const;
bool ignore() const;
private:
Rect _limit;
@ -131,7 +133,7 @@ public:
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 mergeSlot(Segment *seg, Slot *slot, const SlotCollision *cinfo, const Position &currShift, bool isAfter,
bool sameCluster, bool &hasCol, bool isExclusion, GR_MAYBE_UNUSED json * const dbgout);
Position resolve(Segment *seg, bool &isCol, GR_MAYBE_UNUSED json * const dbgout);
void addBox_slope(bool isx, const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, float weight, float m, bool minright, int mode);
@ -191,7 +193,7 @@ public:
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);
Position resolve(Segment *seg, Slot *slot, int dir, json * const dbgout);
void shift(const Position &mv, int dir);
CLASS_NEW_DELETE;

View File

@ -1,103 +0,0 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include "inc/GlyphFace.h"
#include "graphite2/Font.h"
namespace graphite2 {
class Segment;
class Face;
class FeatureVal;
class GlyphFaceCacheHeader
{
public:
bool initialize(const Face & face, const bool dumb_font); //return result indicates success. Do not use if failed.
unsigned short numGlyphs() const { return m_nGlyphs; }
unsigned short numAttrs() const { return m_numAttrs; }
private:
friend class Face;
friend class GlyphFace;
const byte* m_pHead,
* m_pHHea,
* m_pHmtx,
* m_pGlat,
* m_pGloc,
* m_pGlyf,
* m_pLoca;
size_t m_lHmtx,
m_lGlat,
m_lGlyf,
m_lLoca;
uint32 m_fGlat;
unsigned short m_numAttrs, // number of glyph attributes per glyph
m_nGlyphsWithGraphics, //i.e. boundary box and advance
m_nGlyphsWithAttributes,
m_nGlyphs; // number of glyphs in the font. Max of the above 2.
bool m_locFlagsUse32Bit;
};
class GlyphFaceCache : public GlyphFaceCacheHeader
{
public:
static GlyphFaceCache* makeCache(const GlyphFaceCacheHeader& hdr /*, EGlyphCacheStrategy requested */);
GlyphFaceCache(const GlyphFaceCacheHeader& hdr);
~GlyphFaceCache();
const GlyphFace *glyphSafe(unsigned short glyphid) const { return glyphid<numGlyphs()?glyph(glyphid):NULL; }
uint16 glyphAttr(uint16 gid, uint8 gattr) const { if (gattr>=numAttrs()) return 0; const GlyphFace*p=glyphSafe(gid); return p?p->getAttr(gattr):0; }
void * operator new (size_t s, const GlyphFaceCacheHeader& hdr)
{
return malloc(s + sizeof(GlyphFace*)*hdr.numGlyphs());
}
// delete in case an exception is thrown in constructor
void operator delete(void* p, const GlyphFaceCacheHeader& ) throw()
{
free(p);
}
const GlyphFace *glyph(unsigned short glyphid) const; //result may be changed by subsequent call with a different glyphid
void loadAllGlyphs();
CLASS_NEW_DELETE
private:
GlyphFace **glyphPtrDirect(unsigned short glyphid) const { return (GlyphFace **)((const char*)(this)+sizeof(GlyphFaceCache)+sizeof(GlyphFace*)*glyphid);}
private: //defensive
GlyphFaceCache(const GlyphFaceCache&);
GlyphFaceCache& operator=(const GlyphFaceCache&);
};
} // namespace graphite2

View File

@ -74,7 +74,7 @@ private:
uint16 glyphToCol(const uint16 gid) const;
bool runFSM(FiniteStateMachine & fsm, Slot * slot) const;
void dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const;
void dumpRuleEventOutput(const FiniteStateMachine & fsm, vm::Machine & m, const Rule & r, Slot * os) const;
void dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * os) const;
void adjustSlot(int delta, Slot * & slot_out, SlotMap &) const;
bool collisionShift(Segment *seg, int dir, json * const dbgout) const;
bool collisionKern(Segment *seg, int dir, json * const dbgout) const;

View File

@ -1,119 +0,0 @@
/* 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

View File

@ -124,7 +124,7 @@ struct _utf_codec<8>
private:
static const int8 sz_lut[16];
static const byte mask_lut[5];
static const uchar_t limit = 0x110000;
public:
typedef uint8 codeunit_t;
@ -157,7 +157,7 @@ public:
case 0: l = -1; return 0xFFFD;
}
if (l != seq_sz || toolong)
if (l != seq_sz || toolong || u >= limit)
{
l = -l;
return 0xFFFD;

View File

@ -36,8 +36,8 @@ namespace graphite2 {
struct IsoLangEntry
{
unsigned short mnLang;
const char maLangStr[4];
const char maCountry[3];
char maLangStr[4];
char maCountry[3];
};
// Windows Language ID, Locale ISO-639 language, country code as used in

10
gfx/graphite2/src/moz.build Normal file → Executable file
View File

@ -1,4 +1,4 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
@ -23,7 +23,6 @@ else:
# This should contain all of the _SOURCES from files.mk, except *_machine.cpp
UNIFIED_SOURCES += [
'Bidi.cpp',
'CachedFace.cpp',
'CmapCache.cpp',
'Code.cpp',
@ -45,7 +44,6 @@ UNIFIED_SOURCES += [
'Intervals.cpp',
'json.cpp',
'Justifier.cpp',
'NameTable.cpp',
'Pass.cpp',
'Position.cpp',
'SegCache.cpp',
@ -59,6 +57,12 @@ UNIFIED_SOURCES += [
'UtfCodec.cpp',
]
# Excluded from UNIFIED_SOURCES because <cmath> from other files breaks it,
# see bug 1272647.
SOURCES += [
'NameTable.cpp',
]
# tell graphite2 not to export symbols, we'll be linking it directly with
# thebes
DEFINES['GRAPHITE2_STATIC'] = True