mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-23 07:37:29 +09:00
Update graphite2 lib to 1.3.10
(from 1.3.8)
This commit is contained in:
parent
9ef2b80564
commit
4f027a0024
11 changed files with 32 additions and 1799 deletions
|
|
@ -1,3 +1,34 @@
|
||||||
|
1.3.10
|
||||||
|
. Address floating point build parameters to give consistent positioning results across platforms
|
||||||
|
. Various bug fixes
|
||||||
|
|
||||||
|
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
|
1.3.4
|
||||||
. Transition from Mercurial to Git
|
. Transition from Mercurial to Git
|
||||||
. Bug fixes
|
. Bug fixes
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +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/Rule.h"
|
|
||||||
#include "inc/Segment.h"
|
|
||||||
|
|
||||||
using namespace graphite2;
|
|
||||||
|
|
@ -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, "<");
|
|
||||||
break;
|
|
||||||
case '>':
|
|
||||||
fprintf(m_file, ">");
|
|
||||||
break;
|
|
||||||
case '&':
|
|
||||||
fprintf(m_file, "&");
|
|
||||||
break;
|
|
||||||
case '"':
|
|
||||||
fprintf(m_file, """);
|
|
||||||
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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||||
# vim: set filetype=python:
|
# vim: set filetype=python:
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
# 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
|
# 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
|
# This should contain all of the _SOURCES from files.mk, except *_machine.cpp
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'Bidi.cpp',
|
|
||||||
'CachedFace.cpp',
|
'CachedFace.cpp',
|
||||||
'CmapCache.cpp',
|
'CmapCache.cpp',
|
||||||
'Code.cpp',
|
'Code.cpp',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue